/src/lz4_flex/src/frame/decompress.rs
Line | Count | Source |
1 | | use std::{ |
2 | | fmt, |
3 | | hash::Hasher, |
4 | | io::{self, BufRead, ErrorKind}, |
5 | | mem::size_of, |
6 | | }; |
7 | | use twox_hash::XxHash32; |
8 | | |
9 | | use super::header::{ |
10 | | BlockInfo, BlockMode, FrameInfo, LZ4F_LEGACY_MAGIC_NUMBER, MAGIC_NUMBER_SIZE, |
11 | | MAX_FRAME_INFO_SIZE, MIN_FRAME_INFO_SIZE, |
12 | | }; |
13 | | use super::Error; |
14 | | use crate::{ |
15 | | block::WINDOW_SIZE, |
16 | | sink::{vec_sink_for_decompression, SliceSink}, |
17 | | }; |
18 | | |
19 | | /// A reader for decompressing the LZ4 frame format |
20 | | /// |
21 | | /// This Decoder wraps any other reader that implements `io::Read`. |
22 | | /// Bytes read will be decompressed according to the [LZ4 frame format]( |
23 | | /// https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md). |
24 | | /// |
25 | | /// # Example 1 |
26 | | /// Deserializing json values out of a compressed file. |
27 | | /// |
28 | | /// ```no_run |
29 | | /// let compressed_input = std::fs::File::open("datafile").unwrap(); |
30 | | /// let mut decompressed_input = lz4_flex::frame::FrameDecoder::new(compressed_input); |
31 | | /// let json: serde_json::Value = serde_json::from_reader(decompressed_input).unwrap(); |
32 | | /// ``` |
33 | | /// |
34 | | /// # Example |
35 | | /// Deserializing multiple json values out of a compressed file |
36 | | /// |
37 | | /// ```no_run |
38 | | /// let compressed_input = std::fs::File::open("datafile").unwrap(); |
39 | | /// let mut decompressed_input = lz4_flex::frame::FrameDecoder::new(compressed_input); |
40 | | /// loop { |
41 | | /// match serde_json::from_reader::<_, serde_json::Value>(&mut decompressed_input) { |
42 | | /// Ok(json) => { println!("json {:?}", json); } |
43 | | /// Err(e) if e.is_eof() => break, |
44 | | /// Err(e) => panic!("{}", e), |
45 | | /// } |
46 | | /// } |
47 | | /// ``` |
48 | | pub struct FrameDecoder<R: io::Read> { |
49 | | /// The underlying reader. |
50 | | r: R, |
51 | | /// The FrameInfo of the frame currently being decoded. |
52 | | /// It starts as `None` and is filled with the FrameInfo is read from the input. |
53 | | /// It's reset to `None` once the frame EndMarker is read from the input. |
54 | | current_frame_info: Option<FrameInfo>, |
55 | | /// Xxhash32 used when content checksum is enabled. |
56 | | content_hasher: XxHash32, |
57 | | /// Total length of decompressed output for the current frame. |
58 | | content_len: u64, |
59 | | /// The compressed bytes buffer, taken from the underlying reader. |
60 | | src: Vec<u8>, |
61 | | /// The decompressed bytes buffer. Bytes are decompressed from src to dst |
62 | | /// before being passed back to the caller. |
63 | | dst: Vec<u8>, |
64 | | /// Index into dst and length: starting point of bytes previously output |
65 | | /// that are still part of the decompressor window. |
66 | | ext_dict_offset: usize, |
67 | | ext_dict_len: usize, |
68 | | /// Index into dst: starting point of bytes not yet read by caller. |
69 | | dst_start: usize, |
70 | | /// Index into dst: ending point of bytes not yet read by caller. |
71 | | dst_end: usize, |
72 | | } |
73 | | |
74 | | impl<R: io::Read> FrameDecoder<R> { |
75 | | /// Creates a new Decoder for the specified reader. |
76 | 39.3k | pub fn new(rdr: R) -> FrameDecoder<R> { |
77 | 39.3k | FrameDecoder { |
78 | 39.3k | r: rdr, |
79 | 39.3k | src: Default::default(), |
80 | 39.3k | dst: Default::default(), |
81 | 39.3k | ext_dict_offset: 0, |
82 | 39.3k | ext_dict_len: 0, |
83 | 39.3k | dst_start: 0, |
84 | 39.3k | dst_end: 0, |
85 | 39.3k | current_frame_info: None, |
86 | 39.3k | content_hasher: XxHash32::with_seed(0), |
87 | 39.3k | content_len: 0, |
88 | 39.3k | } |
89 | 39.3k | } <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::new Line | Count | Source | 76 | 17.1k | pub fn new(rdr: R) -> FrameDecoder<R> { | 77 | 17.1k | FrameDecoder { | 78 | 17.1k | r: rdr, | 79 | 17.1k | src: Default::default(), | 80 | 17.1k | dst: Default::default(), | 81 | 17.1k | ext_dict_offset: 0, | 82 | 17.1k | ext_dict_len: 0, | 83 | 17.1k | dst_start: 0, | 84 | 17.1k | dst_end: 0, | 85 | 17.1k | current_frame_info: None, | 86 | 17.1k | content_hasher: XxHash32::with_seed(0), | 87 | 17.1k | content_len: 0, | 88 | 17.1k | } | 89 | 17.1k | } |
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::new <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::new Line | Count | Source | 76 | 22.1k | pub fn new(rdr: R) -> FrameDecoder<R> { | 77 | 22.1k | FrameDecoder { | 78 | 22.1k | r: rdr, | 79 | 22.1k | src: Default::default(), | 80 | 22.1k | dst: Default::default(), | 81 | 22.1k | ext_dict_offset: 0, | 82 | 22.1k | ext_dict_len: 0, | 83 | 22.1k | dst_start: 0, | 84 | 22.1k | dst_end: 0, | 85 | 22.1k | current_frame_info: None, | 86 | 22.1k | content_hasher: XxHash32::with_seed(0), | 87 | 22.1k | content_len: 0, | 88 | 22.1k | } | 89 | 22.1k | } |
|
90 | | |
91 | | /// Gets a reference to the underlying reader in this decoder. |
92 | 0 | pub fn get_ref(&self) -> &R { |
93 | 0 | &self.r |
94 | 0 | } |
95 | | |
96 | | /// Gets a mutable reference to the underlying reader in this decoder. |
97 | | /// |
98 | | /// Note that mutation of the stream may result in surprising results if |
99 | | /// this decoder is continued to be used. |
100 | 0 | pub fn get_mut(&mut self) -> &mut R { |
101 | 0 | &mut self.r |
102 | 0 | } |
103 | | |
104 | | /// Consumes the FrameDecoder and returns the underlying reader. |
105 | 0 | pub fn into_inner(self) -> R { |
106 | 0 | self.r |
107 | 0 | } |
108 | | |
109 | 39.3k | fn read_frame_info(&mut self) -> Result<usize, io::Error> { |
110 | 39.3k | let mut buffer = [0u8; MAX_FRAME_INFO_SIZE]; |
111 | | |
112 | 39.3k | match self.r.read(&mut buffer[..MAGIC_NUMBER_SIZE])? { |
113 | 0 | 0 => return Ok(0), |
114 | 39.0k | MAGIC_NUMBER_SIZE => (), |
115 | 226 | read => self.r.read_exact(&mut buffer[read..MAGIC_NUMBER_SIZE])?, |
116 | | } |
117 | | |
118 | 39.0k | if u32::from_le_bytes(buffer[0..MAGIC_NUMBER_SIZE].try_into().unwrap()) |
119 | 39.0k | != LZ4F_LEGACY_MAGIC_NUMBER |
120 | | { |
121 | 38.7k | match self |
122 | 38.7k | .r |
123 | 38.7k | .read(&mut buffer[MAGIC_NUMBER_SIZE..MIN_FRAME_INFO_SIZE])? |
124 | | { |
125 | 348 | 0 => return Ok(0), |
126 | 0 | MIN_FRAME_INFO_SIZE => (), |
127 | 38.3k | read => self |
128 | 38.3k | .r |
129 | 38.3k | .read_exact(&mut buffer[MAGIC_NUMBER_SIZE + read..MIN_FRAME_INFO_SIZE])?, |
130 | | } |
131 | 388 | } |
132 | 38.5k | let required = FrameInfo::read_size(&buffer[..MIN_FRAME_INFO_SIZE])?; |
133 | 33.9k | if required != MIN_FRAME_INFO_SIZE && required != MAGIC_NUMBER_SIZE { |
134 | 2.00k | self.r |
135 | 2.00k | .read_exact(&mut buffer[MIN_FRAME_INFO_SIZE..required])?; |
136 | 31.9k | } |
137 | | |
138 | 33.6k | let frame_info = FrameInfo::read(&buffer[..required])?; |
139 | 31.4k | if frame_info.dict_id.is_some() { |
140 | | // Unsupported right now so it must be None |
141 | 6 | return Err(Error::DictionaryNotSupported.into()); |
142 | 31.4k | } |
143 | | |
144 | 31.4k | let max_block_size = frame_info.block_size.get_size(); |
145 | 31.4k | let dst_size = if frame_info.block_mode == BlockMode::Linked { |
146 | | // In linked mode we consume the output (bumping dst_start) but leave the |
147 | | // beginning of dst to be used as a prefix in subsequent blocks. |
148 | | // That is at least until we have at least `max_block_size + WINDOW_SIZE` |
149 | | // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes |
150 | | // and the output goes to the beginning of dst again. |
151 | | // Since we always want to be able to write a full block (up to max_block_size) |
152 | | // we need a buffer with at least `max_block_size * 2 + WINDOW_SIZE` bytes. |
153 | 15.5k | max_block_size * 2 + WINDOW_SIZE |
154 | | } else { |
155 | 15.9k | max_block_size |
156 | | }; |
157 | 31.4k | self.src.clear(); |
158 | 31.4k | self.dst.clear(); |
159 | 31.4k | self.src.reserve_exact(max_block_size); |
160 | 31.4k | self.dst.reserve_exact(dst_size); |
161 | 31.4k | self.current_frame_info = Some(frame_info); |
162 | 31.4k | self.content_hasher = XxHash32::with_seed(0); |
163 | 31.4k | self.content_len = 0; |
164 | 31.4k | self.ext_dict_len = 0; |
165 | 31.4k | self.dst_start = 0; |
166 | 31.4k | self.dst_end = 0; |
167 | 31.4k | Ok(required) |
168 | 39.3k | } <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_frame_info Line | Count | Source | 109 | 17.1k | fn read_frame_info(&mut self) -> Result<usize, io::Error> { | 110 | 17.1k | let mut buffer = [0u8; MAX_FRAME_INFO_SIZE]; | 111 | | | 112 | 17.1k | match self.r.read(&mut buffer[..MAGIC_NUMBER_SIZE])? { | 113 | 0 | 0 => return Ok(0), | 114 | 17.1k | MAGIC_NUMBER_SIZE => (), | 115 | 0 | read => self.r.read_exact(&mut buffer[read..MAGIC_NUMBER_SIZE])?, | 116 | | } | 117 | | | 118 | 17.1k | if u32::from_le_bytes(buffer[0..MAGIC_NUMBER_SIZE].try_into().unwrap()) | 119 | 17.1k | != LZ4F_LEGACY_MAGIC_NUMBER | 120 | | { | 121 | 17.1k | match self | 122 | 17.1k | .r | 123 | 17.1k | .read(&mut buffer[MAGIC_NUMBER_SIZE..MIN_FRAME_INFO_SIZE])? | 124 | | { | 125 | 0 | 0 => return Ok(0), | 126 | 0 | MIN_FRAME_INFO_SIZE => (), | 127 | 17.1k | read => self | 128 | 17.1k | .r | 129 | 17.1k | .read_exact(&mut buffer[MAGIC_NUMBER_SIZE + read..MIN_FRAME_INFO_SIZE])?, | 130 | | } | 131 | 0 | } | 132 | 17.1k | let required = FrameInfo::read_size(&buffer[..MIN_FRAME_INFO_SIZE])?; | 133 | 17.1k | if required != MIN_FRAME_INFO_SIZE && required != MAGIC_NUMBER_SIZE { | 134 | 0 | self.r | 135 | 0 | .read_exact(&mut buffer[MIN_FRAME_INFO_SIZE..required])?; | 136 | 17.1k | } | 137 | | | 138 | 17.1k | let frame_info = FrameInfo::read(&buffer[..required])?; | 139 | 17.1k | if frame_info.dict_id.is_some() { | 140 | | // Unsupported right now so it must be None | 141 | 0 | return Err(Error::DictionaryNotSupported.into()); | 142 | 17.1k | } | 143 | | | 144 | 17.1k | let max_block_size = frame_info.block_size.get_size(); | 145 | 17.1k | let dst_size = if frame_info.block_mode == BlockMode::Linked { | 146 | | // In linked mode we consume the output (bumping dst_start) but leave the | 147 | | // beginning of dst to be used as a prefix in subsequent blocks. | 148 | | // That is at least until we have at least `max_block_size + WINDOW_SIZE` | 149 | | // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes | 150 | | // and the output goes to the beginning of dst again. | 151 | | // Since we always want to be able to write a full block (up to max_block_size) | 152 | | // we need a buffer with at least `max_block_size * 2 + WINDOW_SIZE` bytes. | 153 | 8.57k | max_block_size * 2 + WINDOW_SIZE | 154 | | } else { | 155 | 8.57k | max_block_size | 156 | | }; | 157 | 17.1k | self.src.clear(); | 158 | 17.1k | self.dst.clear(); | 159 | 17.1k | self.src.reserve_exact(max_block_size); | 160 | 17.1k | self.dst.reserve_exact(dst_size); | 161 | 17.1k | self.current_frame_info = Some(frame_info); | 162 | 17.1k | self.content_hasher = XxHash32::with_seed(0); | 163 | 17.1k | self.content_len = 0; | 164 | 17.1k | self.ext_dict_len = 0; | 165 | 17.1k | self.dst_start = 0; | 166 | 17.1k | self.dst_end = 0; | 167 | 17.1k | Ok(required) | 168 | 17.1k | } |
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::read_frame_info <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_frame_info Line | Count | Source | 109 | 22.1k | fn read_frame_info(&mut self) -> Result<usize, io::Error> { | 110 | 22.1k | let mut buffer = [0u8; MAX_FRAME_INFO_SIZE]; | 111 | | | 112 | 22.1k | match self.r.read(&mut buffer[..MAGIC_NUMBER_SIZE])? { | 113 | 0 | 0 => return Ok(0), | 114 | 21.9k | MAGIC_NUMBER_SIZE => (), | 115 | 226 | read => self.r.read_exact(&mut buffer[read..MAGIC_NUMBER_SIZE])?, | 116 | | } | 117 | | | 118 | 21.9k | if u32::from_le_bytes(buffer[0..MAGIC_NUMBER_SIZE].try_into().unwrap()) | 119 | 21.9k | != LZ4F_LEGACY_MAGIC_NUMBER | 120 | | { | 121 | 21.5k | match self | 122 | 21.5k | .r | 123 | 21.5k | .read(&mut buffer[MAGIC_NUMBER_SIZE..MIN_FRAME_INFO_SIZE])? | 124 | | { | 125 | 348 | 0 => return Ok(0), | 126 | 0 | MIN_FRAME_INFO_SIZE => (), | 127 | 21.2k | read => self | 128 | 21.2k | .r | 129 | 21.2k | .read_exact(&mut buffer[MAGIC_NUMBER_SIZE + read..MIN_FRAME_INFO_SIZE])?, | 130 | | } | 131 | 388 | } | 132 | 21.4k | let required = FrameInfo::read_size(&buffer[..MIN_FRAME_INFO_SIZE])?; | 133 | 16.8k | if required != MIN_FRAME_INFO_SIZE && required != MAGIC_NUMBER_SIZE { | 134 | 2.00k | self.r | 135 | 2.00k | .read_exact(&mut buffer[MIN_FRAME_INFO_SIZE..required])?; | 136 | 14.8k | } | 137 | | | 138 | 16.4k | let frame_info = FrameInfo::read(&buffer[..required])?; | 139 | 14.3k | if frame_info.dict_id.is_some() { | 140 | | // Unsupported right now so it must be None | 141 | 6 | return Err(Error::DictionaryNotSupported.into()); | 142 | 14.2k | } | 143 | | | 144 | 14.2k | let max_block_size = frame_info.block_size.get_size(); | 145 | 14.2k | let dst_size = if frame_info.block_mode == BlockMode::Linked { | 146 | | // In linked mode we consume the output (bumping dst_start) but leave the | 147 | | // beginning of dst to be used as a prefix in subsequent blocks. | 148 | | // That is at least until we have at least `max_block_size + WINDOW_SIZE` | 149 | | // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes | 150 | | // and the output goes to the beginning of dst again. | 151 | | // Since we always want to be able to write a full block (up to max_block_size) | 152 | | // we need a buffer with at least `max_block_size * 2 + WINDOW_SIZE` bytes. | 153 | 6.94k | max_block_size * 2 + WINDOW_SIZE | 154 | | } else { | 155 | 7.35k | max_block_size | 156 | | }; | 157 | 14.2k | self.src.clear(); | 158 | 14.2k | self.dst.clear(); | 159 | 14.2k | self.src.reserve_exact(max_block_size); | 160 | 14.2k | self.dst.reserve_exact(dst_size); | 161 | 14.2k | self.current_frame_info = Some(frame_info); | 162 | 14.2k | self.content_hasher = XxHash32::with_seed(0); | 163 | 14.2k | self.content_len = 0; | 164 | 14.2k | self.ext_dict_len = 0; | 165 | 14.2k | self.dst_start = 0; | 166 | 14.2k | self.dst_end = 0; | 167 | 14.2k | Ok(required) | 168 | 22.1k | } |
|
169 | | |
170 | | #[inline] |
171 | 97.3M | fn read_checksum(r: &mut R) -> Result<u32, io::Error> { |
172 | 97.3M | let mut checksum_buffer = [0u8; size_of::<u32>()]; |
173 | 97.3M | r.read_exact(&mut checksum_buffer[..])?; |
174 | 97.3M | let checksum = u32::from_le_bytes(checksum_buffer); |
175 | 97.3M | Ok(checksum) |
176 | 97.3M | } <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_checksum Line | Count | Source | 171 | 97.3M | fn read_checksum(r: &mut R) -> Result<u32, io::Error> { | 172 | 97.3M | let mut checksum_buffer = [0u8; size_of::<u32>()]; | 173 | 97.3M | r.read_exact(&mut checksum_buffer[..])?; | 174 | 97.3M | let checksum = u32::from_le_bytes(checksum_buffer); | 175 | 97.3M | Ok(checksum) | 176 | 97.3M | } |
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::read_checksum <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_checksum Line | Count | Source | 171 | 2.22k | fn read_checksum(r: &mut R) -> Result<u32, io::Error> { | 172 | 2.22k | let mut checksum_buffer = [0u8; size_of::<u32>()]; | 173 | 2.22k | r.read_exact(&mut checksum_buffer[..])?; | 174 | 2.20k | let checksum = u32::from_le_bytes(checksum_buffer); | 175 | 2.20k | Ok(checksum) | 176 | 2.22k | } |
|
177 | | |
178 | | #[inline] |
179 | 97.3M | fn check_block_checksum(data: &[u8], expected_checksum: u32) -> Result<(), io::Error> { |
180 | 97.3M | let mut block_hasher = XxHash32::with_seed(0); |
181 | 97.3M | block_hasher.write(data); |
182 | 97.3M | let calc_checksum = block_hasher.finish() as u32; |
183 | 97.3M | if calc_checksum != expected_checksum { |
184 | 336 | return Err(Error::BlockChecksumError.into()); |
185 | 97.3M | } |
186 | 97.3M | Ok(()) |
187 | 97.3M | } <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::check_block_checksum Line | Count | Source | 179 | 97.3M | fn check_block_checksum(data: &[u8], expected_checksum: u32) -> Result<(), io::Error> { | 180 | 97.3M | let mut block_hasher = XxHash32::with_seed(0); | 181 | 97.3M | block_hasher.write(data); | 182 | 97.3M | let calc_checksum = block_hasher.finish() as u32; | 183 | 97.3M | if calc_checksum != expected_checksum { | 184 | 0 | return Err(Error::BlockChecksumError.into()); | 185 | 97.3M | } | 186 | 97.3M | Ok(()) | 187 | 97.3M | } |
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::check_block_checksum <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::check_block_checksum Line | Count | Source | 179 | 2.08k | fn check_block_checksum(data: &[u8], expected_checksum: u32) -> Result<(), io::Error> { | 180 | 2.08k | let mut block_hasher = XxHash32::with_seed(0); | 181 | 2.08k | block_hasher.write(data); | 182 | 2.08k | let calc_checksum = block_hasher.finish() as u32; | 183 | 2.08k | if calc_checksum != expected_checksum { | 184 | 336 | return Err(Error::BlockChecksumError.into()); | 185 | 1.75k | } | 186 | 1.75k | Ok(()) | 187 | 2.08k | } |
|
188 | | |
189 | 194M | fn read_block(&mut self) -> io::Result<usize> { |
190 | 194M | debug_assert_eq!(self.dst_start, self.dst_end); |
191 | 194M | let frame_info = self.current_frame_info.as_ref().unwrap(); |
192 | | |
193 | | // Adjust dst buffer offsets to decompress the next block |
194 | 194M | let max_block_size = frame_info.block_size.get_size(); |
195 | 194M | if frame_info.block_mode == BlockMode::Linked { |
196 | | // In linked mode we consume the output (bumping dst_start) but leave the |
197 | | // beginning of dst to be used as a prefix in subsequent blocks. |
198 | | // That is at least until we have at least `max_block_size + WINDOW_SIZE` |
199 | | // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes |
200 | | // and the output goes to the beginning of dst again. |
201 | 97.4M | debug_assert_eq!(self.dst.capacity(), max_block_size * 2 + WINDOW_SIZE); |
202 | 97.4M | if self.dst_start + max_block_size > self.dst.capacity() { |
203 | | // Output might not fit in the buffer. |
204 | | // The ext_dict will become the last WINDOW_SIZE bytes |
205 | 14.0k | debug_assert!(self.dst_start >= max_block_size + WINDOW_SIZE); |
206 | 14.0k | self.ext_dict_offset = self.dst_start - WINDOW_SIZE; |
207 | 14.0k | self.ext_dict_len = WINDOW_SIZE; |
208 | | // Output goes in the beginning of the buffer again. |
209 | 14.0k | self.dst_start = 0; |
210 | 14.0k | self.dst_end = 0; |
211 | 97.3M | } else if self.dst_start + self.ext_dict_len > WINDOW_SIZE { |
212 | | // There's more than WINDOW_SIZE bytes of lookback adding the prefix and ext_dict. |
213 | | // Since we have a limited buffer we must shrink ext_dict in favor of the prefix, |
214 | | // so that we can fit up to max_block_size bytes between dst_start and ext_dict |
215 | | // start. |
216 | 83.9M | let delta = self |
217 | 83.9M | .ext_dict_len |
218 | 83.9M | .min(self.dst_start + self.ext_dict_len - WINDOW_SIZE); |
219 | 83.9M | self.ext_dict_offset += delta; |
220 | 83.9M | self.ext_dict_len -= delta; |
221 | 83.9M | debug_assert!(self.dst_start + self.ext_dict_len >= WINDOW_SIZE) |
222 | 13.4M | } |
223 | | } else { |
224 | 97.3M | debug_assert_eq!(self.ext_dict_len, 0); |
225 | 97.3M | debug_assert_eq!(self.dst.capacity(), max_block_size); |
226 | 97.3M | self.dst_start = 0; |
227 | 97.3M | self.dst_end = 0; |
228 | | } |
229 | | |
230 | | // Read and decompress block |
231 | 194M | let block_info = { |
232 | 194M | let mut buffer = [0u8; 4]; |
233 | 194M | if let Err(err) = self.r.read_exact(&mut buffer) { |
234 | 1.34k | if err.kind() == ErrorKind::UnexpectedEof { |
235 | 1.34k | return Ok(0); |
236 | | } else { |
237 | 0 | return Err(err); |
238 | | } |
239 | 194M | } |
240 | 194M | BlockInfo::read(&buffer)? |
241 | | }; |
242 | 194M | match block_info { |
243 | 92.6M | BlockInfo::Uncompressed(len) => { |
244 | 92.6M | let len = len as usize; |
245 | 92.6M | if len > max_block_size { |
246 | 708 | return Err(Error::BlockTooBig.into()); |
247 | 92.6M | } |
248 | | // TODO: Attempt to avoid initialization of read buffer when |
249 | | // https://github.com/rust-lang/rust/issues/78485 stabilizes |
250 | 92.6M | self.r.read_exact(vec_resize_and_get_mut( |
251 | 92.6M | &mut self.dst, |
252 | 92.6M | self.dst_start, |
253 | 92.6M | self.dst_start + len, |
254 | 92.6M | ))?; |
255 | 92.6M | if frame_info.block_checksums { |
256 | 46.3M | let expected_checksum = Self::read_checksum(&mut self.r)?; |
257 | 46.3M | Self::check_block_checksum( |
258 | 46.3M | &self.dst[self.dst_start..self.dst_start + len], |
259 | 46.3M | expected_checksum, |
260 | 244 | )?; |
261 | 46.3M | } |
262 | | |
263 | 92.6M | self.dst_end += len; |
264 | 92.6M | self.content_len += len as u64; |
265 | | } |
266 | 102M | BlockInfo::Compressed(len) => { |
267 | 102M | let len = len as usize; |
268 | 102M | if len > max_block_size { |
269 | 4.11k | return Err(Error::BlockTooBig.into()); |
270 | 102M | } |
271 | | // TODO: Attempt to avoid initialization of read buffer when |
272 | | // https://github.com/rust-lang/rust/issues/78485 stabilizes |
273 | 102M | self.r |
274 | 102M | .read_exact(vec_resize_and_get_mut(&mut self.src, 0, len))?; |
275 | 102M | if frame_info.block_checksums { |
276 | 51.0M | let expected_checksum = Self::read_checksum(&mut self.r)?; |
277 | 51.0M | Self::check_block_checksum(&self.src[..len], expected_checksum)?; |
278 | 51.0M | } |
279 | | |
280 | 102M | let with_dict_mode = |
281 | 102M | frame_info.block_mode == BlockMode::Linked && self.ext_dict_len != 0; |
282 | 102M | let decomp_size = if with_dict_mode { |
283 | 8.55M | debug_assert!(self.dst_start + max_block_size <= self.ext_dict_offset); |
284 | 8.55M | let (head, tail) = self.dst.split_at_mut(self.ext_dict_offset); |
285 | 8.55M | let ext_dict = &tail[..self.ext_dict_len]; |
286 | | |
287 | 8.55M | debug_assert!(head.len() - self.dst_start >= max_block_size); |
288 | 8.55M | crate::block::decompress::decompress_internal::<true, _>( |
289 | 8.55M | &self.src[..len], |
290 | 8.55M | &mut SliceSink::new(head, self.dst_start), |
291 | 8.55M | ext_dict, |
292 | | ) |
293 | | } else { |
294 | | // Independent blocks OR linked blocks with only prefix data |
295 | 93.5M | debug_assert!(self.dst.capacity() - self.dst_start >= max_block_size); |
296 | 93.5M | crate::block::decompress::decompress_internal::<false, _>( |
297 | 93.5M | &self.src[..len], |
298 | 93.5M | &mut vec_sink_for_decompression( |
299 | 93.5M | &mut self.dst, |
300 | 93.5M | 0, |
301 | 93.5M | self.dst_start, |
302 | 93.5M | self.dst_start + max_block_size, |
303 | 93.5M | ), |
304 | 93.5M | b"", |
305 | | ) |
306 | | } |
307 | 102M | .map_err(Error::DecompressionError)?; |
308 | | |
309 | 102M | self.dst_end += decomp_size; |
310 | 102M | self.content_len += decomp_size as u64; |
311 | | } |
312 | | |
313 | | BlockInfo::EndMark => { |
314 | 17.3k | if let Some(expected) = frame_info.content_size { |
315 | 98 | if self.content_len != expected { |
316 | 95 | return Err(Error::ContentLengthError { |
317 | 95 | expected, |
318 | 95 | actual: self.content_len, |
319 | 95 | } |
320 | 95 | .into()); |
321 | 3 | } |
322 | 17.2k | } |
323 | 17.2k | if frame_info.content_checksum { |
324 | 8.69k | let expected_checksum = Self::read_checksum(&mut self.r)?; |
325 | 8.69k | let calc_checksum = self.content_hasher.finish() as u32; |
326 | 8.69k | if calc_checksum != expected_checksum { |
327 | 111 | return Err(Error::ContentChecksumError.into()); |
328 | 8.58k | } |
329 | 8.59k | } |
330 | 17.1k | self.current_frame_info = None; |
331 | 17.1k | return Ok(0); |
332 | | } |
333 | | } |
334 | | |
335 | | // Content checksum, if applicable |
336 | 194M | if frame_info.content_checksum { |
337 | 97.3M | self.content_hasher |
338 | 97.3M | .write(&self.dst[self.dst_start..self.dst_end]); |
339 | 97.3M | } |
340 | | |
341 | 194M | Ok(self.dst_end - self.dst_start) |
342 | 194M | } <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_block Line | Count | Source | 189 | 194M | fn read_block(&mut self) -> io::Result<usize> { | 190 | 194M | debug_assert_eq!(self.dst_start, self.dst_end); | 191 | 194M | let frame_info = self.current_frame_info.as_ref().unwrap(); | 192 | | | 193 | | // Adjust dst buffer offsets to decompress the next block | 194 | 194M | let max_block_size = frame_info.block_size.get_size(); | 195 | 194M | if frame_info.block_mode == BlockMode::Linked { | 196 | | // In linked mode we consume the output (bumping dst_start) but leave the | 197 | | // beginning of dst to be used as a prefix in subsequent blocks. | 198 | | // That is at least until we have at least `max_block_size + WINDOW_SIZE` | 199 | | // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes | 200 | | // and the output goes to the beginning of dst again. | 201 | 97.3M | debug_assert_eq!(self.dst.capacity(), max_block_size * 2 + WINDOW_SIZE); | 202 | 97.3M | if self.dst_start + max_block_size > self.dst.capacity() { | 203 | | // Output might not fit in the buffer. | 204 | | // The ext_dict will become the last WINDOW_SIZE bytes | 205 | 13.3k | debug_assert!(self.dst_start >= max_block_size + WINDOW_SIZE); | 206 | 13.3k | self.ext_dict_offset = self.dst_start - WINDOW_SIZE; | 207 | 13.3k | self.ext_dict_len = WINDOW_SIZE; | 208 | | // Output goes in the beginning of the buffer again. | 209 | 13.3k | self.dst_start = 0; | 210 | 13.3k | self.dst_end = 0; | 211 | 97.3M | } else if self.dst_start + self.ext_dict_len > WINDOW_SIZE { | 212 | | // There's more than WINDOW_SIZE bytes of lookback adding the prefix and ext_dict. | 213 | | // Since we have a limited buffer we must shrink ext_dict in favor of the prefix, | 214 | | // so that we can fit up to max_block_size bytes between dst_start and ext_dict | 215 | | // start. | 216 | 83.9M | let delta = self | 217 | 83.9M | .ext_dict_len | 218 | 83.9M | .min(self.dst_start + self.ext_dict_len - WINDOW_SIZE); | 219 | 83.9M | self.ext_dict_offset += delta; | 220 | 83.9M | self.ext_dict_len -= delta; | 221 | 83.9M | debug_assert!(self.dst_start + self.ext_dict_len >= WINDOW_SIZE) | 222 | 13.4M | } | 223 | | } else { | 224 | 97.3M | debug_assert_eq!(self.ext_dict_len, 0); | 225 | 97.3M | debug_assert_eq!(self.dst.capacity(), max_block_size); | 226 | 97.3M | self.dst_start = 0; | 227 | 97.3M | self.dst_end = 0; | 228 | | } | 229 | | | 230 | | // Read and decompress block | 231 | 194M | let block_info = { | 232 | 194M | let mut buffer = [0u8; 4]; | 233 | 194M | if let Err(err) = self.r.read_exact(&mut buffer) { | 234 | 0 | if err.kind() == ErrorKind::UnexpectedEof { | 235 | 0 | return Ok(0); | 236 | | } else { | 237 | 0 | return Err(err); | 238 | | } | 239 | 194M | } | 240 | 194M | BlockInfo::read(&buffer)? | 241 | | }; | 242 | 194M | match block_info { | 243 | 92.6M | BlockInfo::Uncompressed(len) => { | 244 | 92.6M | let len = len as usize; | 245 | 92.6M | if len > max_block_size { | 246 | 0 | return Err(Error::BlockTooBig.into()); | 247 | 92.6M | } | 248 | | // TODO: Attempt to avoid initialization of read buffer when | 249 | | // https://github.com/rust-lang/rust/issues/78485 stabilizes | 250 | 92.6M | self.r.read_exact(vec_resize_and_get_mut( | 251 | 92.6M | &mut self.dst, | 252 | 92.6M | self.dst_start, | 253 | 92.6M | self.dst_start + len, | 254 | 92.6M | ))?; | 255 | 92.6M | if frame_info.block_checksums { | 256 | 46.3M | let expected_checksum = Self::read_checksum(&mut self.r)?; | 257 | 46.3M | Self::check_block_checksum( | 258 | 46.3M | &self.dst[self.dst_start..self.dst_start + len], | 259 | 46.3M | expected_checksum, | 260 | 0 | )?; | 261 | 46.3M | } | 262 | | | 263 | 92.6M | self.dst_end += len; | 264 | 92.6M | self.content_len += len as u64; | 265 | | } | 266 | 102M | BlockInfo::Compressed(len) => { | 267 | 102M | let len = len as usize; | 268 | 102M | if len > max_block_size { | 269 | 0 | return Err(Error::BlockTooBig.into()); | 270 | 102M | } | 271 | | // TODO: Attempt to avoid initialization of read buffer when | 272 | | // https://github.com/rust-lang/rust/issues/78485 stabilizes | 273 | 102M | self.r | 274 | 102M | .read_exact(vec_resize_and_get_mut(&mut self.src, 0, len))?; | 275 | 102M | if frame_info.block_checksums { | 276 | 51.0M | let expected_checksum = Self::read_checksum(&mut self.r)?; | 277 | 51.0M | Self::check_block_checksum(&self.src[..len], expected_checksum)?; | 278 | 51.0M | } | 279 | | | 280 | 102M | let with_dict_mode = | 281 | 102M | frame_info.block_mode == BlockMode::Linked && self.ext_dict_len != 0; | 282 | 102M | let decomp_size = if with_dict_mode { | 283 | 8.55M | debug_assert!(self.dst_start + max_block_size <= self.ext_dict_offset); | 284 | 8.55M | let (head, tail) = self.dst.split_at_mut(self.ext_dict_offset); | 285 | 8.55M | let ext_dict = &tail[..self.ext_dict_len]; | 286 | | | 287 | 8.55M | debug_assert!(head.len() - self.dst_start >= max_block_size); | 288 | 8.55M | crate::block::decompress::decompress_internal::<true, _>( | 289 | 8.55M | &self.src[..len], | 290 | 8.55M | &mut SliceSink::new(head, self.dst_start), | 291 | 8.55M | ext_dict, | 292 | | ) | 293 | | } else { | 294 | | // Independent blocks OR linked blocks with only prefix data | 295 | 93.5M | debug_assert!(self.dst.capacity() - self.dst_start >= max_block_size); | 296 | 93.5M | crate::block::decompress::decompress_internal::<false, _>( | 297 | 93.5M | &self.src[..len], | 298 | 93.5M | &mut vec_sink_for_decompression( | 299 | 93.5M | &mut self.dst, | 300 | 93.5M | 0, | 301 | 93.5M | self.dst_start, | 302 | 93.5M | self.dst_start + max_block_size, | 303 | 93.5M | ), | 304 | 93.5M | b"", | 305 | | ) | 306 | | } | 307 | 102M | .map_err(Error::DecompressionError)?; | 308 | | | 309 | 102M | self.dst_end += decomp_size; | 310 | 102M | self.content_len += decomp_size as u64; | 311 | | } | 312 | | | 313 | | BlockInfo::EndMark => { | 314 | 17.1k | if let Some(expected) = frame_info.content_size { | 315 | 0 | if self.content_len != expected { | 316 | 0 | return Err(Error::ContentLengthError { | 317 | 0 | expected, | 318 | 0 | actual: self.content_len, | 319 | 0 | } | 320 | 0 | .into()); | 321 | 0 | } | 322 | 17.1k | } | 323 | 17.1k | if frame_info.content_checksum { | 324 | 8.57k | let expected_checksum = Self::read_checksum(&mut self.r)?; | 325 | 8.57k | let calc_checksum = self.content_hasher.finish() as u32; | 326 | 8.57k | if calc_checksum != expected_checksum { | 327 | 0 | return Err(Error::ContentChecksumError.into()); | 328 | 8.57k | } | 329 | 8.57k | } | 330 | 17.1k | self.current_frame_info = None; | 331 | 17.1k | return Ok(0); | 332 | | } | 333 | | } | 334 | | | 335 | | // Content checksum, if applicable | 336 | 194M | if frame_info.content_checksum { | 337 | 97.3M | self.content_hasher | 338 | 97.3M | .write(&self.dst[self.dst_start..self.dst_end]); | 339 | 97.3M | } | 340 | | | 341 | 194M | Ok(self.dst_end - self.dst_start) | 342 | 194M | } |
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::read_block <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_block Line | Count | Source | 189 | 39.6k | fn read_block(&mut self) -> io::Result<usize> { | 190 | 39.6k | debug_assert_eq!(self.dst_start, self.dst_end); | 191 | 39.6k | let frame_info = self.current_frame_info.as_ref().unwrap(); | 192 | | | 193 | | // Adjust dst buffer offsets to decompress the next block | 194 | 39.6k | let max_block_size = frame_info.block_size.get_size(); | 195 | 39.6k | if frame_info.block_mode == BlockMode::Linked { | 196 | | // In linked mode we consume the output (bumping dst_start) but leave the | 197 | | // beginning of dst to be used as a prefix in subsequent blocks. | 198 | | // That is at least until we have at least `max_block_size + WINDOW_SIZE` | 199 | | // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes | 200 | | // and the output goes to the beginning of dst again. | 201 | 23.7k | debug_assert_eq!(self.dst.capacity(), max_block_size * 2 + WINDOW_SIZE); | 202 | 23.7k | if self.dst_start + max_block_size > self.dst.capacity() { | 203 | | // Output might not fit in the buffer. | 204 | | // The ext_dict will become the last WINDOW_SIZE bytes | 205 | 694 | debug_assert!(self.dst_start >= max_block_size + WINDOW_SIZE); | 206 | 694 | self.ext_dict_offset = self.dst_start - WINDOW_SIZE; | 207 | 694 | self.ext_dict_len = WINDOW_SIZE; | 208 | | // Output goes in the beginning of the buffer again. | 209 | 694 | self.dst_start = 0; | 210 | 694 | self.dst_end = 0; | 211 | 23.1k | } else if self.dst_start + self.ext_dict_len > WINDOW_SIZE { | 212 | | // There's more than WINDOW_SIZE bytes of lookback adding the prefix and ext_dict. | 213 | | // Since we have a limited buffer we must shrink ext_dict in favor of the prefix, | 214 | | // so that we can fit up to max_block_size bytes between dst_start and ext_dict | 215 | | // start. | 216 | 8.55k | let delta = self | 217 | 8.55k | .ext_dict_len | 218 | 8.55k | .min(self.dst_start + self.ext_dict_len - WINDOW_SIZE); | 219 | 8.55k | self.ext_dict_offset += delta; | 220 | 8.55k | self.ext_dict_len -= delta; | 221 | 8.55k | debug_assert!(self.dst_start + self.ext_dict_len >= WINDOW_SIZE) | 222 | 14.5k | } | 223 | | } else { | 224 | 15.8k | debug_assert_eq!(self.ext_dict_len, 0); | 225 | 15.8k | debug_assert_eq!(self.dst.capacity(), max_block_size); | 226 | 15.8k | self.dst_start = 0; | 227 | 15.8k | self.dst_end = 0; | 228 | | } | 229 | | | 230 | | // Read and decompress block | 231 | 38.3k | let block_info = { | 232 | 39.6k | let mut buffer = [0u8; 4]; | 233 | 39.6k | if let Err(err) = self.r.read_exact(&mut buffer) { | 234 | 1.34k | if err.kind() == ErrorKind::UnexpectedEof { | 235 | 1.34k | return Ok(0); | 236 | | } else { | 237 | 0 | return Err(err); | 238 | | } | 239 | 38.3k | } | 240 | 38.3k | BlockInfo::read(&buffer)? | 241 | | }; | 242 | 38.3k | match block_info { | 243 | 18.7k | BlockInfo::Uncompressed(len) => { | 244 | 18.7k | let len = len as usize; | 245 | 18.7k | if len > max_block_size { | 246 | 708 | return Err(Error::BlockTooBig.into()); | 247 | 18.0k | } | 248 | | // TODO: Attempt to avoid initialization of read buffer when | 249 | | // https://github.com/rust-lang/rust/issues/78485 stabilizes | 250 | 18.0k | self.r.read_exact(vec_resize_and_get_mut( | 251 | 18.0k | &mut self.dst, | 252 | 18.0k | self.dst_start, | 253 | 18.0k | self.dst_start + len, | 254 | 18.0k | ))?; | 255 | 17.7k | if frame_info.block_checksums { | 256 | 1.66k | let expected_checksum = Self::read_checksum(&mut self.r)?; | 257 | 1.66k | Self::check_block_checksum( | 258 | 1.66k | &self.dst[self.dst_start..self.dst_start + len], | 259 | 1.66k | expected_checksum, | 260 | 244 | )?; | 261 | 16.1k | } | 262 | | | 263 | 17.5k | self.dst_end += len; | 264 | 17.5k | self.content_len += len as u64; | 265 | | } | 266 | 19.3k | BlockInfo::Compressed(len) => { | 267 | 19.3k | let len = len as usize; | 268 | 19.3k | if len > max_block_size { | 269 | 4.11k | return Err(Error::BlockTooBig.into()); | 270 | 15.2k | } | 271 | | // TODO: Attempt to avoid initialization of read buffer when | 272 | | // https://github.com/rust-lang/rust/issues/78485 stabilizes | 273 | 15.2k | self.r | 274 | 15.2k | .read_exact(vec_resize_and_get_mut(&mut self.src, 0, len))?; | 275 | 14.9k | if frame_info.block_checksums { | 276 | 432 | let expected_checksum = Self::read_checksum(&mut self.r)?; | 277 | 425 | Self::check_block_checksum(&self.src[..len], expected_checksum)?; | 278 | 14.5k | } | 279 | | | 280 | 14.8k | let with_dict_mode = | 281 | 14.8k | frame_info.block_mode == BlockMode::Linked && self.ext_dict_len != 0; | 282 | 14.8k | let decomp_size = if with_dict_mode { | 283 | 1.04k | debug_assert!(self.dst_start + max_block_size <= self.ext_dict_offset); | 284 | 1.04k | let (head, tail) = self.dst.split_at_mut(self.ext_dict_offset); | 285 | 1.04k | let ext_dict = &tail[..self.ext_dict_len]; | 286 | | | 287 | 1.04k | debug_assert!(head.len() - self.dst_start >= max_block_size); | 288 | 1.04k | crate::block::decompress::decompress_internal::<true, _>( | 289 | 1.04k | &self.src[..len], | 290 | 1.04k | &mut SliceSink::new(head, self.dst_start), | 291 | 1.04k | ext_dict, | 292 | | ) | 293 | | } else { | 294 | | // Independent blocks OR linked blocks with only prefix data | 295 | 13.8k | debug_assert!(self.dst.capacity() - self.dst_start >= max_block_size); | 296 | 13.8k | crate::block::decompress::decompress_internal::<false, _>( | 297 | 13.8k | &self.src[..len], | 298 | 13.8k | &mut vec_sink_for_decompression( | 299 | 13.8k | &mut self.dst, | 300 | 13.8k | 0, | 301 | 13.8k | self.dst_start, | 302 | 13.8k | self.dst_start + max_block_size, | 303 | 13.8k | ), | 304 | 13.8k | b"", | 305 | | ) | 306 | | } | 307 | 14.8k | .map_err(Error::DecompressionError)?; | 308 | | | 309 | 8.03k | self.dst_end += decomp_size; | 310 | 8.03k | self.content_len += decomp_size as u64; | 311 | | } | 312 | | | 313 | | BlockInfo::EndMark => { | 314 | 240 | if let Some(expected) = frame_info.content_size { | 315 | 98 | if self.content_len != expected { | 316 | 95 | return Err(Error::ContentLengthError { | 317 | 95 | expected, | 318 | 95 | actual: self.content_len, | 319 | 95 | } | 320 | 95 | .into()); | 321 | 3 | } | 322 | 142 | } | 323 | 145 | if frame_info.content_checksum { | 324 | 122 | let expected_checksum = Self::read_checksum(&mut self.r)?; | 325 | 115 | let calc_checksum = self.content_hasher.finish() as u32; | 326 | 115 | if calc_checksum != expected_checksum { | 327 | 111 | return Err(Error::ContentChecksumError.into()); | 328 | 4 | } | 329 | 23 | } | 330 | 27 | self.current_frame_info = None; | 331 | 27 | return Ok(0); | 332 | | } | 333 | | } | 334 | | | 335 | | // Content checksum, if applicable | 336 | 25.5k | if frame_info.content_checksum { | 337 | 4.80k | self.content_hasher | 338 | 4.80k | .write(&self.dst[self.dst_start..self.dst_end]); | 339 | 20.7k | } | 340 | | | 341 | 25.5k | Ok(self.dst_end - self.dst_start) | 342 | 39.6k | } |
|
343 | | |
344 | 194M | fn read_more(&mut self) -> io::Result<usize> { |
345 | 194M | if self.current_frame_info.is_none() && self.read_frame_info()? == 0 { |
346 | 348 | return Ok(0); |
347 | 194M | } |
348 | 194M | self.read_block() |
349 | 194M | } <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_more Line | Count | Source | 344 | 194M | fn read_more(&mut self) -> io::Result<usize> { | 345 | 194M | if self.current_frame_info.is_none() && self.read_frame_info()? == 0 { | 346 | 0 | return Ok(0); | 347 | 194M | } | 348 | 194M | self.read_block() | 349 | 194M | } |
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::read_more <lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_more Line | Count | Source | 344 | 47.5k | fn read_more(&mut self) -> io::Result<usize> { | 345 | 47.5k | if self.current_frame_info.is_none() && self.read_frame_info()? == 0 { | 346 | 348 | return Ok(0); | 347 | 39.6k | } | 348 | 39.6k | self.read_block() | 349 | 47.5k | } |
|
350 | | } |
351 | | |
352 | | impl<R: io::Read> io::Read for FrameDecoder<R> { |
353 | 194M | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
354 | | loop { |
355 | | // Fill read buffer if there's uncompressed data left |
356 | 389M | if self.dst_start < self.dst_end { |
357 | 194M | let read_len = std::cmp::min(self.dst_end - self.dst_start, buf.len()); |
358 | 194M | let dst_read_end = self.dst_start + read_len; |
359 | 194M | buf[..read_len].copy_from_slice(&self.dst[self.dst_start..dst_read_end]); |
360 | 194M | self.dst_start = dst_read_end; |
361 | 194M | return Ok(read_len); |
362 | 194M | } |
363 | 194M | if self.read_more()? == 0 { |
364 | 17.1k | return Ok(0); |
365 | 194M | } |
366 | | } |
367 | 194M | } <lz4_flex::frame::decompress::FrameDecoder<&[u8]> as std::io::Read>::read Line | Count | Source | 353 | 194M | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | 354 | | loop { | 355 | | // Fill read buffer if there's uncompressed data left | 356 | 389M | if self.dst_start < self.dst_end { | 357 | 194M | let read_len = std::cmp::min(self.dst_end - self.dst_start, buf.len()); | 358 | 194M | let dst_read_end = self.dst_start + read_len; | 359 | 194M | buf[..read_len].copy_from_slice(&self.dst[self.dst_start..dst_read_end]); | 360 | 194M | self.dst_start = dst_read_end; | 361 | 194M | return Ok(read_len); | 362 | 194M | } | 363 | 194M | if self.read_more()? == 0 { | 364 | 17.1k | return Ok(0); | 365 | 194M | } | 366 | | } | 367 | 194M | } |
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_> as std::io::Read>::read |
368 | | |
369 | 0 | fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { |
370 | 0 | let mut written = 0; |
371 | | loop { |
372 | 0 | match self.fill_buf() { |
373 | 0 | Ok([]) => return Ok(written), |
374 | 0 | Ok(b) => { |
375 | 0 | let s = std::str::from_utf8(b).map_err(|_| { |
376 | 0 | io::Error::new( |
377 | 0 | io::ErrorKind::InvalidData, |
378 | | "stream did not contain valid UTF-8", |
379 | | ) |
380 | 0 | })?; |
381 | 0 | buf.push_str(s); |
382 | 0 | let len = s.len(); |
383 | 0 | self.consume(len); |
384 | 0 | written += len; |
385 | | } |
386 | 0 | Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue, |
387 | 0 | Err(e) => return Err(e), |
388 | | } |
389 | | } |
390 | 0 | } |
391 | | |
392 | 22.1k | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { |
393 | 22.1k | let mut written = 0; |
394 | | loop { |
395 | 47.5k | match self.fill_buf() { |
396 | 27.2k | Ok([]) => return Ok(written), |
397 | 25.3k | Ok(b) => { |
398 | 25.3k | buf.extend_from_slice(b); |
399 | 25.3k | let len = b.len(); |
400 | 25.3k | self.consume(len); |
401 | 25.3k | written += len; |
402 | 25.3k | } |
403 | 20.2k | Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue, |
404 | 20.2k | Err(e) => return Err(e), |
405 | | } |
406 | | } |
407 | 22.1k | } Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_> as std::io::Read>::read_to_end <lz4_flex::frame::decompress::FrameDecoder<&[u8]> as std::io::Read>::read_to_end Line | Count | Source | 392 | 22.1k | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { | 393 | 22.1k | let mut written = 0; | 394 | | loop { | 395 | 47.5k | match self.fill_buf() { | 396 | 27.2k | Ok([]) => return Ok(written), | 397 | 25.3k | Ok(b) => { | 398 | 25.3k | buf.extend_from_slice(b); | 399 | 25.3k | let len = b.len(); | 400 | 25.3k | self.consume(len); | 401 | 25.3k | written += len; | 402 | 25.3k | } | 403 | 20.2k | Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue, | 404 | 20.2k | Err(e) => return Err(e), | 405 | | } | 406 | | } | 407 | 22.1k | } |
|
408 | | } |
409 | | |
410 | | impl<R: io::Read> io::BufRead for FrameDecoder<R> { |
411 | 47.5k | fn fill_buf(&mut self) -> io::Result<&[u8]> { |
412 | 47.5k | if self.dst_start == self.dst_end { |
413 | 47.5k | self.read_more()?; |
414 | 0 | } |
415 | 27.2k | Ok(&self.dst[self.dst_start..self.dst_end]) |
416 | 47.5k | } Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_> as std::io::BufRead>::fill_buf <lz4_flex::frame::decompress::FrameDecoder<&[u8]> as std::io::BufRead>::fill_buf Line | Count | Source | 411 | 47.5k | fn fill_buf(&mut self) -> io::Result<&[u8]> { | 412 | 47.5k | if self.dst_start == self.dst_end { | 413 | 47.5k | self.read_more()?; | 414 | 0 | } | 415 | 27.2k | Ok(&self.dst[self.dst_start..self.dst_end]) | 416 | 47.5k | } |
|
417 | | |
418 | 25.3k | fn consume(&mut self, amt: usize) { |
419 | 25.3k | assert!(amt <= self.dst_end - self.dst_start); |
420 | 25.3k | self.dst_start += amt; |
421 | 25.3k | } Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_> as std::io::BufRead>::consume <lz4_flex::frame::decompress::FrameDecoder<&[u8]> as std::io::BufRead>::consume Line | Count | Source | 418 | 25.3k | fn consume(&mut self, amt: usize) { | 419 | 25.3k | assert!(amt <= self.dst_end - self.dst_start); | 420 | 25.3k | self.dst_start += amt; | 421 | 25.3k | } |
|
422 | | } |
423 | | |
424 | | impl<R: fmt::Debug + io::Read> fmt::Debug for FrameDecoder<R> { |
425 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
426 | 0 | f.debug_struct("FrameDecoder") |
427 | 0 | .field("r", &self.r) |
428 | 0 | .field("content_hasher", &self.content_hasher) |
429 | 0 | .field("content_len", &self.content_len) |
430 | 0 | .field("src", &"[...]") |
431 | 0 | .field("dst", &"[...]") |
432 | 0 | .field("dst_start", &self.dst_start) |
433 | 0 | .field("dst_end", &self.dst_end) |
434 | 0 | .field("ext_dict_offset", &self.ext_dict_offset) |
435 | 0 | .field("ext_dict_len", &self.ext_dict_len) |
436 | 0 | .field("current_frame_info", &self.current_frame_info) |
437 | 0 | .finish() |
438 | 0 | } |
439 | | } |
440 | | |
441 | | /// Similar to `v.get_mut(start..end) but will adjust the len if needed. |
442 | | #[inline] |
443 | 194M | fn vec_resize_and_get_mut(v: &mut Vec<u8>, start: usize, end: usize) -> &mut [u8] { |
444 | 194M | if end > v.len() { |
445 | 29.9M | v.resize(end, 0) |
446 | 164M | } |
447 | 194M | &mut v[start..end] |
448 | 194M | } lz4_flex::frame::decompress::vec_resize_and_get_mut Line | Count | Source | 443 | 194M | fn vec_resize_and_get_mut(v: &mut Vec<u8>, start: usize, end: usize) -> &mut [u8] { | 444 | 194M | if end > v.len() { | 445 | 29.9M | v.resize(end, 0) | 446 | 164M | } | 447 | 194M | &mut v[start..end] | 448 | 194M | } |
Unexecuted instantiation: lz4_flex::frame::decompress::vec_resize_and_get_mut lz4_flex::frame::decompress::vec_resize_and_get_mut Line | Count | Source | 443 | 33.2k | fn vec_resize_and_get_mut(v: &mut Vec<u8>, start: usize, end: usize) -> &mut [u8] { | 444 | 33.2k | if end > v.len() { | 445 | 15.8k | v.resize(end, 0) | 446 | 17.3k | } | 447 | 33.2k | &mut v[start..end] | 448 | 33.2k | } |
|