3.1.4.4 Compressing the Message

If IsCompressionSupported is FALSE or Connection.CompressionIds is empty, the sender MUST skip the processing in this section.

If Connection.SupportsChainedCompression is FALSE, the sender SHOULD<99> construct the SMB2_COMPRESSION_TRANSFORM_HEADER_UNCHAINED specified in section 2.2.42.1 as follows:

  1. CompressionAlgorithm MUST be set to LZNT1, LZ77, LZ77+Huffman or LZ4 specified in Connection.CompressionIds. LZNT1, LZ77 and LZ77+Huffman algorithms are specified in [MS-XCA]. LZ4 algorithm is specified in [LZ4].

  2. The sender MAY choose to leave the leading portion of the SMB2 message uncompressed and compressing only the trailing portion.<100>

  3. The sender MUST perform the following:

    • If the entire SMB2 message is being compressed, then set Offset to zero; otherwise, set Offset to the length, in bytes, of the uncompressed part of the message.

    • Set OriginalCompressedSegmentSize to the uncompressed length, in bytes, of the portion of the message that is being compressed.

  4. The sender MUST compress the data using the CompressionAlgorithm.

  5. If the size of the compressed data is less than OriginalCompressedSegmentSize, the sender MUST perform the following:

    • If Offset is zero, the sender MUST replace the SMB2 message with the SMB2_COMPRESSION_TRANSFORM_HEADER_UNCHAINED followed by the compressed SMB2 message.

    • Otherwise, the sender MUST replace the portion of the SMB2 message selected for compression with the compressed part and prepend the SMB2 message with the SMB2_COMPRESSION_TRANSFORM_HEADER_UNCHAINED. The compressed SMB2 message is sent.

  6. Otherwise, the original, uncompressed SMB2 message without the SMB2 COMPRESSION_TRANSFORM_HEADER is sent.

Otherwise, the sender MUST prepare the compressed message as follows:

  1. The sender MUST initialize RemainingUncompressedDataSize with the size of uncompressed data, TotalCompressedDataSize with 0, and CompressedMessage with empty buffer.

  2. The uncompressed data MUST be compressed as follows:

    • If Connection.CompressionIds includes Pattern_V1 and RemainingUncompressedDataSize is greater than 32, the uncompressed data MUST be scanned for data patterns as specified in section 3.1.4.4.1. If the returned ForwardDataPattern.Repetitions is greater than zero, CompressedMessage MUST be appended with newly constructed SMB2_COMPRESSION_CHAINED_PAYLOAD_HEADER. CompressionAlgorithm MUST be set to Pattern_V1. Length MUST be set to the size of SMB2_COMPRESSION_PATTERN_PAYLOAD_V1. CompressedMessage MUST be appended with ForwardDataPattern. RemainingUncompressedDataSize MUST be decremented by ForwardDataPattern.Repetitions. If the returned BackwardDataPattern is not NULL and BackwardDataPattern.Repetitions is greater than zero, RemainingUncompressedDataSize MUST be decremented by BackwardDataPattern.Repetitions. TotalCompressedDataSize MUST be incremented by ForwardDataPattern.Repetitions.

    • If RemainingUncompressedDataSize is greater than 1024, CompressedMessage MUST be appended with newly constructed SMB2_COMPRESSION_CHAINED_PAYLOAD_HEADER. CompressionAlgorithm MUST be set to LZNT1, LZ77, LZ77+Huffman or LZ4 specified in Connection.CompressionIds. The uncompressed data MUST be compressed using the algorithm specified in CompressionAlgorithm. Length MUST be set to sum of the size of the compressed data and the size of OriginalPayloadSize field. OriginalPayloadSize MUST be set to the size of the uncompressed data. CompressedMessage MUST be appended with the compressed data. RemainingUncompressedDataSize MUST be decremented by the size of data before compression. TotalCompressedDataSize MUST be incremented by the size of compressed data.

    • Otherwise, if an implementation decides that the cost of remaining operations that might require copying the data is worth the compression savings, then CompressedMessage MUST be appended with newly constructed SMB2_COMPRESSION_CHAINED_PAYLOAD_HEADER. CompressionAlgorithm MUST be set to NONE. Length MUST be set to RemainingUncompressedDataSize. CompressedMessage MUST be appended with the uncompressed data. RemainingUncompressedDataSize MUST be decremented by the size of data before compression. TotalCompressedDataSize MUST be incremented by the size of compressed data.

    • If BackwardDataPattern is not NULL and BackwardDataPattern.Repetitions is greater than zero, CompressedMessage MUST be appended with newly constructed SMB2_COMPRESSION_CHAINED_PAYLOAD_HEADER. CompressionAlgorithm MUST be set to Pattern_V1. Length MUST be set to the size of SMB2_COMPRESSION_PATTERN_PAYLOAD_V1. CompressedMessage MUST be appended with BackwardDataPattern. TotalCompressedDataSize MUST be incremented by BackwardDataPattern.Repetitions.

    • If RemainingUncompressedDataSize is greater than zero, the sender MUST repeat step 2.

  3. If TotalCompressedDataSize+8 is less than the size of uncompressed SMB2 message, the sender MUST prepend CompressedMessage with first 8 bytes of SMB2_COMPRESSION_TRANSFORM_HEADER_CHAINED. OriginalCompressedSegmentSize MUST be set to the size of uncompressed SMB2 message. The Flags field in the first SMB2_COMPRESSION_CHAINED_PAYLOAD_HEADER MUST be set to SMB2_COMPRESSION_FLAG_CHAINED. The compressed SMB2 message is sent. Otherwise, the original, uncompressed SMB2 message is sent.