nuclear@3: /* nuclear@3: Additional tools for Minizip nuclear@3: Code: Xavier Roche '2004 nuclear@3: License: Same as ZLIB (www.gzip.org) nuclear@3: */ nuclear@3: nuclear@3: /* Code */ nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #include "zlib.h" nuclear@3: #include "unzip.h" nuclear@3: nuclear@3: #define READ_8(adr) ((unsigned char)*(adr)) nuclear@3: #define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) nuclear@3: #define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) nuclear@3: nuclear@3: #define WRITE_8(buff, n) do { \ nuclear@3: *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ nuclear@3: } while(0) nuclear@3: #define WRITE_16(buff, n) do { \ nuclear@3: WRITE_8((unsigned char*)(buff), n); \ nuclear@3: WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ nuclear@3: } while(0) nuclear@3: #define WRITE_32(buff, n) do { \ nuclear@3: WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ nuclear@3: WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ nuclear@3: } while(0) nuclear@3: nuclear@3: extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) nuclear@3: const char* file; nuclear@3: const char* fileOut; nuclear@3: const char* fileOutTmp; nuclear@3: uLong* nRecovered; nuclear@3: uLong* bytesRecovered; nuclear@3: { nuclear@3: int err = Z_OK; nuclear@3: FILE* fpZip = fopen(file, "rb"); nuclear@3: FILE* fpOut = fopen(fileOut, "wb"); nuclear@3: FILE* fpOutCD = fopen(fileOutTmp, "wb"); nuclear@3: if (fpZip != NULL && fpOut != NULL) { nuclear@3: int entries = 0; nuclear@3: uLong totalBytes = 0; nuclear@3: char header[30]; nuclear@3: char filename[1024]; nuclear@3: char extra[1024]; nuclear@3: int offset = 0; nuclear@3: int offsetCD = 0; nuclear@3: while ( fread(header, 1, 30, fpZip) == 30 ) { nuclear@3: int currentOffset = offset; nuclear@3: nuclear@3: /* File entry */ nuclear@3: if (READ_32(header) == 0x04034b50) { nuclear@3: unsigned int version = READ_16(header + 4); nuclear@3: unsigned int gpflag = READ_16(header + 6); nuclear@3: unsigned int method = READ_16(header + 8); nuclear@3: unsigned int filetime = READ_16(header + 10); nuclear@3: unsigned int filedate = READ_16(header + 12); nuclear@3: unsigned int crc = READ_32(header + 14); /* crc */ nuclear@3: unsigned int cpsize = READ_32(header + 18); /* compressed size */ nuclear@3: unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ nuclear@3: unsigned int fnsize = READ_16(header + 26); /* file name length */ nuclear@3: unsigned int extsize = READ_16(header + 28); /* extra field length */ nuclear@3: filename[0] = extra[0] = '\0'; nuclear@3: nuclear@3: /* Header */ nuclear@3: if (fwrite(header, 1, 30, fpOut) == 30) { nuclear@3: offset += 30; nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: nuclear@3: /* Filename */ nuclear@3: if (fnsize > 0) { nuclear@3: if (fnsize < sizeof(filename)) { nuclear@3: if (fread(filename, 1, fnsize, fpZip) == fnsize) { nuclear@3: if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { nuclear@3: offset += fnsize; nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_STREAM_ERROR; nuclear@3: break; nuclear@3: } nuclear@3: nuclear@3: /* Extra field */ nuclear@3: if (extsize > 0) { nuclear@3: if (extsize < sizeof(extra)) { nuclear@3: if (fread(extra, 1, extsize, fpZip) == extsize) { nuclear@3: if (fwrite(extra, 1, extsize, fpOut) == extsize) { nuclear@3: offset += extsize; nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: /* Data */ nuclear@3: { nuclear@3: int dataSize = cpsize; nuclear@3: if (dataSize == 0) { nuclear@3: dataSize = uncpsize; nuclear@3: } nuclear@3: if (dataSize > 0) { nuclear@3: char* data = malloc(dataSize); nuclear@3: if (data != NULL) { nuclear@3: if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { nuclear@3: if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { nuclear@3: offset += dataSize; nuclear@3: totalBytes += dataSize; nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: } nuclear@3: free(data); nuclear@3: if (err != Z_OK) { nuclear@3: break; nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_MEM_ERROR; nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: /* Central directory entry */ nuclear@3: { nuclear@3: char header[46]; nuclear@3: char* comment = ""; nuclear@3: int comsize = (int) strlen(comment); nuclear@3: WRITE_32(header, 0x02014b50); nuclear@3: WRITE_16(header + 4, version); nuclear@3: WRITE_16(header + 6, version); nuclear@3: WRITE_16(header + 8, gpflag); nuclear@3: WRITE_16(header + 10, method); nuclear@3: WRITE_16(header + 12, filetime); nuclear@3: WRITE_16(header + 14, filedate); nuclear@3: WRITE_32(header + 16, crc); nuclear@3: WRITE_32(header + 20, cpsize); nuclear@3: WRITE_32(header + 24, uncpsize); nuclear@3: WRITE_16(header + 28, fnsize); nuclear@3: WRITE_16(header + 30, extsize); nuclear@3: WRITE_16(header + 32, comsize); nuclear@3: WRITE_16(header + 34, 0); /* disk # */ nuclear@3: WRITE_16(header + 36, 0); /* int attrb */ nuclear@3: WRITE_32(header + 38, 0); /* ext attrb */ nuclear@3: WRITE_32(header + 42, currentOffset); nuclear@3: /* Header */ nuclear@3: if (fwrite(header, 1, 46, fpOutCD) == 46) { nuclear@3: offsetCD += 46; nuclear@3: nuclear@3: /* Filename */ nuclear@3: if (fnsize > 0) { nuclear@3: if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { nuclear@3: offsetCD += fnsize; nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_STREAM_ERROR; nuclear@3: break; nuclear@3: } nuclear@3: nuclear@3: /* Extra field */ nuclear@3: if (extsize > 0) { nuclear@3: if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { nuclear@3: offsetCD += extsize; nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: /* Comment field */ nuclear@3: if (comsize > 0) { nuclear@3: if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { nuclear@3: offsetCD += comsize; nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: /* Success */ nuclear@3: entries++; nuclear@3: nuclear@3: } else { nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: /* Final central directory */ nuclear@3: { nuclear@3: int entriesZip = entries; nuclear@3: char header[22]; nuclear@3: char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; nuclear@3: int comsize = (int) strlen(comment); nuclear@3: if (entriesZip > 0xffff) { nuclear@3: entriesZip = 0xffff; nuclear@3: } nuclear@3: WRITE_32(header, 0x06054b50); nuclear@3: WRITE_16(header + 4, 0); /* disk # */ nuclear@3: WRITE_16(header + 6, 0); /* disk # */ nuclear@3: WRITE_16(header + 8, entriesZip); /* hack */ nuclear@3: WRITE_16(header + 10, entriesZip); /* hack */ nuclear@3: WRITE_32(header + 12, offsetCD); /* size of CD */ nuclear@3: WRITE_32(header + 16, offset); /* offset to CD */ nuclear@3: WRITE_16(header + 20, comsize); /* comment */ nuclear@3: nuclear@3: /* Header */ nuclear@3: if (fwrite(header, 1, 22, fpOutCD) == 22) { nuclear@3: nuclear@3: /* Comment field */ nuclear@3: if (comsize > 0) { nuclear@3: if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { nuclear@3: err = Z_ERRNO; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: } else { nuclear@3: err = Z_ERRNO; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: /* Final merge (file + central directory) */ nuclear@3: fclose(fpOutCD); nuclear@3: if (err == Z_OK) { nuclear@3: fpOutCD = fopen(fileOutTmp, "rb"); nuclear@3: if (fpOutCD != NULL) { nuclear@3: int nRead; nuclear@3: char buffer[8192]; nuclear@3: while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { nuclear@3: if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { nuclear@3: err = Z_ERRNO; nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: fclose(fpOutCD); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: /* Close */ nuclear@3: fclose(fpZip); nuclear@3: fclose(fpOut); nuclear@3: nuclear@3: /* Wipe temporary file */ nuclear@3: (void)remove(fileOutTmp); nuclear@3: nuclear@3: /* Number of recovered entries */ nuclear@3: if (err == Z_OK) { nuclear@3: if (nRecovered != NULL) { nuclear@3: *nRecovered = entries; nuclear@3: } nuclear@3: if (bytesRecovered != NULL) { nuclear@3: *bytesRecovered = totalBytes; nuclear@3: } nuclear@3: } nuclear@3: } else { nuclear@3: err = Z_STREAM_ERROR; nuclear@3: } nuclear@3: return err; nuclear@3: }