authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-09 17:52:21+11:00
committergravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-20 09:09:06+11:00
log6d48b055af0cbe17e72426f808fa8408fce3eed6
treecf01976fd842c128b6b7ce15976df1f0aac89d71
parent3975a9d7ca2013a4ac667b637fb273a9432c53aa

std.compress.zstandard: add decodeFrameHeader

Also do some other minor API cleanup

1 files changed, 60 insertions(+), 17 deletions(-)

lib/std/compress/zstandard/decompress.zig+60-17
...@@ -49,6 +49,25 @@ pub fn frameType(magic: u32) error{BadMagic}!frame.Kind {...@@ -49,6 +49,25 @@ pub fn frameType(magic: u32) error{BadMagic}!frame.Kind {
49 error.BadMagic;49 error.BadMagic;
50}50}
5151
52pub const FrameHeader = union(enum) {
53 zstandard: types.frame.Zstandard.Header,
54 skippable: types.frame.Skippable.Header,
55};
56
57pub fn decodeFrameHeader(source: anytype) error{ BadMagic, EndOfStream, ReservedBitSet }!FrameHeader {
58 const magic = try source.readIntLittle(u32);
59 const frame_type = try frameType(magic);
60 switch (frame_type) {
61 .zstandard => return FrameHeader{ .zstandard = try decodeZstandardHeader(source) },
62 .skippable => return FrameHeader{
63 .skippable = .{
64 .magic_number = magic,
65 .frame_size = try source.readIntLittle(u32),
66 },
67 },
68 }
69}
70
52const ReadWriteCount = struct {71const ReadWriteCount = struct {
53 read_count: usize,72 read_count: usize,
54 write_count: usize,73 write_count: usize,
...@@ -129,15 +148,6 @@ pub fn decodeFrame(...@@ -129,15 +148,6 @@ pub fn decodeFrame(
129 }148 }
130}149}
131150
132pub const DecodeResult = struct {
133 bytes: []u8,
134 read_count: usize,
135};
136pub const DecodedFrame = union(enum) {
137 zstandard: DecodeResult,
138 skippable: frame.Skippable.Header,
139};
140
141/// Decodes the frame at the start of `src` into `dest`. Returns the number of151/// Decodes the frame at the start of `src` into `dest`. Returns the number of
142/// bytes read from `src`.152/// bytes read from `src`.
143///153///
...@@ -186,7 +196,6 @@ pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 {...@@ -186,7 +196,6 @@ pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 {
186}196}
187197
188const FrameError = error{198const FrameError = error{
189 DictionaryIdFlagUnsupported,
190 ChecksumFailure,199 ChecksumFailure,
191 BadContentSize,200 BadContentSize,
192 EndOfStream,201 EndOfStream,
...@@ -220,6 +229,7 @@ pub fn decodeZstandardFrame(...@@ -220,6 +229,7 @@ pub fn decodeZstandardFrame(
220 ContentTooLarge,229 ContentTooLarge,
221 ContentSizeTooLarge,230 ContentSizeTooLarge,
222 WindowSizeUnknown,231 WindowSizeUnknown,
232 DictionaryIdFlagUnsupported,
223} || FrameError)!ReadWriteCount {233} || FrameError)!ReadWriteCount {
224 assert(readInt(u32, src[0..4]) == frame.Zstandard.magic_number);234 assert(readInt(u32, src[0..4]) == frame.Zstandard.magic_number);
225 var consumed_count: usize = 4;235 var consumed_count: usize = 4;
...@@ -234,11 +244,27 @@ pub fn decodeZstandardFrame(...@@ -234,11 +244,27 @@ pub fn decodeZstandardFrame(
234 inline else => |e| return e,244 inline else => |e| return e,
235 };245 };
236 };246 };
247 const counts = try decodeZStandardFrameBlocks(
248 dest,
249 src[consumed_count..],
250 &frame_context,
251 );
252 return ReadWriteCount{
253 .read_count = counts.read_count + consumed_count,
254 .write_count = counts.write_count,
255 };
256}
237257
258pub fn decodeZStandardFrameBlocks(
259 dest: []u8,
260 src: []const u8,
261 frame_context: *FrameContext,
262) (error{ ContentTooLarge, UnknownContentSizeUnsupported } || FrameError)!ReadWriteCount {
238 const content_size = frame_context.content_size orelse return error.UnknownContentSizeUnsupported;263 const content_size = frame_context.content_size orelse return error.UnknownContentSizeUnsupported;
239 if (dest.len < content_size) return error.ContentTooLarge;264 if (dest.len < content_size) return error.ContentTooLarge;
240265
241 const written_count = decodeFrameBlocks(266 var consumed_count: usize = 0;
267 const written_count = decodeFrameBlocksInner(
242 dest[0..content_size],268 dest[0..content_size],
243 src[consumed_count..],269 src[consumed_count..],
244 &consumed_count,270 &consumed_count,
...@@ -279,7 +305,7 @@ pub const FrameContext = struct {...@@ -279,7 +305,7 @@ pub const FrameContext = struct {
279 /// Errors returned:305 /// Errors returned:
280 /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary306 /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
281 /// - `error.WindowSizeUnknown` if the frame does not have a valid window size307 /// - `error.WindowSizeUnknown` if the frame does not have a valid window size
282 /// - `error.WindowTooLarge` if the window size is larger than308 /// - `error.WindowTooLarge` if the window size is larger than `window_size_max`
283 pub fn init(309 pub fn init(
284 frame_header: frame.Zstandard.Header,310 frame_header: frame.Zstandard.Header,
285 window_size_max: usize,311 window_size_max: usize,
...@@ -336,7 +362,6 @@ pub fn decodeZstandardFrameArrayList(...@@ -336,7 +362,6 @@ pub fn decodeZstandardFrameArrayList(
336 window_size_max: usize,362 window_size_max: usize,
337) (error{OutOfMemory} || FrameContext.Error || FrameError)!usize {363) (error{OutOfMemory} || FrameContext.Error || FrameError)!usize {
338 assert(readInt(u32, src[0..4]) == frame.Zstandard.magic_number);364 assert(readInt(u32, src[0..4]) == frame.Zstandard.magic_number);
339 const initial_len = dest.items.len;
340 var consumed_count: usize = 4;365 var consumed_count: usize = 4;
341366
342 var frame_context = context: {367 var frame_context = context: {
...@@ -347,6 +372,23 @@ pub fn decodeZstandardFrameArrayList(...@@ -347,6 +372,23 @@ pub fn decodeZstandardFrameArrayList(
347 break :context try FrameContext.init(frame_header, window_size_max, verify_checksum);372 break :context try FrameContext.init(frame_header, window_size_max, verify_checksum);
348 };373 };
349374
375 consumed_count += try decodeZstandardFrameBlocksArrayList(
376 allocator,
377 dest,
378 src[consumed_count..],
379 &frame_context,
380 );
381 return consumed_count;
382}
383
384pub fn decodeZstandardFrameBlocksArrayList(
385 allocator: Allocator,
386 dest: *std.ArrayList(u8),
387 src: []const u8,
388 frame_context: *FrameContext,
389) (error{OutOfMemory} || FrameError)!usize {
390 const initial_len = dest.items.len;
391
350 var ring_buffer = try RingBuffer.init(allocator, frame_context.window_size);392 var ring_buffer = try RingBuffer.init(allocator, frame_context.window_size);
351 defer ring_buffer.deinit(allocator);393 defer ring_buffer.deinit(allocator);
352394
...@@ -355,8 +397,8 @@ pub fn decodeZstandardFrameArrayList(...@@ -355,8 +397,8 @@ pub fn decodeZstandardFrameArrayList(
355 var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined;397 var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined;
356 var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined;398 var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined;
357399
358 var block_header = try block.decodeBlockHeaderSlice(src[consumed_count..]);400 var block_header = try block.decodeBlockHeaderSlice(src);
359 consumed_count += 3;401 var consumed_count: usize = 3;
360 var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data);402 var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data);
361 while (true) : ({403 while (true) : ({
362 block_header = try block.decodeBlockHeaderSlice(src[consumed_count..]);404 block_header = try block.decodeBlockHeaderSlice(src[consumed_count..]);
...@@ -399,8 +441,9 @@ pub fn decodeZstandardFrameArrayList(...@@ -399,8 +441,9 @@ pub fn decodeZstandardFrameArrayList(
399 return consumed_count;441 return consumed_count;
400}442}
401443
402/// Convenience wrapper for decoding all blocks in a frame; see `decodeBlock()`.444/// Convenience wrapper for decoding all blocks in a frame; see
403fn decodeFrameBlocks(445/// `decodeZStandardFrameBlocks()`.
446fn decodeFrameBlocksInner(
404 dest: []u8,447 dest: []u8,
405 src: []const u8,448 src: []const u8,
406 consumed_count: *usize,449 consumed_count: *usize,