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    /// Bytes this decode has reserved so far, across every buffer it sized.
33    ///
34    /// The budget belongs to *one decode of one stream*, and that is what this
35    /// type is: built once per decode, carrying the stream, and already
36    /// threaded to every site that sizes something. Holding the counter here
37    /// is what makes the bound cumulative rather than per-allocation -- see
38    /// [`charge`](Self::charge).
39    spent: usize,
40    /// The caller's ceilings on what this decode may produce, and what it has
41    /// produced so far against the byte one.
42    ///
43    /// Here rather than on the decoders because this type is the stream and
44    /// already reaches every site that learns a count -- the same reason the
45    /// budget above lives here. A decode of a mesh runs a point-cloud decoder
46    /// and an attributes decoder under it; one buffer is what all three share.
47    limits: crate::decode_limits::DecodeLimits,
48    decoded_bytes: u64,
49}
50
51impl<'a> DecoderBuffer<'a> {
52    /// Creates a new `DecoderBuffer` from a byte slice.
53    pub fn new(data: &'a [u8]) -> Self {
54        Self {
55            data,
56            pos: 0,
57            bit_decoder_active: false,
58            bit_start_pos: 0,
59            current_bit_offset: 0,
60            bit_stream_end_pos: 0,
61            bit_sequence_size_known: false,
62            // Default to latest mesh version to match encoder output format
63            version_major: DEFAULT_MESH_VERSION.0,
64            version_minor: DEFAULT_MESH_VERSION.1,
65            spent: 0,
66            limits: crate::decode_limits::DecodeLimits::default(),
67            decoded_bytes: 0,
68        }
69    }
70
71    /// Decodes under `limits` rather than under
72    /// [`DecodeLimits::default`](crate::DecodeLimits::default).
73    ///
74    /// ```
75    /// use draco_core::{DecodeLimits, DecoderBuffer};
76    ///
77    /// let stream = [0u8; 0];
78    /// let buffer = DecoderBuffer::new(&stream).with_limits(DecodeLimits::permissive());
79    /// # let _ = buffer;
80    /// ```
81    #[must_use]
82    pub fn with_limits(mut self, limits: crate::decode_limits::DecodeLimits) -> Self {
83        self.limits = limits;
84        self
85    }
86
87    /// Refuses a decoded point count over the caller's ceiling.
88    #[cfg(feature = "point_cloud_decode")]
89    pub(crate) fn check_points(&self, points: usize) -> crate::status::Status {
90        self.limits.check_points(points as u64)
91    }
92
93    /// Refuses a decoded face count over the caller's ceiling.
94    pub(crate) fn check_faces(&self, faces: usize) -> crate::status::Status {
95        self.limits.check_faces(faces as u64)
96    }
97
98    /// Adds one attribute's declared size to this decode's running total and
99    /// refuses when the total passes the caller's ceiling.
100    ///
101    /// Cumulative for the same reason [`charge`](Self::charge) is: the
102    /// attribute count is the header's, so a per-attribute check bounds
103    /// nothing. Called where the size becomes known and before anything is
104    /// allocated for it.
105    pub(crate) fn charge_decoded_bytes(&mut self, bytes: usize) -> crate::status::Status {
106        let total = self.decoded_bytes.saturating_add(bytes as u64);
107        self.limits.check_decoded_bytes(total)?;
108        self.decoded_bytes = total;
109        Ok(())
110    }
111
112    /// Charges `bytes` against what this stream is allowed to make the decoder
113    /// allocate, and refuses when the running total outgrows it.
114    ///
115    /// Cumulative on purpose. Checked per allocation, the same budget is
116    /// granted again at every site, and the number of sites is the attacker's:
117    /// one attributes decoder carries as many attributes as the header names,
118    /// and their buffers coexist. Measured before this existed, on a stream
119    /// held at ~32 KB while only the attribute count changed:
120    ///
121    /// | attributes | reserved |
122    /// | ---: | ---: |
123    /// | 1 | 19.2 MB |
124    /// | 4 | 76.8 MB |
125    /// | 16 | 307.2 MB |
126    ///
127    /// Linear in a count that costs 7.5 bytes of input each, so the per-site
128    /// form bounded nothing that mattered. One running total does.
129    ///
130    /// Nothing is ever credited back. A decode that frees a buffer and sizes
131    /// another still pays for both, which is why the ceiling has to cover the
132    /// *sum* over a real file rather than its peak -- see
133    /// [`MAX_ALLOCATED_BYTES_PER_INPUT_BYTE`], whose value is measured against
134    /// exactly that.
135    ///
136    /// [`MAX_ALLOCATED_BYTES_PER_INPUT_BYTE`]: crate::decode_budget::MAX_ALLOCATED_BYTES_PER_INPUT_BYTE
137    pub(crate) fn charge(&mut self, bytes: usize) -> crate::status::Status {
138        let total = self.spent.saturating_add(bytes);
139        crate::decode_budget::ensure_allocation_is_backed(total, self.data.len())?;
140        self.spent = total;
141        Ok(())
142    }
143
144    /// [`charge`](Self::charge) for a count of `element_size`-byte elements.
145    pub(crate) fn charge_elements(
146        &mut self,
147        count: usize,
148        element_size: usize,
149    ) -> crate::status::Status {
150        self.charge(count.saturating_mul(element_size))
151    }
152
153    /// What this decode has reserved so far, for the tests that hold the
154    /// budget to being a backstop no legitimate file reaches.
155    #[cfg(test)]
156    pub(crate) fn spent(&self) -> usize {
157        self.spent
158    }
159
160    /// Sets the Draco bitstream version for version-dependent decoding.
161    pub fn set_version(&mut self, major: u8, minor: u8) {
162        self.version_major = major;
163        self.version_minor = minor;
164    }
165
166    /// Returns the major version number.
167    pub fn version_major(&self) -> u8 {
168        self.version_major
169    }
170
171    /// Returns the minor version number.
172    pub fn version_minor(&self) -> u8 {
173        self.version_minor
174    }
175
176    /// Returns the packed `0xMMmm` bitstream version for ordered comparisons.
177    pub fn bitstream_version(&self) -> u16 {
178        crate::version::bitstream_version(self.version_major, self.version_minor)
179    }
180
181    /// Returns the current read position in bytes.
182    pub fn position(&self) -> usize {
183        self.pos
184    }
185
186    /// Sets the read position.
187    ///
188    /// # Errors
189    ///
190    /// Returns an [`ErrorKind::Buffer`](crate::ErrorKind::Buffer) error if:
191    /// - Bit decoding is currently active
192    /// - Position is beyond the buffer length
193    pub fn set_position(&mut self, pos: usize) -> Result<(), DracoError> {
194        if self.bit_decoder_active {
195            return Err(DracoError::buffer(
196                "Cannot set position while bit decoding is active",
197            ));
198        }
199        if pos > self.data.len() {
200            return Err(DracoError::buffer(format!(
201                "Position {} exceeds buffer length {}",
202                pos,
203                self.data.len()
204            )));
205        }
206        self.pos = pos;
207        Ok(())
208    }
209
210    /// Returns the number of bytes remaining in the buffer.
211    pub fn remaining_size(&self) -> usize {
212        self.data.len().saturating_sub(self.pos)
213    }
214
215    /// Returns the total size of the buffer, read or not.
216    ///
217    /// The decode allocation budget measures against this rather than against
218    /// [`remaining_size`](Self::remaining_size): an attribute decoded last has
219    /// a legitimately tiny payload left in front of it while its value count is
220    /// no smaller than the first attribute's, so charging it only for what
221    /// follows would refuse valid streams.
222    pub fn size(&self) -> usize {
223        self.data.len()
224    }
225
226    /// Peeks at the next `len` bytes without advancing the position.
227    pub fn peek_bytes(&self, len: usize) -> Vec<u8> {
228        let start = self.pos.min(self.data.len());
229        let end = start.saturating_add(len).min(self.data.len());
230        self.data[start..end].to_vec()
231    }
232
233    /// Starts bit-level decoding mode.
234    ///
235    /// When `decode_size` is true, reads the bit sequence size from the buffer.
236    /// Returns the size in bytes.
237    ///
238    /// # Errors
239    ///
240    /// Returns an [`ErrorKind::Buffer`](crate::ErrorKind::Buffer) error if bit decoding is already active.
241    pub fn start_bit_decoding(&mut self, decode_size: bool) -> Result<u64, DracoError> {
242        if self.bit_decoder_active {
243            return Err(DracoError::buffer("Bit decoding already active"));
244        }
245        let bitstream_version = self.bitstream_version();
246        // Draco stores the bit-sequence size in BYTES (not bits) when |decode_size| is true.
247        let mut size_bytes: u64 = 0;
248        if decode_size {
249            if bitstream_version < 0x0202 {
250                if !cfg!(feature = "legacy_bitstream_decode") {
251                    return Err(DracoError::bitstream_version_unsupported());
252                }
253                size_bytes = self.decode_u64()?;
254            } else {
255                size_bytes = self.decode_varint()?;
256            }
257        }
258
259        self.bit_start_pos = self.pos;
260        self.bit_decoder_active = true;
261        self.current_bit_offset = 0;
262        self.bit_sequence_size_known = decode_size;
263
264        if decode_size {
265            let size_bytes = usize::try_from(size_bytes)
266                .map_err(|_| DracoError::buffer("Bit stream size too large"))?;
267            // Bounded by the buffer, not by the number: the size is a varint
268            // out of the stream, and a stream claiming more than it carries is
269            // one upstream reads to the end of rather than refuses -- its bit
270            // decoder is handed `remaining_size()` and never sees the claim.
271            // Left unbounded, the claim lands in `pos` when bit decoding ends,
272            // and a position past the buffer is one no later bounds check is
273            // written to expect.
274            let declared_end = self
275                .bit_start_pos
276                .checked_add(size_bytes)
277                .ok_or_else(|| DracoError::buffer("Bit stream end position overflow"))?;
278            self.bit_stream_end_pos = declared_end.min(self.data.len());
279        } else {
280            // If size is not encoded, assume the rest of the buffer.
281            self.bit_stream_end_pos = self.data.len();
282        }
283
284        Ok(size_bytes)
285    }
286
287    /// Ends bit-level decoding mode and advances the byte position.
288    pub fn end_bit_decoding(&mut self) {
289        self.bit_decoder_active = false;
290        // Draco behavior:
291        // - When decoding with size known, the caller typically skips by the stored byte size.
292        // - When decoding without size, advance by the number of decoded bits (rounded up).
293        if self.bit_sequence_size_known {
294            self.pos = self.bit_stream_end_pos;
295        } else {
296            let bytes_consumed = self.current_bit_offset.div_ceil(8);
297            self.pos = self.bit_start_pos + bytes_consumed;
298        }
299    }
300
301    /// Decodes `nbits` least significant bits as a u32.
302    ///
303    /// # Errors
304    ///
305    /// Returns an [`ErrorKind::Buffer`](crate::ErrorKind::Buffer) error if bit decoding is not active or end of stream.
306    #[inline(always)]
307    pub fn decode_least_significant_bits32(&mut self, nbits: u32) -> Result<u32, DracoError> {
308        if !self.bit_decoder_active {
309            return Err(DracoError::buffer("Bit decoding not active"));
310        }
311        self.decode_least_significant_bits32_fast(nbits)
312    }
313
314    /// Optimized version for hot paths - reads multiple bytes at once.
315    #[inline(always)]
316    pub fn decode_least_significant_bits32_fast(&mut self, nbits: u32) -> Result<u32, DracoError> {
317        if nbits == 0 {
318            return Ok(0);
319        }
320        // The tagged symbol scheme's per-chunk bit length is a full byte
321        // (0..=255) read straight off the wire and checked only against
322        // `> 32`, so 32 itself reaches here as a legitimate width -- a
323        // 32-bit-wide residual is what the scheme exists for. `nbits` past
324        // 32 is not a width this format defines.
325        if nbits > 32 {
326            return Err(DracoError::buffer("Bit width exceeds 32 bits"));
327        }
328
329        let total_bit_offset = self.current_bit_offset;
330        let byte_offset = self.bit_start_pos + total_bit_offset / 8;
331        let bit_shift = (total_bit_offset % 8) as u32;
332
333        if byte_offset >= self.bit_stream_end_pos || byte_offset >= self.data.len() {
334            return Err(DracoError::buffer("Unexpected end of bit stream"));
335        }
336        let available_end = self.bit_stream_end_pos.min(self.data.len());
337        let remaining = available_end - byte_offset;
338
339        // Fast path: read 8 bytes at once when enough data remains (avoids per-byte loop).
340        let raw = if remaining >= 8 {
341            let mut bytes = [0u8; 8];
342            bytes.copy_from_slice(&self.data[byte_offset..byte_offset + 8]);
343            u64::from_le_bytes(bytes)
344        } else {
345            let needed_bytes = (bit_shift + nbits).div_ceil(8) as usize;
346            if remaining < needed_bytes {
347                return Err(DracoError::buffer("Unexpected end of bit stream"));
348            }
349            let mut v = 0u64;
350            for i in 0..needed_bytes {
351                v |= (self.data[byte_offset + i] as u64) << (i * 8);
352            }
353            v
354        };
355        // Masking with a u64 keeps `nbits == 32` in range for the shift;
356        // `1u32 << 32` is exactly the overflow this guards against.
357        let mask = (1u64 << nbits) - 1;
358        let value = ((raw >> bit_shift) & mask) as u32;
359
360        self.current_bit_offset += nbits as usize;
361        Ok(value)
362    }
363
364    #[inline]
365    #[allow(dead_code)]
366    fn get_bit(&mut self) -> Result<u32, DracoError> {
367        let total_bit_offset = self.current_bit_offset;
368        let byte_offset = self.bit_start_pos + total_bit_offset / 8;
369        let bit_shift = total_bit_offset % 8;
370
371        if byte_offset < self.bit_stream_end_pos && byte_offset < self.data.len() {
372            let bit = (self.data[byte_offset] >> bit_shift) & 1;
373            self.current_bit_offset += 1;
374            Ok(bit as u32)
375        } else {
376            Err(DracoError::buffer("Unexpected end of bit stream"))
377        }
378    }
379
380    /// Decodes a value of type T using raw memory copy.
381    ///
382    /// # Errors
383    ///
384    /// Returns an [`ErrorKind::Buffer`](crate::ErrorKind::Buffer) error if:
385    /// - Bit decoding is active
386    /// - Not enough bytes remaining
387    pub fn decode<T: Copy + bytemuck::Pod>(&mut self) -> Result<T, DracoError> {
388        if self.bit_decoder_active {
389            return Err(DracoError::buffer(
390                "Cannot decode bytes while bit decoding is active",
391            ));
392        }
393        let size = mem::size_of::<T>();
394        if size > self.data.len().saturating_sub(self.pos) {
395            return Err(DracoError::buffer(format!(
396                "Unexpected end of buffer: need {} bytes, have {}",
397                size,
398                self.remaining_size()
399            )));
400        }
401
402        // Safety: bytemuck::Pod guarantees T can be safely read from any bit pattern
403        let val = bytemuck::pod_read_unaligned::<T>(&self.data[self.pos..self.pos + size]);
404        self.pos += size;
405        Ok(val)
406    }
407
408    /// Decodes a single byte.
409    pub fn decode_u8(&mut self) -> Result<u8, DracoError> {
410        self.decode::<u8>()
411    }
412
413    /// Decodes a little-endian u16.
414    pub fn decode_u16(&mut self) -> Result<u16, DracoError> {
415        let mut bytes = [0u8; 2];
416        self.decode_bytes(&mut bytes)?;
417        Ok(u16::from_le_bytes(bytes))
418    }
419
420    /// Decodes a little-endian u32.
421    pub fn decode_u32(&mut self) -> Result<u32, DracoError> {
422        let mut bytes = [0u8; 4];
423        self.decode_bytes(&mut bytes)?;
424        Ok(u32::from_le_bytes(bytes))
425    }
426
427    /// Decodes a little-endian u64.
428    pub fn decode_u64(&mut self) -> Result<u64, DracoError> {
429        let mut bytes = [0u8; 8];
430        self.decode_bytes(&mut bytes)?;
431        Ok(u64::from_le_bytes(bytes))
432    }
433
434    /// Decodes a little-endian f32.
435    pub fn decode_f32(&mut self) -> Result<f32, DracoError> {
436        let mut bytes = [0u8; 4];
437        self.decode_bytes(&mut bytes)?;
438        Ok(f32::from_le_bytes(bytes))
439    }
440
441    /// Decodes a little-endian f64.
442    pub fn decode_f64(&mut self) -> Result<f64, DracoError> {
443        let mut bytes = [0u8; 8];
444        self.decode_bytes(&mut bytes)?;
445        Ok(f64::from_le_bytes(bytes))
446    }
447
448    /// Decodes a null-terminated string.
449    pub fn decode_string(&mut self) -> Result<String, DracoError> {
450        let mut bytes = Vec::new();
451        loop {
452            let b = self.decode_u8()?;
453            if b == 0 {
454                break;
455            }
456            bytes.push(b);
457        }
458        String::from_utf8(bytes)
459            .map_err(|e| DracoError::buffer(format!("Invalid UTF-8 string: {}", e)))
460    }
461
462    /// Decodes bytes into the provided buffer.
463    ///
464    /// # Errors
465    ///
466    /// Returns an [`ErrorKind::Buffer`](crate::ErrorKind::Buffer) error if not enough bytes remaining.
467    pub fn decode_bytes(&mut self, out: &mut [u8]) -> Result<(), DracoError> {
468        let size = out.len();
469        if size > self.data.len().saturating_sub(self.pos) {
470            return Err(DracoError::buffer(format!(
471                "Unexpected end of buffer: need {} bytes, have {}",
472                size,
473                self.remaining_size()
474            )));
475        }
476        out.copy_from_slice(&self.data[self.pos..self.pos + size]);
477        self.pos += size;
478        Ok(())
479    }
480
481    /// Decodes a variable-length unsigned integer (varint).
482    pub fn decode_varint(&mut self) -> Result<u64, DracoError> {
483        let mut val = 0u64;
484        let mut shift = 0;
485        loop {
486            let b = self.decode_u8()?;
487            val |= ((b & 0x7F) as u64) << shift;
488            if (b & 0x80) == 0 {
489                break;
490            }
491            shift += 7;
492            if shift >= 64 {
493                return Err(DracoError::buffer("Varint exceeds 64 bits"));
494            }
495        }
496        Ok(val)
497    }
498
499    /// Decodes a Draco-compatible signed varint.
500    ///
501    /// Uses unsigned varint encoding with ConvertSymbolToSignedInt transformation.
502    pub fn decode_varint_signed_i32(&mut self) -> Result<i32, DracoError> {
503        let symbol = self.decode_varint()? as u32;
504        let is_positive = (symbol & 1) == 0;
505        let v = symbol >> 1;
506        if is_positive {
507            Ok(v as i32)
508        } else {
509            Ok(-(v as i32) - 1)
510        }
511    }
512
513    /// Returns a slice of the remaining data without advancing.
514    pub fn remaining_data(&self) -> &'a [u8] {
515        &self.data[self.pos..]
516    }
517
518    /// Advances the position by `n` bytes without reading.
519    pub fn advance(&mut self, n: usize) {
520        self.pos = self.pos.saturating_add(n).min(self.data.len());
521    }
522
523    /// Advances the position by `n` bytes without reading.
524    ///
525    /// # Errors
526    ///
527    /// Returns an [`ErrorKind::Buffer`](crate::ErrorKind::Buffer) error if the requested advance would move
528    /// beyond the end of the input buffer.
529    pub fn try_advance(&mut self, n: usize) -> Result<(), DracoError> {
530        let new_pos = self
531            .pos
532            .checked_add(n)
533            .ok_or_else(|| DracoError::buffer("Buffer advance overflow"))?;
534        if new_pos > self.data.len() {
535            return Err(DracoError::buffer(format!(
536                "Cannot advance buffer by {} bytes: need position {}, buffer length {}",
537                n,
538                new_pos,
539                self.data.len()
540            )));
541        }
542        self.pos = new_pos;
543        Ok(())
544    }
545
546    /// Decodes and returns a slice of the specified size.
547    ///
548    /// # Errors
549    ///
550    /// Returns an [`ErrorKind::Buffer`](crate::ErrorKind::Buffer) error if not enough bytes remaining.
551    pub fn decode_slice(&mut self, size: usize) -> Result<&'a [u8], DracoError> {
552        if size > self.data.len().saturating_sub(self.pos) {
553            return Err(DracoError::buffer(format!(
554                "Unexpected end of buffer: need {} bytes, have {}",
555                size,
556                self.remaining_size()
557            )));
558        }
559        let slice = &self.data[self.pos..self.pos + size];
560        self.pos += size;
561        Ok(slice)
562    }
563}
564
565#[cfg(test)]
566mod tests {
567    use super::DecoderBuffer;
568
569    #[test]
570    fn bit_decode_respects_declared_byte_size() {
571        let data = [1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
572        let mut buffer = DecoderBuffer::new(&data);
573
574        assert_eq!(buffer.start_bit_decoding(true).unwrap(), 1);
575        assert!(buffer.decode_least_significant_bits32(16).is_err());
576    }
577
578    #[test]
579    fn try_advance_rejects_out_of_bounds_skip() {
580        let data = [0u8; 4];
581        let mut buffer = DecoderBuffer::new(&data);
582
583        assert!(buffer.try_advance(5).is_err());
584        assert_eq!(buffer.position(), 0);
585        assert!(buffer.try_advance(4).is_ok());
586        assert_eq!(buffer.position(), 4);
587    }
588
589    #[test]
590    fn decode_least_significant_bits32_reads_full_width() {
591        // `(1u32 << 32) - 1` is the overflow this width used to hit.
592        let data = [0xffu8; 5];
593        let mut buffer = DecoderBuffer::new(&data);
594
595        buffer.start_bit_decoding(false).unwrap();
596        assert_eq!(
597            buffer.decode_least_significant_bits32(32).unwrap(),
598            u32::MAX
599        );
600    }
601
602    #[test]
603    fn decode_least_significant_bits32_reads_full_width_past_a_bit_shift() {
604        // Same width, but starting mid-byte so the fast path's `raw >>
605        // bit_shift` also has to keep all 32 bits in range.
606        let data = [0xffu8; 6];
607        let mut buffer = DecoderBuffer::new(&data);
608
609        buffer.start_bit_decoding(false).unwrap();
610        assert_eq!(buffer.decode_least_significant_bits32(3).unwrap(), 0b111);
611        assert_eq!(
612            buffer.decode_least_significant_bits32(32).unwrap(),
613            u32::MAX
614        );
615    }
616
617    #[test]
618    fn decode_least_significant_bits32_rejects_width_above_32() {
619        let data = [0xffu8; 5];
620        let mut buffer = DecoderBuffer::new(&data);
621
622        buffer.start_bit_decoding(false).unwrap();
623        assert!(buffer.decode_least_significant_bits32(33).is_err());
624    }
625}