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