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