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