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