authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-01-22 16:12:05+11:00
committergravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-20 09:09:05+11:00
logc819e58c20b23d625b2b2350d1fc655481309d9f
treeb194db5242309094becfddddf56f490d23287760
parent05e63f241edb2199e91ce29c488e104dfb826935

std.compress.zstandard: add decodeZStandardFrameAlloc

This is a convenience wrapper - best to use `decodeZStandardFrame()` if the content size is known, or directly use `decodeBlockRingBuffer()`.

1 files changed, 84 insertions(+), 0 deletions(-)

lib/std/compress/zstandard/decompress.zig+84
......@@ -480,6 +480,90 @@ pub fn decodeZStandardFrame(dest: []u8, src: []const u8, verify_checksum: bool)
480480 return ReadWriteCount{ .read_count = consumed_count, .write_count = written_count };
481481}
482482
483pub fn decodeZStandardFrameAlloc(allocator: std.mem.Allocator, src: []const u8, verify_checksum: bool) ![]u8 {
484 var result = std.ArrayList(u8).init(allocator);
485 assert(readInt(u32, src[0..4]) == frame.ZStandard.magic_number);
486 var consumed_count: usize = 4;
487
488 const frame_header = try decodeZStandardHeader(src[consumed_count..], &consumed_count);
489
490 if (frame_header.descriptor.dictionary_id_flag != 0) return error.DictionaryIdFlagUnsupported;
491
492 const window_size = frameWindowSize(frame_header) orelse return error.WindowSizeUnknown;
493 log.debug("window size = {d}", .{window_size});
494
495 const should_compute_checksum = frame_header.descriptor.content_checksum_flag and verify_checksum;
496 var hash = if (should_compute_checksum) std.hash.XxHash64.init(0) else null;
497
498 const block_size_maximum = @min(1 << 17, window_size);
499 log.debug("block size maximum = {d}", .{block_size_maximum});
500
501 var window_data = try allocator.alloc(u8, window_size);
502 defer allocator.free(window_data);
503 var ring_buffer = RingBuffer{
504 .data = window_data,
505 .write_index = 0,
506 .read_index = 0,
507 };
508
509 // These tables take 7680 bytes
510 var literal_fse_data: [literal_table_size_max]Table.Fse = undefined;
511 var match_fse_data: [match_table_size_max]Table.Fse = undefined;
512 var offset_fse_data: [offset_table_size_max]Table.Fse = undefined;
513
514 var block_header = decodeBlockHeader(src[consumed_count..][0..3]);
515 consumed_count += 3;
516 var decode_state = DecodeState{
517 .repeat_offsets = .{
518 types.compressed_block.start_repeated_offset_1,
519 types.compressed_block.start_repeated_offset_2,
520 types.compressed_block.start_repeated_offset_3,
521 },
522
523 .offset = undefined,
524 .match = undefined,
525 .literal = undefined,
526
527 .literal_fse_buffer = &literal_fse_data,
528 .match_fse_buffer = &match_fse_data,
529 .offset_fse_buffer = &offset_fse_data,
530
531 .fse_tables_undefined = true,
532
533 .literal_written_count = 0,
534 .literal_stream_reader = undefined,
535 .literal_stream_bytes = undefined,
536 .literal_stream_index = undefined,
537 .huffman_tree = null,
538 };
539 var written_count: usize = 0;
540 while (true) : ({
541 block_header = decodeBlockHeader(src[consumed_count..][0..3]);
542 consumed_count += 3;
543 }) {
544 if (block_header.block_size > block_size_maximum) return error.CompressedBlockSizeOverMaximum;
545 const written_size = try decodeBlockRingBuffer(
546 &ring_buffer,
547 src[consumed_count..],
548 block_header,
549 &decode_state,
550 &consumed_count,
551 block_size_maximum,
552 );
553 if (written_size > block_size_maximum) return error.DecompressedBlockSizeOverMaximum;
554 const written_slice = ring_buffer.sliceLast(written_size);
555 try result.appendSlice(written_slice.first);
556 try result.appendSlice(written_slice.second);
557 if (hash) |*hash_state| {
558 hash_state.update(written_slice.first);
559 hash_state.update(written_slice.second);
560 }
561 written_count += written_size;
562 if (block_header.last_block) break;
563 }
564 return result.toOwnedSlice();
565}
566
483567pub fn decodeFrameBlocks(dest: []u8, src: []const u8, consumed_count: *usize, hash: ?*std.hash.XxHash64) !usize {
484568 // These tables take 7680 bytes
485569 var literal_fse_data: [literal_table_size_max]Table.Fse = undefined;