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