1
1
const std = @import ("std" );
2
2
const assert = std .debug .assert ;
3
+ const Allocator = std .mem .Allocator ;
3
4
4
5
const types = @import ("types.zig" );
5
6
const frame = types .frame ;
@@ -32,6 +33,14 @@ pub fn isSkippableMagic(magic: u32) bool {
32
33
/// - `error.EndOfStream` if `source` contains fewer than 4 bytes
33
34
pub fn decodeFrameType (source : anytype ) error { BadMagic , EndOfStream }! frame.Kind {
34
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.
43
+ pub fn frameType (magic : u32 ) error {BadMagic }! frame.Kind {
35
44
return if (magic == frame .ZStandard .magic_number )
36
45
.zstandard
37
46
else if (isSkippableMagic (magic ))
@@ -78,6 +87,56 @@ pub fn decodeFrame(
78
87
};
79
88
}
80
89
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
+
81
140
/// Returns the frame checksum corresponding to the data fed into `hasher`
82
141
pub fn computeChecksum (hasher : * std.hash.XxHash64 ) u32 {
83
142
const hash = hasher .final ();
@@ -181,10 +240,11 @@ pub const FrameContext = struct {
181
240
}
182
241
};
183
242
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.
188
248
///
189
249
/// Errors returned:
190
250
/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
@@ -200,11 +260,11 @@ pub const FrameContext = struct {
200
260
/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
201
261
/// - an error in `block.Error` if there are errors decoding a block
202
262
pub fn decodeZStandardFrameAlloc (
203
- allocator : std.mem. Allocator ,
263
+ allocator : Allocator ,
204
264
src : []const u8 ,
205
265
verify_checksum : bool ,
206
266
window_size_max : usize ,
207
- ) (error {OutOfMemory } || FrameContext .Error || FrameError )! [] u8 {
267
+ ) (error {OutOfMemory } || FrameContext .Error || FrameError )! DecodeResult {
208
268
var result = std .ArrayList (u8 ).init (allocator );
209
269
assert (readInt (u32 , src [0.. 4]) == frame .ZStandard .magic_number );
210
270
var consumed_count : usize = 4 ;
@@ -258,7 +318,7 @@ pub fn decodeZStandardFrameAlloc(
258
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
}
263
323
264
324
/// Convenience wrapper for decoding all blocks in a frame; see `decodeBlock()`.
0 commit comments