Skip to main content

draco_core/
decoder_buffer.rs

1use crate::status::DracoError;
2use crate::version::DEFAULT_MESH_VERSION;
3use std::mem;
4
5/// Input buffer for reading compressed Draco data.
6///
7/// `DecoderBuffer` provides sequential byte and bit-level access to compressed data.
8/// It supports both byte-aligned reads (integers, floats, strings) and bit-level
9/// reads for entropy-coded data.
10///
11/// # Example
12///
13/// ```
14/// use draco_core::DecoderBuffer;
15///
16/// let data = &[0x44, 0x52, 0x41, 0x43, 0x4F]; // "DRACO" header
17/// let mut buffer = DecoderBuffer::new(data);
18///
19/// assert_eq!(buffer.decode_u8().unwrap(), 0x44);
20/// assert_eq!(buffer.remaining_size(), 4);
21/// ```
22pub struct DecoderBuffer<'a> {
23    data: &'a [u8],
24    pos: usize,
25    bit_decoder_active: bool,
26    bit_start_pos: usize,
27    current_bit_offset: usize,
28    bit_stream_end_pos: usize,
29    bit_sequence_size_known: bool,
30    version_major: u8,
31    version_minor: u8,
32}
33
34impl<'a> DecoderBuffer<'a> {
35    /// Creates a new `DecoderBuffer` from a byte slice.
36    pub fn new(data: &'a [u8]) -> Self {
37        Self {
38            data,
39            pos: 0,
40            bit_decoder_active: false,
41            bit_start_pos: 0,
42            current_bit_offset: 0,
43            bit_stream_end_pos: 0,
44            bit_sequence_size_known: false,
45            // Default to latest mesh version to match encoder output format
46            version_major: DEFAULT_MESH_VERSION.0,
47            version_minor: DEFAULT_MESH_VERSION.1,
48        }
49    }
50
51    /// Sets the Draco bitstream version for version-dependent decoding.
52    pub fn set_version(&mut self, major: u8, minor: u8) {
53        self.version_major = major;
54        self.version_minor = minor;
55    }
56
57    /// Returns the major version number.
58    pub fn version_major(&self) -> u8 {
59        self.version_major
60    }
61
62    /// Returns the minor version number.
63    pub fn version_minor(&self) -> u8 {
64        self.version_minor
65    }
66
67    /// Returns the packed `0xMMmm` bitstream version for ordered comparisons.
68    pub fn bitstream_version(&self) -> u16 {
69        crate::version::bitstream_version(self.version_major, self.version_minor)
70    }
71
72    /// Returns the current read position in bytes.
73    pub fn position(&self) -> usize {
74        self.pos
75    }
76
77    /// Sets the read position.
78    ///
79    /// # Errors
80    ///
81    /// Returns `DracoError::BufferError` if:
82    /// - Bit decoding is currently active
83    /// - Position is beyond the buffer length
84    pub fn set_position(&mut self, pos: usize) -> Result<(), DracoError> {
85        if self.bit_decoder_active {
86            return Err(DracoError::BufferError(
87                "Cannot set position while bit decoding is active".into(),
88            ));
89        }
90        if pos > self.data.len() {
91            return Err(DracoError::BufferError(format!(
92                "Position {} exceeds buffer length {}",
93                pos,
94                self.data.len()
95            )));
96        }
97        self.pos = pos;
98        Ok(())
99    }
100
101    /// Returns the number of bytes remaining in the buffer.
102    pub fn remaining_size(&self) -> usize {
103        self.data.len().saturating_sub(self.pos)
104    }
105
106    /// Peeks at the next `len` bytes without advancing the position.
107    pub fn peek_bytes(&self, len: usize) -> Vec<u8> {
108        let end = std::cmp::min(self.pos + len, self.data.len());
109        self.data[self.pos..end].to_vec()
110    }
111
112    /// Starts bit-level decoding mode.
113    ///
114    /// When `decode_size` is true, reads the bit sequence size from the buffer.
115    /// Returns the size in bytes.
116    ///
117    /// # Errors
118    ///
119    /// Returns `DracoError::BufferError` if bit decoding is already active.
120    pub fn start_bit_decoding(&mut self, decode_size: bool) -> Result<u64, DracoError> {
121        if self.bit_decoder_active {
122            return Err(DracoError::BufferError(
123                "Bit decoding already active".into(),
124            ));
125        }
126        let bitstream_version = self.bitstream_version();
127        // Draco stores the bit-sequence size in BYTES (not bits) when |decode_size| is true.
128        let mut size_bytes: u64 = 0;
129        if decode_size {
130            if bitstream_version < 0x0202 {
131                if !cfg!(feature = "legacy_bitstream_decode") {
132                    return Err(DracoError::BitstreamVersionUnsupported);
133                }
134                size_bytes = self.decode_u64()?;
135            } else {
136                size_bytes = self.decode_varint()?;
137            }
138        }
139
140        self.bit_start_pos = self.pos;
141        self.bit_decoder_active = true;
142        self.current_bit_offset = 0;
143        self.bit_sequence_size_known = decode_size;
144
145        if decode_size {
146            let size_bytes = usize::try_from(size_bytes)
147                .map_err(|_| DracoError::BufferError("Bit stream size too large".into()))?;
148            self.bit_stream_end_pos =
149                self.bit_start_pos.checked_add(size_bytes).ok_or_else(|| {
150                    DracoError::BufferError("Bit stream end position overflow".into())
151                })?;
152        } else {
153            // If size is not encoded, assume the rest of the buffer.
154            self.bit_stream_end_pos = self.data.len();
155        }
156
157        Ok(size_bytes)
158    }
159
160    /// Ends bit-level decoding mode and advances the byte position.
161    pub fn end_bit_decoding(&mut self) {
162        self.bit_decoder_active = false;
163        // Draco behavior:
164        // - When decoding with size known, the caller typically skips by the stored byte size.
165        // - When decoding without size, advance by the number of decoded bits (rounded up).
166        if self.bit_sequence_size_known {
167            self.pos = self.bit_stream_end_pos;
168        } else {
169            let bytes_consumed = self.current_bit_offset.div_ceil(8);
170            self.pos = self.bit_start_pos + bytes_consumed;
171        }
172    }
173
174    /// Decodes `nbits` least significant bits as a u32.
175    ///
176    /// # Errors
177    ///
178    /// Returns `DracoError::BufferError` if bit decoding is not active or end of stream.
179    #[inline(always)]
180    pub fn decode_least_significant_bits32(&mut self, nbits: u32) -> Result<u32, DracoError> {
181        if !self.bit_decoder_active {
182            return Err(DracoError::BufferError("Bit decoding not active".into()));
183        }
184        self.decode_least_significant_bits32_fast(nbits)
185    }
186
187    /// Optimized version for hot paths - reads multiple bytes at once.
188    #[inline(always)]
189    pub fn decode_least_significant_bits32_fast(&mut self, nbits: u32) -> Result<u32, DracoError> {
190        if nbits == 0 {
191            return Ok(0);
192        }
193
194        let total_bit_offset = self.current_bit_offset;
195        let byte_offset = self.bit_start_pos + total_bit_offset / 8;
196        let bit_shift = (total_bit_offset % 8) as u32;
197
198        if byte_offset >= self.bit_stream_end_pos || byte_offset >= self.data.len() {
199            return Err(DracoError::BufferError(
200                "Unexpected end of bit stream".into(),
201            ));
202        }
203        let available_end = self.bit_stream_end_pos.min(self.data.len());
204        let remaining = available_end - byte_offset;
205
206        // Fast path: read 8 bytes at once when enough data remains (avoids per-byte loop).
207        let raw = if remaining >= 8 {
208            let mut bytes = [0u8; 8];
209            bytes.copy_from_slice(&self.data[byte_offset..byte_offset + 8]);
210            u64::from_le_bytes(bytes)
211        } else {
212            let needed_bytes = (bit_shift + nbits).div_ceil(8) as usize;
213            if remaining < needed_bytes {
214                return Err(DracoError::BufferError(
215                    "Unexpected end of bit stream".into(),
216                ));
217            }
218            let mut v = 0u64;
219            for i in 0..needed_bytes {
220                v |= (self.data[byte_offset + i] as u64) << (i * 8);
221            }
222            v
223        };
224        let value = ((raw >> bit_shift) as u32) & ((1u32 << nbits) - 1);
225
226        self.current_bit_offset += nbits as usize;
227        Ok(value)
228    }
229
230    #[inline]
231    #[allow(dead_code)]
232    fn get_bit(&mut self) -> Result<u32, DracoError> {
233        let total_bit_offset = self.current_bit_offset;
234        let byte_offset = self.bit_start_pos + total_bit_offset / 8;
235        let bit_shift = total_bit_offset % 8;
236
237        if byte_offset < self.bit_stream_end_pos && byte_offset < self.data.len() {
238            let bit = (self.data[byte_offset] >> bit_shift) & 1;
239            self.current_bit_offset += 1;
240            Ok(bit as u32)
241        } else {
242            Err(DracoError::BufferError(
243                "Unexpected end of bit stream".into(),
244            ))
245        }
246    }
247
248    /// Decodes a value of type T using raw memory copy.
249    ///
250    /// # Errors
251    ///
252    /// Returns `DracoError::BufferError` if:
253    /// - Bit decoding is active
254    /// - Not enough bytes remaining
255    pub fn decode<T: Copy + bytemuck::Pod>(&mut self) -> Result<T, DracoError> {
256        if self.bit_decoder_active {
257            return Err(DracoError::BufferError(
258                "Cannot decode bytes while bit decoding is active".into(),
259            ));
260        }
261        let size = mem::size_of::<T>();
262        if self.pos + size > self.data.len() {
263            return Err(DracoError::BufferError(format!(
264                "Unexpected end of buffer: need {} bytes, have {}",
265                size,
266                self.remaining_size()
267            )));
268        }
269
270        // Safety: bytemuck::Pod guarantees T can be safely read from any bit pattern
271        let val = bytemuck::pod_read_unaligned::<T>(&self.data[self.pos..self.pos + size]);
272        self.pos += size;
273        Ok(val)
274    }
275
276    /// Decodes a single byte.
277    pub fn decode_u8(&mut self) -> Result<u8, DracoError> {
278        self.decode::<u8>()
279    }
280
281    /// Decodes a little-endian u16.
282    pub fn decode_u16(&mut self) -> Result<u16, DracoError> {
283        let mut bytes = [0u8; 2];
284        self.decode_bytes(&mut bytes)?;
285        Ok(u16::from_le_bytes(bytes))
286    }
287
288    /// Decodes a little-endian u32.
289    pub fn decode_u32(&mut self) -> Result<u32, DracoError> {
290        let mut bytes = [0u8; 4];
291        self.decode_bytes(&mut bytes)?;
292        Ok(u32::from_le_bytes(bytes))
293    }
294
295    /// Decodes a little-endian u64.
296    pub fn decode_u64(&mut self) -> Result<u64, DracoError> {
297        let mut bytes = [0u8; 8];
298        self.decode_bytes(&mut bytes)?;
299        Ok(u64::from_le_bytes(bytes))
300    }
301
302    /// Decodes a little-endian f32.
303    pub fn decode_f32(&mut self) -> Result<f32, DracoError> {
304        let mut bytes = [0u8; 4];
305        self.decode_bytes(&mut bytes)?;
306        Ok(f32::from_le_bytes(bytes))
307    }
308
309    /// Decodes a little-endian f64.
310    pub fn decode_f64(&mut self) -> Result<f64, DracoError> {
311        let mut bytes = [0u8; 8];
312        self.decode_bytes(&mut bytes)?;
313        Ok(f64::from_le_bytes(bytes))
314    }
315
316    /// Decodes a null-terminated string.
317    pub fn decode_string(&mut self) -> Result<String, DracoError> {
318        let mut bytes = Vec::new();
319        loop {
320            let b = self.decode_u8()?;
321            if b == 0 {
322                break;
323            }
324            bytes.push(b);
325        }
326        String::from_utf8(bytes)
327            .map_err(|e| DracoError::BufferError(format!("Invalid UTF-8 string: {}", e)))
328    }
329
330    /// Decodes bytes into the provided buffer.
331    ///
332    /// # Errors
333    ///
334    /// Returns `DracoError::BufferError` if not enough bytes remaining.
335    pub fn decode_bytes(&mut self, out: &mut [u8]) -> Result<(), DracoError> {
336        let size = out.len();
337        if self.pos + size > self.data.len() {
338            return Err(DracoError::BufferError(format!(
339                "Unexpected end of buffer: need {} bytes, have {}",
340                size,
341                self.remaining_size()
342            )));
343        }
344        out.copy_from_slice(&self.data[self.pos..self.pos + size]);
345        self.pos += size;
346        Ok(())
347    }
348
349    /// Decodes a variable-length unsigned integer (varint).
350    pub fn decode_varint(&mut self) -> Result<u64, DracoError> {
351        let mut val = 0u64;
352        let mut shift = 0;
353        loop {
354            let b = self.decode_u8()?;
355            val |= ((b & 0x7F) as u64) << shift;
356            if (b & 0x80) == 0 {
357                break;
358            }
359            shift += 7;
360            if shift >= 64 {
361                return Err(DracoError::BufferError("Varint exceeds 64 bits".into()));
362            }
363        }
364        Ok(val)
365    }
366
367    /// Decodes a Draco-compatible signed varint.
368    ///
369    /// Uses unsigned varint encoding with ConvertSymbolToSignedInt transformation.
370    pub fn decode_varint_signed_i32(&mut self) -> Result<i32, DracoError> {
371        let symbol = self.decode_varint()? as u32;
372        let is_positive = (symbol & 1) == 0;
373        let v = symbol >> 1;
374        if is_positive {
375            Ok(v as i32)
376        } else {
377            Ok(-(v as i32) - 1)
378        }
379    }
380
381    /// Returns a slice of the remaining data without advancing.
382    pub fn remaining_data(&self) -> &'a [u8] {
383        &self.data[self.pos..]
384    }
385
386    /// Advances the position by `n` bytes without reading.
387    pub fn advance(&mut self, n: usize) {
388        self.pos = self.pos.saturating_add(n).min(self.data.len());
389    }
390
391    /// Advances the position by `n` bytes without reading.
392    ///
393    /// # Errors
394    ///
395    /// Returns `DracoError::BufferError` if the requested advance would move
396    /// beyond the end of the input buffer.
397    pub fn try_advance(&mut self, n: usize) -> Result<(), DracoError> {
398        let new_pos = self
399            .pos
400            .checked_add(n)
401            .ok_or_else(|| DracoError::BufferError("Buffer advance overflow".into()))?;
402        if new_pos > self.data.len() {
403            return Err(DracoError::BufferError(format!(
404                "Cannot advance buffer by {} bytes: need position {}, buffer length {}",
405                n,
406                new_pos,
407                self.data.len()
408            )));
409        }
410        self.pos = new_pos;
411        Ok(())
412    }
413
414    /// Decodes and returns a slice of the specified size.
415    ///
416    /// # Errors
417    ///
418    /// Returns `DracoError::BufferError` if not enough bytes remaining.
419    pub fn decode_slice(&mut self, size: usize) -> Result<&'a [u8], DracoError> {
420        if self.pos + size > self.data.len() {
421            return Err(DracoError::BufferError(format!(
422                "Unexpected end of buffer: need {} bytes, have {}",
423                size,
424                self.remaining_size()
425            )));
426        }
427        let slice = &self.data[self.pos..self.pos + size];
428        self.pos += size;
429        Ok(slice)
430    }
431}
432
433#[cfg(test)]
434mod tests {
435    use super::DecoderBuffer;
436
437    #[test]
438    fn bit_decode_respects_declared_byte_size() {
439        let data = [1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
440        let mut buffer = DecoderBuffer::new(&data);
441
442        assert_eq!(buffer.start_bit_decoding(true).unwrap(), 1);
443        assert!(buffer.decode_least_significant_bits32(16).is_err());
444    }
445
446    #[test]
447    fn try_advance_rejects_out_of_bounds_skip() {
448        let data = [0u8; 4];
449        let mut buffer = DecoderBuffer::new(&data);
450
451        assert!(buffer.try_advance(5).is_err());
452        assert_eq!(buffer.position(), 0);
453        assert!(buffer.try_advance(4).is_ok());
454        assert_eq!(buffer.position(), 4);
455    }
456}