1 /*
2 Additional tools for Minizip
3 Code: Xavier Roche '2004
4 License: Same as ZLIB (www.gzip.org)
5 */
6
7 /* Code */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "zlib.h"
12 #include "unzip.h"
13
14 #define READ_8(adr) ((unsigned char)*(adr))
15 #define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) )
16 #define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) )
17
18 #define WRITE_8(buff, n) do { \
19 *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \
20 } while(0)
21 #define WRITE_16(buff, n) do { \
22 WRITE_8((unsigned char*)(buff), n); \
23 WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \
24 } while(0)
25 #define WRITE_32(buff, n) do { \
26 WRITE_16((unsigned char*)(buff), (n) & 0xffff); \
27 WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \
28 } while(0)
29
unzRepair(const char* file, const char* fileOut, const char* fileOutTmp, uLong* nRecovered, uLong* bytesRecovered)30 extern int ZEXPORT unzRepair(const char* file,
31 const char* fileOut,
32 const char* fileOutTmp,
33 uLong* nRecovered,
34 uLong* bytesRecovered)
35 {
36 int err = Z_OK;
37 FILE* fpZip = fopen(file, "rb");
38 FILE* fpOut = fopen(fileOut, "wb");
39 FILE* fpOutCD = fopen(fileOutTmp, "wb");
40 if (fpZip != NULL && fpOut != NULL) {
41 int entries = 0;
42 uLong totalBytes = 0;
43 char header[30];
44 char filename[1024];
45 char extra[1024];
46 int offset = 0;
47 int offsetCD = 0;
48 while ( fread(header, 1, 30, fpZip) == 30 ) {
49 int currentOffset = offset;
50
51 /* File entry */
52 if (READ_32(header) == 0x04034b50) {
53 unsigned int version = READ_16(header + 4);
54 unsigned int gpflag = READ_16(header + 6);
55 unsigned int method = READ_16(header + 8);
56 unsigned int filetime = READ_16(header + 10);
57 unsigned int filedate = READ_16(header + 12);
58 unsigned int crc = READ_32(header + 14); /* crc */
59 unsigned int cpsize = READ_32(header + 18); /* compressed size */
60 unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */
61 unsigned int fnsize = READ_16(header + 26); /* file name length */
62 unsigned int extsize = READ_16(header + 28); /* extra field length */
63 filename[0] = extra[0] = '\0';
64
65 /* Header */
66 if (fwrite(header, 1, 30, fpOut) == 30) {
67 offset += 30;
68 } else {
69 err = Z_ERRNO;
70 break;
71 }
72
73 /* Filename */
74 if (fnsize > 0) {
75 if (fnsize < sizeof(filename)) {
76 if (fread(filename, 1, fnsize, fpZip) == fnsize) {
77 if (fwrite(filename, 1, fnsize, fpOut) == fnsize) {
78 offset += fnsize;
79 } else {
80 err = Z_ERRNO;
81 break;
82 }
83 } else {
84 err = Z_ERRNO;
85 break;
86 }
87 } else {
88 err = Z_ERRNO;
89 break;
90 }
91 } else {
92 err = Z_STREAM_ERROR;
93 break;
94 }
95
96 /* Extra field */
97 if (extsize > 0) {
98 if (extsize < sizeof(extra)) {
99 if (fread(extra, 1, extsize, fpZip) == extsize) {
100 if (fwrite(extra, 1, extsize, fpOut) == extsize) {
101 offset += extsize;
102 } else {
103 err = Z_ERRNO;
104 break;
105 }
106 } else {
107 err = Z_ERRNO;
108 break;
109 }
110 } else {
111 err = Z_ERRNO;
112 break;
113 }
114 }
115
116 /* Data */
117 {
118 int dataSize = cpsize;
119 if (dataSize == 0) {
120 dataSize = uncpsize;
121 }
122 if (dataSize > 0) {
123 char* data = malloc(dataSize);
124 if (data != NULL) {
125 if ((int)fread(data, 1, dataSize, fpZip) == dataSize) {
126 if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) {
127 offset += dataSize;
128 totalBytes += dataSize;
129 } else {
130 err = Z_ERRNO;
131 }
132 } else {
133 err = Z_ERRNO;
134 }
135 free(data);
136 if (err != Z_OK) {
137 break;
138 }
139 } else {
140 err = Z_MEM_ERROR;
141 break;
142 }
143 }
144 }
145
146 /* Central directory entry */
147 {
148 char header[46];
149 char* comment = "";
150 int comsize = (int) strlen(comment);
151 WRITE_32(header, 0x02014b50);
152 WRITE_16(header + 4, version);
153 WRITE_16(header + 6, version);
154 WRITE_16(header + 8, gpflag);
155 WRITE_16(header + 10, method);
156 WRITE_16(header + 12, filetime);
157 WRITE_16(header + 14, filedate);
158 WRITE_32(header + 16, crc);
159 WRITE_32(header + 20, cpsize);
160 WRITE_32(header + 24, uncpsize);
161 WRITE_16(header + 28, fnsize);
162 WRITE_16(header + 30, extsize);
163 WRITE_16(header + 32, comsize);
164 WRITE_16(header + 34, 0); /* disk # */
165 WRITE_16(header + 36, 0); /* int attrb */
166 WRITE_32(header + 38, 0); /* ext attrb */
167 WRITE_32(header + 42, currentOffset);
168 /* Header */
169 if (fwrite(header, 1, 46, fpOutCD) == 46) {
170 offsetCD += 46;
171
172 /* Filename */
173 if (fnsize > 0) {
174 if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) {
175 offsetCD += fnsize;
176 } else {
177 err = Z_ERRNO;
178 break;
179 }
180 } else {
181 err = Z_STREAM_ERROR;
182 break;
183 }
184
185 /* Extra field */
186 if (extsize > 0) {
187 if (fwrite(extra, 1, extsize, fpOutCD) == extsize) {
188 offsetCD += extsize;
189 } else {
190 err = Z_ERRNO;
191 break;
192 }
193 }
194
195 /* Comment field */
196 if (comsize > 0) {
197 if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) {
198 offsetCD += comsize;
199 } else {
200 err = Z_ERRNO;
201 break;
202 }
203 }
204
205
206 } else {
207 err = Z_ERRNO;
208 break;
209 }
210 }
211
212 /* Success */
213 entries++;
214
215 } else {
216 break;
217 }
218 }
219
220 /* Final central directory */
221 {
222 int entriesZip = entries;
223 char header[22];
224 char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools";
225 int comsize = (int) strlen(comment);
226 if (entriesZip > 0xffff) {
227 entriesZip = 0xffff;
228 }
229 WRITE_32(header, 0x06054b50);
230 WRITE_16(header + 4, 0); /* disk # */
231 WRITE_16(header + 6, 0); /* disk # */
232 WRITE_16(header + 8, entriesZip); /* hack */
233 WRITE_16(header + 10, entriesZip); /* hack */
234 WRITE_32(header + 12, offsetCD); /* size of CD */
235 WRITE_32(header + 16, offset); /* offset to CD */
236 WRITE_16(header + 20, comsize); /* comment */
237
238 /* Header */
239 if (fwrite(header, 1, 22, fpOutCD) == 22) {
240
241 /* Comment field */
242 if (comsize > 0) {
243 if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) {
244 err = Z_ERRNO;
245 }
246 }
247
248 } else {
249 err = Z_ERRNO;
250 }
251 }
252
253 /* Final merge (file + central directory) */
254 fclose(fpOutCD);
255 if (err == Z_OK) {
256 fpOutCD = fopen(fileOutTmp, "rb");
257 if (fpOutCD != NULL) {
258 int nRead;
259 char buffer[8192];
260 while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) {
261 if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) {
262 err = Z_ERRNO;
263 break;
264 }
265 }
266 fclose(fpOutCD);
267 }
268 }
269
270 /* Close */
271 fclose(fpZip);
272 fclose(fpOut);
273
274 /* Wipe temporary file */
275 (void)remove(fileOutTmp);
276
277 /* Number of recovered entries */
278 if (err == Z_OK) {
279 if (nRecovered != NULL) {
280 *nRecovered = entries;
281 }
282 if (bytesRecovered != NULL) {
283 *bytesRecovered = totalBytes;
284 }
285 }
286 } else {
287 err = Z_STREAM_ERROR;
288 }
289 return err;
290 }
291