OSDN Git Service

auto import from //branches/cupcake/...@126645
[android-x86/build.git] / tools / applypatch / xdelta3.c
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <errno.h>
22 #include <unistd.h>
23
24 #include "xdelta3.h"
25 #include "mincrypt/sha.h"
26
27 int ApplyXDelta3Patch(const unsigned char* old_data, ssize_t old_size,
28                       const char* patch_filename,
29                       FILE* output, SHA_CTX* ctx) {
30 #define WINDOW_SIZE 32768
31
32   int ret;
33   xd3_stream stream;
34   xd3_config config;
35
36   xd3_init_config(&config, 0);
37   config.winsize = WINDOW_SIZE;
38   ret = xd3_config_stream(&stream, &config);
39   if (ret != 0) {
40     fprintf(stderr, "xd3_config_stream error: %s\n", xd3_strerror(ret));
41     return 1;
42   }
43
44   // In xdelta3 terms, the "input" is the patch file: it contains a
45   // sequence of instruction codes and data that will be executed to
46   // produce the output file.  The "source" is the original data file;
47   // it is a blob of data to which instructions in the input may refer
48   // (eg, an instruction may say "copy such-and-such range of bytes
49   // from the source to the output").
50
51   // For simplicity, we provide the entire source to xdelta as a
52   // single block.  This means it should never have to ask us to load
53   // blocks of the source file.
54   xd3_source source;
55   source.name = "old name";
56   source.size = old_size;
57   source.ioh = NULL;
58   source.blksize = old_size;
59   source.curblkno = 0;
60   source.curblk = old_data;
61   source.onblk = old_size;
62
63   ret = xd3_set_source(&stream, &source);
64   if (ret != 0) {
65     fprintf(stderr, "xd3_set_source error: %s\n", xd3_strerror(ret));
66     return 1;
67   }
68
69   unsigned char buffer[WINDOW_SIZE];
70   FILE* input = fopen(patch_filename, "rb");
71   if (input == NULL) {
72     fprintf(stderr, "failed to open patch file %s: %d (%s)\n",
73             patch_filename, errno, strerror(errno));
74     return 1;
75   }
76
77   size_t bytes_read;
78
79   do {
80     bytes_read = fread(buffer, 1, WINDOW_SIZE, input);
81     if (feof(input)) {
82       xd3_set_flags(&stream, XD3_FLUSH);
83     }
84     xd3_avail_input(&stream, buffer, bytes_read);
85  process:
86     ret = xd3_decode_input(&stream);
87     switch (ret) {
88       case XD3_INPUT:
89         continue;
90       case XD3_OUTPUT:
91         SHA_update(ctx, stream.next_out, stream.avail_out);
92         if (fwrite(stream.next_out, 1, stream.avail_out, output) !=
93             stream.avail_out) {
94           fprintf(stderr, "short write of output file: %d (%s)\n",
95                   errno, strerror(errno));
96           return 1;
97         }
98         xd3_consume_output(&stream);
99         goto process;
100       case XD3_GETSRCBLK:
101         // We provided the entire source file already; it should never
102         // have to ask us for a block.
103         fprintf(stderr, "xd3_decode_input: unexpected GETSRCBLK\n");
104         return 1;
105       case XD3_GOTHEADER:
106       case XD3_WINSTART:
107       case XD3_WINFINISH:
108         // These are informational events we don't care about.
109         goto process;
110       default:
111         fprintf(stderr, "xd3_decode_input: unknown error %s (%s)\n",
112                 xd3_strerror(ret), stream.msg);
113         return 1;
114     }
115   } while (!feof(input));
116
117   fclose(input);
118   return 0;
119
120 #undef WINDOW_SIZE
121 }