| ... | @@ -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 | } |
| 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 | const ReadWriteCount = struct { | 71 | const 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 | } |
| 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 | /// Decodes the frame at the start of `src` into `dest`. Returns the number of | 151 | /// 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 | } |
| 187 | | 197 | |
| 188 | const FrameError = error{ | 198 | const 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 | } |
| 237 | | 257 | |
| | 258 | pub 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; |
| 240 | | 265 | |
| 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 dictionary | 306 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary |
| 281 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size | 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 | 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; |
| 341 | | 366 | |
| 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 | }; |
| 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 | 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); |
| 352 | | 394 | |
| ... | @@ -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; |
| 357 | | 399 | |
| 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 | } |
| 401 | | 443 | |
| 402 | /// Convenience wrapper for decoding all blocks in a frame; see `decodeBlock()`. | 444 | /// Convenience wrapper for decoding all blocks in a frame; see |
| 403 | fn decodeFrameBlocks( | 445 | /// `decodeZStandardFrameBlocks()`. |
| | 446 | fn decodeFrameBlocksInner( |
| 404 | dest: []u8, | 447 | dest: []u8, |
| 405 | src: []const u8, | 448 | src: []const u8, |
| 406 | consumed_count: *usize, | 449 | consumed_count: *usize, |