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