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