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