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