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