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[256];
     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 (fread(filename, 1, fnsize, fpZip) == fnsize) {
     77             if (fwrite(filename, 1, fnsize, fpOut) == fnsize) {
     78               offset += fnsize;
     79             } else {
     80               err = Z_ERRNO;
     81               break;
     82             }
     83           } else {
     84             err = Z_ERRNO;
     85             break;
     86           }
     87         } else {
     88           err = Z_STREAM_ERROR;
     89           break;
     90         }
     91 
     92         /* Extra field */
     93         if (extsize > 0) {
     94           if (fread(extra, 1, extsize, fpZip) == extsize) {
     95             if (fwrite(extra, 1, extsize, fpOut) == extsize) {
     96               offset += extsize;
     97             } else {
     98               err = Z_ERRNO;
     99               break;
    100             }
    101           } else {
    102             err = Z_ERRNO;
    103             break;
    104           }
    105         }
    106 
    107         /* Data */
    108         {
    109           int dataSize = cpsize;
    110           if (dataSize == 0) {
    111             dataSize = uncpsize;
    112           }
    113           if (dataSize > 0) {
    114             char* data = malloc(dataSize);
    115             if (data != NULL) {
    116               if ((int)fread(data, 1, dataSize, fpZip) == dataSize) {
    117                 if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) {
    118                   offset += dataSize;
    119                   totalBytes += dataSize;
    120                 } else {
    121                   err = Z_ERRNO;
    122                 }
    123               } else {
    124                 err = Z_ERRNO;
    125               }
    126               free(data);
    127               if (err != Z_OK) {
    128                 break;
    129               }
    130             } else {
    131               err = Z_MEM_ERROR;
    132               break;
    133             }
    134           }
    135         }
    136 
    137         /* Central directory entry */
    138         {
    139           char header[46];
    140           char* comment = "";
    141           int comsize = (int) strlen(comment);
    142           WRITE_32(header, 0x02014b50);
    143           WRITE_16(header + 4, version);
    144           WRITE_16(header + 6, version);
    145           WRITE_16(header + 8, gpflag);
    146           WRITE_16(header + 10, method);
    147           WRITE_16(header + 12, filetime);
    148           WRITE_16(header + 14, filedate);
    149           WRITE_32(header + 16, crc);
    150           WRITE_32(header + 20, cpsize);
    151           WRITE_32(header + 24, uncpsize);
    152           WRITE_16(header + 28, fnsize);
    153           WRITE_16(header + 30, extsize);
    154           WRITE_16(header + 32, comsize);
    155           WRITE_16(header + 34, 0);     /* disk # */
    156           WRITE_16(header + 36, 0);     /* int attrb */
    157           WRITE_32(header + 38, 0);     /* ext attrb */
    158           WRITE_32(header + 42, currentOffset);
    159           /* Header */
    160           if (fwrite(header, 1, 46, fpOutCD) == 46) {
    161             offsetCD += 46;
    162 
    163             /* Filename */
    164             if (fnsize > 0) {
    165               if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) {
    166                 offsetCD += fnsize;
    167               } else {
    168                 err = Z_ERRNO;
    169                 break;
    170               }
    171             } else {
    172               err = Z_STREAM_ERROR;
    173               break;
    174             }
    175 
    176             /* Extra field */
    177             if (extsize > 0) {
    178               if (fwrite(extra, 1, extsize, fpOutCD) == extsize) {
    179                 offsetCD += extsize;
    180               } else {
    181                 err = Z_ERRNO;
    182                 break;
    183               }
    184             }
    185 
    186             /* Comment field */
    187             if (comsize > 0) {
    188               if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) {
    189                 offsetCD += comsize;
    190               } else {
    191                 err = Z_ERRNO;
    192                 break;
    193               }
    194             }
    195 
    196 
    197           } else {
    198             err = Z_ERRNO;
    199             break;
    200           }
    201         }
    202 
    203         /* Success */
    204         entries++;
    205 
    206       } else {
    207         break;
    208       }
    209     }
    210 
    211     /* Final central directory  */
    212     {
    213       int entriesZip = entries;
    214       char header[22];
    215       char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools";
    216       int comsize = (int) strlen(comment);
    217       if (entriesZip > 0xffff) {
    218         entriesZip = 0xffff;
    219       }
    220       WRITE_32(header, 0x06054b50);
    221       WRITE_16(header + 4, 0);    /* disk # */
    222       WRITE_16(header + 6, 0);    /* disk # */
    223       WRITE_16(header + 8, entriesZip);   /* hack */
    224       WRITE_16(header + 10, entriesZip);  /* hack */
    225       WRITE_32(header + 12, offsetCD);    /* size of CD */
    226       WRITE_32(header + 16, offset);      /* offset to CD */
    227       WRITE_16(header + 20, comsize);     /* comment */
    228 
    229       /* Header */
    230       if (fwrite(header, 1, 22, fpOutCD) == 22) {
    231 
    232         /* Comment field */
    233         if (comsize > 0) {
    234           if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) {
    235             err = Z_ERRNO;
    236           }
    237         }
    238 
    239       } else {
    240         err = Z_ERRNO;
    241       }
    242     }
    243 
    244     /* Final merge (file + central directory) */
    245     fclose(fpOutCD);
    246     if (err == Z_OK) {
    247       fpOutCD = fopen(fileOutTmp, "rb");
    248       if (fpOutCD != NULL) {
    249         int nRead;
    250         char buffer[8192];
    251         while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) {
    252           if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) {
    253             err = Z_ERRNO;
    254             break;
    255           }
    256         }
    257         fclose(fpOutCD);
    258       }
    259     }
    260 
    261     /* Close */
    262     fclose(fpZip);
    263     fclose(fpOut);
    264 
    265     /* Wipe temporary file */
    266     (void)remove(fileOutTmp);
    267 
    268     /* Number of recovered entries */
    269     if (err == Z_OK) {
    270       if (nRecovered != NULL) {
    271         *nRecovered = entries;
    272       }
    273       if (bytesRecovered != NULL) {
    274         *bytesRecovered = totalBytes;
    275       }
    276     }
    277   } else {
    278     err = Z_STREAM_ERROR;
    279   }
    280   return err;
    281 }
    282