| ... | @@ -147,88 +147,85 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void { | ... | @@ -147,88 +147,85 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void { |
| 147 | fn readInFrame(d: *Decompress, bw: *BufferedWriter, limit: Reader.Limit, state: *State.InFrame) !usize { | 147 | fn readInFrame(d: *Decompress, bw: *BufferedWriter, limit: Reader.Limit, state: *State.InFrame) !usize { |
| 148 | const in = d.input; | 148 | const in = d.input; |
| 149 | | 149 | |
| 150 | var literal_fse_buffer: [zstd.table_size_max.literal]Table.Fse = undefined; | | |
| 151 | var match_fse_buffer: [zstd.table_size_max.match]Table.Fse = undefined; | | |
| 152 | var offset_fse_buffer: [zstd.table_size_max.offset]Table.Fse = undefined; | | |
| 153 | var literals_buffer: [zstd.block_size_max]u8 = undefined; | | |
| 154 | var sequence_buffer: [zstd.block_size_max]u8 = undefined; | | |
| 155 | | | |
| 156 | var decode: Frame.Zstandard.Decode = .init(&literal_fse_buffer, &match_fse_buffer, &offset_fse_buffer); | | |
| 157 | | | |
| 158 | const header_bytes = try in.takeArray(3); | 150 | const header_bytes = try in.takeArray(3); |
| 159 | const block_header: Frame.Zstandard.Block.Header = @bitCast(header_bytes.*); | 151 | const block_header: Frame.Zstandard.Block.Header = @bitCast(header_bytes.*); |
| 160 | const block_size = block_header.size; | 152 | const block_size = block_header.size; |
| 161 | if (state.frame.block_size_max < block_size) return error.BlockOversize; | 153 | if (state.frame.block_size_max < block_size) return error.BlockOversize; |
| 162 | if (@intFromEnum(limit) < block_size) return error.OutputBufferUndersize; | 154 | if (@intFromEnum(limit) < block_size) return error.OutputBufferUndersize; |
| | 155 | var bytes_written: usize = 0; |
| 163 | switch (block_header.type) { | 156 | switch (block_header.type) { |
| 164 | .raw => { | 157 | .raw => { |
| 165 | try in.readAll(bw, .limited(block_size)); | 158 | try in.readAll(bw, .limited(block_size)); |
| 166 | return block_size; | 159 | bytes_written = block_size; |
| 167 | }, | 160 | }, |
| 168 | .rle => { | 161 | .rle => { |
| 169 | const byte = try in.takeByte(); | 162 | const byte = try in.takeByte(); |
| 170 | try bw.splatByteAll(byte, block_size); | 163 | try bw.splatByteAll(byte, block_size); |
| 171 | return block_size; | 164 | bytes_written = block_size; |
| 172 | }, | 165 | }, |
| 173 | .compressed => {}, | 166 | .compressed => { |
| 174 | .reserved => return error.ReservedBlock, | 167 | var literal_fse_buffer: [zstd.table_size_max.literal]Table.Fse = undefined; |
| 175 | } | 168 | var match_fse_buffer: [zstd.table_size_max.match]Table.Fse = undefined; |
| | 169 | var offset_fse_buffer: [zstd.table_size_max.offset]Table.Fse = undefined; |
| | 170 | var literals_buffer: [zstd.block_size_max]u8 = undefined; |
| | 171 | var sequence_buffer: [zstd.block_size_max]u8 = undefined; |
| | 172 | var decode: Frame.Zstandard.Decode = .init(&literal_fse_buffer, &match_fse_buffer, &offset_fse_buffer); |
| | 173 | var remaining: Reader.Limit = .limited(block_size); |
| | 174 | const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer); |
| | 175 | const sequences_header = try SequencesSection.Header.decode(in, &remaining); |
| | 176 | |
| | 177 | try decode.prepare(in, &remaining, literals, sequences_header); |
| | 178 | |
| | 179 | { |
| | 180 | if (sequence_buffer.len < @intFromEnum(remaining)) |
| | 181 | return error.SequenceBufferUndersize; |
| | 182 | const seq_slice = remaining.slice(&sequence_buffer); |
| | 183 | try in.readSlice(seq_slice); |
| | 184 | var bit_stream = try ReverseBitReader.init(seq_slice); |
| 176 | | 185 | |
| 177 | var remaining: Reader.Limit = .limited(block_size); | 186 | if (sequences_header.sequence_count > 0) { |
| 178 | const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer); | 187 | try decode.readInitialFseState(&bit_stream); |
| 179 | const sequences_header = try SequencesSection.Header.decode(in, &remaining); | 188 | |
| | 189 | var sequence_size_limit = state.frame.block_size_max; |
| | 190 | for (0..sequences_header.sequence_count) |i| { |
| | 191 | const decompressed_size = try decode.decodeSequence( |
| | 192 | bw, |
| | 193 | &bit_stream, |
| | 194 | sequence_size_limit, |
| | 195 | i == sequences_header.sequence_count - 1, |
| | 196 | ); |
| | 197 | sequence_size_limit -= decompressed_size; |
| | 198 | bytes_written += decompressed_size; |
| | 199 | } |
| | 200 | } |
| 180 | | 201 | |
| 181 | try decode.prepare(in, &remaining, literals, sequences_header); | 202 | if (!bit_stream.isEmpty()) { |
| | 203 | return error.MalformedCompressedBlock; |
| | 204 | } |
| | 205 | } |
| 182 | | 206 | |
| 183 | var bytes_written: usize = 0; | 207 | if (decode.literal_written_count < literals.header.regenerated_size) { |
| 184 | { | 208 | const len = literals.header.regenerated_size - decode.literal_written_count; |
| 185 | if (sequence_buffer.len < @intFromEnum(remaining)) | 209 | try decode.decodeLiterals(bw, len); |
| 186 | return error.SequenceBufferUndersize; | 210 | bytes_written += len; |
| 187 | const seq_slice = remaining.slice(&sequence_buffer); | | |
| 188 | try in.readSlice(seq_slice); | | |
| 189 | var bit_stream = try ReverseBitReader.init(seq_slice); | | |
| 190 | | | |
| 191 | if (sequences_header.sequence_count > 0) { | | |
| 192 | try decode.readInitialFseState(&bit_stream); | | |
| 193 | | | |
| 194 | var sequence_size_limit = state.frame.block_size_max; | | |
| 195 | for (0..sequences_header.sequence_count) |i| { | | |
| 196 | const decompressed_size = try decode.decodeSequence( | | |
| 197 | bw, | | |
| 198 | &bit_stream, | | |
| 199 | sequence_size_limit, | | |
| 200 | i == sequences_header.sequence_count - 1, | | |
| 201 | ); | | |
| 202 | sequence_size_limit -= decompressed_size; | | |
| 203 | bytes_written += decompressed_size; | | |
| 204 | } | 211 | } |
| 205 | } | | |
| 206 | | 212 | |
| 207 | if (!bit_stream.isEmpty()) { | 213 | switch (decode.literal_header.block_type) { |
| 208 | return error.MalformedCompressedBlock; | 214 | .treeless, .compressed => { |
| 209 | } | 215 | if (!decode.isLiteralStreamEmpty()) return error.MalformedCompressedBlock; |
| 210 | } | 216 | }, |
| | 217 | .raw, .rle => {}, |
| | 218 | } |
| 211 | | 219 | |
| 212 | if (decode.literal_written_count < literals.header.regenerated_size) { | 220 | if (bytes_written > state.frame.block_size_max) return error.BlockOversize; |
| 213 | const len = literals.header.regenerated_size - decode.literal_written_count; | 221 | if (remaining.nonzero()) return error.MalformedCompressedBlock; |
| 214 | try decode.decodeLiterals(bw, len); | | |
| 215 | bytes_written += len; | | |
| 216 | } | | |
| 217 | | 222 | |
| 218 | switch (decode.literal_header.block_type) { | 223 | state.decompressed_size += bytes_written; |
| 219 | .treeless, .compressed => { | 224 | if (state.frame.content_size) |size| { |
| 220 | if (!decode.isLiteralStreamEmpty()) return error.MalformedCompressedBlock; | 225 | if (state.decompressed_size > size) return error.MalformedFrame; |
| | 226 | } |
| 221 | }, | 227 | }, |
| 222 | .raw, .rle => {}, | 228 | .reserved => return error.ReservedBlock, |
| 223 | } | | |
| 224 | | | |
| 225 | if (bytes_written > state.frame.block_size_max) return error.BlockOversize; | | |
| 226 | if (remaining.nonzero()) return error.MalformedCompressedBlock; | | |
| 227 | | | |
| 228 | state.decompressed_size += bytes_written; | | |
| 229 | | | |
| 230 | if (state.frame.content_size) |size| { | | |
| 231 | if (state.decompressed_size > size) return error.MalformedFrame; | | |
| 232 | } | 229 | } |
| 233 | | 230 | |
| 234 | if (state.frame.hasher_opt) |*hasher| { | 231 | if (state.frame.hasher_opt) |*hasher| { |