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