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