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