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