| ... | @@ -6,6 +6,8 @@ const types = @import("types.zig"); | ... | @@ -6,6 +6,8 @@ const types = @import("types.zig"); |
| 6 | const frame = types.frame; | 6 | const frame = types.frame; |
| 7 | const LiteralsSection = types.compressed_block.LiteralsSection; | 7 | const LiteralsSection = types.compressed_block.LiteralsSection; |
| 8 | const SequencesSection = types.compressed_block.SequencesSection; | 8 | const SequencesSection = types.compressed_block.SequencesSection; |
| | 9 | const SkippableHeader = types.frame.Skippable.Header; |
| | 10 | const ZstandardHeader = types.frame.Zstandard.Header; |
| 9 | const Table = types.compressed_block.Table; | 11 | const Table = types.compressed_block.Table; |
| 10 | | 12 | |
| 11 | pub const block = @import("decode/block.zig"); | 13 | pub const block = @import("decode/block.zig"); |
| ... | @@ -16,15 +18,13 @@ const readers = @import("readers.zig"); | ... | @@ -16,15 +18,13 @@ const readers = @import("readers.zig"); |
| 16 | | 18 | |
| 17 | const readInt = std.mem.readIntLittle; | 19 | const readInt = std.mem.readIntLittle; |
| 18 | const readIntSlice = std.mem.readIntSliceLittle; | 20 | const readIntSlice = std.mem.readIntSliceLittle; |
| 19 | fn readVarInt(comptime T: type, bytes: []const u8) T { | | |
| 20 | return std.mem.readVarInt(T, bytes, .Little); | | |
| 21 | } | | |
| 22 | | 21 | |
| | 22 | /// Returns `true` is `magic` is a valid magic number for a skippable frame |
| 23 | pub fn isSkippableMagic(magic: u32) bool { | 23 | pub fn isSkippableMagic(magic: u32) bool { |
| 24 | return frame.Skippable.magic_number_min <= magic and magic <= frame.Skippable.magic_number_max; | 24 | return frame.Skippable.magic_number_min <= magic and magic <= frame.Skippable.magic_number_max; |
| 25 | } | 25 | } |
| 26 | | 26 | |
| 27 | /// Returns the kind of frame at the beginning of `src`. | 27 | /// Returns the kind of frame at the beginning of `source`. |
| 28 | /// | 28 | /// |
| 29 | /// Errors returned: | 29 | /// Errors returned: |
| 30 | /// - `error.BadMagic` if `source` begins with bytes not equal to the | 30 | /// - `error.BadMagic` if `source` begins with bytes not equal to the |
| ... | @@ -50,11 +50,22 @@ pub fn frameType(magic: u32) error{BadMagic}!frame.Kind { | ... | @@ -50,11 +50,22 @@ pub fn frameType(magic: u32) error{BadMagic}!frame.Kind { |
| 50 | } | 50 | } |
| 51 | | 51 | |
| 52 | pub const FrameHeader = union(enum) { | 52 | pub const FrameHeader = union(enum) { |
| 53 | zstandard: types.frame.Zstandard.Header, | 53 | zstandard: ZstandardHeader, |
| 54 | skippable: types.frame.Skippable.Header, | 54 | skippable: SkippableHeader, |
| 55 | }; | 55 | }; |
| 56 | | 56 | |
| 57 | pub fn decodeFrameHeader(source: anytype) error{ BadMagic, EndOfStream, ReservedBitSet }!FrameHeader { | 57 | pub const HeaderError = error{ BadMagic, EndOfStream, ReservedBitSet }; |
| | 58 | |
| | 59 | /// Returns the header of the frame at the beginning of `source`. |
| | 60 | /// |
| | 61 | /// Errors returned: |
| | 62 | /// - `error.BadMagic` if `source` begins with bytes not equal to the |
| | 63 | /// Zstandard frame magic number, or outside the range of magic numbers for |
| | 64 | /// skippable frames. |
| | 65 | /// - `error.EndOfStream` if `source` contains fewer than 4 bytes |
| | 66 | /// - `error.ReservedBitSet` if the frame is a Zstandard frame and any of the |
| | 67 | /// reserved bits are set |
| | 68 | pub fn decodeFrameHeader(source: anytype) HeaderError!FrameHeader { |
| 58 | const magic = try source.readIntLittle(u32); | 69 | const magic = try source.readIntLittle(u32); |
| 59 | const frame_type = try frameType(magic); | 70 | const frame_type = try frameType(magic); |
| 60 | switch (frame_type) { | 71 | switch (frame_type) { |
| ... | @@ -68,41 +79,74 @@ pub fn decodeFrameHeader(source: anytype) error{ BadMagic, EndOfStream, Reserved | ... | @@ -68,41 +79,74 @@ pub fn decodeFrameHeader(source: anytype) error{ BadMagic, EndOfStream, Reserved |
| 68 | } | 79 | } |
| 69 | } | 80 | } |
| 70 | | 81 | |
| 71 | const ReadWriteCount = struct { | 82 | pub const ReadWriteCount = struct { |
| 72 | read_count: usize, | 83 | read_count: usize, |
| 73 | write_count: usize, | 84 | write_count: usize, |
| 74 | }; | 85 | }; |
| 75 | | 86 | |
| 76 | /// Decodes frames from `src` into `dest`; see `decodeFrame()`. | 87 | /// Decodes frames from `src` into `dest`; returns the length of the result. |
| 77 | pub fn decode(dest: []u8, src: []const u8, verify_checksum: bool) !usize { | 88 | /// The stream should not have extra trailing bytes - either all bytes in `src` |
| | 89 | /// will be decoded, or an error will be returned. An error will be returned if |
| | 90 | /// a Zstandard frame in `src` does not declare its content size. |
| | 91 | /// |
| | 92 | /// Errors returned: |
| | 93 | /// - `error.DictionaryIdFlagUnsupported` if a `src` contains a frame that |
| | 94 | /// uses a dictionary |
| | 95 | /// - `error.MalformedFrame` if a frame in `src` is invalid |
| | 96 | /// - `error.UnknownContentSizeUnsupported` if a frame in `src` does not |
| | 97 | /// declare its content size |
| | 98 | pub fn decode(dest: []u8, src: []const u8, verify_checksum: bool) error{ |
| | 99 | MalformedFrame, |
| | 100 | UnknownContentSizeUnsupported, |
| | 101 | DictionaryIdFlagUnsupported, |
| | 102 | }!usize { |
| 78 | var write_count: usize = 0; | 103 | var write_count: usize = 0; |
| 79 | var read_count: usize = 0; | 104 | var read_count: usize = 0; |
| 80 | while (read_count < src.len) { | 105 | while (read_count < src.len) { |
| 81 | const counts = try decodeFrame(dest, src[read_count..], verify_checksum); | 106 | const counts = decodeFrame(dest, src[read_count..], verify_checksum) catch |err| { |
| | 107 | switch (err) { |
| | 108 | error.UnknownContentSizeUnsupported => return error.UnknownContentSizeUnsupported, |
| | 109 | error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported, |
| | 110 | else => return error.MalformedFrame, |
| | 111 | } |
| | 112 | }; |
| 82 | read_count += counts.read_count; | 113 | read_count += counts.read_count; |
| 83 | write_count += counts.write_count; | 114 | write_count += counts.write_count; |
| 84 | } | 115 | } |
| 85 | return write_count; | 116 | return write_count; |
| 86 | } | 117 | } |
| 87 | | 118 | |
| | 119 | /// Decodes a stream of frames from `src`; returns the decoded bytes. The stream |
| | 120 | /// should not have extra trailing bytes - either all bytes in `src` will be |
| | 121 | /// decoded, or an error will be returned. |
| | 122 | /// |
| | 123 | /// Errors returned: |
| | 124 | /// - `error.DictionaryIdFlagUnsupported` if a `src` contains a frame that |
| | 125 | /// uses a dictionary |
| | 126 | /// - `error.MalformedFrame` if a frame in `src` is invalid |
| | 127 | /// - `error.OutOfMemory` if `allocator` cannot allocate enough memory |
| 88 | pub fn decodeAlloc( | 128 | pub fn decodeAlloc( |
| 89 | allocator: Allocator, | 129 | allocator: Allocator, |
| 90 | src: []const u8, | 130 | src: []const u8, |
| 91 | verify_checksum: bool, | 131 | verify_checksum: bool, |
| 92 | window_size_max: usize, | 132 | window_size_max: usize, |
| 93 | ) ![]u8 { | 133 | ) error{ DictionaryIdFlagUnsupported, MalformedFrame, OutOfMemory }![]u8 { |
| 94 | var result = std.ArrayList(u8).init(allocator); | 134 | var result = std.ArrayList(u8).init(allocator); |
| 95 | errdefer result.deinit(); | 135 | errdefer result.deinit(); |
| 96 | | 136 | |
| 97 | var read_count: usize = 0; | 137 | var read_count: usize = 0; |
| 98 | while (read_count < src.len) { | 138 | while (read_count < src.len) { |
| 99 | read_count += try decodeFrameArrayList( | 139 | read_count += decodeFrameArrayList( |
| 100 | allocator, | 140 | allocator, |
| 101 | &result, | 141 | &result, |
| 102 | src[read_count..], | 142 | src[read_count..], |
| 103 | verify_checksum, | 143 | verify_checksum, |
| 104 | window_size_max, | 144 | window_size_max, |
| 105 | ); | 145 | ) catch |err| switch (err) { |
| | 146 | error.OutOfMemory => return error.OutOfMemory, |
| | 147 | error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported, |
| | 148 | else => return error.MalformedFrame, |
| | 149 | }; |
| 106 | } | 150 | } |
| 107 | return result.toOwnedSlice(); | 151 | return result.toOwnedSlice(); |
| 108 | } | 152 | } |
| ... | @@ -112,18 +156,24 @@ pub fn decodeAlloc( | ... | @@ -112,18 +156,24 @@ pub fn decodeAlloc( |
| 112 | /// frames that declare the decompressed content size. | 156 | /// frames that declare the decompressed content size. |
| 113 | /// | 157 | /// |
| 114 | /// Errors returned: | 158 | /// Errors returned: |
| | 159 | /// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic |
| | 160 | /// number for a Zstandard or skippable frame |
| 115 | /// - `error.UnknownContentSizeUnsupported` if the frame does not declare the | 161 | /// - `error.UnknownContentSizeUnsupported` if the frame does not declare the |
| 116 | /// uncompressed content size | 162 | /// uncompressed content size |
| | 163 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size |
| 117 | /// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data | 164 | /// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data |
| 118 | /// size declared by the frame header | 165 | /// size declared by the frame header |
| 119 | /// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic | 166 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content size |
| 120 | /// number for a Zstandard or Skippable frame | 167 | /// that is larger than `std.math.maxInt(usize)` |
| 121 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | 168 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary |
| 122 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame | 169 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame |
| 123 | /// contains a checksum that does not match the checksum of the decompressed | 170 | /// contains a checksum that does not match the checksum of the decompressed |
| 124 | /// data | 171 | /// data |
| 125 | /// - `error.ReservedBitSet` if the reserved bit of the frame header is set | 172 | /// - `error.ReservedBitSet` if any of the reserved bits of the frame header |
| | 173 | /// are set |
| 126 | /// - `error.EndOfStream` if `src` does not contain a complete frame | 174 | /// - `error.EndOfStream` if `src` does not contain a complete frame |
| | 175 | /// - `error.BadContentSize` if the content size declared by the frame does |
| | 176 | /// not equal the actual size of decompressed data |
| 127 | /// - an error in `block.Error` if there are errors decoding a block | 177 | /// - an error in `block.Error` if there are errors decoding a block |
| 128 | /// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a | 178 | /// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a |
| 129 | /// size greater than `src.len` | 179 | /// size greater than `src.len` |
| ... | @@ -131,7 +181,15 @@ pub fn decodeFrame( | ... | @@ -131,7 +181,15 @@ pub fn decodeFrame( |
| 131 | dest: []u8, | 181 | dest: []u8, |
| 132 | src: []const u8, | 182 | src: []const u8, |
| 133 | verify_checksum: bool, | 183 | verify_checksum: bool, |
| 134 | ) !ReadWriteCount { | 184 | ) (error{ |
| | 185 | BadMagic, |
| | 186 | UnknownContentSizeUnsupported, |
| | 187 | ContentTooLarge, |
| | 188 | ContentSizeTooLarge, |
| | 189 | WindowSizeUnknown, |
| | 190 | DictionaryIdFlagUnsupported, |
| | 191 | SkippableSizeTooLarge, |
| | 192 | } || FrameError)!ReadWriteCount { |
| 135 | var fbs = std.io.fixedBufferStream(src); | 193 | var fbs = std.io.fixedBufferStream(src); |
| 136 | switch (try decodeFrameType(fbs.reader())) { | 194 | switch (try decodeFrameType(fbs.reader())) { |
| 137 | .zstandard => return decodeZstandardFrame(dest, src, verify_checksum), | 195 | .zstandard => return decodeZstandardFrame(dest, src, verify_checksum), |
| ... | @@ -153,16 +211,21 @@ pub fn decodeFrame( | ... | @@ -153,16 +211,21 @@ pub fn decodeFrame( |
| 153 | /// | 211 | /// |
| 154 | /// Errors returned: | 212 | /// Errors returned: |
| 155 | /// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic | 213 | /// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic |
| 156 | /// number for a Zstandard or Skippable frame | 214 | /// number for a Zstandard or skippable frame |
| 157 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size | 215 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size |
| 158 | /// - `error.WindowTooLarge` if the window size is larger than | 216 | /// - `error.WindowTooLarge` if the window size is larger than |
| 159 | /// `window_size_max` | 217 | /// `window_size_max` |
| | 218 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content size |
| | 219 | /// that is larger than `std.math.maxInt(usize)` |
| 160 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | 220 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary |
| 161 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame | 221 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame |
| 162 | /// contains a checksum that does not match the checksum of the decompressed | 222 | /// contains a checksum that does not match the checksum of the decompressed |
| 163 | /// data | 223 | /// data |
| 164 | /// - `error.ReservedBitSet` if the reserved bit of the frame header is set | 224 | /// - `error.ReservedBitSet` if any of the reserved bits of the frame header |
| | 225 | /// are set |
| 165 | /// - `error.EndOfStream` if `src` does not contain a complete frame | 226 | /// - `error.EndOfStream` if `src` does not contain a complete frame |
| | 227 | /// - `error.BadContentSize` if the content size declared by the frame does |
| | 228 | /// not equal the actual size of decompressed data |
| 166 | /// - `error.OutOfMemory` if `allocator` cannot allocate enough memory | 229 | /// - `error.OutOfMemory` if `allocator` cannot allocate enough memory |
| 167 | /// - an error in `block.Error` if there are errors decoding a block | 230 | /// - an error in `block.Error` if there are errors decoding a block |
| 168 | /// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a | 231 | /// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a |
| ... | @@ -173,12 +236,18 @@ pub fn decodeFrameArrayList( | ... | @@ -173,12 +236,18 @@ pub fn decodeFrameArrayList( |
| 173 | src: []const u8, | 236 | src: []const u8, |
| 174 | verify_checksum: bool, | 237 | verify_checksum: bool, |
| 175 | window_size_max: usize, | 238 | window_size_max: usize, |
| 176 | ) !usize { | 239 | ) (error{ BadMagic, OutOfMemory, SkippableSizeTooLarge } || FrameContext.Error || FrameError)!usize { |
| 177 | var fbs = std.io.fixedBufferStream(src); | 240 | var fbs = std.io.fixedBufferStream(src); |
| 178 | const reader = fbs.reader(); | 241 | const reader = fbs.reader(); |
| 179 | const magic = try reader.readIntLittle(u32); | 242 | const magic = try reader.readIntLittle(u32); |
| 180 | switch (try frameType(magic)) { | 243 | switch (try frameType(magic)) { |
| 181 | .zstandard => return decodeZstandardFrameArrayList(allocator, dest, src, verify_checksum, window_size_max), | 244 | .zstandard => return decodeZstandardFrameArrayList( |
| | 245 | allocator, |
| | 246 | dest, |
| | 247 | src, |
| | 248 | verify_checksum, |
| | 249 | window_size_max, |
| | 250 | ), |
| 182 | .skippable => { | 251 | .skippable => { |
| 183 | const content_size = try fbs.reader().readIntLittle(u32); | 252 | const content_size = try fbs.reader().readIntLittle(u32); |
| 184 | if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge; | 253 | if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge; |
| ... | @@ -211,7 +280,10 @@ const FrameError = error{ | ... | @@ -211,7 +280,10 @@ const FrameError = error{ |
| 211 | /// uncompressed content size | 280 | /// uncompressed content size |
| 212 | /// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data | 281 | /// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data |
| 213 | /// size declared by the frame header | 282 | /// size declared by the frame header |
| | 283 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size |
| 214 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | 284 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary |
| | 285 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content size |
| | 286 | /// that is larger than `std.math.maxInt(usize)` |
| 215 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame | 287 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame |
| 216 | /// contains a checksum that does not match the checksum of the decompressed | 288 | /// contains a checksum that does not match the checksum of the decompressed |
| 217 | /// data | 289 | /// data |
| ... | @@ -239,7 +311,11 @@ pub fn decodeZstandardFrame( | ... | @@ -239,7 +311,11 @@ pub fn decodeZstandardFrame( |
| 239 | var source = fbs.reader(); | 311 | var source = fbs.reader(); |
| 240 | const frame_header = try decodeZstandardHeader(source); | 312 | const frame_header = try decodeZstandardHeader(source); |
| 241 | consumed_count += fbs.pos; | 313 | consumed_count += fbs.pos; |
| 242 | break :context FrameContext.init(frame_header, std.math.maxInt(usize), verify_checksum) catch |err| switch (err) { | 314 | break :context FrameContext.init( |
| | 315 | frame_header, |
| | 316 | std.math.maxInt(usize), |
| | 317 | verify_checksum, |
| | 318 | ) catch |err| switch (err) { |
| 243 | error.WindowTooLarge => unreachable, | 319 | error.WindowTooLarge => unreachable, |
| 244 | inline else => |e| return e, | 320 | inline else => |e| return e, |
| 245 | }; | 321 | }; |
| ... | @@ -260,7 +336,8 @@ pub fn decodeZStandardFrameBlocks( | ... | @@ -260,7 +336,8 @@ pub fn decodeZStandardFrameBlocks( |
| 260 | src: []const u8, | 336 | src: []const u8, |
| 261 | frame_context: *FrameContext, | 337 | frame_context: *FrameContext, |
| 262 | ) (error{ ContentTooLarge, UnknownContentSizeUnsupported } || FrameError)!ReadWriteCount { | 338 | ) (error{ ContentTooLarge, UnknownContentSizeUnsupported } || FrameError)!ReadWriteCount { |
| 263 | const content_size = frame_context.content_size orelse return error.UnknownContentSizeUnsupported; | 339 | const content_size = frame_context.content_size orelse |
| | 340 | return error.UnknownContentSizeUnsupported; |
| 264 | if (dest.len < content_size) return error.ContentTooLarge; | 341 | if (dest.len < content_size) return error.ContentTooLarge; |
| 265 | | 342 | |
| 266 | var consumed_count: usize = 0; | 343 | var consumed_count: usize = 0; |
| ... | @@ -304,14 +381,19 @@ pub const FrameContext = struct { | ... | @@ -304,14 +381,19 @@ pub const FrameContext = struct { |
| 304 | /// | 381 | /// |
| 305 | /// Errors returned: | 382 | /// Errors returned: |
| 306 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | 383 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary |
| 307 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size | 384 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window |
| 308 | /// - `error.WindowTooLarge` if the window size is larger than `window_size_max` | 385 | /// size |
| | 386 | /// - `error.WindowTooLarge` if the window size is larger than |
| | 387 | /// `window_size_max` |
| | 388 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content |
| | 389 | /// size larger than `std.math.maxInt(usize)` |
| 309 | pub fn init( | 390 | pub fn init( |
| 310 | frame_header: frame.Zstandard.Header, | 391 | frame_header: ZstandardHeader, |
| 311 | window_size_max: usize, | 392 | window_size_max: usize, |
| 312 | verify_checksum: bool, | 393 | verify_checksum: bool, |
| 313 | ) Error!FrameContext { | 394 | ) Error!FrameContext { |
| 314 | if (frame_header.descriptor.dictionary_id_flag != 0) return error.DictionaryIdFlagUnsupported; | 395 | if (frame_header.descriptor.dictionary_id_flag != 0) |
| | 396 | return error.DictionaryIdFlagUnsupported; |
| 315 | | 397 | |
| 316 | const window_size_raw = frameWindowSize(frame_header) orelse return error.WindowSizeUnknown; | 398 | const window_size_raw = frameWindowSize(frame_header) orelse return error.WindowSizeUnknown; |
| 317 | const window_size = if (window_size_raw > window_size_max) | 399 | const window_size = if (window_size_raw > window_size_max) |
| ... | @@ -319,7 +401,8 @@ pub const FrameContext = struct { | ... | @@ -319,7 +401,8 @@ pub const FrameContext = struct { |
| 319 | else | 401 | else |
| 320 | @intCast(usize, window_size_raw); | 402 | @intCast(usize, window_size_raw); |
| 321 | | 403 | |
| 322 | const should_compute_checksum = frame_header.descriptor.content_checksum_flag and verify_checksum; | 404 | const should_compute_checksum = |
| | 405 | frame_header.descriptor.content_checksum_flag and verify_checksum; |
| 323 | | 406 | |
| 324 | const content_size = if (frame_header.content_size) |size| | 407 | const content_size = if (frame_header.content_size) |size| |
| 325 | std.math.cast(usize, size) orelse return error.ContentSizeTooLarge | 408 | std.math.cast(usize, size) orelse return error.ContentSizeTooLarge |
| ... | @@ -345,6 +428,8 @@ pub const FrameContext = struct { | ... | @@ -345,6 +428,8 @@ pub const FrameContext = struct { |
| 345 | /// - `error.WindowTooLarge` if the window size is larger than | 428 | /// - `error.WindowTooLarge` if the window size is larger than |
| 346 | /// `window_size_max` | 429 | /// `window_size_max` |
| 347 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | 430 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary |
| | 431 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content size |
| | 432 | /// that is larger than `std.math.maxInt(usize)` |
| 348 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame | 433 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame |
| 349 | /// contains a checksum that does not match the checksum of the decompressed | 434 | /// contains a checksum that does not match the checksum of the decompressed |
| 350 | /// data | 435 | /// data |
| ... | @@ -441,8 +526,6 @@ pub fn decodeZstandardFrameBlocksArrayList( | ... | @@ -441,8 +526,6 @@ pub fn decodeZstandardFrameBlocksArrayList( |
| 441 | return consumed_count; | 526 | return consumed_count; |
| 442 | } | 527 | } |
| 443 | | 528 | |
| 444 | /// Convenience wrapper for decoding all blocks in a frame; see | | |
| 445 | /// `decodeZStandardFrameBlocks()`. | | |
| 446 | fn decodeFrameBlocksInner( | 529 | fn decodeFrameBlocksInner( |
| 447 | dest: []u8, | 530 | dest: []u8, |
| 448 | src: []const u8, | 531 | src: []const u8, |
| ... | @@ -459,7 +542,7 @@ fn decodeFrameBlocksInner( | ... | @@ -459,7 +542,7 @@ fn decodeFrameBlocksInner( |
| 459 | var bytes_read: usize = 3; | 542 | var bytes_read: usize = 3; |
| 460 | defer consumed_count.* += bytes_read; | 543 | defer consumed_count.* += bytes_read; |
| 461 | var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data); | 544 | var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data); |
| 462 | var written_count: usize = 0; | 545 | var count: usize = 0; |
| 463 | while (true) : ({ | 546 | while (true) : ({ |
| 464 | block_header = try block.decodeBlockHeaderSlice(src[bytes_read..]); | 547 | block_header = try block.decodeBlockHeaderSlice(src[bytes_read..]); |
| 465 | bytes_read += 3; | 548 | bytes_read += 3; |
| ... | @@ -471,18 +554,18 @@ fn decodeFrameBlocksInner( | ... | @@ -471,18 +554,18 @@ fn decodeFrameBlocksInner( |
| 471 | &decode_state, | 554 | &decode_state, |
| 472 | &bytes_read, | 555 | &bytes_read, |
| 473 | block_size_max, | 556 | block_size_max, |
| 474 | written_count, | 557 | count, |
| 475 | ); | 558 | ); |
| 476 | if (hash) |hash_state| hash_state.update(dest[written_count .. written_count + written_size]); | 559 | if (hash) |hash_state| hash_state.update(dest[count .. count + written_size]); |
| 477 | written_count += written_size; | 560 | count += written_size; |
| 478 | if (block_header.last_block) break; | 561 | if (block_header.last_block) break; |
| 479 | } | 562 | } |
| 480 | return written_count; | 563 | return count; |
| 481 | } | 564 | } |
| 482 | | 565 | |
| 483 | /// Decode the header of a skippable frame. The first four bytes of `src` must | 566 | /// Decode the header of a skippable frame. The first four bytes of `src` must |
| 484 | /// be a valid magic number for a Skippable frame. | 567 | /// be a valid magic number for a skippable frame. |
| 485 | pub fn decodeSkippableHeader(src: *const [8]u8) frame.Skippable.Header { | 568 | pub fn decodeSkippableHeader(src: *const [8]u8) SkippableHeader { |
| 486 | const magic = readInt(u32, src[0..4]); | 569 | const magic = readInt(u32, src[0..4]); |
| 487 | assert(isSkippableMagic(magic)); | 570 | assert(isSkippableMagic(magic)); |
| 488 | const frame_size = readInt(u32, src[4..8]); | 571 | const frame_size = readInt(u32, src[4..8]); |
| ... | @@ -494,7 +577,7 @@ pub fn decodeSkippableHeader(src: *const [8]u8) frame.Skippable.Header { | ... | @@ -494,7 +577,7 @@ pub fn decodeSkippableHeader(src: *const [8]u8) frame.Skippable.Header { |
| 494 | | 577 | |
| 495 | /// Returns the window size required to decompress a frame, or `null` if it | 578 | /// Returns the window size required to decompress a frame, or `null` if it |
| 496 | /// cannot be determined (which indicates a malformed frame header). | 579 | /// cannot be determined (which indicates a malformed frame header). |
| 497 | pub fn frameWindowSize(header: frame.Zstandard.Header) ?u64 { | 580 | pub fn frameWindowSize(header: ZstandardHeader) ?u64 { |
| 498 | if (header.window_descriptor) |descriptor| { | 581 | if (header.window_descriptor) |descriptor| { |
| 499 | const exponent = (descriptor & 0b11111000) >> 3; | 582 | const exponent = (descriptor & 0b11111000) >> 3; |
| 500 | const mantissa = descriptor & 0b00000111; | 583 | const mantissa = descriptor & 0b00000111; |
| ... | @@ -508,10 +591,10 @@ pub fn frameWindowSize(header: frame.Zstandard.Header) ?u64 { | ... | @@ -508,10 +591,10 @@ pub fn frameWindowSize(header: frame.Zstandard.Header) ?u64 { |
| 508 | /// Decode the header of a Zstandard frame. | 591 | /// Decode the header of a Zstandard frame. |
| 509 | /// | 592 | /// |
| 510 | /// Errors returned: | 593 | /// Errors returned: |
| 511 | /// - `error.ReservedBitSet` if the reserved bits of the header are set | 594 | /// - `error.ReservedBitSet` if any of the reserved bits of the header are set |
| 512 | /// - `error.EndOfStream` if `source` does not contain a complete header | 595 | /// - `error.EndOfStream` if `source` does not contain a complete header |
| 513 | pub fn decodeZstandardHeader(source: anytype) error{ EndOfStream, ReservedBitSet }!frame.Zstandard.Header { | 596 | pub fn decodeZstandardHeader(source: anytype) error{ EndOfStream, ReservedBitSet }!ZstandardHeader { |
| 514 | const descriptor = @bitCast(frame.Zstandard.Header.Descriptor, try source.readByte()); | 597 | const descriptor = @bitCast(ZstandardHeader.Descriptor, try source.readByte()); |
| 515 | | 598 | |
| 516 | if (descriptor.reserved) return error.ReservedBitSet; | 599 | if (descriptor.reserved) return error.ReservedBitSet; |
| 517 | | 600 | |
| ... | @@ -534,7 +617,7 @@ pub fn decodeZstandardHeader(source: anytype) error{ EndOfStream, ReservedBitSet | ... | @@ -534,7 +617,7 @@ pub fn decodeZstandardHeader(source: anytype) error{ EndOfStream, ReservedBitSet |
| 534 | if (field_size == 2) content_size.? += 256; | 617 | if (field_size == 2) content_size.? += 256; |
| 535 | } | 618 | } |
| 536 | | 619 | |
| 537 | const header = frame.Zstandard.Header{ | 620 | const header = ZstandardHeader{ |
| 538 | .descriptor = descriptor, | 621 | .descriptor = descriptor, |
| 539 | .window_descriptor = window_descriptor, | 622 | .window_descriptor = window_descriptor, |
| 540 | .dictionary_id = dictionary_id, | 623 | .dictionary_id = dictionary_id, |