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