Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

474 lines
13 KiB

  1. //
  2. // gzip.c
  3. //
  4. // All of the gzip-related additions to deflate (both encoder and decoder) are in this file
  5. //
  6. #include <string.h>
  7. #include <stdio.h>
  8. #include <crtdbg.h>
  9. #include "deflate.h"
  10. #include "inflate.h"
  11. #include "infmacro.h"
  12. #include "defgzip.h"
  13. #include "infgzip.h"
  14. #include "crc32.h"
  15. #define GZIP_FLG_FTEXT 1
  16. #define GZIP_FLG_CRC 2
  17. #define GZIP_FLG_FEXTRA 4
  18. #define GZIP_FLG_FNAME 8
  19. #define GZIP_FLG_FCOMMENT 16
  20. typedef enum
  21. {
  22. // GZIP header
  23. GZIP_HDR_STATE_READING_ID1,
  24. GZIP_HDR_STATE_READING_ID2,
  25. GZIP_HDR_STATE_READING_CM,
  26. GZIP_HDR_STATE_READING_FLG,
  27. GZIP_HDR_STATE_READING_MMTIME, // iterates 4 times
  28. GZIP_HDR_STATE_READING_XFL,
  29. GZIP_HDR_STATE_READING_OS,
  30. GZIP_HDR_STATE_READING_XLEN1,
  31. GZIP_HDR_STATE_READING_XLEN2,
  32. GZIP_HDR_STATE_READING_XLEN_DATA,
  33. GZIP_HDR_STATE_READING_FILENAME,
  34. GZIP_HDR_STATE_READING_COMMENT,
  35. GZIP_HDR_STATE_READING_CRC16_PART1,
  36. GZIP_HDR_STATE_READING_CRC16_PART2,
  37. GZIP_HDR_STATE_DONE, // done reading GZIP header
  38. // GZIP footer
  39. GZIP_FTR_STATE_READING_CRC, // iterates 4 times
  40. GZIP_FTR_STATE_READING_FILE_SIZE // iterates 4 times
  41. } t_gzip_state;
  42. void EncoderInitGzipVariables(t_encoder_context *context)
  43. {
  44. context->gzip_crc32 = 0;
  45. context->gzip_input_stream_size = 0;
  46. context->gzip_fOutputGzipHeader = FALSE;
  47. }
  48. void DecoderInitGzipVariables(t_decoder_context *context)
  49. {
  50. context->gzip_crc32 = 0;
  51. context->gzip_output_stream_size = 0;
  52. }
  53. void WriteGzipHeader(t_encoder_context *context, int compression_level)
  54. {
  55. BYTE *output_curpos = context->output_curpos;
  56. // only need 11 bytes
  57. _ASSERT(context->output_curpos + 16 < context->output_endpos);
  58. #ifndef TESTING
  59. // the proper code path
  60. *output_curpos++ = 0x1F; // ID1
  61. *output_curpos++ = 0x8B; // ID2
  62. *output_curpos++ = 8; // CM = deflate
  63. *output_curpos++ = 0; // FLG, no text, no crc, no extra, no name, no comment
  64. *output_curpos++ = 0; // MTIME (Modification Time) - no time available
  65. *output_curpos++ = 0;
  66. *output_curpos++ = 0;
  67. *output_curpos++ = 0;
  68. // XFL
  69. // 2 = compressor used max compression, slowest algorithm
  70. // 4 = compressor used fastest algorithm
  71. if (compression_level == 10)
  72. *output_curpos++ = 2;
  73. else
  74. *output_curpos++ = 4;
  75. *output_curpos++ = 0; // OS: 0 = FAT filesystem (MS-DOS, OS/2, NT/Win32)
  76. #else /* TESTING */
  77. // this code is for code path testing only
  78. // it uses all of the headers to ensure that the decoder can handle them correctly
  79. *output_curpos++ = 0x1F; // ID1
  80. *output_curpos++ = 0x8B; // ID2
  81. *output_curpos++ = 8; // CM = deflate
  82. *output_curpos++ = (GZIP_FLG_CRC|GZIP_FLG_FEXTRA|GZIP_FLG_FNAME|GZIP_FLG_FCOMMENT); // FLG
  83. *output_curpos++ = 0; // MTIME (Modification Time) - no time available
  84. *output_curpos++ = 0;
  85. *output_curpos++ = 0;
  86. *output_curpos++ = 0;
  87. *output_curpos++ = 2; // XFL
  88. *output_curpos++ = 0; // OS: 0 = FAT filesystem (MS-DOS, OS/2, NT/Win32)
  89. // FEXTRA
  90. *output_curpos++ = 3; // LSB
  91. *output_curpos++ = 0; // MSB
  92. output_curpos += 3; // 3 bytes of data
  93. // FNAME, null terminated filename
  94. output_curpos += strlen(strcpy(output_curpos, "my filename"))+1;
  95. // FCOMMENT, null terminated comment
  96. output_curpos += strlen(strcpy(output_curpos, "my comment"))+1;
  97. // CRC16
  98. *output_curpos++ = 0x12;
  99. *output_curpos++ = 0x34;
  100. #endif
  101. context->output_curpos = output_curpos;
  102. }
  103. void WriteGzipFooter(t_encoder_context *context)
  104. {
  105. BYTE *output_curpos = context->output_curpos;
  106. *output_curpos++ = (BYTE) (context->gzip_crc32 & 255);
  107. *output_curpos++ = (BYTE) ((context->gzip_crc32 >> 8) & 255);
  108. *output_curpos++ = (BYTE) ((context->gzip_crc32 >> 16) & 255);
  109. *output_curpos++ = (BYTE) ((context->gzip_crc32 >> 24) & 255);
  110. *output_curpos++ = (BYTE) (context->gzip_input_stream_size & 255);
  111. *output_curpos++ = (BYTE) ((context->gzip_input_stream_size >> 8) & 255);
  112. *output_curpos++ = (BYTE) ((context->gzip_input_stream_size >> 16) & 255);
  113. *output_curpos++ = (BYTE) ((context->gzip_input_stream_size >> 24) & 255);
  114. context->output_curpos = output_curpos;
  115. }
  116. BOOL ReadGzipFooter(t_decoder_context *context)
  117. {
  118. if (context->state == STATE_START_READING_GZIP_FOOTER)
  119. {
  120. context->state = STATE_READING_GZIP_FOOTER;
  121. context->gzip_footer_substate = GZIP_FTR_STATE_READING_CRC;
  122. context->gzip_footer_loop_counter = 0;
  123. }
  124. _ASSERT(context->state == STATE_READING_GZIP_FOOTER);
  125. if (INPUT_EOF())
  126. return TRUE;
  127. if (context->gzip_footer_substate == GZIP_FTR_STATE_READING_CRC)
  128. {
  129. if (context->gzip_footer_loop_counter == 0)
  130. context->gzip_footer_crc32 = 0;
  131. while (context->gzip_footer_loop_counter < 4)
  132. {
  133. context->gzip_footer_crc32 |= ((*context->input_curpos++) << (8*context->gzip_footer_loop_counter));
  134. context->gzip_footer_loop_counter++;
  135. if (INPUT_EOF())
  136. break;
  137. }
  138. if (context->gzip_footer_loop_counter >= 4)
  139. {
  140. context->gzip_footer_substate = GZIP_FTR_STATE_READING_FILE_SIZE;
  141. context->gzip_footer_loop_counter = 0;
  142. }
  143. if (INPUT_EOF())
  144. return TRUE;
  145. }
  146. if (context->gzip_footer_substate == GZIP_FTR_STATE_READING_FILE_SIZE)
  147. {
  148. if (context->gzip_footer_loop_counter == 0)
  149. context->gzip_footer_output_stream_size = 0;
  150. while (context->gzip_footer_loop_counter < 4)
  151. {
  152. context->gzip_footer_output_stream_size |= ((*context->input_curpos++) << (8*context->gzip_footer_loop_counter));
  153. context->gzip_footer_loop_counter++;
  154. if (INPUT_EOF())
  155. break;
  156. }
  157. if (context->gzip_footer_loop_counter >= 4)
  158. context->state = STATE_VERIFYING_GZIP_FOOTER;
  159. }
  160. return TRUE;
  161. }
  162. BOOL ReadGzipHeader(t_decoder_context *context)
  163. {
  164. if (context->state != STATE_READING_GZIP_HEADER)
  165. {
  166. context->state = STATE_READING_GZIP_HEADER;
  167. context->gzip_header_substate = GZIP_HDR_STATE_READING_ID1;
  168. }
  169. if (INPUT_EOF())
  170. return TRUE;
  171. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_ID1)
  172. {
  173. if (*context->input_curpos++ != 0x1F)
  174. return FALSE;
  175. context->gzip_header_substate = GZIP_HDR_STATE_READING_ID2;
  176. if (INPUT_EOF())
  177. return TRUE;
  178. }
  179. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_ID2)
  180. {
  181. if (*context->input_curpos++ != 0x8B)
  182. return FALSE;
  183. context->gzip_header_substate = GZIP_HDR_STATE_READING_CM;
  184. if (INPUT_EOF())
  185. return TRUE;
  186. }
  187. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_CM)
  188. {
  189. // compression mode must be 8 (deflate)
  190. if (*context->input_curpos++ != 8)
  191. return FALSE;
  192. context->gzip_header_substate = GZIP_HDR_STATE_READING_FLG;
  193. if (INPUT_EOF())
  194. return TRUE;
  195. }
  196. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_FLG)
  197. {
  198. context->gzip_header_flag = *context->input_curpos++;
  199. context->gzip_header_substate = GZIP_HDR_STATE_READING_MMTIME;
  200. context->gzip_header_loop_counter = 0; // 4 MMTIME bytes
  201. if (INPUT_EOF())
  202. return TRUE;
  203. }
  204. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_MMTIME)
  205. {
  206. // MTIME
  207. while (context->gzip_header_loop_counter < 4)
  208. {
  209. context->input_curpos++;
  210. context->gzip_header_loop_counter++;
  211. if (INPUT_EOF())
  212. return TRUE;
  213. }
  214. context->gzip_header_substate = GZIP_HDR_STATE_READING_XFL;
  215. context->gzip_header_loop_counter = 0;
  216. }
  217. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_XFL)
  218. {
  219. context->input_curpos++; // ignore XFL
  220. context->gzip_header_substate = GZIP_HDR_STATE_READING_OS;
  221. if (INPUT_EOF())
  222. return TRUE;
  223. }
  224. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_OS)
  225. {
  226. context->input_curpos++; // ignore OS
  227. context->gzip_header_substate = GZIP_HDR_STATE_READING_XLEN1;
  228. if (INPUT_EOF())
  229. return TRUE;
  230. }
  231. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_XLEN1)
  232. {
  233. // skip over some states if there's no "extra" data
  234. if ((context->gzip_header_flag & GZIP_FLG_FEXTRA) == 0)
  235. {
  236. context->gzip_header_substate = GZIP_HDR_STATE_READING_FILENAME;
  237. goto gzip_state_reading_fname;
  238. }
  239. context->gzip_header_xlen1_byte = *context->input_curpos++;
  240. context->gzip_header_substate = GZIP_HDR_STATE_READING_XLEN2;
  241. if (INPUT_EOF())
  242. return TRUE;
  243. }
  244. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_XLEN2)
  245. {
  246. BYTE xlen2 = *context->input_curpos++;
  247. context->gzip_header_xlen = context->gzip_header_xlen1_byte | (xlen2 << 8);
  248. context->gzip_header_substate = GZIP_HDR_STATE_READING_XLEN_DATA;
  249. context->gzip_header_loop_counter = 0; // 0 bytes of XLEN data read so far
  250. if (INPUT_EOF())
  251. return TRUE;
  252. }
  253. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_XLEN_DATA)
  254. {
  255. while (context->gzip_header_loop_counter < context->gzip_header_xlen)
  256. {
  257. context->input_curpos++;
  258. context->gzip_header_loop_counter++;
  259. if (INPUT_EOF())
  260. break;
  261. }
  262. if (context->gzip_header_loop_counter >= context->gzip_header_xlen)
  263. context->gzip_header_substate = GZIP_HDR_STATE_READING_FILENAME;
  264. if (INPUT_EOF())
  265. return TRUE;
  266. }
  267. gzip_state_reading_fname:
  268. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_FILENAME)
  269. {
  270. // skip over this state if there's no filename
  271. if ((context->gzip_header_flag & GZIP_FLG_FNAME) == 0)
  272. {
  273. context->gzip_header_substate = GZIP_HDR_STATE_READING_COMMENT;
  274. goto gzip_state_reading_comment;
  275. }
  276. do
  277. {
  278. if (*context->input_curpos++ == 0)
  279. {
  280. // filename null terminator found
  281. context->gzip_header_substate = GZIP_HDR_STATE_READING_COMMENT;
  282. break;
  283. }
  284. } while (!INPUT_EOF());
  285. if (INPUT_EOF())
  286. return TRUE;
  287. }
  288. gzip_state_reading_comment:
  289. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_COMMENT)
  290. {
  291. // skip over this state if there's no filename
  292. if ((context->gzip_header_flag & GZIP_FLG_FCOMMENT) == 0)
  293. {
  294. context->gzip_header_substate = GZIP_HDR_STATE_READING_CRC16_PART1;
  295. goto gzip_state_reading_crc16;
  296. }
  297. do
  298. {
  299. if (*context->input_curpos++ == 0)
  300. {
  301. // filename null terminator found
  302. context->gzip_header_substate = GZIP_HDR_STATE_READING_CRC16_PART1;
  303. break;
  304. }
  305. } while (!INPUT_EOF());
  306. if (INPUT_EOF())
  307. return TRUE;
  308. }
  309. gzip_state_reading_crc16:
  310. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_CRC16_PART1)
  311. {
  312. // skip over these states if there's no crc16
  313. if ((context->gzip_header_flag & GZIP_FLG_CRC) == 0)
  314. {
  315. context->gzip_header_substate = GZIP_HDR_STATE_DONE;
  316. goto gzip_state_done;
  317. }
  318. context->input_curpos++; // ignore crc
  319. context->gzip_header_substate = GZIP_HDR_STATE_READING_CRC16_PART2;
  320. if (INPUT_EOF())
  321. return TRUE;
  322. }
  323. if (context->gzip_header_substate == GZIP_HDR_STATE_READING_CRC16_PART2)
  324. {
  325. context->input_curpos++; // ignore crc
  326. context->gzip_header_substate = GZIP_HDR_STATE_DONE;
  327. if (INPUT_EOF())
  328. return TRUE;
  329. }
  330. gzip_state_done:
  331. if (context->gzip_header_substate == GZIP_HDR_STATE_DONE)
  332. context->state = STATE_READING_BFINAL_NEED_TO_INIT_BITBUF;
  333. return TRUE;
  334. }
  335. #define DO1(buf) crc = g_CrcTable[((ULONG)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
  336. #define DO2(buf) DO1(buf); DO1(buf);
  337. #define DO4(buf) DO2(buf); DO2(buf);
  338. #define DO8(buf) DO4(buf); DO4(buf);
  339. ULONG GzipCRC32(ULONG crc, const BYTE *buf, ULONG len)
  340. {
  341. crc = crc ^ 0xffffffffUL;
  342. while (len >= 8)
  343. {
  344. DO8(buf);
  345. len -= 8;
  346. }
  347. if (len)
  348. {
  349. do
  350. {
  351. DO1(buf);
  352. } while (--len);
  353. }
  354. return crc ^ 0xffffffffUL;
  355. }
  356. //
  357. // Works just like memcpy() except that we update context->crc32 and context->input_stream_size
  358. // at the same time.
  359. //
  360. // BUGBUG Could possibly improve the perf by copying 4 or 8 bytes at a time as above
  361. //
  362. void GzipCRCmemcpy(t_encoder_context *context, BYTE *dest, const BYTE *src, ULONG count)
  363. {
  364. ULONG crc = context->gzip_crc32 ^ 0xffffffffUL;
  365. context->gzip_input_stream_size += count;
  366. while (count-- > 0)
  367. {
  368. *dest++ = *src;
  369. DO1(src); // increments src
  370. }
  371. context->gzip_crc32 = crc ^ 0xffffffffUL;
  372. }