| ... | ... | @@ -680,7 +680,8 @@ pub fn decodeFrameBlocks(dest: []u8, src: []const u8, consumed_count: *usize, ha |
| 680 | 680 | return written_count; |
| 681 | 681 | } |
| 682 | 682 | |
| 683 | | fn decodeRawBlock(dest: []u8, src: []const u8, block_size: u21, consumed_count: *usize) usize { |
| 683 | fn decodeRawBlock(dest: []u8, src: []const u8, block_size: u21, consumed_count: *usize) !usize { |
| 684 | if (src.len < block_size) return error.MalformedBlockSize; |
| 684 | 685 | log.debug("writing raw block - size {d}", .{block_size}); |
| 685 | 686 | const data = src[0..block_size]; |
| 686 | 687 | std.mem.copy(u8, dest, data); |
| ... | ... | @@ -688,7 +689,8 @@ fn decodeRawBlock(dest: []u8, src: []const u8, block_size: u21, consumed_count: |
| 688 | 689 | return block_size; |
| 689 | 690 | } |
| 690 | 691 | |
| 691 | | fn decodeRawBlockRingBuffer(dest: *RingBuffer, src: []const u8, block_size: u21, consumed_count: *usize) usize { |
| 692 | fn decodeRawBlockRingBuffer(dest: *RingBuffer, src: []const u8, block_size: u21, consumed_count: *usize) !usize { |
| 693 | if (src.len < block_size) return error.MalformedBlockSize; |
| 692 | 694 | log.debug("writing raw block - size {d}", .{block_size}); |
| 693 | 695 | const data = src[0..block_size]; |
| 694 | 696 | dest.writeSliceAssumeCapacity(data); |
| ... | ... | @@ -696,7 +698,8 @@ fn decodeRawBlockRingBuffer(dest: *RingBuffer, src: []const u8, block_size: u21, |
| 696 | 698 | return block_size; |
| 697 | 699 | } |
| 698 | 700 | |
| 699 | | fn decodeRleBlock(dest: []u8, src: []const u8, block_size: u21, consumed_count: *usize) usize { |
| 701 | fn decodeRleBlock(dest: []u8, src: []const u8, block_size: u21, consumed_count: *usize) !usize { |
| 702 | if (src.len < 1) return error.MalformedRleBlock; |
| 700 | 703 | log.debug("writing rle block - '{x}'x{d}", .{ src[0], block_size }); |
| 701 | 704 | var write_pos: usize = 0; |
| 702 | 705 | while (write_pos < block_size) : (write_pos += 1) { |
| ... | ... | @@ -706,7 +709,8 @@ fn decodeRleBlock(dest: []u8, src: []const u8, block_size: u21, consumed_count: |
| 706 | 709 | return block_size; |
| 707 | 710 | } |
| 708 | 711 | |
| 709 | | fn decodeRleBlockRingBuffer(dest: *RingBuffer, src: []const u8, block_size: u21, consumed_count: *usize) usize { |
| 712 | fn decodeRleBlockRingBuffer(dest: *RingBuffer, src: []const u8, block_size: u21, consumed_count: *usize) !usize { |
| 713 | if (src.len < 1) return error.MalformedRleBlock; |
| 710 | 714 | log.debug("writing rle block - '{x}'x{d}", .{ src[0], block_size }); |
| 711 | 715 | var write_pos: usize = 0; |
| 712 | 716 | while (write_pos < block_size) : (write_pos += 1) { |
| ... | ... | @@ -727,11 +731,11 @@ pub fn decodeBlock( |
| 727 | 731 | const block_size_max = @min(1 << 17, dest[written_count..].len); // 128KiB |
| 728 | 732 | const block_size = block_header.block_size; |
| 729 | 733 | if (block_size_max < block_size) return error.BlockSizeOverMaximum; |
| 730 | | // TODO: we probably want to enable safety for release-fast and release-small (or insert custom checks) |
| 731 | 734 | switch (block_header.block_type) { |
| 732 | 735 | .raw => return decodeRawBlock(dest[written_count..], src, block_size, consumed_count), |
| 733 | 736 | .rle => return decodeRleBlock(dest[written_count..], src, block_size, consumed_count), |
| 734 | 737 | .compressed => { |
| 738 | if (src.len < block_size) return error.MalformedBlockSize; |
| 735 | 739 | var bytes_read: usize = 0; |
| 736 | 740 | const literals = try decodeLiteralsSection(src, &bytes_read); |
| 737 | 741 | const sequences_header = try decodeSequencesHeader(src[bytes_read..], &bytes_read); |
| ... | ... | @@ -796,11 +800,11 @@ pub fn decodeBlockRingBuffer( |
| 796 | 800 | ) !usize { |
| 797 | 801 | const block_size = block_header.block_size; |
| 798 | 802 | if (block_size_max < block_size) return error.BlockSizeOverMaximum; |
| 799 | | // TODO: we probably want to enable safety for release-fast and release-small (or insert custom checks) |
| 800 | 803 | switch (block_header.block_type) { |
| 801 | 804 | .raw => return decodeRawBlockRingBuffer(dest, src, block_size, consumed_count), |
| 802 | 805 | .rle => return decodeRleBlockRingBuffer(dest, src, block_size, consumed_count), |
| 803 | 806 | .compressed => { |
| 807 | if (src.len < block_size) return error.MalformedBlockSize; |
| 804 | 808 | var bytes_read: usize = 0; |
| 805 | 809 | const literals = try decodeLiteralsSection(src, &bytes_read); |
| 806 | 810 | const sequences_header = try decodeSequencesHeader(src[bytes_read..], &bytes_read); |
| ... | ... | @@ -957,11 +961,11 @@ pub fn decodeBlockHeader(src: *const [3]u8) frame.ZStandard.Block.Header { |
| 957 | 961 | } |
| 958 | 962 | |
| 959 | 963 | pub fn decodeLiteralsSection(src: []const u8, consumed_count: *usize) !LiteralsSection { |
| 960 | | // TODO: we probably want to enable safety for release-fast and release-small (or insert custom checks) |
| 961 | 964 | var bytes_read: usize = 0; |
| 962 | | const header = decodeLiteralsHeader(src, &bytes_read); |
| 965 | const header = try decodeLiteralsHeader(src, &bytes_read); |
| 963 | 966 | switch (header.block_type) { |
| 964 | 967 | .raw => { |
| 968 | if (src.len < bytes_read + header.regenerated_size) return error.MalformedLiteralsSection; |
| 965 | 969 | const stream = src[bytes_read .. bytes_read + header.regenerated_size]; |
| 966 | 970 | consumed_count.* += header.regenerated_size + bytes_read; |
| 967 | 971 | return LiteralsSection{ |
| ... | ... | @@ -971,6 +975,7 @@ pub fn decodeLiteralsSection(src: []const u8, consumed_count: *usize) !LiteralsS |
| 971 | 975 | }; |
| 972 | 976 | }, |
| 973 | 977 | .rle => { |
| 978 | if (src.len < bytes_read + 1) return error.MalformedLiteralsSection; |
| 974 | 979 | const stream = src[bytes_read .. bytes_read + 1]; |
| 975 | 980 | consumed_count.* += 1 + bytes_read; |
| 976 | 981 | return LiteralsSection{ |
| ... | ... | @@ -990,18 +995,19 @@ pub fn decodeLiteralsSection(src: []const u8, consumed_count: *usize) !LiteralsS |
| 990 | 995 | log.debug("huffman tree size = {}, total streams size = {}", .{ huffman_tree_size, total_streams_size }); |
| 991 | 996 | if (huffman_tree) |tree| dumpHuffmanTree(tree); |
| 992 | 997 | |
| 998 | if (src.len < bytes_read + total_streams_size) return error.MalformedLiteralsSection; |
| 999 | const stream_data = src[bytes_read .. bytes_read + total_streams_size]; |
| 1000 | |
| 993 | 1001 | if (header.size_format == 0) { |
| 994 | | const stream = src[bytes_read .. bytes_read + total_streams_size]; |
| 995 | | bytes_read += total_streams_size; |
| 996 | | consumed_count.* += bytes_read; |
| 1002 | consumed_count.* += total_streams_size + bytes_read; |
| 997 | 1003 | return LiteralsSection{ |
| 998 | 1004 | .header = header, |
| 999 | 1005 | .huffman_tree = huffman_tree, |
| 1000 | | .streams = .{ .one = stream }, |
| 1006 | .streams = .{ .one = stream_data }, |
| 1001 | 1007 | }; |
| 1002 | 1008 | } |
| 1003 | 1009 | |
| 1004 | | const stream_data = src[bytes_read .. bytes_read + total_streams_size]; |
| 1010 | if (stream_data.len < 6) return error.MalformedLiteralsSection; |
| 1005 | 1011 | |
| 1006 | 1012 | log.debug("jump table: {}", .{std.fmt.fmtSliceHexUpper(stream_data[0..6])}); |
| 1007 | 1013 | const stream_1_length = @as(usize, readInt(u16, stream_data[0..2])); |
| ... | ... | @@ -1014,6 +1020,7 @@ pub fn decodeLiteralsSection(src: []const u8, consumed_count: *usize) !LiteralsS |
| 1014 | 1020 | const stream_3_start = stream_2_start + stream_2_length; |
| 1015 | 1021 | const stream_4_start = stream_3_start + stream_3_length; |
| 1016 | 1022 | |
| 1023 | if (stream_data.len < stream_4_start + stream_4_length) return error.MalformedLiteralsSection; |
| 1017 | 1024 | consumed_count.* += total_streams_size + bytes_read; |
| 1018 | 1025 | |
| 1019 | 1026 | return LiteralsSection{ |
| ... | ... | @@ -1033,13 +1040,15 @@ pub fn decodeLiteralsSection(src: []const u8, consumed_count: *usize) !LiteralsS |
| 1033 | 1040 | fn decodeHuffmanTree(src: []const u8, consumed_count: *usize) !LiteralsSection.HuffmanTree { |
| 1034 | 1041 | var bytes_read: usize = 0; |
| 1035 | 1042 | bytes_read += 1; |
| 1043 | if (src.len == 0) return error.MalformedHuffmanTree; |
| 1036 | 1044 | const header = src[0]; |
| 1037 | 1045 | var symbol_count: usize = undefined; |
| 1038 | 1046 | var weights: [256]u4 = undefined; |
| 1039 | 1047 | var max_number_of_bits: u4 = undefined; |
| 1040 | 1048 | if (header < 128) { |
| 1041 | | // FSE compressed weigths |
| 1049 | // FSE compressed weights |
| 1042 | 1050 | const compressed_size = header; |
| 1051 | if (src.len < 1 + compressed_size) return error.MalformedHuffmanTree; |
| 1043 | 1052 | var stream = std.io.fixedBufferStream(src[1 .. compressed_size + 1]); |
| 1044 | 1053 | var counting_reader = std.io.countingReader(stream.reader()); |
| 1045 | 1054 | var bit_reader = bitReader(counting_reader.reader()); |
| ... | ... | @@ -1185,8 +1194,8 @@ fn lessThanByWeight( |
| 1185 | 1194 | return weights[lhs.symbol] < weights[rhs.symbol]; |
| 1186 | 1195 | } |
| 1187 | 1196 | |
| 1188 | | pub fn decodeLiteralsHeader(src: []const u8, consumed_count: *usize) LiteralsSection.Header { |
| 1189 | | // TODO: we probably want to enable safety for release-fast and release-small (or insert custom checks) |
| 1197 | pub fn decodeLiteralsHeader(src: []const u8, consumed_count: *usize) !LiteralsSection.Header { |
| 1198 | if (src.len == 0) return error.MalformedLiteralsSection; |
| 1190 | 1199 | const start = consumed_count.*; |
| 1191 | 1200 | const byte0 = src[0]; |
| 1192 | 1201 | const block_type = @intToEnum(LiteralsSection.BlockType, byte0 & 0b11); |
| ... | ... | @@ -1201,14 +1210,16 @@ pub fn decodeLiteralsHeader(src: []const u8, consumed_count: *usize) LiteralsSec |
| 1201 | 1210 | consumed_count.* += 1; |
| 1202 | 1211 | }, |
| 1203 | 1212 | 1 => { |
| 1213 | if (src.len < 2) return error.MalformedLiteralsHeader; |
| 1204 | 1214 | regenerated_size = (byte0 >> 4) + |
| 1205 | | (@as(u20, src[consumed_count.* + 1]) << 4); |
| 1215 | (@as(u20, src[1]) << 4); |
| 1206 | 1216 | consumed_count.* += 2; |
| 1207 | 1217 | }, |
| 1208 | 1218 | 3 => { |
| 1219 | if (src.len < 3) return error.MalformedLiteralsHeader; |
| 1209 | 1220 | regenerated_size = (byte0 >> 4) + |
| 1210 | | (@as(u20, src[consumed_count.* + 1]) << 4) + |
| 1211 | | (@as(u20, src[consumed_count.* + 2]) << 12); |
| 1221 | (@as(u20, src[1]) << 4) + |
| 1222 | (@as(u20, src[2]) << 12); |
| 1212 | 1223 | consumed_count.* += 3; |
| 1213 | 1224 | }, |
| 1214 | 1225 | } |
| ... | ... | @@ -1218,17 +1229,20 @@ pub fn decodeLiteralsHeader(src: []const u8, consumed_count: *usize) LiteralsSec |
| 1218 | 1229 | const byte2 = src[2]; |
| 1219 | 1230 | switch (size_format) { |
| 1220 | 1231 | 0, 1 => { |
| 1232 | if (src.len < 3) return error.MalformedLiteralsHeader; |
| 1221 | 1233 | regenerated_size = (byte0 >> 4) + ((@as(u20, byte1) & 0b00111111) << 4); |
| 1222 | 1234 | compressed_size = ((byte1 & 0b11000000) >> 6) + (@as(u18, byte2) << 2); |
| 1223 | 1235 | consumed_count.* += 3; |
| 1224 | 1236 | }, |
| 1225 | 1237 | 2 => { |
| 1238 | if (src.len < 4) return error.MalformedLiteralsHeader; |
| 1226 | 1239 | const byte3 = src[3]; |
| 1227 | 1240 | regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00000011) << 12); |
| 1228 | 1241 | compressed_size = ((byte2 & 0b11111100) >> 2) + (@as(u18, byte3) << 6); |
| 1229 | 1242 | consumed_count.* += 4; |
| 1230 | 1243 | }, |
| 1231 | 1244 | 3 => { |
| 1245 | if (src.len < 5) return error.MalformedLiteralsHeader; |
| 1232 | 1246 | const byte3 = src[3]; |
| 1233 | 1247 | const byte4 = src[4]; |
| 1234 | 1248 | regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00111111) << 12); |
| ... | ... | @@ -1257,6 +1271,7 @@ pub fn decodeLiteralsHeader(src: []const u8, consumed_count: *usize) LiteralsSec |
| 1257 | 1271 | } |
| 1258 | 1272 | |
| 1259 | 1273 | pub fn decodeSequencesHeader(src: []const u8, consumed_count: *usize) !SequencesSection.Header { |
| 1274 | if (src.len == 0) return error.MalformedSequencesSection; |
| 1260 | 1275 | var sequence_count: u24 = undefined; |
| 1261 | 1276 | |
| 1262 | 1277 | var bytes_read: usize = 0; |
| ... | ... | @@ -1275,13 +1290,16 @@ pub fn decodeSequencesHeader(src: []const u8, consumed_count: *usize) !Sequences |
| 1275 | 1290 | sequence_count = byte0; |
| 1276 | 1291 | bytes_read += 1; |
| 1277 | 1292 | } else if (byte0 < 255) { |
| 1293 | if (src.len < 2) return error.MalformedSequencesSection; |
| 1278 | 1294 | sequence_count = (@as(u24, (byte0 - 128)) << 8) + src[1]; |
| 1279 | 1295 | bytes_read += 2; |
| 1280 | 1296 | } else { |
| 1297 | if (src.len < 3) return error.MalformedSequencesSection; |
| 1281 | 1298 | sequence_count = src[1] + (@as(u24, src[2]) << 8) + 0x7F00; |
| 1282 | 1299 | bytes_read += 3; |
| 1283 | 1300 | } |
| 1284 | 1301 | |
| 1302 | if (src.len < bytes_read + 1) return error.MalformedSequencesSection; |
| 1285 | 1303 | const compression_modes = src[bytes_read]; |
| 1286 | 1304 | bytes_read += 1; |
| 1287 | 1305 | |