| ... | ... | @@ -49,6 +49,25 @@ pub fn frameType(magic: u32) error{BadMagic}!frame.Kind { |
| 49 | 49 | error.BadMagic; |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | pub const FrameHeader = union(enum) { |
| 53 | zstandard: types.frame.Zstandard.Header, |
| 54 | skippable: types.frame.Skippable.Header, |
| 55 | }; |
| 56 | |
| 57 | pub 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 | |
| 52 | 71 | const ReadWriteCount = struct { |
| 53 | 72 | read_count: usize, |
| 54 | 73 | write_count: usize, |
| ... | ... | @@ -129,15 +148,6 @@ pub fn decodeFrame( |
| 129 | 148 | } |
| 130 | 149 | } |
| 131 | 150 | |
| 132 | | pub const DecodeResult = struct { |
| 133 | | bytes: []u8, |
| 134 | | read_count: usize, |
| 135 | | }; |
| 136 | | pub const DecodedFrame = union(enum) { |
| 137 | | zstandard: DecodeResult, |
| 138 | | skippable: frame.Skippable.Header, |
| 139 | | }; |
| 140 | | |
| 141 | 151 | /// Decodes the frame at the start of `src` into `dest`. Returns the number of |
| 142 | 152 | /// bytes read from `src`. |
| 143 | 153 | /// |
| ... | ... | @@ -186,7 +196,6 @@ pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 { |
| 186 | 196 | } |
| 187 | 197 | |
| 188 | 198 | const FrameError = error{ |
| 189 | | DictionaryIdFlagUnsupported, |
| 190 | 199 | ChecksumFailure, |
| 191 | 200 | BadContentSize, |
| 192 | 201 | EndOfStream, |
| ... | ... | @@ -220,6 +229,7 @@ pub fn decodeZstandardFrame( |
| 220 | 229 | ContentTooLarge, |
| 221 | 230 | ContentSizeTooLarge, |
| 222 | 231 | WindowSizeUnknown, |
| 232 | DictionaryIdFlagUnsupported, |
| 223 | 233 | } || FrameError)!ReadWriteCount { |
| 224 | 234 | assert(readInt(u32, src[0..4]) == frame.Zstandard.magic_number); |
| 225 | 235 | var consumed_count: usize = 4; |
| ... | ... | @@ -234,11 +244,27 @@ pub fn decodeZstandardFrame( |
| 234 | 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 | } |
| 237 | 257 | |
| 258 | pub fn decodeZStandardFrameBlocks( |
| 259 | dest: []u8, |
| 260 | src: []const u8, |
| 261 | frame_context: *FrameContext, |
| 262 | ) (error{ ContentTooLarge, UnknownContentSizeUnsupported } || FrameError)!ReadWriteCount { |
| 238 | 263 | const content_size = frame_context.content_size orelse return error.UnknownContentSizeUnsupported; |
| 239 | 264 | if (dest.len < content_size) return error.ContentTooLarge; |
| 240 | 265 | |
| 241 | | const written_count = decodeFrameBlocks( |
| 266 | var consumed_count: usize = 0; |
| 267 | const written_count = decodeFrameBlocksInner( |
| 242 | 268 | dest[0..content_size], |
| 243 | 269 | src[consumed_count..], |
| 244 | 270 | &consumed_count, |
| ... | ... | @@ -279,7 +305,7 @@ pub const FrameContext = struct { |
| 279 | 305 | /// Errors returned: |
| 280 | 306 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary |
| 281 | 307 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size |
| 282 | | /// - `error.WindowTooLarge` if the window size is larger than |
| 308 | /// - `error.WindowTooLarge` if the window size is larger than `window_size_max` |
| 283 | 309 | pub fn init( |
| 284 | 310 | frame_header: frame.Zstandard.Header, |
| 285 | 311 | window_size_max: usize, |
| ... | ... | @@ -336,7 +362,6 @@ pub fn decodeZstandardFrameArrayList( |
| 336 | 362 | window_size_max: usize, |
| 337 | 363 | ) (error{OutOfMemory} || FrameContext.Error || FrameError)!usize { |
| 338 | 364 | assert(readInt(u32, src[0..4]) == frame.Zstandard.magic_number); |
| 339 | | const initial_len = dest.items.len; |
| 340 | 365 | var consumed_count: usize = 4; |
| 341 | 366 | |
| 342 | 367 | var frame_context = context: { |
| ... | ... | @@ -347,6 +372,23 @@ pub fn decodeZstandardFrameArrayList( |
| 347 | 372 | break :context try FrameContext.init(frame_header, window_size_max, verify_checksum); |
| 348 | 373 | }; |
| 349 | 374 | |
| 375 | consumed_count += try decodeZstandardFrameBlocksArrayList( |
| 376 | allocator, |
| 377 | dest, |
| 378 | src[consumed_count..], |
| 379 | &frame_context, |
| 380 | ); |
| 381 | return consumed_count; |
| 382 | } |
| 383 | |
| 384 | pub 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 | 392 | var ring_buffer = try RingBuffer.init(allocator, frame_context.window_size); |
| 351 | 393 | defer ring_buffer.deinit(allocator); |
| 352 | 394 | |
| ... | ... | @@ -355,8 +397,8 @@ pub fn decodeZstandardFrameArrayList( |
| 355 | 397 | var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined; |
| 356 | 398 | var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined; |
| 357 | 399 | |
| 358 | | var block_header = try block.decodeBlockHeaderSlice(src[consumed_count..]); |
| 359 | | consumed_count += 3; |
| 400 | var block_header = try block.decodeBlockHeaderSlice(src); |
| 401 | var consumed_count: usize = 3; |
| 360 | 402 | var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data); |
| 361 | 403 | while (true) : ({ |
| 362 | 404 | block_header = try block.decodeBlockHeaderSlice(src[consumed_count..]); |
| ... | ... | @@ -399,8 +441,9 @@ pub fn decodeZstandardFrameArrayList( |
| 399 | 441 | return consumed_count; |
| 400 | 442 | } |
| 401 | 443 | |
| 402 | | /// Convenience wrapper for decoding all blocks in a frame; see `decodeBlock()`. |
| 403 | | fn decodeFrameBlocks( |
| 444 | /// Convenience wrapper for decoding all blocks in a frame; see |
| 445 | /// `decodeZStandardFrameBlocks()`. |
| 446 | fn decodeFrameBlocksInner( |
| 404 | 447 | dest: []u8, |
| 405 | 448 | src: []const u8, |
| 406 | 449 | consumed_count: *usize, |