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