mztools.c 7.9 KB

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