Skip to content

Commit ce048af

Browse files
author
dweiller
committed
std.compress.zstandard: add decodeFrameAlloc()
1 parent ffcec5e commit ce048af

File tree

1 file changed

+67
-7
lines changed

1 file changed

+67
-7
lines changed

lib/std/compress/zstandard/decompress.zig

+67-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const std = @import("std");
22
const assert = std.debug.assert;
3+
const Allocator = std.mem.Allocator;
34

45
const types = @import("types.zig");
56
const frame = types.frame;
@@ -32,6 +33,14 @@ pub fn isSkippableMagic(magic: u32) bool {
3233
/// - `error.EndOfStream` if `source` contains fewer than 4 bytes
3334
pub fn decodeFrameType(source: anytype) error{ BadMagic, EndOfStream }!frame.Kind {
3435
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.
43+
pub fn frameType(magic: u32) error{BadMagic}!frame.Kind {
3544
return if (magic == frame.ZStandard.magic_number)
3645
.zstandard
3746
else if (isSkippableMagic(magic))
@@ -78,6 +87,56 @@ pub fn decodeFrame(
7887
};
7988
}
8089

90+
pub const DecodeResult = struct {
91+
bytes: []u8,
92+
read_count: usize,
93+
};
94+
pub 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
118+
pub 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+
81140
/// Returns the frame checksum corresponding to the data fed into `hasher`
82141
pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 {
83142
const hash = hasher.final();
@@ -181,10 +240,11 @@ pub const FrameContext = struct {
181240
}
182241
};
183242

184-
/// Decode a Zstandard from from `src` and return the decompressed bytes; see
185-
/// `decodeZStandardFrame()`. `allocator` is used to allocate both the returned
186-
/// slice and internal buffers used during decoding. The first four bytes of
187-
/// `src` must be the magic number for a Zstandard frame.
243+
/// Decode a Zstandard from from `src` and return the decompressed bytes and the
244+
/// number of bytes read; see `decodeZStandardFrame()`. `allocator` is used to
245+
/// allocate both the returned slice and internal buffers used during decoding.
246+
/// The first four bytes of `src` must be the magic number for a Zstandard
247+
/// frame.
188248
///
189249
/// Errors returned:
190250
/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
@@ -200,11 +260,11 @@ pub const FrameContext = struct {
200260
/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
201261
/// - an error in `block.Error` if there are errors decoding a block
202262
pub fn decodeZStandardFrameAlloc(
203-
allocator: std.mem.Allocator,
263+
allocator: Allocator,
204264
src: []const u8,
205265
verify_checksum: bool,
206266
window_size_max: usize,
207-
) (error{OutOfMemory} || FrameContext.Error || FrameError)![]u8 {
267+
) (error{OutOfMemory} || FrameContext.Error || FrameError)!DecodeResult {
208268
var result = std.ArrayList(u8).init(allocator);
209269
assert(readInt(u32, src[0..4]) == frame.ZStandard.magic_number);
210270
var consumed_count: usize = 4;
@@ -258,7 +318,7 @@ pub fn decodeZStandardFrameAlloc(
258318
if (checksum != computeChecksum(hasher)) return error.ChecksumFailure;
259319
}
260320
}
261-
return result.toOwnedSlice();
321+
return DecodeResult{ .bytes = try result.toOwnedSlice(), .read_count = consumed_count };
262322
}
263323

264324
/// Convenience wrapper for decoding all blocks in a frame; see `decodeBlock()`.

0 commit comments

Comments
 (0)