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