authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-02 22:06:23+11:00
committergravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-20 09:09:06+11:00
logddeabc9aa7a465793ccbfd56dc29f04bf0d2854b
tree26ba00a38c8cc89c7828c1c691b9aa2c65bc3de5
parent89f9c5cb373c81af5cb052cd9e68e44a123d0b04

std.compress.zstandard: add `decodeFrameAlloc()`


1 files changed, 67 insertions(+), 7 deletions(-)

lib/std/compress/zstandard/decompress.zig+67-7
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;
34
4const types = @import("types.zig");5const types = @import("types.zig");
5const frame = types.frame;6const frame = types.frame;
...@@ -32,6 +33,14 @@ pub fn isSkippableMagic(magic: u32) bool {...@@ -32,6 +33,14 @@ pub fn isSkippableMagic(magic: u32) bool {
32/// - `error.EndOfStream` if `source` contains fewer than 4 bytes33/// - `error.EndOfStream` if `source` contains fewer than 4 bytes
33pub fn decodeFrameType(source: anytype) error{ BadMagic, EndOfStream }!frame.Kind {34pub fn decodeFrameType(source: anytype) error{ BadMagic, EndOfStream }!frame.Kind {
34 const magic = try source.readIntLittle(u32);35 const magic = try source.readIntLittle(u32);
36 return frameType(magic);
37}
38
39/// Returns the kind of frame associated to `magic`.
40///
41/// Errors returned:
42/// - `error.BadMagic` if `magic` is not a valid magic number.
43pub fn frameType(magic: u32) error{BadMagic}!frame.Kind {
35 return if (magic == frame.ZStandard.magic_number)44 return if (magic == frame.ZStandard.magic_number)
36 .zstandard45 .zstandard
37 else if (isSkippableMagic(magic))46 else if (isSkippableMagic(magic))
...@@ -78,6 +87,56 @@ pub fn decodeFrame(...@@ -78,6 +87,56 @@ pub fn decodeFrame(
78 };87 };
79}88}
8089
90pub const DecodeResult = struct {
91 bytes: []u8,
92 read_count: usize,
93};
94pub const DecodedFrame = union(enum) {
95 zstandard: DecodeResult,
96 skippable: frame.Skippable.Header,
97};
98
99/// Decodes the frame at the start of `src` into `dest`. Returns the number of
100/// bytes read from `src` and the decoded bytes for a Zstandard frame, or the
101/// frame header for a Skippable frame.
102///
103/// Errors returned:
104/// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic
105/// number for a Zstandard or Skippable frame
106/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
107/// - `error.WindowTooLarge` if the window size is larger than
108/// `window_size_max`
109/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
110/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
111/// contains a checksum that does not match the checksum of the decompressed
112/// data
113/// - `error.ReservedBitSet` if the reserved bit of the frame header is set
114/// - `error.UnusedBitSet` if the unused bit of the frame header is set
115/// - `error.EndOfStream` if `src` does not contain a complete frame
116/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
117/// - an error in `block.Error` if there are errors decoding a block
118pub fn decodeFrameAlloc(
119 allocator: Allocator,
120 src: []const u8,
121 verify_checksum: bool,
122 window_size_max: usize,
123) !DecodedFrame {
124 var fbs = std.io.fixedBufferStream(src);
125 const reader = fbs.reader();
126 const magic = try reader.readIntLittle(u32);
127 return switch (try frameType(magic)) {
128 .zstandard => .{
129 .zstandard = try decodeZStandardFrameAlloc(allocator, src, verify_checksum, window_size_max),
130 },
131 .skippable => .{
132 .skippable = .{
133 .magic_number = magic,
134 .frame_size = try reader.readIntLittle(u32),
135 },
136 },
137 };
138}
139
81/// Returns the frame checksum corresponding to the data fed into `hasher`140/// Returns the frame checksum corresponding to the data fed into `hasher`
82pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 {141pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 {
83 const hash = hasher.final();142 const hash = hasher.final();
...@@ -181,10 +240,11 @@ pub const FrameContext = struct {...@@ -181,10 +240,11 @@ pub const FrameContext = struct {
181 }240 }
182};241};
183242
184/// Decode a Zstandard from from `src` and return the decompressed bytes; see243/// Decode a Zstandard from from `src` and return the decompressed bytes and the
185/// `decodeZStandardFrame()`. `allocator` is used to allocate both the returned244/// number of bytes read; see `decodeZStandardFrame()`. `allocator` is used to
186/// slice and internal buffers used during decoding. The first four bytes of245/// allocate both the returned slice and internal buffers used during decoding.
187/// `src` must be the magic number for a Zstandard frame.246/// The first four bytes of `src` must be the magic number for a Zstandard
247/// frame.
188///248///
189/// Errors returned:249/// Errors returned:
190/// - `error.WindowSizeUnknown` if the frame does not have a valid window size250/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
...@@ -200,11 +260,11 @@ pub const FrameContext = struct {...@@ -200,11 +260,11 @@ pub const FrameContext = struct {
200/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory260/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
201/// - an error in `block.Error` if there are errors decoding a block261/// - an error in `block.Error` if there are errors decoding a block
202pub fn decodeZStandardFrameAlloc(262pub fn decodeZStandardFrameAlloc(
203 allocator: std.mem.Allocator,263 allocator: Allocator,
204 src: []const u8,264 src: []const u8,
205 verify_checksum: bool,265 verify_checksum: bool,
206 window_size_max: usize,266 window_size_max: usize,
207) (error{OutOfMemory} || FrameContext.Error || FrameError)![]u8 {267) (error{OutOfMemory} || FrameContext.Error || FrameError)!DecodeResult {
208 var result = std.ArrayList(u8).init(allocator);268 var result = std.ArrayList(u8).init(allocator);
209 assert(readInt(u32, src[0..4]) == frame.ZStandard.magic_number);269 assert(readInt(u32, src[0..4]) == frame.ZStandard.magic_number);
210 var consumed_count: usize = 4;270 var consumed_count: usize = 4;
...@@ -258,7 +318,7 @@ pub fn decodeZStandardFrameAlloc(...@@ -258,7 +318,7 @@ pub fn decodeZStandardFrameAlloc(
258 if (checksum != computeChecksum(hasher)) return error.ChecksumFailure;318 if (checksum != computeChecksum(hasher)) return error.ChecksumFailure;
259 }319 }
260 }320 }
261 return result.toOwnedSlice();321 return DecodeResult{ .bytes = try result.toOwnedSlice(), .read_count = consumed_count };
262}322}
263323
264/// Convenience wrapper for decoding all blocks in a frame; see `decodeBlock()`.324/// Convenience wrapper for decoding all blocks in a frame; see `decodeBlock()`.