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, 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
245 .checked_add(size)
246 .and_then(|v| if v > max_bytes { None } else { Some(v) })
247 {
248 *accumulator = new_value;
249 Ok(())
250 } else {
251 Err(MltError::MemoryLimitExceeded {
252 limit: max_bytes,
253 used: *accumulator,
254 requested: size,
255 })
256 }
257 }
258
259 fn consumed(&self) -> u32 {
260 self.bytes_used
261 }
262}
263
264impl<'a> Layer01<'a, Lazy> {
265 pub(crate) fn from_bytes(input: &'a [u8], parser: &mut Parser) -> MltResult<Self> {
267 let (input, layer_name) = parse_string(input)?;
268 if layer_name.is_empty() {
269 return Err(MissingLayerName);
270 }
271 let (input, extent) = parse_varint::<u32>(input)?;
272 let (input, column_count) = parse_varint::<u32>(input)?;
273
274 if input.len() < column_count.into_usize() {
276 return Err(BufferUnderflow(column_count, input.len()));
277 }
278
279 let (mut input, (col_info, prop_count)) = parse_columns_meta(input, column_count, parser)?;
282 #[cfg(fuzzing)]
283 let layer_order = col_info
284 .iter()
285 .map(|column| column.typ)
286 .map(crate::decoder::fuzzing::LayerOrdering::from)
287 .collect();
288
289 let mut properties = Vec::with_capacity(prop_count.into_usize());
290 let mut id_column: Option<Id> = None;
291 let mut geometry: Option<Geometry> = None;
292
293 for column in col_info {
294 use crate::decoder::RawProperty as RP;
295
296 let opt;
297 let value;
298 let name = column.name.unwrap_or("");
299
300 match column.typ {
301 ColumnType::Id | ColumnType::OptId => {
302 (input, opt) = parse_optional(column.typ, input, parser)?;
303 (input, value) = RawStream::from_bytes(input, parser)?;
304 id_column.set_once(Raw(RawId {
305 presence: RawPresence(opt),
306 value: RawIdValue::Id32(value),
307 }))?;
308 }
309 ColumnType::LongId | ColumnType::OptLongId => {
310 (input, opt) = parse_optional(column.typ, input, parser)?;
311 (input, value) = RawStream::from_bytes(input, parser)?;
312 id_column.set_once(Raw(RawId {
313 presence: RawPresence(opt),
314 value: RawIdValue::Id64(value),
315 }))?;
316 }
317 ColumnType::Geometry => {
318 input = parse_geometry_column(input, &mut geometry, parser)?;
319 }
320 ColumnType::Bool | ColumnType::OptBool => {
321 (input, opt) = parse_optional(column.typ, input, parser)?;
322 (input, value) = RawStream::parse_bool(input, parser)?;
323 properties.push(Raw(RP::Bool(scalar(name, opt, value))));
324 }
325 ColumnType::I8 | ColumnType::OptI8 => {
326 (input, opt) = parse_optional(column.typ, input, parser)?;
327 (input, value) = RawStream::from_bytes(input, parser)?;
328 properties.push(Raw(RP::I8(scalar(name, opt, value))));
329 }
330 ColumnType::U8 | ColumnType::OptU8 => {
331 (input, opt) = parse_optional(column.typ, input, parser)?;
332 (input, value) = RawStream::from_bytes(input, parser)?;
333 properties.push(Raw(RP::U8(scalar(name, opt, value))));
334 }
335 ColumnType::I32 | ColumnType::OptI32 => {
336 (input, opt) = parse_optional(column.typ, input, parser)?;
337 (input, value) = RawStream::from_bytes(input, parser)?;
338 properties.push(Raw(RP::I32(scalar(name, opt, value))));
339 }
340 ColumnType::U32 | ColumnType::OptU32 => {
341 (input, opt) = parse_optional(column.typ, input, parser)?;
342 (input, value) = RawStream::from_bytes(input, parser)?;
343 properties.push(Raw(RP::U32(scalar(name, opt, value))));
344 }
345 ColumnType::I64 | ColumnType::OptI64 => {
346 (input, opt) = parse_optional(column.typ, input, parser)?;
347 (input, value) = RawStream::from_bytes(input, parser)?;
348 properties.push(Raw(RP::I64(scalar(name, opt, value))));
349 }
350 ColumnType::U64 | ColumnType::OptU64 => {
351 (input, opt) = parse_optional(column.typ, input, parser)?;
352 (input, value) = RawStream::from_bytes(input, parser)?;
353 properties.push(Raw(RP::U64(scalar(name, opt, value))));
354 }
355 ColumnType::F32 | ColumnType::OptF32 => {
356 (input, opt) = parse_optional(column.typ, input, parser)?;
357 (input, value) = RawStream::from_bytes(input, parser)?;
358 properties.push(Raw(RP::F32(scalar(name, opt, value))));
359 }
360 ColumnType::F64 | ColumnType::OptF64 => {
361 (input, opt) = parse_optional(column.typ, input, parser)?;
362 (input, value) = RawStream::from_bytes(input, parser)?;
363 properties.push(Raw(RP::F64(scalar(name, opt, value))));
364 }
365 ColumnType::Str | ColumnType::OptStr => {
366 let prop;
367 (input, prop) = parse_str_column(input, name, column.typ, parser)?;
368 properties.push(Raw(prop));
369 }
370 ColumnType::SharedDict => {
371 let prop;
372 (input, prop) = parse_shared_dict_column(input, &column, parser)?;
373 properties.push(Raw(prop));
374 }
375 }
376 }
377 if input.is_empty() {
378 Ok(Layer01 {
379 name: layer_name,
380 extent,
381 id: id_column,
382 geometry: geometry.ok_or(MissingGeometry)?,
383 properties,
384 #[cfg(fuzzing)]
385 layer_order,
386 })
387 } else {
388 Err(TrailingLayerData(input.len()))
389 }
390 }
391
392 pub fn decode_all(self, dec: &mut Decoder) -> MltResult<ParsedLayer01<'a>> {
397 Ok(Layer01 {
398 name: self.name,
399 extent: self.extent,
400 id: self.id.map(|id| id.into_parsed(dec)).transpose()?,
401 geometry: self.geometry.into_parsed(dec)?,
402 properties: self
403 .properties
404 .into_iter()
405 .map(|p| p.into_parsed(dec))
406 .collect::<MltResult<Vec<_>>>()?,
407 #[cfg(fuzzing)]
408 layer_order: self.layer_order,
409 })
410 }
411}
412
413fn parse_struct_children<'a>(
414 mut input: &'a [u8],
415 column: &Column<'a>,
416 parser: &mut Parser,
417) -> MltRefResult<'a, Vec<RawSharedDictItem<'a>>> {
418 let mut children = Vec::with_capacity(column.children.len());
419 for child in &column.children {
420 let (inp, sc) = parse_varint::<u32>(input)?;
421 let (inp, child_optional) = parse_optional(child.typ, inp, parser)?;
422 let optional_stream_count = u32::from(child_optional.is_some());
423 if let Some(data_count) = sc.checked_sub(optional_stream_count)
424 && data_count != 1
425 {
426 return Err(UnexpectedStructChildCount(data_count));
427 }
428 let (inp, child_data) = RawStream::from_bytes(inp, parser)?;
429 children.push(RawSharedDictItem {
430 name: child.name.unwrap_or(""),
431 presence: RawPresence(child_optional),
432 data: child_data,
433 });
434 input = inp;
435 }
436 Ok((input, children))
437}
438
439fn parse_optional<'a>(
440 typ: ColumnType,
441 input: &'a [u8],
442 parser: &mut Parser,
443) -> MltRefResult<'a, Option<RawStream<'a>>> {
444 if typ.is_optional() {
445 let (input, optional) = RawStream::parse_bool(input, parser)?;
446 Ok((input, Some(optional)))
447 } else {
448 Ok((input, None))
449 }
450}
451
452fn parse_geometry_column<'a>(
453 input: &'a [u8],
454 geometry: &mut Option<Geometry<'a>>,
455 parser: &mut Parser,
456) -> MltResult<&'a [u8]> {
457 let (input, stream_count) = parse_varint::<u32>(input)?;
458 if stream_count == 0 {
459 return Err(GeometryWithoutStreams);
460 }
461 let stream_count_capa = stream_count.into_usize();
463 if input.len() < stream_count_capa {
464 return Err(BufferUnderflow(stream_count, input.len()));
465 }
466 let (input, meta) = RawStream::from_bytes(input, parser)?;
468 let (input, items) = RawStream::parse_multiple(input, stream_count_capa - 1, parser)?;
470 geometry.set_once(Raw(RawGeometry { meta, items }))?;
471 Ok(input)
472}
473
474fn parse_str_column<'a>(
475 mut input: &'a [u8],
476 name: &'a str,
477 typ: ColumnType,
478 parser: &mut Parser,
479) -> MltRefResult<'a, RawProperty<'a>> {
480 let mut stream_count = {
481 let stream_count_u32;
482 (input, stream_count_u32) = parse_varint::<u32>(input)?;
483 stream_count_u32.into_usize()
484 };
485 let presence;
486 (input, presence) = parse_optional(typ, input, parser)?;
487 if presence.is_some() {
488 if stream_count == 0 {
489 return Err(UnsupportedStringStreamCount(stream_count));
490 }
491 stream_count -= 1;
492 }
493 let mut str_streams = [None, None, None, None, None];
494 if stream_count > str_streams.len() {
495 return Err(UnsupportedStringStreamCount(stream_count));
496 }
497 for slot in str_streams.iter_mut().take(stream_count) {
498 let stream;
499 (input, stream) = RawStream::from_bytes(input, parser)?;
500 *slot = Some(stream);
501 }
502 let encoding = match str_streams {
503 [Some(s1), Some(s2), None, None, None] => {
504 RawStringsEncoding::plain(RawPlainData::new(s1, s2)?)
505 }
506 [Some(s1), Some(s2), Some(s3), None, None] => {
507 RawStringsEncoding::dictionary(RawPlainData::new(s1, s3)?, s2)?
508 }
509 [Some(s1), Some(s2), Some(s3), Some(s4), None] => {
510 RawStringsEncoding::fsst_plain(RawFsstData::new(s1, s2, s3, s4)?)
511 }
512 [Some(s1), Some(s2), Some(s3), Some(s4), Some(s5)] => {
513 RawStringsEncoding::fsst_dictionary(RawFsstData::new(s1, s2, s3, s4)?, s5)?
514 }
515 _ => Err(UnsupportedStringStreamCount(stream_count))?,
516 };
517 Ok((
518 input,
519 RawProperty::Str(RawStrings {
520 name,
521 presence: RawPresence(presence),
522 encoding,
523 }),
524 ))
525}
526
527fn parse_shared_dict_column<'a>(
528 mut input: &'a [u8],
529 column: &Column<'a>,
530 parser: &mut Parser,
531) -> MltRefResult<'a, RawProperty<'a>> {
532 let stream_count;
534 (input, stream_count) = parse_varint::<u32>(input)?;
535 let mut dict_streams = [None, None, None, None, None];
536 let mut streams_taken = 0_usize;
537 while streams_taken < stream_count.into_usize() {
538 let stream;
539 (input, stream) = RawStream::from_bytes(input, parser)?;
540 let is_last = matches!(
541 stream.meta.stream_type,
542 StreamType::Data(DictionaryType::Single | DictionaryType::Shared)
543 );
544 dict_streams[streams_taken] = Some(stream);
545 streams_taken += 1;
546 if is_last {
547 break;
548 } else if streams_taken >= dict_streams.len() {
549 return Err(UnsupportedStringStreamCount(streams_taken + 1));
550 }
551 }
552 let children;
553 (input, children) = parse_struct_children(input, column, parser)?;
554
555 let children_n = u32::try_from(children.len()).or_overflow()?;
557 let optional_n = children
558 .iter()
559 .filter(|c| c.presence.0.is_some())
560 .count()
561 .try_into()
562 .or_overflow()?;
563 let dict_n = u32::try_from(streams_taken).or_overflow()?;
564 let expected = crate::utils::checked_sum3(dict_n, children_n, optional_n)?;
565 let java_legacy = expected.checked_add(1).or_overflow()?;
568 if stream_count != expected && stream_count != java_legacy {
569 return Err(InvalidSharedDictStreamCount {
570 actual: stream_count,
571 expected,
572 });
573 }
574
575 let name = column.name.unwrap_or("");
576 let encoding = match dict_streams {
577 [Some(s1), Some(s2), None, None, None] => {
578 RawSharedDictEncoding::plain(RawPlainData::new(s1, s2)?)
579 }
580 [Some(s1), Some(s2), Some(s3), Some(s4), None] => {
581 RawSharedDictEncoding::fsst_plain(RawFsstData::new(s1, s2, s3, s4)?)
582 }
583 _ => Err(SharedDictRequiresStreams(streams_taken))?,
584 };
585 Ok((
586 input,
587 RawProperty::SharedDict(RawSharedDict {
588 name,
589 encoding,
590 children,
591 }),
592 ))
593}
594
595fn parse_columns_meta<'a>(
596 mut input: &'a [u8],
597 column_count: u32,
598 parser: &mut Parser,
599) -> MltRefResult<'a, (Vec<Column<'a>>, u32)> {
600 use crate::decoder::ColumnType::{Geometry, Id, LongId, OptId, OptLongId, SharedDict};
601
602 let mut col_info = Vec::with_capacity(column_count.into_usize());
603 let mut geometries = 0;
604 let mut ids = 0;
605 for _ in 0..column_count {
606 let mut typ;
607 (input, typ) = Column::from_bytes(input, parser)?;
608 match typ.typ {
609 Geometry => geometries += 1,
610 Id | OptId | LongId | OptLongId => ids += 1,
611 SharedDict => {
612 let child_column_count;
614 (input, child_column_count) = parse_varint::<u32>(input)?;
615
616 let child_col_capacity = child_column_count.into_usize();
618 if input.len() < child_col_capacity {
619 return Err(BufferUnderflow(child_column_count, input.len()));
620 }
621 let mut children = Vec::with_capacity(child_col_capacity);
622 for _ in 0..child_column_count {
623 let child;
624 (input, child) = Column::from_bytes(input, parser)?;
625 children.push(child);
626 }
627 typ.children = children;
628 }
629 _ => {}
630 }
631 col_info.push(typ);
632 }
633 if geometries > 1 {
634 return Err(MultipleGeometryColumns);
635 }
636 if ids > 1 {
637 return Err(MultipleIdColumns);
638 }
639
640 Ok((input, (col_info, column_count - geometries - ids)))
641}
642
643fn scalar<'a>(name: &'a str, opt: Option<RawStream<'a>>, value: RawStream<'a>) -> RawScalar<'a> {
644 RawScalar {
645 name,
646 presence: RawPresence(opt),
647 data: value,
648 }
649}
650
651#[cfg(test)]
652mod tests {
653 use crate::{MltError, Parser};
654
655 #[test]
656 fn parse_layers_rejects_empty_layer_name() {
657 let bytes = [
658 5, 1, 0, 0x80, 0x20, 0, ];
664
665 assert!(matches!(
666 Parser::default().parse_layers(&bytes),
667 Err(MltError::MissingLayerName)
668 ));
669 }
670}