| ... | @@ -573,6 +573,11 @@ const literal_table_size_max = 1 << types.compressed_block.table_accuracy_log_ma | ... | @@ -573,6 +573,11 @@ const literal_table_size_max = 1 << types.compressed_block.table_accuracy_log_ma |
| 573 | const match_table_size_max = 1 << types.compressed_block.table_accuracy_log_max.match; | 573 | const match_table_size_max = 1 << types.compressed_block.table_accuracy_log_max.match; |
| 574 | const offset_table_size_max = 1 << types.compressed_block.table_accuracy_log_max.match; | 574 | const offset_table_size_max = 1 << types.compressed_block.table_accuracy_log_max.match; |
| 575 | | 575 | |
| | 576 | pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 { |
| | 577 | const hash = hasher.final(); |
| | 578 | return @intCast(u32, hash & 0xFFFFFFFF); |
| | 579 | } |
| | 580 | |
| 576 | const FrameError = error{ | 581 | const FrameError = error{ |
| 577 | DictionaryIdFlagUnsupported, | 582 | DictionaryIdFlagUnsupported, |
| 578 | ChecksumFailure, | 583 | ChecksumFailure, |
| ... | @@ -601,24 +606,20 @@ pub fn decodeZStandardFrame( | ... | @@ -601,24 +606,20 @@ pub fn decodeZStandardFrame( |
| 601 | if (dest.len < content_size) return error.ContentTooLarge; | 606 | if (dest.len < content_size) return error.ContentTooLarge; |
| 602 | | 607 | |
| 603 | const should_compute_checksum = frame_header.descriptor.content_checksum_flag and verify_checksum; | 608 | const should_compute_checksum = frame_header.descriptor.content_checksum_flag and verify_checksum; |
| 604 | var hash_state = if (should_compute_checksum) std.hash.XxHash64.init(0) else undefined; | 609 | var hasher_opt = if (should_compute_checksum) std.hash.XxHash64.init(0) else null; |
| 605 | | 610 | |
| 606 | const written_count = try decodeFrameBlocks( | 611 | const written_count = try decodeFrameBlocks( |
| 607 | dest, | 612 | dest, |
| 608 | src[consumed_count..], | 613 | src[consumed_count..], |
| 609 | &consumed_count, | 614 | &consumed_count, |
| 610 | if (should_compute_checksum) &hash_state else null, | 615 | if (hasher_opt) |*hasher| hasher else null, |
| 611 | ); | 616 | ); |
| 612 | | 617 | |
| 613 | if (frame_header.descriptor.content_checksum_flag) { | 618 | if (frame_header.descriptor.content_checksum_flag) { |
| 614 | const checksum = readIntSlice(u32, src[consumed_count .. consumed_count + 4]); | 619 | const checksum = readIntSlice(u32, src[consumed_count .. consumed_count + 4]); |
| 615 | consumed_count += 4; | 620 | consumed_count += 4; |
| 616 | if (verify_checksum) { | 621 | if (hasher_opt) |*hasher| { |
| 617 | const hash = hash_state.final(); | 622 | if (checksum != computeChecksum(hasher)) return error.ChecksumFailure; |
| 618 | const hash_low_bytes = hash & 0xFFFFFFFF; | | |
| 619 | if (checksum != hash_low_bytes) { | | |
| 620 | return error.ChecksumFailure; | | |
| 621 | } | | |
| 622 | } | 623 | } |
| 623 | } | 624 | } |
| 624 | return ReadWriteCount{ .read_count = consumed_count, .write_count = written_count }; | 625 | return ReadWriteCount{ .read_count = consumed_count, .write_count = written_count }; |
| ... | @@ -649,7 +650,7 @@ pub fn decodeZStandardFrameAlloc( | ... | @@ -649,7 +650,7 @@ pub fn decodeZStandardFrameAlloc( |
| 649 | @intCast(usize, window_size_raw); | 650 | @intCast(usize, window_size_raw); |
| 650 | | 651 | |
| 651 | const should_compute_checksum = frame_header.descriptor.content_checksum_flag and verify_checksum; | 652 | const should_compute_checksum = frame_header.descriptor.content_checksum_flag and verify_checksum; |
| 652 | var hash = if (should_compute_checksum) std.hash.XxHash64.init(0) else null; | 653 | var hasher_opt = if (should_compute_checksum) std.hash.XxHash64.init(0) else null; |
| 653 | | 654 | |
| 654 | const block_size_maximum = @min(1 << 17, window_size); | 655 | const block_size_maximum = @min(1 << 17, window_size); |
| 655 | | 656 | |
| ... | @@ -707,12 +708,20 @@ pub fn decodeZStandardFrameAlloc( | ... | @@ -707,12 +708,20 @@ pub fn decodeZStandardFrameAlloc( |
| 707 | const written_slice = ring_buffer.sliceLast(written_size); | 708 | const written_slice = ring_buffer.sliceLast(written_size); |
| 708 | try result.appendSlice(written_slice.first); | 709 | try result.appendSlice(written_slice.first); |
| 709 | try result.appendSlice(written_slice.second); | 710 | try result.appendSlice(written_slice.second); |
| 710 | if (hash) |*hash_state| { | 711 | if (hasher_opt) |*hasher| { |
| 711 | hash_state.update(written_slice.first); | 712 | hasher.update(written_slice.first); |
| 712 | hash_state.update(written_slice.second); | 713 | hasher.update(written_slice.second); |
| 713 | } | 714 | } |
| 714 | if (block_header.last_block) break; | 715 | if (block_header.last_block) break; |
| 715 | } | 716 | } |
| | 717 | |
| | 718 | if (frame_header.descriptor.content_checksum_flag) { |
| | 719 | const checksum = readIntSlice(u32, src[consumed_count .. consumed_count + 4]); |
| | 720 | consumed_count += 4; |
| | 721 | if (hasher_opt) |*hasher| { |
| | 722 | if (checksum != computeChecksum(hasher)) return error.ChecksumFailure; |
| | 723 | } |
| | 724 | } |
| 716 | return result.toOwnedSlice(); | 725 | return result.toOwnedSlice(); |
| 717 | } | 726 | } |
| 718 | | 727 | |