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