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.

1282 lines
38 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. compress.c
  5. Abstract:
  6. This module implements the NT Rtl compression engine.
  7. Author:
  8. Gary Kimura [GaryKi] 21-Jan-1994
  9. Revision History:
  10. --*/
  11. #include "ntrtlp.h"
  12. //
  13. // The following arrays hold procedures that we call to do the various
  14. // compression functions. Each new compression function will need to
  15. // be added to this array. For one that are currently not supported
  16. // we will fill in a not supported routine.
  17. //
  18. NTSTATUS
  19. RtlCompressWorkSpaceSizeNS (
  20. IN USHORT CompressionEngine,
  21. OUT PULONG CompressBufferWorkSpaceSize,
  22. OUT PULONG CompressFragmentWorkSpaceSize
  23. );
  24. NTSTATUS
  25. RtlCompressBufferNS (
  26. IN USHORT CompressionEngine,
  27. IN PUCHAR UncompressedBuffer,
  28. IN ULONG UncompressedBufferSize,
  29. OUT PUCHAR CompressedBuffer,
  30. IN ULONG CompressedBufferSize,
  31. IN ULONG UncompressedChunkSize,
  32. OUT PULONG FinalCompressedSize,
  33. IN PVOID WorkSpace
  34. );
  35. NTSTATUS
  36. RtlDecompressBufferNS (
  37. OUT PUCHAR UncompressedBuffer,
  38. IN ULONG UncompressedBufferSize,
  39. IN PUCHAR CompressedBuffer,
  40. IN ULONG CompressedBufferSize,
  41. OUT PULONG FinalUncompressedSize
  42. );
  43. NTSTATUS
  44. RtlDecompressFragmentNS (
  45. OUT PUCHAR UncompressedFragment,
  46. IN ULONG UncompressedFragmentSize,
  47. IN PUCHAR CompressedBuffer,
  48. IN ULONG CompressedBufferSize,
  49. IN ULONG FragmentOffset,
  50. OUT PULONG FinalUncompressedSize,
  51. IN PVOID WorkSpace
  52. );
  53. NTSTATUS
  54. RtlDescribeChunkNS (
  55. IN OUT PUCHAR *CompressedBuffer,
  56. IN PUCHAR EndOfCompressedBufferPlus1,
  57. OUT PUCHAR *ChunkBuffer,
  58. OUT PULONG ChunkSize
  59. );
  60. NTSTATUS
  61. RtlReserveChunkNS (
  62. IN OUT PUCHAR *CompressedBuffer,
  63. IN PUCHAR EndOfCompressedBufferPlus1,
  64. OUT PUCHAR *ChunkBuffer,
  65. IN ULONG ChunkSize
  66. );
  67. #if defined(ALLOC_DATA_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  68. #pragma const_seg("PAGELKCONST")
  69. #endif
  70. //
  71. // Routines to query the amount of memory needed for each workspace
  72. //
  73. const PRTL_COMPRESS_WORKSPACE_SIZE RtlWorkSpaceProcs[8] = {
  74. NULL, // 0
  75. NULL, // 1
  76. RtlCompressWorkSpaceSizeLZNT1, // 2
  77. RtlCompressWorkSpaceSizeNS, // 3
  78. RtlCompressWorkSpaceSizeNS, // 4
  79. RtlCompressWorkSpaceSizeNS, // 5
  80. RtlCompressWorkSpaceSizeNS, // 6
  81. RtlCompressWorkSpaceSizeNS // 7
  82. };
  83. //
  84. // Routines to compress a buffer
  85. //
  86. const PRTL_COMPRESS_BUFFER RtlCompressBufferProcs[8] = {
  87. NULL, // 0
  88. NULL, // 1
  89. RtlCompressBufferLZNT1, // 2
  90. RtlCompressBufferNS, // 3
  91. RtlCompressBufferNS, // 4
  92. RtlCompressBufferNS, // 5
  93. RtlCompressBufferNS, // 6
  94. RtlCompressBufferNS // 7
  95. };
  96. #if defined(ALLOC_DATA_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  97. #pragma const_seg("PAGECONST")
  98. #endif
  99. //
  100. // Routines to decompress a buffer
  101. //
  102. const PRTL_DECOMPRESS_BUFFER RtlDecompressBufferProcs[8] = {
  103. NULL, // 0
  104. NULL, // 1
  105. RtlDecompressBufferLZNT1, // 2
  106. RtlDecompressBufferNS, // 3
  107. RtlDecompressBufferNS, // 4
  108. RtlDecompressBufferNS, // 5
  109. RtlDecompressBufferNS, // 6
  110. RtlDecompressBufferNS // 7
  111. };
  112. //
  113. // Routines to decompress a fragment
  114. //
  115. const PRTL_DECOMPRESS_FRAGMENT RtlDecompressFragmentProcs[8] = {
  116. NULL, // 0
  117. NULL, // 1
  118. RtlDecompressFragmentLZNT1, // 2
  119. RtlDecompressFragmentNS, // 3
  120. RtlDecompressFragmentNS, // 4
  121. RtlDecompressFragmentNS, // 5
  122. RtlDecompressFragmentNS, // 6
  123. RtlDecompressFragmentNS // 7
  124. };
  125. //
  126. // Routines to describe the current chunk
  127. //
  128. const PRTL_DESCRIBE_CHUNK RtlDescribeChunkProcs[8] = {
  129. NULL, // 0
  130. NULL, // 1
  131. RtlDescribeChunkLZNT1, // 2
  132. RtlDescribeChunkNS, // 3
  133. RtlDescribeChunkNS, // 4
  134. RtlDescribeChunkNS, // 5
  135. RtlDescribeChunkNS, // 6
  136. RtlDescribeChunkNS // 7
  137. };
  138. //
  139. // Routines to reserve for a chunk
  140. //
  141. const PRTL_RESERVE_CHUNK RtlReserveChunkProcs[8] = {
  142. NULL, // 0
  143. NULL, // 1
  144. RtlReserveChunkLZNT1, // 2
  145. RtlReserveChunkNS, // 3
  146. RtlReserveChunkNS, // 4
  147. RtlReserveChunkNS, // 5
  148. RtlReserveChunkNS, // 6
  149. RtlReserveChunkNS // 7
  150. };
  151. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  152. //
  153. // N.B. The two functions below are placed in the PAGELK section
  154. // because they need to be locked down in memory during Hibernation,
  155. // since they are used to enable compression of the Hiberfile.
  156. //
  157. #pragma alloc_text(PAGELK, RtlGetCompressionWorkSpaceSize)
  158. #pragma alloc_text(PAGELK, RtlCompressBuffer)
  159. #pragma alloc_text(PAGE, RtlDecompressChunks)
  160. #pragma alloc_text(PAGE, RtlCompressChunks)
  161. #pragma alloc_text(PAGE, RtlDecompressBuffer)
  162. #pragma alloc_text(PAGE, RtlDecompressFragment)
  163. #pragma alloc_text(PAGE, RtlDescribeChunk)
  164. #pragma alloc_text(PAGE, RtlReserveChunk)
  165. #pragma alloc_text(PAGE, RtlCompressWorkSpaceSizeNS)
  166. #pragma alloc_text(PAGE, RtlCompressBufferNS)
  167. #pragma alloc_text(PAGE, RtlDecompressBufferNS)
  168. #pragma alloc_text(PAGE, RtlDecompressFragmentNS)
  169. #pragma alloc_text(PAGE, RtlDescribeChunkNS)
  170. #pragma alloc_text(PAGE, RtlReserveChunkNS)
  171. #endif
  172. NTSTATUS
  173. RtlGetCompressionWorkSpaceSize (
  174. IN USHORT CompressionFormatAndEngine,
  175. OUT PULONG CompressBufferWorkSpaceSize,
  176. OUT PULONG CompressFragmentWorkSpaceSize
  177. )
  178. /*++
  179. Routine Description:
  180. This routine returns to the caller the size in bytes of the
  181. different work space buffers need to perform the compression
  182. Arguments:
  183. CompressionFormatAndEngine - Supplies the format and engine
  184. specification for the compressed data.
  185. CompressBufferWorkSpaceSize - Receives the size in bytes needed
  186. to compress a buffer.
  187. CompressBufferWorkSpaceSize - Receives the size in bytes needed
  188. to decompress a fragment.
  189. Return Value:
  190. STATUS_SUCCESS - the operation worked without a hitch.
  191. STATUS_INVALID_PARAMETER - The specified format is illegal
  192. STATUS_UNSUPPORTED_COMPRESSION - the specified compression format and/or engine
  193. is not support.
  194. --*/
  195. {
  196. //
  197. // Declare two variables to hold the format and engine specification
  198. //
  199. USHORT Format = CompressionFormatAndEngine & 0x00ff;
  200. USHORT Engine = CompressionFormatAndEngine & 0xff00;
  201. //
  202. // make sure the format is sort of supported
  203. //
  204. if ((Format == COMPRESSION_FORMAT_NONE) || (Format == COMPRESSION_FORMAT_DEFAULT)) {
  205. return STATUS_INVALID_PARAMETER;
  206. }
  207. if (Format & 0x00f0) {
  208. return STATUS_UNSUPPORTED_COMPRESSION;
  209. }
  210. //
  211. // Call the routine to return the workspace sizes.
  212. //
  213. return RtlWorkSpaceProcs[ Format ]( Engine,
  214. CompressBufferWorkSpaceSize,
  215. CompressFragmentWorkSpaceSize );
  216. }
  217. NTSTATUS
  218. RtlCompressBuffer (
  219. IN USHORT CompressionFormatAndEngine,
  220. IN PUCHAR UncompressedBuffer,
  221. IN ULONG UncompressedBufferSize,
  222. OUT PUCHAR CompressedBuffer,
  223. IN ULONG CompressedBufferSize,
  224. IN ULONG UncompressedChunkSize,
  225. OUT PULONG FinalCompressedSize,
  226. IN PVOID WorkSpace
  227. )
  228. /*++
  229. Routine Description:
  230. This routine takes as input an uncompressed buffer and produces
  231. its compressed equivalent provided the compressed data fits within
  232. the specified destination buffer.
  233. An output variable indicates the number of bytes used to store
  234. the compressed buffer.
  235. Arguments:
  236. CompressionFormatAndEngine - Supplies the format and engine
  237. specification for the compressed data.
  238. UncompressedBuffer - Supplies a pointer to the uncompressed data.
  239. UncompressedBufferSize - Supplies the size, in bytes, of the
  240. uncompressed buffer.
  241. CompressedBuffer - Supplies a pointer to where the compressed data
  242. is to be stored.
  243. CompressedBufferSize - Supplies the size, in bytes, of the
  244. compressed buffer.
  245. UncompressedChunkSize - Supplies the chunk size to use when
  246. compressing the input buffer. The only valid values are
  247. 512, 1024, 2048, and 4096.
  248. FinalCompressedSize - Receives the number of bytes needed in
  249. the compressed buffer to store the compressed data.
  250. WorkSpace - Mind your own business, just give it to me.
  251. Return Value:
  252. STATUS_SUCCESS - the compression worked without a hitch.
  253. STATUS_INVALID_PARAMETER - The specified format is illegal
  254. STATUS_BUFFER_ALL_ZEROS - the compression worked without a hitch and in
  255. addition the input buffer was all zeros.
  256. STATUS_BUFFER_TOO_SMALL - the compressed buffer is too small to hold the
  257. compressed data.
  258. STATUS_UNSUPPORTED_COMPRESSION - the specified compression format and/or engine
  259. is not support.
  260. --*/
  261. {
  262. //
  263. // Declare two variables to hold the format and engine specification
  264. //
  265. USHORT Format = CompressionFormatAndEngine & 0x00ff;
  266. USHORT Engine = CompressionFormatAndEngine & 0xff00;
  267. //
  268. // make sure the format is sort of supported
  269. //
  270. if ((Format == COMPRESSION_FORMAT_NONE) || (Format == COMPRESSION_FORMAT_DEFAULT)) {
  271. return STATUS_INVALID_PARAMETER;
  272. }
  273. if (Format & 0x00f0) {
  274. return STATUS_UNSUPPORTED_COMPRESSION;
  275. }
  276. //
  277. // Call the compression routine for the individual format
  278. //
  279. return RtlCompressBufferProcs[ Format ]( Engine,
  280. UncompressedBuffer,
  281. UncompressedBufferSize,
  282. CompressedBuffer,
  283. CompressedBufferSize,
  284. UncompressedChunkSize,
  285. FinalCompressedSize,
  286. WorkSpace );
  287. }
  288. NTSTATUS
  289. RtlDecompressBuffer (
  290. IN USHORT CompressionFormat,
  291. OUT PUCHAR UncompressedBuffer,
  292. IN ULONG UncompressedBufferSize,
  293. IN PUCHAR CompressedBuffer,
  294. IN ULONG CompressedBufferSize,
  295. OUT PULONG FinalUncompressedSize
  296. )
  297. /*++
  298. Routine Description:
  299. This routine takes as input a compressed buffer and produces
  300. its uncompressed equivalent provided the uncompressed data fits
  301. within the specified destination buffer.
  302. An output variable indicates the number of bytes used to store the
  303. uncompressed data.
  304. Arguments:
  305. CompressionFormat - Supplies the format of the compressed data.
  306. UncompressedBuffer - Supplies a pointer to where the uncompressed
  307. data is to be stored.
  308. UncompressedBufferSize - Supplies the size, in bytes, of the
  309. uncompressed buffer.
  310. CompressedBuffer - Supplies a pointer to the compressed data.
  311. CompressedBufferSize - Supplies the size, in bytes, of the
  312. compressed buffer.
  313. FinalUncompressedSize - Receives the number of bytes needed in
  314. the uncompressed buffer to store the uncompressed data.
  315. Return Value:
  316. STATUS_SUCCESS - the decompression worked without a hitch.
  317. STATUS_INVALID_PARAMETER - The specified format is illegal
  318. STATUS_BAD_COMPRESSION_BUFFER - the input compressed buffer is
  319. ill-formed.
  320. STATUS_UNSUPPORTED_COMPRESSION - the specified compression format and/or engine
  321. is not support.
  322. --*/
  323. {
  324. //
  325. // Declare two variables to hold the format specification
  326. //
  327. USHORT Format = CompressionFormat & 0x00ff;
  328. //
  329. // make sure the format is sort of supported
  330. //
  331. if ((Format == COMPRESSION_FORMAT_NONE) || (Format == COMPRESSION_FORMAT_DEFAULT)) {
  332. return STATUS_INVALID_PARAMETER;
  333. }
  334. if (Format & 0x00f0) {
  335. return STATUS_UNSUPPORTED_COMPRESSION;
  336. }
  337. //
  338. // Call the compression routine for the individual format
  339. //
  340. return RtlDecompressBufferProcs[ Format ]( UncompressedBuffer,
  341. UncompressedBufferSize,
  342. CompressedBuffer,
  343. CompressedBufferSize,
  344. FinalUncompressedSize );
  345. }
  346. NTSTATUS
  347. RtlDecompressFragment (
  348. IN USHORT CompressionFormat,
  349. OUT PUCHAR UncompressedFragment,
  350. IN ULONG UncompressedFragmentSize,
  351. IN PUCHAR CompressedBuffer,
  352. IN ULONG CompressedBufferSize,
  353. IN ULONG FragmentOffset,
  354. OUT PULONG FinalUncompressedSize,
  355. IN PVOID WorkSpace
  356. )
  357. /*++
  358. Routine Description:
  359. This routine takes as input a compressed buffer and extract an
  360. uncompressed fragment.
  361. Output bytes are copied to the fragment buffer until either the
  362. fragment buffer is full or the end of the uncompressed buffer is
  363. reached.
  364. An output variable indicates the number of bytes used to store the
  365. uncompressed fragment.
  366. Arguments:
  367. CompressionFormat - Supplies the format of the compressed data.
  368. UncompressedFragment - Supplies a pointer to where the uncompressed
  369. fragment is to be stored.
  370. UncompressedFragmentSize - Supplies the size, in bytes, of the
  371. uncompressed fragment buffer.
  372. CompressedBuffer - Supplies a pointer to the compressed data buffer.
  373. CompressedBufferSize - Supplies the size, in bytes, of the
  374. compressed buffer.
  375. FragmentOffset - Supplies the offset (zero based) where the uncompressed
  376. fragment is being extract from. The offset is the position within
  377. the original uncompressed buffer.
  378. FinalUncompressedSize - Receives the number of bytes needed in
  379. the Uncompressed fragment buffer to store the data.
  380. Return Value:
  381. STATUS_SUCCESS - the operation worked without a hitch.
  382. STATUS_INVALID_PARAMETER - The specified format is illegal
  383. STATUS_BAD_COMPRESSION_BUFFER - the input compressed buffer is
  384. ill-formed.
  385. STATUS_UNSUPPORTED_COMPRESSION - the specified compression format and/or engine
  386. is not support.
  387. --*/
  388. {
  389. //
  390. // Declare two variables to hold the format specification
  391. //
  392. USHORT Format = CompressionFormat & 0x00ff;
  393. //
  394. // make sure the format is sort of supported
  395. //
  396. if ((Format == COMPRESSION_FORMAT_NONE) || (Format == COMPRESSION_FORMAT_DEFAULT)) {
  397. return STATUS_INVALID_PARAMETER;
  398. }
  399. if (Format & 0x00f0) {
  400. return STATUS_UNSUPPORTED_COMPRESSION;
  401. }
  402. //
  403. // Call the compression routine for the individual format
  404. //
  405. return RtlDecompressFragmentProcs[ Format ]( UncompressedFragment,
  406. UncompressedFragmentSize,
  407. CompressedBuffer,
  408. CompressedBufferSize,
  409. FragmentOffset,
  410. FinalUncompressedSize,
  411. WorkSpace );
  412. }
  413. NTSYSAPI
  414. NTSTATUS
  415. NTAPI
  416. RtlDescribeChunk (
  417. IN USHORT CompressionFormat,
  418. IN OUT PUCHAR *CompressedBuffer,
  419. IN PUCHAR EndOfCompressedBufferPlus1,
  420. OUT PUCHAR *ChunkBuffer,
  421. OUT PULONG ChunkSize
  422. )
  423. /*++
  424. Routine Description:
  425. This routine takes as input a compressed buffer, and returns
  426. a description of the current chunk in that buffer, updating
  427. the CompressedBuffer pointer to point to the next chunk (if
  428. there is one).
  429. Arguments:
  430. CompressionFormat - Supplies the format of the compressed data.
  431. CompressedBuffer - Supplies a pointer to the current chunk in
  432. the compressed data, and returns pointing to the next chunk
  433. EndOfCompressedBufferPlus1 - Points at first byte beyond
  434. compressed buffer
  435. ChunkBuffer - Receives a pointer to the chunk, if ChunkSize
  436. is nonzero, else undefined
  437. ChunkSize - Receives the size of the current chunk pointed
  438. to by CompressedBuffer. Returns 0 if STATUS_NO_MORE_ENTRIES.
  439. Return Value:
  440. STATUS_SUCCESS - the decompression worked without a hitch.
  441. STATUS_INVALID_PARAMETER - The specified format is illegal
  442. STATUS_BAD_COMPRESSION_BUFFER - the input compressed buffer is
  443. ill-formed.
  444. STATUS_UNSUPPORTED_COMPRESSION - the specified compression format and/or engine
  445. is not support.
  446. STATUS_NO_MORE_ENTRIES - There is no chunk at the current pointer.
  447. --*/
  448. {
  449. //
  450. // Declare two variables to hold the format specification
  451. //
  452. USHORT Format = CompressionFormat & 0x00ff;
  453. //
  454. // make sure the format is sort of supported
  455. //
  456. if ((Format == COMPRESSION_FORMAT_NONE) || (Format == COMPRESSION_FORMAT_DEFAULT)) {
  457. return STATUS_INVALID_PARAMETER;
  458. }
  459. if (Format & 0x00f0) {
  460. return STATUS_UNSUPPORTED_COMPRESSION;
  461. }
  462. //
  463. // Call the compression routine for the individual format
  464. //
  465. return RtlDescribeChunkProcs[ Format ]( CompressedBuffer,
  466. EndOfCompressedBufferPlus1,
  467. ChunkBuffer,
  468. ChunkSize );
  469. }
  470. NTSYSAPI
  471. NTSTATUS
  472. NTAPI
  473. RtlReserveChunk (
  474. IN USHORT CompressionFormat,
  475. IN OUT PUCHAR *CompressedBuffer,
  476. IN PUCHAR EndOfCompressedBufferPlus1,
  477. OUT PUCHAR *ChunkBuffer,
  478. IN ULONG ChunkSize
  479. )
  480. /*++
  481. Routine Description:
  482. This routine takes as input a compressed buffer, and reserves
  483. space for a chunk of the specified size - filling in any pattern
  484. as is necessary for a chunk of that size. On return it has
  485. updated the CompressedBuffer pointer to point to the next chunk (if
  486. there is one).
  487. Arguments:
  488. CompressionFormat - Supplies the format of the compressed data.
  489. CompressedBuffer - Supplies a pointer to the current chunk in
  490. the compressed data, and returns pointing to the next chunk
  491. EndOfCompressedBufferPlus1 - Points at first byte beyond
  492. compressed buffer
  493. ChunkBuffer - Receives a pointer to the chunk, if ChunkSize
  494. is nonzero, else undefined
  495. ChunkSize - Supplies the compressed size of the chunk to be received.
  496. Two special values are 0, and whatever the maximum
  497. uncompressed chunk size is for the routine. 0 means
  498. the chunk should be filled with a pattern that equates
  499. to all 0's. The maximum chunk size implies that the
  500. compression routine should prepare to receive all of the
  501. data in uncompressed form.
  502. Return Value:
  503. STATUS_SUCCESS - the decompression worked without a hitch.
  504. STATUS_INVALID_PARAMETER - The specified format is illegal
  505. STATUS_BAD_COMPRESSION_BUFFER - the input compressed buffer is
  506. ill-formed.
  507. STATUS_UNSUPPORTED_COMPRESSION - the specified compression format and/or engine
  508. is not support.
  509. --*/
  510. {
  511. //
  512. // Declare two variables to hold the format specification
  513. //
  514. USHORT Format = CompressionFormat & 0x00ff;
  515. //
  516. // make sure the format is sort of supported
  517. //
  518. if ((Format == COMPRESSION_FORMAT_NONE) || (Format == COMPRESSION_FORMAT_DEFAULT)) {
  519. return STATUS_INVALID_PARAMETER;
  520. }
  521. if (Format & 0x00f0) {
  522. return STATUS_UNSUPPORTED_COMPRESSION;
  523. }
  524. //
  525. // Call the compression routine for the individual format
  526. //
  527. return RtlReserveChunkProcs[ Format ]( CompressedBuffer,
  528. EndOfCompressedBufferPlus1,
  529. ChunkBuffer,
  530. ChunkSize );
  531. }
  532. NTSTATUS
  533. RtlDecompressChunks (
  534. OUT PUCHAR UncompressedBuffer,
  535. IN ULONG UncompressedBufferSize,
  536. IN PUCHAR CompressedBuffer,
  537. IN ULONG CompressedBufferSize,
  538. IN PUCHAR CompressedTail,
  539. IN ULONG CompressedTailSize,
  540. IN PCOMPRESSED_DATA_INFO CompressedDataInfo
  541. )
  542. /*++
  543. Routine Description:
  544. This routine takes as input a compressed buffer which is a stream
  545. of chunks and decompresses it into the specified destination buffer.
  546. The compressed data may be in two pieces, such that the "tail" of
  547. the buffer is top aligned in the buffer at CompressedTail, and the
  548. rest of the data is top aligned in the CompressedBuffer. The
  549. CompressedBuffer can overlap and be top-aligned in the UncompressedBuffer,
  550. to allow something close to in-place decompression. The CompressedTail
  551. must be large enough to completely contain the final chunk and it
  552. chunk header.
  553. Arguments:
  554. UncompressedBuffer - Supplies a pointer to where the uncompressed
  555. data is to be stored.
  556. UncompressedBufferSize - Supplies the size, in bytes, of the
  557. uncompressed buffer.
  558. CompressedBuffer - Supplies a pointer to the compressed data, part 1.
  559. CompressedBufferSize - Supplies the size, in bytes, of the
  560. compressed buffer.
  561. CompressedTail - Supplies a pointer to the compressed data, part 2,
  562. which must be the bytes immediately following the CompressedBuffer.
  563. CompressedTailSize - Supplies the size of the CompressedTail.
  564. CompressedDataInfo - Supplies a complete description of the
  565. compressed data with all the chunk sizes and compression
  566. parameters.
  567. Return Value:
  568. STATUS_SUCCESS - the decompression worked without a hitch.
  569. STATUS_INVALID_PARAMETER - The specified format is illegal
  570. STATUS_BAD_COMPRESSION_BUFFER - the input compressed buffer is
  571. ill-formed.
  572. STATUS_UNSUPPORTED_COMPRESSION - the specified compression format and/or engine
  573. is not support.
  574. --*/
  575. {
  576. NTSTATUS Status;
  577. PULONG CurrentCompressedChunkSize;
  578. ULONG SizeToDecompress, FinalUncompressedSize;
  579. ULONG ChunksToGo = CompressedDataInfo->NumberOfChunks;
  580. ULONG UncompressedChunkSize = 1 << CompressedDataInfo->ChunkShift;
  581. CurrentCompressedChunkSize = &CompressedDataInfo->CompressedChunkSizes[0];
  582. //
  583. // Loop to decompress chunks.
  584. //
  585. do {
  586. //
  587. // Calculate uncompressed size of next chunk to decompress.
  588. //
  589. SizeToDecompress = UncompressedBufferSize;
  590. if (SizeToDecompress >= UncompressedChunkSize) {
  591. SizeToDecompress = UncompressedChunkSize;
  592. }
  593. //
  594. // If the next chunk is all zeros, then zero it.
  595. //
  596. if ((ChunksToGo == 0) || (*CurrentCompressedChunkSize == 0)) {
  597. RtlZeroMemory( UncompressedBuffer, SizeToDecompress );
  598. //
  599. // Test for out of chunks here and set to 1, so we can
  600. // unconditionally decrement below. Also back up the
  601. // CompressedChunkSize pointer because we dereference
  602. // it as well.
  603. //
  604. if (ChunksToGo == 0) {
  605. ChunksToGo = 1;
  606. CurrentCompressedChunkSize -= 1;
  607. }
  608. //
  609. // If the next chunk is not compressed, just copy it.
  610. //
  611. } else if (*CurrentCompressedChunkSize == UncompressedChunkSize) {
  612. //
  613. // Does this chunk extend beyond the end of the current
  614. // buffer? If so, that probably means we can move the
  615. // first part of the chunk, and then switch to the Compressed
  616. // tail to get the rest.
  617. //
  618. if (SizeToDecompress >= CompressedBufferSize) {
  619. //
  620. // If we have already switched to the tail, then this must
  621. // be badly formatted compressed data.
  622. //
  623. if ((CompressedTailSize == 0) && (SizeToDecompress > CompressedBufferSize)) {
  624. return STATUS_BAD_COMPRESSION_BUFFER;
  625. }
  626. //
  627. // Copy the first part, and then the second part from the tail.
  628. // Then switch to make the tail the current buffer.
  629. //
  630. RtlCopyMemory( UncompressedBuffer, CompressedBuffer, CompressedBufferSize );
  631. RtlCopyMemory( UncompressedBuffer + CompressedBufferSize,
  632. CompressedTail,
  633. SizeToDecompress - CompressedBufferSize );
  634. //
  635. // If we exhausted the first buffer, move into the tail, knowing
  636. // that we adjust these pointers by *CurrentCompressedChunkSize
  637. // below.
  638. //
  639. CompressedBuffer = CompressedTail - CompressedBufferSize;
  640. CompressedBufferSize = CompressedTailSize + CompressedBufferSize;
  641. CompressedTailSize = 0;
  642. //
  643. // Otherwise we can just copy the whole chunk.
  644. //
  645. } else {
  646. RtlCopyMemory( UncompressedBuffer, CompressedBuffer, SizeToDecompress );
  647. }
  648. //
  649. // Otherwise it is a normal chunk to decompress.
  650. //
  651. } else {
  652. //
  653. // Does this chunk extend beyond the end of the current
  654. // buffer? If so, that probably means we can move the
  655. // first part of the chunk, and then switch to the Compressed
  656. // tail to get the rest. Since the tail must be at least
  657. // ChunkSize, the last chunk cannot be the one that is
  658. // overlapping into the tail. Therefore, it is safe for
  659. // us to copy the chunk to decompress into the last chunk
  660. // of the uncompressed buffer, and decompress it from there.
  661. //
  662. if (*CurrentCompressedChunkSize > CompressedBufferSize) {
  663. //
  664. // If we have already switched to the tail, then this must
  665. // be badly formatted compressed data.
  666. //
  667. if (CompressedTailSize == 0) {
  668. return STATUS_BAD_COMPRESSION_BUFFER;
  669. }
  670. //
  671. // Move the beginning of the chunk to the beginning of the last
  672. // chunk in the uncompressed buffer. This move could overlap.
  673. //
  674. RtlMoveMemory( UncompressedBuffer + UncompressedBufferSize - UncompressedChunkSize,
  675. CompressedBuffer,
  676. CompressedBufferSize );
  677. //
  678. // Move the rest of the chunk from the tail.
  679. //
  680. RtlCopyMemory( UncompressedBuffer + UncompressedBufferSize - UncompressedChunkSize + CompressedBufferSize,
  681. CompressedTail,
  682. *CurrentCompressedChunkSize - CompressedBufferSize );
  683. //
  684. // We temporarily set CompressedBuffer to describe where we
  685. // copied the chunk to make the call in common code, then we
  686. // switch it into the tail below.
  687. //
  688. CompressedBuffer = UncompressedBuffer + UncompressedBufferSize - UncompressedChunkSize;
  689. }
  690. //
  691. // Attempt the decompress.
  692. //
  693. Status =
  694. RtlDecompressBuffer( CompressedDataInfo->CompressionFormatAndEngine,
  695. UncompressedBuffer,
  696. SizeToDecompress,
  697. CompressedBuffer,
  698. *CurrentCompressedChunkSize,
  699. &FinalUncompressedSize );
  700. if (!NT_SUCCESS(Status)) {
  701. return Status;
  702. }
  703. //
  704. // If we did not get a full chunk, zero the rest.
  705. //
  706. if (SizeToDecompress > FinalUncompressedSize) {
  707. RtlZeroMemory( UncompressedBuffer + FinalUncompressedSize,
  708. SizeToDecompress - FinalUncompressedSize );
  709. }
  710. //
  711. // If we exhausted the first buffer, move into the tail, knowing
  712. // that we adjust these pointers by *CurrentCompressedChunkSize
  713. // below.
  714. //
  715. if (*CurrentCompressedChunkSize >= CompressedBufferSize) {
  716. CompressedBuffer = CompressedTail - CompressedBufferSize;
  717. CompressedBufferSize = CompressedTailSize + CompressedBufferSize;
  718. CompressedTailSize = 0;
  719. }
  720. }
  721. //
  722. // Update for next possible pass through the loop.
  723. //
  724. UncompressedBuffer += SizeToDecompress;
  725. UncompressedBufferSize -= SizeToDecompress;
  726. CompressedBuffer += *CurrentCompressedChunkSize;
  727. CompressedBufferSize -= *CurrentCompressedChunkSize;
  728. CurrentCompressedChunkSize += 1;
  729. ChunksToGo -= 1;
  730. } while (UncompressedBufferSize != 0);
  731. return STATUS_SUCCESS;
  732. }
  733. NTSTATUS
  734. RtlCompressChunks(
  735. IN PUCHAR UncompressedBuffer,
  736. IN ULONG UncompressedBufferSize,
  737. OUT PUCHAR CompressedBuffer,
  738. IN ULONG CompressedBufferSize,
  739. IN OUT PCOMPRESSED_DATA_INFO CompressedDataInfo,
  740. IN ULONG CompressedDataInfoLength,
  741. IN PVOID WorkSpace
  742. )
  743. /*++
  744. Routine Description:
  745. This routine takes as input an uncompressed buffer and produces
  746. its compressed equivalent provided the compressed data fits within
  747. the specified destination buffer.
  748. The desired compression parameters must be supplied via the
  749. CompressedDataInfo structure, and this structure then returns all
  750. of the compressed chunk sizes.
  751. Note that since any given chunk (or all chunks) can simply be
  752. transmitted uncompressed, all error possibilities are actually
  753. stopped in this routine, except for STATUS_BUFFER_TOO_SMALL.
  754. This code will be returned when the data is not compressing
  755. sufficiently to warrant sending the data compressed. The caller
  756. must field this error, and send the data uncompressed.
  757. Arguments:
  758. UncompressedBuffer - Supplies a pointer to the uncompressed data.
  759. UncompressedBufferSize - Supplies the size, in bytes, of the
  760. uncompressed buffer.
  761. CompressedBuffer - Supplies a pointer to where the compressed data
  762. is to be stored.
  763. CompressedBufferSize - Supplies the size, in bytes, of the
  764. compressed buffer.
  765. CompressedDataInfo - Supplies the compression parameters, such as
  766. CompressionFormat, CompressionUnitSize, ChunkSize and ClusterSize,
  767. returns all of the compressed chunk sizes.
  768. CompressedDataInfoLength - Size of the supplied CompressedDataInfo
  769. in bytes.
  770. WorkSpace - A workspace area of the correct size as returned from
  771. RtlGetCompressionWorkSpaceSize.
  772. Return Value:
  773. STATUS_SUCCESS - the compression worked without a hitch.
  774. STATUS_BUFFER_TOO_SMALL - the data is not compressing sufficiently to
  775. warrant sending the data compressed.
  776. --*/
  777. {
  778. NTSTATUS Status;
  779. PULONG CurrentCompressedChunkSize;
  780. ULONG SizeToCompress, FinalCompressedSize;
  781. ULONG UncompressedChunkSize = 1 << CompressedDataInfo->ChunkShift;
  782. //
  783. // Make sure CompressedDataInfo is long enough.
  784. //
  785. ASSERT(CompressedDataInfoLength >=
  786. (sizeof(COMPRESSED_DATA_INFO) +
  787. ((UncompressedBufferSize - 1) >> (CompressedDataInfo->ChunkShift - 2))));
  788. //
  789. // For the worst case, the compressed buffer actually has to be
  790. // the same size as the uncompressed buffer, minus 1/16th. We then
  791. // will actually use that size. If the data is not compressing very
  792. // well, it is cheaper for us to actually send the data to the
  793. // server uncompressed, than poorly compressed, because if the
  794. // data is poorly compressed, the server will end up doing an
  795. // extra copy before trying to compress the data again anyway.
  796. //
  797. ASSERT(CompressedBufferSize >= (UncompressedBufferSize - (UncompressedBufferSize / 16)));
  798. CompressedBufferSize = (UncompressedBufferSize - (UncompressedBufferSize / 16));
  799. //
  800. // Initialize NumberOfChunks returned and the pointer to the first chunk size.
  801. //
  802. CompressedDataInfo->NumberOfChunks = 0;
  803. CurrentCompressedChunkSize = &CompressedDataInfo->CompressedChunkSizes[0];
  804. //
  805. // Loop to decompress chunks.
  806. //
  807. do {
  808. //
  809. // Calculate uncompressed size of next chunk to decompress.
  810. //
  811. SizeToCompress = UncompressedBufferSize;
  812. if (SizeToCompress >= UncompressedChunkSize) {
  813. SizeToCompress = UncompressedChunkSize;
  814. }
  815. //
  816. // Now compress the next chunk.
  817. //
  818. Status = RtlCompressBuffer( CompressedDataInfo->CompressionFormatAndEngine,
  819. UncompressedBuffer,
  820. SizeToCompress,
  821. CompressedBuffer,
  822. CompressedBufferSize,
  823. UncompressedChunkSize,
  824. &FinalCompressedSize,
  825. WorkSpace );
  826. //
  827. // If the Buffer was all zeros, then we will not send anything.
  828. //
  829. if (Status == STATUS_BUFFER_ALL_ZEROS) {
  830. FinalCompressedSize = 0;
  831. //
  832. // Otherwise, if there was any kind of error (we only expect the
  833. // case where the data did not compress), then just copy the
  834. // data and return UncompressedChunkSize for this one.
  835. //
  836. } else if (!NT_SUCCESS(Status)) {
  837. //
  838. // The most likely error is STATUS_BUFFER_TOO_SMALL.
  839. // But in any case, our only recourse would be to send
  840. // the data uncompressed. To be completely safe, we
  841. // see if there is enough space for an uncompressed chunk
  842. // in the CompressedBuffer, and if not we return
  843. // buffer too small (which is probably what we had anyway!).
  844. //
  845. if (CompressedBufferSize < UncompressedChunkSize) {
  846. Status = STATUS_BUFFER_TOO_SMALL;
  847. break;
  848. }
  849. //
  850. // Copy the uncompressed chunk.
  851. //
  852. RtlCopyMemory( CompressedBuffer, UncompressedBuffer, SizeToCompress );
  853. if (UncompressedChunkSize > SizeToCompress) {
  854. RtlZeroMemory( (PCHAR)CompressedBuffer + SizeToCompress,
  855. UncompressedChunkSize - SizeToCompress );
  856. }
  857. FinalCompressedSize = UncompressedChunkSize;
  858. }
  859. ASSERT(FinalCompressedSize <= CompressedBufferSize);
  860. //
  861. // At this point, we have handled any error status.
  862. //
  863. Status = STATUS_SUCCESS;
  864. //
  865. // Store the final chunk size.
  866. //
  867. *CurrentCompressedChunkSize = FinalCompressedSize;
  868. CurrentCompressedChunkSize += 1;
  869. CompressedDataInfo->NumberOfChunks += 1;
  870. //
  871. // Prepare for the next trip through the loop.
  872. //
  873. UncompressedBuffer += SizeToCompress;
  874. UncompressedBufferSize -= SizeToCompress;
  875. CompressedBuffer += FinalCompressedSize;
  876. CompressedBufferSize -= FinalCompressedSize;
  877. } while (UncompressedBufferSize != 0);
  878. return Status;
  879. }
  880. NTSTATUS
  881. RtlCompressWorkSpaceSizeNS (
  882. IN USHORT CompressionEngine,
  883. OUT PULONG CompressBufferWorkSpaceSize,
  884. OUT PULONG CompressFragmentWorkSpaceSize
  885. )
  886. {
  887. return STATUS_UNSUPPORTED_COMPRESSION;
  888. }
  889. NTSTATUS
  890. RtlCompressBufferNS (
  891. IN USHORT CompressionEngine,
  892. IN PUCHAR UncompressedBuffer,
  893. IN ULONG UncompressedBufferSize,
  894. OUT PUCHAR CompressedBuffer,
  895. IN ULONG CompressedBufferSize,
  896. IN ULONG UncompressedChunkSize,
  897. OUT PULONG FinalCompressedSize,
  898. IN PVOID WorkSpace
  899. )
  900. {
  901. return STATUS_UNSUPPORTED_COMPRESSION;
  902. }
  903. NTSTATUS
  904. RtlDecompressBufferNS (
  905. OUT PUCHAR UncompressedBuffer,
  906. IN ULONG UncompressedBufferSize,
  907. IN PUCHAR CompressedBuffer,
  908. IN ULONG CompressedBufferSize,
  909. OUT PULONG FinalUncompressedSize
  910. )
  911. {
  912. return STATUS_UNSUPPORTED_COMPRESSION;
  913. }
  914. NTSTATUS
  915. RtlDecompressFragmentNS (
  916. OUT PUCHAR UncompressedFragment,
  917. IN ULONG UncompressedFragmentSize,
  918. IN PUCHAR CompressedBuffer,
  919. IN ULONG CompressedBufferSize,
  920. IN ULONG FragmentOffset,
  921. OUT PULONG FinalUncompressedSize,
  922. IN PVOID WorkSpace
  923. )
  924. {
  925. return STATUS_UNSUPPORTED_COMPRESSION;
  926. }
  927. NTSYSAPI
  928. NTSTATUS
  929. NTAPI
  930. RtlDescribeChunkNS (
  931. IN OUT PUCHAR *CompressedBuffer,
  932. IN PUCHAR EndOfCompressedBufferPlus1,
  933. OUT PUCHAR *ChunkBuffer,
  934. OUT PULONG ChunkSize
  935. )
  936. {
  937. return STATUS_UNSUPPORTED_COMPRESSION;
  938. }
  939. NTSYSAPI
  940. NTSTATUS
  941. NTAPI
  942. RtlReserveChunkNS (
  943. IN OUT PUCHAR *CompressedBuffer,
  944. IN PUCHAR EndOfCompressedBufferPlus1,
  945. OUT PUCHAR *ChunkBuffer,
  946. IN ULONG ChunkSize
  947. )
  948. {
  949. return STATUS_UNSUPPORTED_COMPRESSION;
  950. }
  951. #if defined(ALLOC_DATA_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  952. #pragma const_seg()
  953. #endif