1275793eaSopenharmony_ci/* 2275793eaSopenharmony_ci Additional tools for Minizip 3275793eaSopenharmony_ci Code: Xavier Roche '2004 4275793eaSopenharmony_ci License: Same as ZLIB (www.gzip.org) 5275793eaSopenharmony_ci*/ 6275793eaSopenharmony_ci 7275793eaSopenharmony_ci/* Code */ 8275793eaSopenharmony_ci#include <stdio.h> 9275793eaSopenharmony_ci#include <stdlib.h> 10275793eaSopenharmony_ci#include <string.h> 11275793eaSopenharmony_ci#include "zlib.h" 12275793eaSopenharmony_ci#include "unzip.h" 13275793eaSopenharmony_ci 14275793eaSopenharmony_ci#define READ_8(adr) ((unsigned char)*(adr)) 15275793eaSopenharmony_ci#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) 16275793eaSopenharmony_ci#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) 17275793eaSopenharmony_ci 18275793eaSopenharmony_ci#define WRITE_8(buff, n) do { \ 19275793eaSopenharmony_ci *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ 20275793eaSopenharmony_ci} while(0) 21275793eaSopenharmony_ci#define WRITE_16(buff, n) do { \ 22275793eaSopenharmony_ci WRITE_8((unsigned char*)(buff), n); \ 23275793eaSopenharmony_ci WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ 24275793eaSopenharmony_ci} while(0) 25275793eaSopenharmony_ci#define WRITE_32(buff, n) do { \ 26275793eaSopenharmony_ci WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ 27275793eaSopenharmony_ci WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ 28275793eaSopenharmony_ci} while(0) 29275793eaSopenharmony_ci 30275793eaSopenharmony_ciextern int ZEXPORT unzRepair(const char* file, 31275793eaSopenharmony_ci const char* fileOut, 32275793eaSopenharmony_ci const char* fileOutTmp, 33275793eaSopenharmony_ci uLong* nRecovered, 34275793eaSopenharmony_ci uLong* bytesRecovered) 35275793eaSopenharmony_ci{ 36275793eaSopenharmony_ci int err = Z_OK; 37275793eaSopenharmony_ci FILE* fpZip = fopen(file, "rb"); 38275793eaSopenharmony_ci FILE* fpOut = fopen(fileOut, "wb"); 39275793eaSopenharmony_ci FILE* fpOutCD = fopen(fileOutTmp, "wb"); 40275793eaSopenharmony_ci if (fpZip != NULL && fpOut != NULL) { 41275793eaSopenharmony_ci int entries = 0; 42275793eaSopenharmony_ci uLong totalBytes = 0; 43275793eaSopenharmony_ci char header[30]; 44275793eaSopenharmony_ci char filename[1024]; 45275793eaSopenharmony_ci char extra[1024]; 46275793eaSopenharmony_ci int offset = 0; 47275793eaSopenharmony_ci int offsetCD = 0; 48275793eaSopenharmony_ci while ( fread(header, 1, 30, fpZip) == 30 ) { 49275793eaSopenharmony_ci int currentOffset = offset; 50275793eaSopenharmony_ci 51275793eaSopenharmony_ci /* File entry */ 52275793eaSopenharmony_ci if (READ_32(header) == 0x04034b50) { 53275793eaSopenharmony_ci unsigned int version = READ_16(header + 4); 54275793eaSopenharmony_ci unsigned int gpflag = READ_16(header + 6); 55275793eaSopenharmony_ci unsigned int method = READ_16(header + 8); 56275793eaSopenharmony_ci unsigned int filetime = READ_16(header + 10); 57275793eaSopenharmony_ci unsigned int filedate = READ_16(header + 12); 58275793eaSopenharmony_ci unsigned int crc = READ_32(header + 14); /* crc */ 59275793eaSopenharmony_ci unsigned int cpsize = READ_32(header + 18); /* compressed size */ 60275793eaSopenharmony_ci unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ 61275793eaSopenharmony_ci unsigned int fnsize = READ_16(header + 26); /* file name length */ 62275793eaSopenharmony_ci unsigned int extsize = READ_16(header + 28); /* extra field length */ 63275793eaSopenharmony_ci filename[0] = extra[0] = '\0'; 64275793eaSopenharmony_ci 65275793eaSopenharmony_ci /* Header */ 66275793eaSopenharmony_ci if (fwrite(header, 1, 30, fpOut) == 30) { 67275793eaSopenharmony_ci offset += 30; 68275793eaSopenharmony_ci } else { 69275793eaSopenharmony_ci err = Z_ERRNO; 70275793eaSopenharmony_ci break; 71275793eaSopenharmony_ci } 72275793eaSopenharmony_ci 73275793eaSopenharmony_ci /* Filename */ 74275793eaSopenharmony_ci if (fnsize > 0) { 75275793eaSopenharmony_ci if (fnsize < sizeof(filename)) { 76275793eaSopenharmony_ci if (fread(filename, 1, fnsize, fpZip) == fnsize) { 77275793eaSopenharmony_ci if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { 78275793eaSopenharmony_ci offset += fnsize; 79275793eaSopenharmony_ci } else { 80275793eaSopenharmony_ci err = Z_ERRNO; 81275793eaSopenharmony_ci break; 82275793eaSopenharmony_ci } 83275793eaSopenharmony_ci } else { 84275793eaSopenharmony_ci err = Z_ERRNO; 85275793eaSopenharmony_ci break; 86275793eaSopenharmony_ci } 87275793eaSopenharmony_ci } else { 88275793eaSopenharmony_ci err = Z_ERRNO; 89275793eaSopenharmony_ci break; 90275793eaSopenharmony_ci } 91275793eaSopenharmony_ci } else { 92275793eaSopenharmony_ci err = Z_STREAM_ERROR; 93275793eaSopenharmony_ci break; 94275793eaSopenharmony_ci } 95275793eaSopenharmony_ci 96275793eaSopenharmony_ci /* Extra field */ 97275793eaSopenharmony_ci if (extsize > 0) { 98275793eaSopenharmony_ci if (extsize < sizeof(extra)) { 99275793eaSopenharmony_ci if (fread(extra, 1, extsize, fpZip) == extsize) { 100275793eaSopenharmony_ci if (fwrite(extra, 1, extsize, fpOut) == extsize) { 101275793eaSopenharmony_ci offset += extsize; 102275793eaSopenharmony_ci } else { 103275793eaSopenharmony_ci err = Z_ERRNO; 104275793eaSopenharmony_ci break; 105275793eaSopenharmony_ci } 106275793eaSopenharmony_ci } else { 107275793eaSopenharmony_ci err = Z_ERRNO; 108275793eaSopenharmony_ci break; 109275793eaSopenharmony_ci } 110275793eaSopenharmony_ci } else { 111275793eaSopenharmony_ci err = Z_ERRNO; 112275793eaSopenharmony_ci break; 113275793eaSopenharmony_ci } 114275793eaSopenharmony_ci } 115275793eaSopenharmony_ci 116275793eaSopenharmony_ci /* Data */ 117275793eaSopenharmony_ci { 118275793eaSopenharmony_ci int dataSize = cpsize; 119275793eaSopenharmony_ci if (dataSize == 0) { 120275793eaSopenharmony_ci dataSize = uncpsize; 121275793eaSopenharmony_ci } 122275793eaSopenharmony_ci if (dataSize > 0) { 123275793eaSopenharmony_ci char* data = malloc(dataSize); 124275793eaSopenharmony_ci if (data != NULL) { 125275793eaSopenharmony_ci if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { 126275793eaSopenharmony_ci if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { 127275793eaSopenharmony_ci offset += dataSize; 128275793eaSopenharmony_ci totalBytes += dataSize; 129275793eaSopenharmony_ci } else { 130275793eaSopenharmony_ci err = Z_ERRNO; 131275793eaSopenharmony_ci } 132275793eaSopenharmony_ci } else { 133275793eaSopenharmony_ci err = Z_ERRNO; 134275793eaSopenharmony_ci } 135275793eaSopenharmony_ci free(data); 136275793eaSopenharmony_ci if (err != Z_OK) { 137275793eaSopenharmony_ci break; 138275793eaSopenharmony_ci } 139275793eaSopenharmony_ci } else { 140275793eaSopenharmony_ci err = Z_MEM_ERROR; 141275793eaSopenharmony_ci break; 142275793eaSopenharmony_ci } 143275793eaSopenharmony_ci } 144275793eaSopenharmony_ci } 145275793eaSopenharmony_ci 146275793eaSopenharmony_ci /* Central directory entry */ 147275793eaSopenharmony_ci { 148275793eaSopenharmony_ci char header[46]; 149275793eaSopenharmony_ci char* comment = ""; 150275793eaSopenharmony_ci int comsize = (int) strlen(comment); 151275793eaSopenharmony_ci WRITE_32(header, 0x02014b50); 152275793eaSopenharmony_ci WRITE_16(header + 4, version); 153275793eaSopenharmony_ci WRITE_16(header + 6, version); 154275793eaSopenharmony_ci WRITE_16(header + 8, gpflag); 155275793eaSopenharmony_ci WRITE_16(header + 10, method); 156275793eaSopenharmony_ci WRITE_16(header + 12, filetime); 157275793eaSopenharmony_ci WRITE_16(header + 14, filedate); 158275793eaSopenharmony_ci WRITE_32(header + 16, crc); 159275793eaSopenharmony_ci WRITE_32(header + 20, cpsize); 160275793eaSopenharmony_ci WRITE_32(header + 24, uncpsize); 161275793eaSopenharmony_ci WRITE_16(header + 28, fnsize); 162275793eaSopenharmony_ci WRITE_16(header + 30, extsize); 163275793eaSopenharmony_ci WRITE_16(header + 32, comsize); 164275793eaSopenharmony_ci WRITE_16(header + 34, 0); /* disk # */ 165275793eaSopenharmony_ci WRITE_16(header + 36, 0); /* int attrb */ 166275793eaSopenharmony_ci WRITE_32(header + 38, 0); /* ext attrb */ 167275793eaSopenharmony_ci WRITE_32(header + 42, currentOffset); 168275793eaSopenharmony_ci /* Header */ 169275793eaSopenharmony_ci if (fwrite(header, 1, 46, fpOutCD) == 46) { 170275793eaSopenharmony_ci offsetCD += 46; 171275793eaSopenharmony_ci 172275793eaSopenharmony_ci /* Filename */ 173275793eaSopenharmony_ci if (fnsize > 0) { 174275793eaSopenharmony_ci if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { 175275793eaSopenharmony_ci offsetCD += fnsize; 176275793eaSopenharmony_ci } else { 177275793eaSopenharmony_ci err = Z_ERRNO; 178275793eaSopenharmony_ci break; 179275793eaSopenharmony_ci } 180275793eaSopenharmony_ci } else { 181275793eaSopenharmony_ci err = Z_STREAM_ERROR; 182275793eaSopenharmony_ci break; 183275793eaSopenharmony_ci } 184275793eaSopenharmony_ci 185275793eaSopenharmony_ci /* Extra field */ 186275793eaSopenharmony_ci if (extsize > 0) { 187275793eaSopenharmony_ci if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { 188275793eaSopenharmony_ci offsetCD += extsize; 189275793eaSopenharmony_ci } else { 190275793eaSopenharmony_ci err = Z_ERRNO; 191275793eaSopenharmony_ci break; 192275793eaSopenharmony_ci } 193275793eaSopenharmony_ci } 194275793eaSopenharmony_ci 195275793eaSopenharmony_ci /* Comment field */ 196275793eaSopenharmony_ci if (comsize > 0) { 197275793eaSopenharmony_ci if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { 198275793eaSopenharmony_ci offsetCD += comsize; 199275793eaSopenharmony_ci } else { 200275793eaSopenharmony_ci err = Z_ERRNO; 201275793eaSopenharmony_ci break; 202275793eaSopenharmony_ci } 203275793eaSopenharmony_ci } 204275793eaSopenharmony_ci 205275793eaSopenharmony_ci 206275793eaSopenharmony_ci } else { 207275793eaSopenharmony_ci err = Z_ERRNO; 208275793eaSopenharmony_ci break; 209275793eaSopenharmony_ci } 210275793eaSopenharmony_ci } 211275793eaSopenharmony_ci 212275793eaSopenharmony_ci /* Success */ 213275793eaSopenharmony_ci entries++; 214275793eaSopenharmony_ci 215275793eaSopenharmony_ci } else { 216275793eaSopenharmony_ci break; 217275793eaSopenharmony_ci } 218275793eaSopenharmony_ci } 219275793eaSopenharmony_ci 220275793eaSopenharmony_ci /* Final central directory */ 221275793eaSopenharmony_ci { 222275793eaSopenharmony_ci int entriesZip = entries; 223275793eaSopenharmony_ci char header[22]; 224275793eaSopenharmony_ci char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; 225275793eaSopenharmony_ci int comsize = (int) strlen(comment); 226275793eaSopenharmony_ci if (entriesZip > 0xffff) { 227275793eaSopenharmony_ci entriesZip = 0xffff; 228275793eaSopenharmony_ci } 229275793eaSopenharmony_ci WRITE_32(header, 0x06054b50); 230275793eaSopenharmony_ci WRITE_16(header + 4, 0); /* disk # */ 231275793eaSopenharmony_ci WRITE_16(header + 6, 0); /* disk # */ 232275793eaSopenharmony_ci WRITE_16(header + 8, entriesZip); /* hack */ 233275793eaSopenharmony_ci WRITE_16(header + 10, entriesZip); /* hack */ 234275793eaSopenharmony_ci WRITE_32(header + 12, offsetCD); /* size of CD */ 235275793eaSopenharmony_ci WRITE_32(header + 16, offset); /* offset to CD */ 236275793eaSopenharmony_ci WRITE_16(header + 20, comsize); /* comment */ 237275793eaSopenharmony_ci 238275793eaSopenharmony_ci /* Header */ 239275793eaSopenharmony_ci if (fwrite(header, 1, 22, fpOutCD) == 22) { 240275793eaSopenharmony_ci 241275793eaSopenharmony_ci /* Comment field */ 242275793eaSopenharmony_ci if (comsize > 0) { 243275793eaSopenharmony_ci if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { 244275793eaSopenharmony_ci err = Z_ERRNO; 245275793eaSopenharmony_ci } 246275793eaSopenharmony_ci } 247275793eaSopenharmony_ci 248275793eaSopenharmony_ci } else { 249275793eaSopenharmony_ci err = Z_ERRNO; 250275793eaSopenharmony_ci } 251275793eaSopenharmony_ci } 252275793eaSopenharmony_ci 253275793eaSopenharmony_ci /* Final merge (file + central directory) */ 254275793eaSopenharmony_ci fclose(fpOutCD); 255275793eaSopenharmony_ci if (err == Z_OK) { 256275793eaSopenharmony_ci fpOutCD = fopen(fileOutTmp, "rb"); 257275793eaSopenharmony_ci if (fpOutCD != NULL) { 258275793eaSopenharmony_ci int nRead; 259275793eaSopenharmony_ci char buffer[8192]; 260275793eaSopenharmony_ci while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { 261275793eaSopenharmony_ci if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { 262275793eaSopenharmony_ci err = Z_ERRNO; 263275793eaSopenharmony_ci break; 264275793eaSopenharmony_ci } 265275793eaSopenharmony_ci } 266275793eaSopenharmony_ci fclose(fpOutCD); 267275793eaSopenharmony_ci } 268275793eaSopenharmony_ci } 269275793eaSopenharmony_ci 270275793eaSopenharmony_ci /* Close */ 271275793eaSopenharmony_ci fclose(fpZip); 272275793eaSopenharmony_ci fclose(fpOut); 273275793eaSopenharmony_ci 274275793eaSopenharmony_ci /* Wipe temporary file */ 275275793eaSopenharmony_ci (void)remove(fileOutTmp); 276275793eaSopenharmony_ci 277275793eaSopenharmony_ci /* Number of recovered entries */ 278275793eaSopenharmony_ci if (err == Z_OK) { 279275793eaSopenharmony_ci if (nRecovered != NULL) { 280275793eaSopenharmony_ci *nRecovered = entries; 281275793eaSopenharmony_ci } 282275793eaSopenharmony_ci if (bytesRecovered != NULL) { 283275793eaSopenharmony_ci *bytesRecovered = totalBytes; 284275793eaSopenharmony_ci } 285275793eaSopenharmony_ci } 286275793eaSopenharmony_ci } else { 287275793eaSopenharmony_ci err = Z_STREAM_ERROR; 288275793eaSopenharmony_ci } 289275793eaSopenharmony_ci return err; 290275793eaSopenharmony_ci} 291