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