1use usize_cast::IntoUsize as _;
2
3use crate::LazyParsed::Raw;
4use crate::MltError::{
5 BufferUnderflow, GeometryWithoutStreams, InvalidSharedDictStreamCount, MissingGeometry,
6 MissingLayerName, MultipleGeometryColumns, MultipleIdColumns, SharedDictRequiresStreams,
7 TrailingLayerData, UnexpectedStructChildCount, UnsupportedStringStreamCount,
8};
9use crate::codecs::varint::parse_varint;
10use crate::decoder::{
11 Column, ColumnType, DictionaryType, Extent, Geometry, Id, Layer01, ParsedLayer01, RawFsstData,
12 RawGeometry, RawId, RawIdValue, RawPlainData, RawPresence, RawProperty, RawScalar,
13 RawSharedDict, RawSharedDictEncoding, RawSharedDictItem, RawStream, RawStrings,
14 RawStringsEncoding, StreamType,
15};
16use crate::errors::AsMltError as _;
17use crate::utils::{SetOptionOnce as _, parse_string};
18use crate::{Layer, Lazy, MltError, MltRefResult, MltResult, ParsedLayer};
19
20const DEFAULT_MAX_BYTES: u32 = 20 * 1024 * 1024;
22
23#[derive(Debug, Clone, PartialEq, Eq, Default)]
40pub struct Decoder {
41 budget: MemBudget,
43 pub(crate) buffer_u32: Vec<u32>,
46 pub(crate) buffer_u64: Vec<u64>,
49}
50
51impl Decoder {
52 #[must_use]
54 pub fn with_max_size(max_bytes: u32) -> Self {
55 Self {
56 budget: MemBudget::with_max_size(max_bytes),
57 ..Default::default()
58 }
59 }
60
61 pub fn decode_all<'a>(
62 &mut self,
63 layers: impl IntoIterator<Item = Layer<'a>>,
64 ) -> MltResult<Vec<ParsedLayer<'a>>> {
65 layers
66 .into_iter()
67 .map(|l| l.decode_all(self))
68 .collect::<MltResult<_>>()
69 }
70
71 #[inline]
74 pub(crate) fn alloc<T>(&mut self, capacity: usize) -> MltResult<Vec<T>> {
75 let bytes = capacity.checked_mul(size_of::<T>()).or_overflow()?;
76 let bytes_u32 = u32::try_from(bytes).or_overflow()?;
77 self.budget.consume(bytes_u32)?;
78 Ok(Vec::with_capacity(capacity))
79 }
80
81 #[inline]
84 pub(crate) fn consume(&mut self, size: u32) -> MltResult<()> {
85 self.budget.consume(size)
86 }
87
88 #[inline]
90 pub(crate) fn consume_items<T>(&mut self, count: usize) -> MltResult<()> {
91 let bytes = count.checked_mul(size_of::<T>()).or_overflow()?;
92 self.budget.consume(u32::try_from(bytes).or_overflow()?)
93 }
94
95 #[inline]
96 pub(crate) fn adjust(&mut self, adjustment: u32) {
97 self.budget.adjust(adjustment);
98 }
99
100 #[inline]
108 pub(crate) fn adjust_alloc<T>(&mut self, buf: &[T], alloc_size: usize) -> MltResult<()> {
109 if buf.len() > alloc_size {
110 return Err(MltError::InvalidDecodingStreamSize(buf.len(), alloc_size));
111 }
112 let unused = (alloc_size - buf.len()) * size_of::<T>();
114 #[expect(
117 clippy::cast_possible_truncation,
118 reason = "unused <= alloc_size * size_of::<T>() which was verified to fit in u32 by alloc()"
119 )]
120 self.budget.adjust(unused as u32);
121 Ok(())
122 }
123
124 #[must_use]
125 pub fn consumed(&self) -> u32 {
126 self.budget.consumed()
127 }
128
129 pub fn reset_budget(&mut self) {
144 self.budget.reset();
145 }
146}
147
148impl MemBudget {
149 fn reset(&mut self) {
154 self.bytes_used = 0;
155 }
156}
157#[derive(Debug, Clone, PartialEq, Eq, Default)]
172pub struct Parser {
173 budget: MemBudget,
174}
175
176impl Parser {
177 #[must_use]
179 pub fn with_max_size(max_bytes: u32) -> Self {
180 Self {
181 budget: MemBudget::with_max_size(max_bytes),
182 }
183 }
184
185 pub fn parse_layers<'a>(&mut self, mut input: &'a [u8]) -> MltResult<Vec<Layer<'a>>> {
187 let mut result = Vec::new();
188 while !input.is_empty() {
189 let layer;
190 (input, layer) = Layer::from_bytes(input, self)?;
191 result.push(layer);
192 }
193 Ok(result)
194 }
195
196 #[inline]
198 pub(crate) fn reserve(&mut self, size: u32) -> MltResult<()> {
199 self.budget.consume(size)
200 }
201
202 #[must_use]
203 pub fn reserved(&self) -> u32 {
204 self.budget.consumed()
205 }
206}
207
208#[derive(Debug, Clone, PartialEq, Eq)]
209struct MemBudget {
210 pub max_bytes: u32,
212 pub bytes_used: u32,
214}
215
216impl Default for MemBudget {
217 fn default() -> Self {
219 Self::with_max_size(DEFAULT_MAX_BYTES)
220 }
221}
222
223impl MemBudget {
224 #[must_use]
226 fn with_max_size(max_bytes: u32) -> Self {
227 Self {
228 max_bytes,
229 bytes_used: 0,
230 }
231 }
232
233 #[inline]
235 fn adjust(&mut self, adjustment: u32) {
236 self.bytes_used = self.bytes_used.checked_sub(adjustment).unwrap();
237 }
238
239 #[inline]
241 fn consume(&mut self, size: u32) -> MltResult<()> {
242 let accumulator = &mut self.bytes_used;
243 let max_bytes = self.max_bytes;
244 if let Some(new_value) = accumulator.checked_add(size).filter(|&v| v <= max_bytes) {
245 *accumulator = new_value;
246 Ok(())
247 } else {
248 Err(MltError::MemoryLimitExceeded {
249 limit: max_bytes,
250 used: *accumulator,
251 requested: size,
252 })
253 }
254 }
255
256 fn consumed(&self) -> u32 {
257 self.bytes_used
258 }
259}
260
261impl<'a> Layer01<'a, Lazy> {
262 pub(crate) fn from_bytes(input: &'a [u8], parser: &mut Parser) -> MltResult<Self> {
264 let (input, layer_name) = parse_string(input)?;
265 if layer_name.is_empty() {
266 return Err(MissingLayerName);
267 }
268 let (input, extent) = parse_varint::<u32>(input)?;
269 let extent = Extent::new(extent)?;
270 let (input, column_count) = parse_varint::<u32>(input)?;
271
272 if input.len() < column_count.into_usize() {
274 return Err(BufferUnderflow(column_count, input.len()));
275 }
276
277 let (mut input, (col_info, prop_count)) = parse_columns_meta(input, column_count, parser)?;
280 #[cfg(fuzzing)]
281 let layer_order = col_info
282 .iter()
283 .map(|column| column.typ)
284 .map(crate::decoder::fuzzing::LayerOrdering::from)
285 .collect();
286
287 let mut properties = Vec::with_capacity(prop_count.into_usize());
288 let mut id_column: Option<Id> = None;
289 let mut geometry: Option<Geometry> = None;
290
291 for column in col_info {
292 use crate::decoder::RawProperty as RP;
293
294 let presence;
295 let value;
296 let name = column.name.unwrap_or("");
297
298 match column.typ {
299 ColumnType::Id | ColumnType::OptId => {
300 (input, presence) = parse_optional(column.typ, input, parser)?;
301 (input, value) = RawStream::from_bytes(input, parser)?;
302 id_column.set_once(Raw(RawId {
303 presence,
304 value: RawIdValue::Id32(value),
305 }))?;
306 }
307 ColumnType::LongId | ColumnType::OptLongId => {
308 (input, presence) = parse_optional(column.typ, input, parser)?;
309 (input, value) = RawStream::from_bytes(input, parser)?;
310 id_column.set_once(Raw(RawId {
311 presence,
312 value: RawIdValue::Id64(value),
313 }))?;
314 }
315 ColumnType::Geometry => {
316 input = parse_geometry_column(input, &mut geometry, parser)?;
317 }
318 ColumnType::Bool | ColumnType::OptBool => {
319 (input, presence) = parse_optional(column.typ, input, parser)?;
320 (input, value) = RawStream::parse_bool(input, parser)?;
321 properties.push(Raw(RP::Bool(RawScalar::new(name, presence, value))));
322 }
323 ColumnType::I8 | ColumnType::OptI8 => {
324 (input, presence) = parse_optional(column.typ, input, parser)?;
325 (input, value) = RawStream::from_bytes(input, parser)?;
326 properties.push(Raw(RP::I8(RawScalar::new(name, presence, value))));
327 }
328 ColumnType::U8 | ColumnType::OptU8 => {
329 (input, presence) = parse_optional(column.typ, input, parser)?;
330 (input, value) = RawStream::from_bytes(input, parser)?;
331 properties.push(Raw(RP::U8(RawScalar::new(name, presence, value))));
332 }
333 ColumnType::I32 | ColumnType::OptI32 => {
334 (input, presence) = parse_optional(column.typ, input, parser)?;
335 (input, value) = RawStream::from_bytes(input, parser)?;
336 properties.push(Raw(RP::I32(RawScalar::new(name, presence, value))));
337 }
338 ColumnType::U32 | ColumnType::OptU32 => {
339 (input, presence) = parse_optional(column.typ, input, parser)?;
340 (input, value) = RawStream::from_bytes(input, parser)?;
341 properties.push(Raw(RP::U32(RawScalar::new(name, presence, value))));
342 }
343 ColumnType::I64 | ColumnType::OptI64 => {
344 (input, presence) = parse_optional(column.typ, input, parser)?;
345 (input, value) = RawStream::from_bytes(input, parser)?;
346 properties.push(Raw(RP::I64(RawScalar::new(name, presence, value))));
347 }
348 ColumnType::U64 | ColumnType::OptU64 => {
349 (input, presence) = parse_optional(column.typ, input, parser)?;
350 (input, value) = RawStream::from_bytes(input, parser)?;
351 properties.push(Raw(RP::U64(RawScalar::new(name, presence, value))));
352 }
353 ColumnType::F32 | ColumnType::OptF32 => {
354 (input, presence) = parse_optional(column.typ, input, parser)?;
355 (input, value) = RawStream::from_bytes(input, parser)?;
356 properties.push(Raw(RP::F32(RawScalar::new(name, presence, value))));
357 }
358 ColumnType::F64 | ColumnType::OptF64 => {
359 (input, presence) = parse_optional(column.typ, input, parser)?;
360 (input, value) = RawStream::from_bytes(input, parser)?;
361 properties.push(Raw(RP::F64(RawScalar::new(name, presence, value))));
362 }
363 ColumnType::Str | ColumnType::OptStr => {
364 let prop;
365 (input, prop) = parse_str_column(input, name, column.typ, parser)?;
366 properties.push(Raw(prop));
367 }
368 ColumnType::SharedDict => {
369 let prop;
370 (input, prop) = parse_shared_dict_column(input, &column, parser)?;
371 properties.push(Raw(prop));
372 }
373 }
374 }
375 if input.is_empty() {
376 Ok(Layer01 {
377 name: layer_name,
378 extent,
379 id: id_column,
380 geometry: geometry.ok_or(MissingGeometry)?,
381 properties,
382 #[cfg(fuzzing)]
383 layer_order,
384 })
385 } else {
386 Err(TrailingLayerData(input.len()))
387 }
388 }
389
390 pub fn decode_all(self, dec: &mut Decoder) -> MltResult<ParsedLayer01<'a>> {
395 Ok(Layer01 {
396 name: self.name,
397 extent: self.extent,
398 id: self.id.map(|id| id.into_parsed(dec)).transpose()?,
399 geometry: self.geometry.into_parsed(dec)?,
400 properties: self
401 .properties
402 .into_iter()
403 .map(|p| p.into_parsed(dec))
404 .collect::<MltResult<Vec<_>>>()?,
405 #[cfg(fuzzing)]
406 layer_order: self.layer_order,
407 })
408 }
409}
410
411fn parse_shared_dict_children<'a>(
412 mut input: &'a [u8],
413 column: &Column<'a>,
414 parser: &mut Parser,
415) -> MltRefResult<'a, Vec<RawSharedDictItem<'a>>> {
416 let mut children = Vec::with_capacity(column.children.len());
417 for child in &column.children {
418 let (inp, sc) = parse_varint::<u32>(input)?;
419 let (inp, presence) = parse_optional(child.typ, inp, parser)?;
420 let optional_stream_count = u32::from(presence.is_optional());
421 if let Some(data_count) = sc.checked_sub(optional_stream_count)
422 && data_count != 1
423 {
424 return Err(UnexpectedStructChildCount(data_count));
425 }
426 let (inp, data) = RawStream::from_bytes(inp, parser)?;
427 children.push(RawSharedDictItem {
428 name: child.name.unwrap_or(""),
429 presence,
430 data,
431 });
432 input = inp;
433 }
434 Ok((input, children))
435}
436
437fn parse_optional<'a>(
438 typ: ColumnType,
439 input: &'a [u8],
440 parser: &mut Parser,
441) -> MltRefResult<'a, RawPresence<'a>> {
442 if typ.is_optional() {
443 let (input, optional) = RawStream::parse_bool(input, parser)?;
444 Ok((input, RawPresence::Stream(optional)))
445 } else {
446 Ok((input, RawPresence::AllPresent))
447 }
448}
449
450fn parse_geometry_column<'a>(
451 input: &'a [u8],
452 geometry: &mut Option<Geometry<'a>>,
453 parser: &mut Parser,
454) -> MltResult<&'a [u8]> {
455 let (input, stream_count) = parse_varint::<u32>(input)?;
456 if stream_count == 0 {
457 return Err(GeometryWithoutStreams);
458 }
459 let stream_count_capa = stream_count.into_usize();
461 if input.len() < stream_count_capa {
462 return Err(BufferUnderflow(stream_count, input.len()));
463 }
464 let (input, meta) = RawStream::from_bytes(input, parser)?;
466 let (input, items) = RawStream::parse_multiple(input, stream_count_capa - 1, parser)?;
468 geometry.set_once(Raw(RawGeometry { meta, items }))?;
469 Ok(input)
470}
471
472fn parse_str_column<'a>(
473 mut input: &'a [u8],
474 name: &'a str,
475 typ: ColumnType,
476 parser: &mut Parser,
477) -> MltRefResult<'a, RawProperty<'a>> {
478 let mut stream_count = {
479 let stream_count_u32;
480 (input, stream_count_u32) = parse_varint::<u32>(input)?;
481 stream_count_u32.into_usize()
482 };
483 let presence;
484 (input, presence) = parse_optional(typ, input, parser)?;
485 if presence.is_optional() {
486 if stream_count == 0 {
487 return Err(UnsupportedStringStreamCount(stream_count));
488 }
489 stream_count -= 1;
490 }
491 let mut str_streams = [None, None, None, None, None];
492 if stream_count > str_streams.len() {
493 return Err(UnsupportedStringStreamCount(stream_count));
494 }
495 for slot in str_streams.iter_mut().take(stream_count) {
496 let stream;
497 (input, stream) = RawStream::from_bytes(input, parser)?;
498 *slot = Some(stream);
499 }
500 let encoding = match str_streams {
501 [Some(s1), Some(s2), None, None, None] => {
502 RawStringsEncoding::plain(RawPlainData::new(s1, s2)?)
503 }
504 [Some(s1), Some(s2), Some(s3), None, None] => {
505 RawStringsEncoding::dictionary(RawPlainData::new(s1, s3)?, s2)?
506 }
507 [Some(s1), Some(s2), Some(s3), Some(s4), None] => {
508 RawStringsEncoding::fsst_plain(RawFsstData::new(s1, s2, s3, s4)?)
509 }
510 [Some(s1), Some(s2), Some(s3), Some(s4), Some(s5)] => {
511 RawStringsEncoding::fsst_dictionary(RawFsstData::new(s1, s2, s3, s4)?, s5)?
512 }
513 _ => Err(UnsupportedStringStreamCount(stream_count))?,
514 };
515 Ok((
516 input,
517 RawProperty::Str(RawStrings {
518 name,
519 presence,
520 encoding,
521 }),
522 ))
523}
524
525fn parse_shared_dict_column<'a>(
526 mut input: &'a [u8],
527 column: &Column<'a>,
528 parser: &mut Parser,
529) -> MltRefResult<'a, RawProperty<'a>> {
530 let stream_count;
532 (input, stream_count) = parse_varint::<u32>(input)?;
533 let mut dict_streams = [None, None, None, None, None];
534 let mut streams_taken = 0_usize;
535 while streams_taken < stream_count.into_usize() {
536 let stream;
537 (input, stream) = RawStream::from_bytes(input, parser)?;
538 let is_last = matches!(
539 stream.meta.stream_type,
540 StreamType::Data(DictionaryType::Single | DictionaryType::Shared)
541 );
542 dict_streams[streams_taken] = Some(stream);
543 streams_taken += 1;
544 if is_last {
545 break;
546 } else if streams_taken >= dict_streams.len() {
547 return Err(UnsupportedStringStreamCount(streams_taken + 1));
548 }
549 }
550 let children;
551 (input, children) = parse_shared_dict_children(input, column, parser)?;
552
553 let children_n = u32::try_from(children.len()).or_overflow()?;
555 let optional_n = children
556 .iter()
557 .filter(|c| c.presence.is_optional())
558 .count()
559 .try_into()
560 .or_overflow()?;
561 let dict_n = u32::try_from(streams_taken).or_overflow()?;
562 let expected = crate::utils::checked_sum3(dict_n, children_n, optional_n)?;
563 let java_legacy = expected.checked_add(1).or_overflow()?;
566 if stream_count != expected && stream_count != java_legacy {
567 return Err(InvalidSharedDictStreamCount {
568 actual: stream_count,
569 expected,
570 });
571 }
572
573 let name = column.name.unwrap_or("");
574 let encoding = match dict_streams {
575 [Some(s1), Some(s2), None, None, None] => {
576 RawSharedDictEncoding::plain(RawPlainData::new(s1, s2)?)
577 }
578 [Some(s1), Some(s2), Some(s3), Some(s4), None] => {
579 RawSharedDictEncoding::fsst_plain(RawFsstData::new(s1, s2, s3, s4)?)
580 }
581 _ => Err(SharedDictRequiresStreams(streams_taken))?,
582 };
583 Ok((
584 input,
585 RawProperty::SharedDict(RawSharedDict {
586 name,
587 encoding,
588 children,
589 }),
590 ))
591}
592
593fn parse_columns_meta<'a>(
594 mut input: &'a [u8],
595 column_count: u32,
596 parser: &mut Parser,
597) -> MltRefResult<'a, (Vec<Column<'a>>, u32)> {
598 use crate::decoder::ColumnType::{Geometry, Id, LongId, OptId, OptLongId, SharedDict};
599
600 let mut col_info = Vec::with_capacity(column_count.into_usize());
601 let mut geometries = 0;
602 let mut ids = 0;
603 for _ in 0..column_count {
604 let mut typ;
605 (input, typ) = Column::from_bytes(input, parser)?;
606 match typ.typ {
607 Geometry => geometries += 1,
608 Id | OptId | LongId | OptLongId => ids += 1,
609 SharedDict => {
610 let child_column_count;
612 (input, child_column_count) = parse_varint::<u32>(input)?;
613
614 let child_col_capacity = child_column_count.into_usize();
616 if input.len() < child_col_capacity {
617 return Err(BufferUnderflow(child_column_count, input.len()));
618 }
619 let mut children = Vec::with_capacity(child_col_capacity);
620 for _ in 0..child_column_count {
621 let child;
622 (input, child) = Column::from_bytes(input, parser)?;
623 children.push(child);
624 }
625 typ.children = children;
626 }
627 _ => {}
628 }
629 col_info.push(typ);
630 }
631 if geometries > 1 {
632 return Err(MultipleGeometryColumns);
633 }
634 if ids > 1 {
635 return Err(MultipleIdColumns);
636 }
637
638 Ok((input, (col_info, column_count - geometries - ids)))
639}
640
641impl<'a> RawScalar<'a> {
642 fn new(name: &'a str, presence: RawPresence<'a>, data: RawStream<'a>) -> Self {
643 Self {
644 name,
645 presence,
646 data,
647 }
648 }
649}
650
651impl RawPresence<'_> {
652 #[must_use]
654 pub(crate) fn is_optional(&self) -> bool {
655 !matches!(self, Self::AllPresent)
656 }
657}
658
659#[cfg(test)]
660mod tests {
661 use crate::{MltError, Parser};
662
663 #[test]
664 fn parse_layers_rejects_empty_layer_name() {
665 let bytes = [
666 5, 1, 0, 0x80, 0x20, 0, ];
672
673 assert!(matches!(
674 Parser::default().parse_layers(&bytes),
675 Err(MltError::MissingLayerName)
676 ));
677 }
678}