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