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