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