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