1use std::sync::Arc;
2
3use crate::{
4 Attribute, Attributes, ByteCursor, EnvHandle, Error, Header, Limits, NativeEncodingSource,
5 Persisted, REncoding, RObject, RStr, RValue, SexpKind, Symbol,
6};
7
8const TYPE_MASK: u32 = 0xff;
9const ATTRIBUTES_BIT: u32 = 1 << 9;
10const TAG_BIT: u32 = 1 << 10;
11const LEVELS_SHIFT: u32 = 12;
12
13const NILSXP: u8 = 0;
14const SYMSXP: u8 = 1;
15const LISTSXP: u8 = 2;
16const CLOSXP: u8 = 3;
17const ENVSXP: u8 = 4;
18const PROMSXP: u8 = 5;
19const LANGSXP: u8 = 6;
20const SPECIALSXP: u8 = 7;
21const BUILTINSXP: u8 = 8;
22const CHARSXP: u8 = 9;
23const LGLSXP: u8 = 10;
24const INTSXP: u8 = 13;
25const REALSXP: u8 = 14;
26const CPLXSXP: u8 = 15;
27const STRSXP: u8 = 16;
28const DOTSXP: u8 = 17;
29const VECSXP: u8 = 19;
30const EXPRSXP: u8 = 20;
31const RAWSXP: u8 = 24;
32const S4SXP: u8 = 25;
33#[cfg(test)]
34const EXTPTRSXP: u8 = 22;
35const BASEENV_SXP: u8 = 241;
36const EMPTYENV_SXP: u8 = 242;
37const PACKAGESXP: u8 = 248;
38const NAMESPACESXP: u8 = 249;
39const BASENAMESPACE_SXP: u8 = 250;
40const MISSINGARG_SXP: u8 = 251;
41const UNBOUNDVALUE_SXP: u8 = 252;
42const GLOBALENV_SXP: u8 = 253;
43const NILVALUE_SXP: u8 = 254;
44const REFSXP: u8 = 255;
45const PERSISTSXP: u8 = 247;
46
47const NA_INTEGER: i32 = i32::MIN;
48const NA_REAL_BITS: u64 = 0x7ff0_0000_0000_07a2;
49
50pub fn parse(bytes: &[u8]) -> Result<RObject, Error> {
51 parse_with_options(bytes, ParseOptions::default())
52}
53
54pub fn parse_with_limits(bytes: &[u8], limits: Limits) -> Result<RObject, Error> {
55 parse_with_options(bytes, ParseOptions::default().limits(limits))
56}
57
58#[derive(Debug, Clone, Copy, Default)]
60#[must_use]
61pub struct ParseOptions {
62 limits: Limits,
63 native_encoding_policy: NativeEncodingPolicy,
64}
65
66impl ParseOptions {
67 pub fn limits(mut self, limits: Limits) -> Self {
69 self.limits = limits;
70 self
71 }
72
73 pub fn native_encoding_policy(mut self, policy: NativeEncodingPolicy) -> Self {
77 self.native_encoding_policy = policy;
78 self
79 }
80
81 pub(crate) fn limits_value(self) -> Limits {
82 self.limits
83 }
84
85 pub(crate) fn native_encoding_policy_value(self) -> NativeEncodingPolicy {
86 self.native_encoding_policy
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
97#[non_exhaustive]
98pub enum NativeEncodingPolicy {
99 #[default]
104 RejectUnknown,
105 AssumeUtf8,
110}
111
112pub fn parse_with_options(bytes: &[u8], options: ParseOptions) -> Result<RObject, Error> {
114 let mut cursor = ByteCursor::new(bytes);
115 let header = Header::parse(&mut cursor)?;
116 Decoder::new(
117 options.limits_value(),
118 header.native_encoding,
119 options.native_encoding_policy_value(),
120 )
121 .decode_root(&mut cursor)
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125pub(crate) struct ItemFlags {
126 raw: u32,
127 type_code: u8,
128}
129
130impl ItemFlags {
131 pub(crate) fn from_raw(raw: u32) -> Self {
132 Self {
133 raw,
134 type_code: (raw & TYPE_MASK) as u8,
135 }
136 }
137
138 fn type_code(self) -> u8 {
139 self.type_code
140 }
141
142 fn kind(self) -> SexpKind {
143 SexpKind::from_type_code(self.type_code)
144 }
145
146 fn has_attributes(self) -> bool {
147 self.raw & ATTRIBUTES_BIT != 0
148 }
149
150 fn has_tag(self) -> bool {
151 self.raw & TAG_BIT != 0
152 }
153
154 fn levels(self) -> u32 {
155 self.raw >> LEVELS_SHIFT
156 }
157
158 fn ref_index_inline(self) -> u32 {
159 self.raw >> 8
160 }
161
162 #[cfg(test)]
163 fn is_object(self) -> bool {
164 self.raw & (1 << 8) != 0
165 }
166}
167
168#[derive(Debug, Clone)]
169enum RefEntry {
170 Symbol(Symbol),
171 Persisted(Persisted),
172 Env(EnvHandle),
173}
174
175#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185enum Mode {
186 Strict,
187 Discard,
188}
189
190#[derive(Default)]
191struct RefTable {
192 entries: Vec<RefEntry>,
193}
194
195impl RefTable {
196 fn register(&mut self, entry: RefEntry) {
197 self.entries.push(entry);
198 }
199
200 fn resolve(&self, index: u32, offset: usize) -> Result<&RefEntry, Error> {
201 if index == 0 {
202 return Err(Error::RefIndexOutOfRange {
203 index,
204 len: self.entries.len(),
205 offset,
206 });
207 }
208 self.entries
209 .get(index as usize - 1)
210 .ok_or(Error::RefIndexOutOfRange {
211 index,
212 len: self.entries.len(),
213 offset,
214 })
215 }
216}
217
218struct Decoder {
219 refs: RefTable,
220 limits: Limits,
221 total_elements: usize,
222 native_encoding_source: NativeEncodingSource,
223}
224
225impl Decoder {
226 fn new(
227 limits: Limits,
228 native_encoding: Option<String>,
229 native_encoding_policy: NativeEncodingPolicy,
230 ) -> Self {
231 Self {
232 refs: RefTable::default(),
233 limits,
234 total_elements: 0,
235 native_encoding_source: match native_encoding {
236 Some(name) => NativeEncodingSource::Header(Arc::from(name)),
237 None => match native_encoding_policy {
238 NativeEncodingPolicy::RejectUnknown => NativeEncodingSource::Unknown,
239 NativeEncodingPolicy::AssumeUtf8 => NativeEncodingSource::AssumedUtf8,
240 },
241 },
242 }
243 }
244
245 fn decode_root(&mut self, cursor: &mut ByteCursor<'_>) -> Result<RObject, Error> {
246 self.decode_object(cursor, 0, Mode::Strict)
247 }
248
249 fn decode_object(
250 &mut self,
251 cursor: &mut ByteCursor<'_>,
252 depth: u32,
253 mode: Mode,
254 ) -> Result<RObject, Error> {
255 self.check_depth(depth)?;
256 let flags = self.read_flags(cursor)?;
257 self.decode_object_with_flags(cursor, flags, depth, mode)
258 }
259
260 fn decode_object_with_flags(
261 &mut self,
262 cursor: &mut ByteCursor<'_>,
263 flags: ItemFlags,
264 depth: u32,
265 mode: Mode,
266 ) -> Result<RObject, Error> {
267 match flags.type_code() {
273 REFSXP => return self.decode_ref(cursor, flags),
274 ENVSXP => return self.decode_env(cursor, depth),
275 GLOBALENV_SXP => return Ok(env_object(EnvHandle::Global)),
276 BASEENV_SXP | BASENAMESPACE_SXP => return Ok(env_object(EnvHandle::Base)),
277 EMPTYENV_SXP => return Ok(env_object(EnvHandle::Empty)),
278 _ => {}
279 }
280
281 let value = match flags.type_code() {
282 NILSXP | NILVALUE_SXP => RValue::Null,
283 CHARSXP => RValue::Character(vec![self.decode_char_with_flags(cursor, flags)?]),
284 STRSXP => RValue::Character(self.decode_character_vector(cursor)?),
285 LGLSXP => RValue::Logical(self.decode_logical_vector(cursor)?),
286 INTSXP => RValue::Integer(self.decode_integer_vector(cursor)?),
287 REALSXP => RValue::Real(self.decode_real_vector(cursor)?),
288 VECSXP => RValue::List(self.decode_list(cursor, depth, mode)?),
289 SYMSXP => RValue::Symbol(self.decode_symbol_with_flags(cursor, flags)?),
290 PERSISTSXP => RValue::Persisted(self.decode_persisted(cursor)?),
291 PACKAGESXP | NAMESPACESXP => {
292 RValue::Environment(self.decode_package_or_namespace(cursor)?)
293 }
294 other => {
295 if mode == Mode::Discard {
296 return self.decode_discard(cursor, flags, depth);
297 }
298 return Err(Error::UnsupportedSexp {
299 kind: SexpKind::from_type_code(other),
300 type_code: other,
301 offset: cursor.position().saturating_sub(4),
302 });
303 }
304 };
305
306 let attributes = if flags.has_attributes() {
307 self.decode_attributes(cursor, depth + 1, mode)?
308 } else {
309 Attributes::default()
310 };
311
312 Ok(RObject::from_parts(value, attributes))
313 }
314
315 fn decode_env(&mut self, cursor: &mut ByteCursor<'_>, depth: u32) -> Result<RObject, Error> {
321 let _locked = cursor.read_be_i32()?;
322 self.refs.register(RefEntry::Env(EnvHandle::Other));
323 for _ in 0..4 {
324 let _ = self.decode_object(cursor, depth + 1, Mode::Discard)?;
325 }
326 Ok(env_object(EnvHandle::Other))
327 }
328
329 fn decode_package_or_namespace(
333 &mut self,
334 cursor: &mut ByteCursor<'_>,
335 ) -> Result<EnvHandle, Error> {
336 let _ = self.decode_string_vec(cursor)?;
337 self.refs.register(RefEntry::Env(EnvHandle::Other));
338 Ok(EnvHandle::Other)
339 }
340
341 fn decode_discard(
347 &mut self,
348 cursor: &mut ByteCursor<'_>,
349 flags: ItemFlags,
350 depth: u32,
351 ) -> Result<RObject, Error> {
352 if is_dotted_pair(flags) {
353 self.discard_pairlist_chain(cursor, flags, depth)?;
357 return Ok(RObject::from_parts(RValue::Null, Attributes::default()));
358 }
359
360 match flags.type_code() {
361 UNBOUNDVALUE_SXP | MISSINGARG_SXP => {
362 return Ok(RObject::from_parts(RValue::Null, Attributes::default()));
363 }
364 SPECIALSXP | BUILTINSXP => {
365 let len = self.read_vector_len(cursor)?;
366 let _ = cursor.read_exact(len)?;
367 }
368 CPLXSXP => {
369 let len = self.read_vector_len(cursor)?;
370 for _ in 0..len {
371 let _ = cursor.read_exact(16)?;
372 }
373 }
374 RAWSXP => {
375 let len = self.read_vector_len(cursor)?;
376 let _ = cursor.read_exact(len)?;
377 }
378 EXPRSXP => {
379 let _ = self.decode_list(cursor, depth, Mode::Discard)?;
381 }
382 S4SXP => {
383 }
385 other => {
386 return Err(Error::UnsupportedSexp {
387 kind: SexpKind::from_type_code(other),
388 type_code: other,
389 offset: cursor.position().saturating_sub(4),
390 });
391 }
392 }
393
394 let attributes = if flags.has_attributes() {
395 self.decode_attributes(cursor, depth + 1, Mode::Discard)?
396 } else {
397 Attributes::default()
398 };
399
400 Ok(RObject::from_parts(RValue::Null, attributes))
401 }
402
403 fn discard_pairlist_chain(
411 &mut self,
412 cursor: &mut ByteCursor<'_>,
413 flags: ItemFlags,
414 depth: u32,
415 ) -> Result<(), Error> {
416 let mut flags = flags;
417 loop {
418 self.account_elements(1, cursor.position())?;
419 if flags.has_attributes() {
420 let _ = self.decode_attributes(cursor, depth + 1, Mode::Discard)?;
421 }
422 if flags.has_tag() {
423 let _ = self.decode_object(cursor, depth + 1, Mode::Discard)?;
424 }
425 let _ = self.decode_object(cursor, depth + 1, Mode::Discard)?;
426
427 let cdr_flags = self.read_flags(cursor)?;
428 if is_dotted_pair(cdr_flags) {
429 flags = cdr_flags;
430 continue;
431 }
432 if is_nil(cdr_flags) {
433 return Ok(());
434 }
435 let _ = self.decode_object_with_flags(cursor, cdr_flags, depth + 1, Mode::Discard)?;
436 return Ok(());
437 }
438 }
439
440 fn read_flags(&mut self, cursor: &mut ByteCursor<'_>) -> Result<ItemFlags, Error> {
441 Ok(ItemFlags::from_raw(cursor.read_be_u32()?))
442 }
443
444 fn decode_ref(
445 &mut self,
446 cursor: &mut ByteCursor<'_>,
447 flags: ItemFlags,
448 ) -> Result<RObject, Error> {
449 let inline_index = flags.ref_index_inline();
450 let index = if inline_index == 0 {
451 cursor.read_be_i32()? as u32
452 } else {
453 inline_index
454 };
455
456 match self
457 .refs
458 .resolve(index, cursor.position().saturating_sub(4))?
459 {
460 RefEntry::Symbol(symbol) => Ok(RObject::from_parts(
461 RValue::Symbol(symbol.clone()),
462 Attributes::default(),
463 )),
464 RefEntry::Persisted(persisted) => Ok(RObject::from_parts(
465 RValue::Persisted(persisted.clone()),
466 Attributes::default(),
467 )),
468 RefEntry::Env(handle) => Ok(env_object(*handle)),
469 }
470 }
471
472 fn decode_list(
473 &mut self,
474 cursor: &mut ByteCursor<'_>,
475 depth: u32,
476 mode: Mode,
477 ) -> Result<Vec<RObject>, Error> {
478 let len = self.read_vector_len(cursor)?;
479 (0..len)
480 .map(|_| self.decode_object(cursor, depth + 1, mode))
481 .collect()
482 }
483
484 fn decode_logical_vector(
485 &mut self,
486 cursor: &mut ByteCursor<'_>,
487 ) -> Result<Vec<Option<bool>>, Error> {
488 let len = self.read_vector_len(cursor)?;
489 (0..len)
490 .map(|_| {
491 Ok(match cursor.read_be_i32()? {
492 NA_INTEGER => None,
493 0 => Some(false),
494 _ => Some(true),
495 })
496 })
497 .collect()
498 }
499
500 fn decode_integer_vector(
501 &mut self,
502 cursor: &mut ByteCursor<'_>,
503 ) -> Result<Vec<Option<i32>>, Error> {
504 let len = self.read_vector_len(cursor)?;
505 (0..len)
506 .map(|_| {
507 let value = cursor.read_be_i32()?;
508 Ok((value != NA_INTEGER).then_some(value))
509 })
510 .collect()
511 }
512
513 fn decode_real_vector(
514 &mut self,
515 cursor: &mut ByteCursor<'_>,
516 ) -> Result<Vec<Option<f64>>, Error> {
517 let len = self.read_vector_len(cursor)?;
518 (0..len)
519 .map(|_| {
520 let bits = cursor.read_be_u64()?;
521 Ok((bits != NA_REAL_BITS).then_some(f64::from_bits(bits)))
522 })
523 .collect()
524 }
525
526 fn decode_character_vector(&mut self, cursor: &mut ByteCursor<'_>) -> Result<Vec<RStr>, Error> {
527 let len = self.read_vector_len(cursor)?;
528 (0..len).map(|_| self.decode_char_item(cursor)).collect()
529 }
530
531 fn decode_char_item(&mut self, cursor: &mut ByteCursor<'_>) -> Result<RStr, Error> {
532 let flags = self.read_flags(cursor)?;
533 if flags.type_code() != CHARSXP {
534 return Err(Error::UnsupportedSexp {
535 kind: flags.kind(),
536 type_code: flags.type_code(),
537 offset: cursor.position().saturating_sub(4),
538 });
539 }
540 self.decode_char_with_flags(cursor, flags)
541 }
542
543 fn decode_char_with_flags(
544 &mut self,
545 cursor: &mut ByteCursor<'_>,
546 flags: ItemFlags,
547 ) -> Result<RStr, Error> {
548 let len = cursor.read_be_i32()?;
549 if len == -1 {
550 return Ok(RStr::Na);
551 }
552 if len < 0 {
553 return Err(Error::NegativeLength {
554 len,
555 offset: cursor.position().saturating_sub(4),
556 });
557 }
558
559 let encoding = decode_encoding(flags);
560 let bytes = cursor.read_exact(len as usize)?;
561 Ok(RStr::new(
562 bytes,
563 encoding,
564 self.native_encoding_source.clone(),
565 ))
566 }
567
568 fn decode_symbol_with_flags(
569 &mut self,
570 cursor: &mut ByteCursor<'_>,
571 _flags: ItemFlags,
572 ) -> Result<Symbol, Error> {
573 let print_name = self.decode_char_item(cursor)?;
574 let text = print_name
575 .as_str()
576 .ok_or(Error::InvalidSymbolName)?
577 .map_err(|_| Error::InvalidSymbolName)?;
578 let symbol = Symbol::new(Arc::<str>::from(text.as_ref()));
579 self.refs.register(RefEntry::Symbol(symbol.clone()));
580 Ok(symbol)
581 }
582
583 fn decode_persisted(&mut self, cursor: &mut ByteCursor<'_>) -> Result<Persisted, Error> {
584 let values = self.decode_string_vec(cursor)?;
585 let persisted = Persisted::new(values);
586 self.refs.register(RefEntry::Persisted(persisted.clone()));
587 Ok(persisted)
588 }
589
590 fn decode_string_vec(&mut self, cursor: &mut ByteCursor<'_>) -> Result<Vec<RStr>, Error> {
595 let _placeholder = cursor.read_be_i32()?;
596 let offset = cursor.position();
597 let len = cursor.read_be_i32()?;
598 let len = if len == -1 {
599 let len = read_long_len(cursor)?;
600 return Err(Error::PersistedLongVectorUnsupported { len, offset });
601 } else if len < 0 {
602 return Err(Error::NegativeLength { len, offset });
603 } else {
604 len as usize
605 };
606
607 if len > self.limits.max_vector_len_value() {
608 return Err(Error::VectorLengthLimitExceeded {
609 limit: self.limits.max_vector_len_value(),
610 length: len,
611 offset,
612 });
613 }
614 self.account_elements(len, offset)?;
615 (0..len)
616 .map(|_| self.decode_char_item(cursor))
617 .collect::<Result<Vec<_>, _>>()
618 }
619
620 fn decode_attributes(
621 &mut self,
622 cursor: &mut ByteCursor<'_>,
623 depth: u32,
624 mode: Mode,
625 ) -> Result<Attributes, Error> {
626 self.check_depth(depth)?;
627 let flags = self.read_flags(cursor)?;
628 if is_nil(flags) {
629 return Ok(Attributes::default());
630 }
631 let attributes = self.decode_attribute_pairlist_with_flags(cursor, flags, depth, mode)?;
632 Ok(Attributes::new(attributes))
633 }
634
635 fn decode_attribute_pairlist_with_flags(
636 &mut self,
637 cursor: &mut ByteCursor<'_>,
638 flags: ItemFlags,
639 depth: u32,
640 mode: Mode,
641 ) -> Result<Vec<Attribute>, Error> {
642 let flags_offset = cursor.position().saturating_sub(4);
646 if flags.type_code() != LISTSXP {
647 return Err(Error::UnsupportedSexp {
648 kind: flags.kind(),
649 type_code: flags.type_code(),
650 offset: flags_offset,
651 });
652 }
653
654 self.account_elements(1, cursor.position())?;
655
656 if flags.has_attributes() {
657 let _ = self.decode_attributes(cursor, depth + 1, mode)?;
658 }
659
660 let name = if flags.has_tag() {
661 self.decode_attribute_tag(cursor, depth + 1)?
662 } else {
663 return Err(Error::InvalidAttributeTag {
664 offset: flags_offset,
665 });
666 };
667
668 let value = self.decode_object(cursor, depth + 1, mode)?;
669 let cdr_flags = self.read_flags(cursor)?;
670 let mut attributes = vec![Attribute::new(name, value)];
671
672 if !is_nil(cdr_flags) {
673 attributes.extend(self.decode_attribute_pairlist_with_flags(
674 cursor,
675 cdr_flags,
676 depth + 1,
677 mode,
678 )?);
679 }
680
681 Ok(attributes)
682 }
683
684 fn decode_attribute_tag(
685 &mut self,
686 cursor: &mut ByteCursor<'_>,
687 depth: u32,
688 ) -> Result<Symbol, Error> {
689 self.check_depth(depth)?;
690 let flags = self.read_flags(cursor)?;
691 match flags.type_code() {
692 SYMSXP => self.decode_symbol_with_flags(cursor, flags),
693 REFSXP => {
694 let inline_index = flags.ref_index_inline();
695 let index = if inline_index == 0 {
696 cursor.read_be_i32()? as u32
697 } else {
698 inline_index
699 };
700 match self
701 .refs
702 .resolve(index, cursor.position().saturating_sub(4))?
703 {
704 RefEntry::Symbol(symbol) => Ok(symbol.clone()),
705 RefEntry::Persisted(_) | RefEntry::Env(_) => Err(Error::InvalidAttributeTag {
706 offset: cursor.position().saturating_sub(4),
707 }),
708 }
709 }
710 _ => Err(Error::InvalidAttributeTag {
711 offset: cursor.position().saturating_sub(4),
712 }),
713 }
714 }
715
716 fn read_vector_len(&mut self, cursor: &mut ByteCursor<'_>) -> Result<usize, Error> {
717 let offset = cursor.position();
718 let len = cursor.read_be_i32()?;
719 if len == -1 {
720 let len = read_long_len(cursor)?;
721 return Err(Error::LongVectorUnsupported { len, offset });
722 }
723 if len < 0 {
724 return Err(Error::NegativeLength { len, offset });
725 }
726 let len = len as usize;
727 if len > self.limits.max_vector_len_value() {
728 return Err(Error::VectorLengthLimitExceeded {
729 limit: self.limits.max_vector_len_value(),
730 length: len,
731 offset,
732 });
733 }
734 self.account_elements(len, offset)?;
735 Ok(len)
736 }
737
738 fn check_depth(&self, depth: u32) -> Result<(), Error> {
739 if depth > self.limits.max_depth_value() {
740 Err(Error::DepthLimitExceeded {
741 limit: self.limits.max_depth_value(),
742 })
743 } else {
744 Ok(())
745 }
746 }
747
748 fn account_elements(&mut self, count: usize, offset: usize) -> Result<(), Error> {
749 let total = self.total_elements.saturating_add(count);
750 if total > self.limits.max_total_elements_value() {
751 return Err(Error::TotalElementsLimitExceeded {
752 limit: self.limits.max_total_elements_value(),
753 total,
754 offset,
755 });
756 }
757 self.total_elements = total;
758 Ok(())
759 }
760}
761
762fn decode_encoding(flags: ItemFlags) -> REncoding {
767 let levels = flags.levels();
768 if levels & (1 << 3) != 0 {
769 REncoding::Utf8
770 } else if levels & (1 << 2) != 0 {
771 REncoding::Latin1
772 } else if levels & (1 << 1) != 0 {
773 REncoding::Bytes
774 } else {
775 REncoding::Native
776 }
777}
778
779fn is_nil(flags: ItemFlags) -> bool {
780 matches!(flags.type_code(), NILSXP | NILVALUE_SXP)
781}
782
783fn is_dotted_pair(flags: ItemFlags) -> bool {
784 matches!(
785 flags.type_code(),
786 LISTSXP | LANGSXP | CLOSXP | PROMSXP | DOTSXP
787 )
788}
789
790fn env_object(handle: EnvHandle) -> RObject {
791 RObject::from_parts(RValue::Environment(handle), Attributes::default())
792}
793
794fn read_long_len(cursor: &mut ByteCursor<'_>) -> Result<u64, Error> {
795 let upper = cursor.read_be_i32()? as u32 as u64;
796 let lower = cursor.read_be_i32()? as u32 as u64;
797 Ok((upper << 32) | lower)
798}
799
800#[cfg(test)]
801mod tests {
802 use super::*;
803 use std::{fs, io::Read, path::PathBuf};
804
805 use flate2::read::GzDecoder;
806
807 fn item(bytes: &[u8]) -> Result<RObject, Error> {
808 item_with_limits(bytes, Limits::default())
809 }
810
811 fn item_with_limits(bytes: &[u8], limits: Limits) -> Result<RObject, Error> {
812 let mut cursor = ByteCursor::new(bytes);
813 Decoder::new(limits, None, NativeEncodingPolicy::RejectUnknown).decode_root(&mut cursor)
814 }
815
816 fn fixture_dir() -> PathBuf {
817 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/data")
818 }
819
820 fn fixture(name: &str) -> RObject {
821 let bytes = fs::read(fixture_dir().join(name)).expect("fixture bytes");
822 let mut decoder = GzDecoder::new(bytes.as_slice());
823 let mut decompressed = Vec::new();
824 decoder
825 .read_to_end(&mut decompressed)
826 .expect("fixture gzip stream");
827 parse(&decompressed).expect(name)
828 }
829
830 fn rstr(value: &RStr) -> String {
831 value.as_str().unwrap().unwrap().into_owned()
832 }
833
834 fn strings(value: &RObject) -> Vec<String> {
835 let RValue::Character(values) = value.value() else {
836 panic!("expected character vector, got {value:?}");
837 };
838 values.iter().map(rstr).collect()
839 }
840
841 fn list(value: &RObject) -> &[RObject] {
842 let RValue::List(values) = value.value() else {
843 panic!("expected list, got {value:?}");
844 };
845 values
846 }
847
848 fn persisted(value: &RObject) -> &Persisted {
849 let RValue::Persisted(value) = value.value() else {
850 panic!("expected persisted value, got {value:?}");
851 };
852 value
853 }
854
855 fn env_handle(value: &RObject) -> EnvHandle {
856 let RValue::Environment(handle) = value.value() else {
857 panic!("expected environment, got {value:?}");
858 };
859 *handle
860 }
861
862 fn symbol_name(value: &RObject) -> &str {
863 let RValue::Symbol(symbol) = value.value() else {
864 panic!("expected symbol, got {value:?}");
865 };
866 symbol.as_str()
867 }
868
869 #[test]
870 fn decodes_flags_word() {
871 let flags = ItemFlags::from_raw(0x0004_0713);
872 assert_eq!(flags.type_code(), VECSXP);
873 assert!(flags.is_object());
874 assert!(flags.has_attributes());
875 assert!(flags.has_tag());
876 assert_eq!(flags.levels(), 0x40);
877
878 let ref_flags = ItemFlags::from_raw(0x0000_05ff);
879 assert_eq!(ref_flags.type_code(), REFSXP);
880 assert_eq!(ref_flags.ref_index_inline(), 5);
881 }
882
883 #[test]
884 fn decodes_na_string_integer_and_logical() {
885 let charsxp_na = [0, 0, 0, CHARSXP, 0xff, 0xff, 0xff, 0xff];
886 let value = item(&charsxp_na).unwrap();
887 assert_eq!(value.value(), &RValue::Character(vec![RStr::Na]));
888
889 let int_vec = [0, 0, 0, INTSXP, 0, 0, 0, 1, 0x80, 0, 0, 0];
890 let value = item(&int_vec).unwrap();
891 assert_eq!(value.value(), &RValue::Integer(vec![None]));
892
893 let logical_vec = [0, 0, 0, LGLSXP, 0, 0, 0, 2, 0x80, 0, 0, 0, 0, 0, 0, 1];
894 let value = item(&logical_vec).unwrap();
895 assert_eq!(value.value(), &RValue::Logical(vec![None, Some(true)]));
896 }
897
898 #[test]
899 fn charsxp_encoding_levels_bits() {
900 let flags: u32 = 9 | (8 << 12);
902 let mut bytes = flags.to_be_bytes().to_vec();
903 bytes.extend_from_slice(&1i32.to_be_bytes());
904 bytes.push(b'a');
905 let value = item(&bytes).unwrap();
906 let RValue::Character(strs) = value.value() else {
907 panic!("expected character vector, got {value:?}");
908 };
909 assert_eq!(strs[0].encoding(), Some(REncoding::Utf8));
910
911 let flags: u32 = 9 | (64 << 12);
914 let mut bytes = flags.to_be_bytes().to_vec();
915 bytes.extend_from_slice(&1i32.to_be_bytes());
916 bytes.push(b'a');
917 let value = item(&bytes).unwrap();
918 let RValue::Character(strs) = value.value() else {
919 panic!("expected character vector, got {value:?}");
920 };
921 assert_eq!(strs[0].encoding(), Some(REncoding::Native));
922 assert_eq!(strs[0].as_str().unwrap().unwrap().as_ref(), "a");
923 }
924
925 #[test]
926 fn native_symbol_names_are_decoded_during_format_v2_parsing() {
927 fn stream(print_name: &[u8]) -> Vec<u8> {
930 let mut bytes = vec![b'X', b'\n', 0, 0, 0, 2, 0, 4, 6, 1, 0, 3, 5, 0];
931 bytes.extend_from_slice(&u32::from(SYMSXP).to_be_bytes());
932 bytes.extend_from_slice(&u32::from(CHARSXP).to_be_bytes());
933 bytes.extend_from_slice(&(print_name.len() as i32).to_be_bytes());
934 bytes.extend_from_slice(print_name);
935 bytes
936 }
937
938 let valid_utf8 = stream("é".as_bytes());
939 assert_eq!(parse(&valid_utf8), Err(Error::InvalidSymbolName));
940
941 let symbol = parse_with_options(
942 &valid_utf8,
943 ParseOptions::default().native_encoding_policy(NativeEncodingPolicy::AssumeUtf8),
944 )
945 .expect("AssumeUtf8 should decode a valid Native symbol name");
946 assert_eq!(symbol_name(&symbol), "é");
947
948 let invalid_utf8 = stream(&[0xff]);
949 assert_eq!(
950 parse_with_options(
951 &invalid_utf8,
952 ParseOptions::default().native_encoding_policy(NativeEncodingPolicy::AssumeUtf8),
953 ),
954 Err(Error::InvalidSymbolName)
955 );
956 }
957
958 #[test]
959 fn untagged_attribute_cell_with_nested_attributes_reports_cell_offset() {
960 let mut bytes = Vec::new();
961 bytes.extend_from_slice(&(u32::from(LGLSXP) | ATTRIBUTES_BIT).to_be_bytes());
963 bytes.extend_from_slice(&1i32.to_be_bytes());
964 bytes.extend_from_slice(&1i32.to_be_bytes());
965 let cell_flags_offset = bytes.len();
966 bytes.extend_from_slice(&(u32::from(LISTSXP) | ATTRIBUTES_BIT).to_be_bytes());
969 bytes.extend_from_slice(&(u32::from(LISTSXP) | TAG_BIT).to_be_bytes());
970 bytes.extend_from_slice(&u32::from(SYMSXP).to_be_bytes());
971 bytes.extend_from_slice(&(u32::from(CHARSXP) | (8 << 12)).to_be_bytes());
972 bytes.extend_from_slice(&1i32.to_be_bytes());
973 bytes.push(b'x');
974 bytes.extend_from_slice(&u32::from(NILVALUE_SXP).to_be_bytes());
975 bytes.extend_from_slice(&u32::from(NILVALUE_SXP).to_be_bytes());
976
977 let err = item(&bytes).unwrap_err();
978 assert!(
979 matches!(err, Error::InvalidAttributeTag { offset } if offset == cell_flags_offset),
980 "expected InvalidAttributeTag at {cell_flags_offset}, got {err:?}"
981 );
982 }
983
984 #[test]
985 fn singleton_env_byte_level_decoding() {
986 for (byte, expected) in [
987 (253u8, EnvHandle::Global),
988 (241u8, EnvHandle::Base),
989 (242u8, EnvHandle::Empty),
990 (250u8, EnvHandle::Base),
991 ] {
992 let bytes = [0, 0, 0, byte];
993 let mut cursor = ByteCursor::new(&bytes);
994 let value = Decoder::new(Limits::default(), None, NativeEncodingPolicy::RejectUnknown)
995 .decode_root(&mut cursor)
996 .unwrap();
997 assert_eq!(value.value(), &RValue::Environment(expected));
998 assert_eq!(cursor.remaining(), 0);
999 }
1000 }
1001
1002 #[test]
1003 fn environment_frame_pairlist_cells_count_toward_total_elements_limit() {
1004 let mut bytes = Vec::new();
1005 bytes.extend_from_slice(&u32::from(ENVSXP).to_be_bytes());
1006 bytes.extend_from_slice(&0i32.to_be_bytes());
1007 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(LISTSXP).to_be_bytes());
1010 for index in 0..3 {
1011 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); let cdr = if index == 2 { 0 } else { u32::from(LISTSXP) };
1013 bytes.extend_from_slice(&cdr.to_be_bytes());
1014 }
1015 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); let error = item_with_limits(&bytes, Limits::default().max_total_elements(2))
1019 .expect_err("frame pairlist should exceed the element limit");
1020 assert!(matches!(
1021 error,
1022 Error::TotalElementsLimitExceeded { limit: 2, .. }
1023 ));
1024 }
1025
1026 #[test]
1027 fn compliant_environment_frame_pairlist_decodes_to_other() {
1028 let mut bytes = Vec::new();
1029 bytes.extend_from_slice(&u32::from(ENVSXP).to_be_bytes());
1030 bytes.extend_from_slice(&0i32.to_be_bytes());
1031 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(LISTSXP).to_be_bytes());
1033 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); let value = item_with_limits(&bytes, Limits::default().max_total_elements(1))
1039 .expect("compliant environment should decode");
1040 assert_eq!(env_handle(&value), EnvHandle::Other);
1041 }
1042
1043 #[test]
1044 fn refsxp_out_of_range_index_is_reported() {
1045 let err = item(&[0, 0, 1, REFSXP]).unwrap_err();
1046 assert_eq!(
1047 err,
1048 Error::RefIndexOutOfRange {
1049 index: 1,
1050 len: 0,
1051 offset: 0
1052 }
1053 );
1054 }
1055
1056 #[test]
1057 fn persistsxp_long_vector_escape_is_reported() {
1058 let err = item(&[
1059 0, 0, 0, PERSISTSXP, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 1, 0, 0, 0, 2,
1060 ])
1061 .unwrap_err();
1062 assert_eq!(
1063 err,
1064 Error::PersistedLongVectorUnsupported {
1065 len: 0x1_0000_0002,
1066 offset: 8
1067 }
1068 );
1069 }
1070
1071 #[test]
1072 fn unsupported_type_is_reported() {
1073 let err = item(&[0, 0, 0, EXTPTRSXP]).unwrap_err();
1074 assert_eq!(
1075 err,
1076 Error::UnsupportedSexp {
1077 kind: SexpKind::ExtPtr,
1078 type_code: EXTPTRSXP,
1079 offset: 0
1080 }
1081 );
1082 }
1083
1084 #[test]
1085 fn strict_mode_rejects_dotted_pair_at_top_level() {
1086 let err = item(&[0, 0, 0, CLOSXP]).unwrap_err();
1087 assert_eq!(
1088 err,
1089 Error::UnsupportedSexp {
1090 kind: SexpKind::Closure,
1091 type_code: CLOSXP,
1092 offset: 0
1093 }
1094 );
1095 }
1096
1097 #[test]
1098 fn decodes_aliases_vector_fixtures() {
1099 for version in [2, 3] {
1100 let root = fixture(&format!("aliases_vector_v{version}.rds"));
1101 assert_eq!(
1102 strings(&root),
1103 vec![
1104 "minimal",
1105 "multialias",
1106 "multialias",
1107 "multialias",
1108 "multialias"
1109 ]
1110 );
1111 assert_eq!(
1112 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1113 vec![
1114 "minimal",
1115 "multialias",
1116 "multialias-method",
1117 "multialias.default",
1118 "print.multialias"
1119 ]
1120 );
1121 }
1122 }
1123
1124 #[test]
1125 fn decodes_shared_symbols_fixtures() {
1126 for version in [2, 3] {
1127 let root = fixture(&format!("shared_symbols_v{version}.rds"));
1128 assert_eq!(
1129 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1130 vec!["a", "b", "d"]
1131 );
1132 let items = list(&root);
1133 assert_eq!(items.len(), 3);
1134
1135 assert_eq!(
1136 items[0]
1137 .class()
1138 .unwrap()
1139 .iter()
1140 .map(rstr)
1141 .collect::<Vec<_>>(),
1142 vec!["widget"]
1143 );
1144 assert_eq!(
1145 strings(items[0].attributes().get("note").unwrap()),
1146 vec!["first"]
1147 );
1148
1149 let b_items = list(&items[1]);
1150 assert_eq!(
1151 items[1]
1152 .class()
1153 .unwrap()
1154 .iter()
1155 .map(rstr)
1156 .collect::<Vec<_>>(),
1157 vec!["widget"]
1158 );
1159 assert_eq!(
1160 strings(items[1].attributes().get("note").unwrap()),
1161 vec!["third"]
1162 );
1163 assert_eq!(
1164 items[1]
1165 .names()
1166 .unwrap()
1167 .iter()
1168 .map(rstr)
1169 .collect::<Vec<_>>(),
1170 vec!["c"]
1171 );
1172 assert_eq!(
1173 b_items[0]
1174 .class()
1175 .unwrap()
1176 .iter()
1177 .map(rstr)
1178 .collect::<Vec<_>>(),
1179 vec!["widget"]
1180 );
1181 assert_eq!(
1182 strings(b_items[0].attributes().get("note").unwrap()),
1183 vec!["second"]
1184 );
1185
1186 assert_eq!(strings(&items[2]), vec!["x"]);
1187 assert_eq!(
1188 items[2]
1189 .class()
1190 .unwrap()
1191 .iter()
1192 .map(rstr)
1193 .collect::<Vec<_>>(),
1194 vec!["widget"]
1195 );
1196 assert_eq!(
1197 strings(items[2].attributes().get("note").unwrap()),
1198 vec!["fourth"]
1199 );
1200 }
1201 }
1202
1203 #[test]
1204 fn decodes_persistsxp_basic_fixtures() {
1205 for version in [2, 3] {
1206 let root = fixture(&format!("persistsxp_basic_v{version}.rds"));
1207 assert_eq!(
1208 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1209 vec!["env", "tail"]
1210 );
1211 let items = list(&root);
1212 assert_eq!(
1213 persisted(&items[0])
1214 .as_slice()
1215 .iter()
1216 .map(rstr)
1217 .collect::<Vec<_>>(),
1218 vec!["srcref-env"]
1219 );
1220 assert_eq!(strings(&items[1]), vec!["tail-marker"]);
1221 }
1222 }
1223
1224 #[test]
1225 fn decodes_persistsxp_twice_fixtures() {
1226 for version in [2, 3] {
1227 let root = fixture(&format!("persistsxp_twice_v{version}.rds"));
1228 assert_eq!(
1229 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1230 vec!["first", "second", "after"]
1231 );
1232 let items = list(&root);
1233 let first = persisted(&items[0]);
1234 let second = persisted(&items[1]);
1235 assert_eq!(
1236 first.as_slice().iter().map(rstr).collect::<Vec<_>>(),
1237 vec!["srcref-env"]
1238 );
1239 assert_eq!(
1240 second.as_slice().iter().map(rstr).collect::<Vec<_>>(),
1241 vec!["srcref-env"]
1242 );
1243 assert!(!first.ptr_eq(second));
1244 assert_eq!(strings(&items[2]), vec!["tail-marker"]);
1245 }
1246 }
1247
1248 #[test]
1249 fn decodes_persistsxp_multi_fixtures() {
1250 for version in [2, 3] {
1251 let root = fixture(&format!("persistsxp_multi_v{version}.rds"));
1252 let items = list(&root);
1253 assert_eq!(
1254 persisted(&items[0])
1255 .as_slice()
1256 .iter()
1257 .map(rstr)
1258 .collect::<Vec<_>>(),
1259 vec!["a", "b", "c"]
1260 );
1261 assert_eq!(strings(&items[1]), vec!["tail-marker"]);
1262 }
1263 }
1264
1265 #[test]
1266 fn decodes_singleton_envs_fixtures() {
1267 for version in [2, 3] {
1268 let root = fixture(&format!("singleton_envs_v{version}.rds"));
1269 assert_eq!(
1270 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1271 vec!["global", "base", "empty"]
1272 );
1273 let items = list(&root);
1274 assert_eq!(env_handle(&items[0]), EnvHandle::Global);
1275 assert_eq!(env_handle(&items[1]), EnvHandle::Base);
1276 assert_eq!(env_handle(&items[2]), EnvHandle::Empty);
1277 }
1278 }
1279
1280 #[test]
1281 fn decodes_plain_env_fixtures() {
1282 for version in [2, 3] {
1283 let root = fixture(&format!("plain_env_v{version}.rds"));
1284 assert_eq!(env_handle(&root), EnvHandle::Other);
1285 assert!(root.attributes().is_empty());
1286 }
1287 }
1288
1289 #[test]
1290 fn decodes_env_with_closure_fixtures() {
1291 for version in [2, 3] {
1292 let root = fixture(&format!("env_with_closure_v{version}.rds"));
1293 assert_eq!(
1294 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1295 vec!["env", "tail"]
1296 );
1297 let items = list(&root);
1298 assert_eq!(items[0].value(), &RValue::Environment(EnvHandle::Other));
1299 assert_eq!(strings(&items[1]), vec!["tail-marker"]);
1300 }
1301 }
1302
1303 #[test]
1304 fn decodes_shared_env_refs_fixtures() {
1305 for version in [2, 3] {
1306 let root = fixture(&format!("shared_env_refs_v{version}.rds"));
1307 assert_eq!(
1308 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1309 vec!["vec", "sym_a", "env_first", "sym_b", "env_second"]
1310 );
1311 let items = list(&root);
1312 assert_eq!(
1313 items[0].value(),
1314 &RValue::Integer(vec![Some(4), Some(2), Some(7)])
1315 );
1316 assert_eq!(symbol_name(&items[1]), "dup_sym");
1317 assert_eq!(env_handle(&items[2]), EnvHandle::Other);
1318 assert_eq!(symbol_name(&items[3]), "dup_sym");
1319 assert_eq!(env_handle(&items[4]), EnvHandle::Other);
1320 }
1321 }
1322
1323 #[test]
1327 fn altrep_is_rejected() {
1328 let bytes = fs::read(fixture_dir().join("altrep_intseq_v3.rds")).expect("fixture bytes");
1329 let mut decoder = GzDecoder::new(bytes.as_slice());
1330 let mut decompressed = Vec::new();
1331 decoder
1332 .read_to_end(&mut decompressed)
1333 .expect("fixture gzip stream");
1334 let err = parse(&decompressed).unwrap_err();
1335 assert_eq!(
1336 err,
1337 Error::UnsupportedSexp {
1338 kind: SexpKind::Other(238),
1339 type_code: 238,
1340 offset: 23
1341 }
1342 );
1343 }
1344
1345 #[test]
1346 fn decodes_namespace_refs_fixtures() {
1347 for version in [2, 3] {
1348 let root = fixture(&format!("namespace_refs_v{version}.rds"));
1349 assert_eq!(
1350 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1351 vec!["ns_first", "ns_second", "tail"]
1352 );
1353 let items = list(&root);
1354 assert_eq!(items[0].value(), &RValue::Environment(EnvHandle::Other));
1355 assert_eq!(items[1].value(), &RValue::Environment(EnvHandle::Other));
1356 assert_eq!(strings(&items[2]), vec!["tail-marker"]);
1357 }
1358 }
1359
1360 #[test]
1361 fn decodes_rd_fixtures_as_rd_class_lists() {
1362 for name in ["rd_minimal", "rd_aliases", "rd_arguments", "rd_seealso"] {
1363 for version in [2, 3] {
1364 let root = fixture(&format!("{name}_v{version}.rds"));
1365 assert!(matches!(root.value(), &RValue::List(_)));
1366 assert_eq!(
1367 root.class().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1368 vec!["Rd"]
1369 );
1370 if name == "rd_seealso" {
1371 assert!(root.attributes().get("srcref").is_some());
1372 }
1373
1374 let items = list(&root);
1380 assert!(!items.is_empty(), "{name}_v{version}: empty root list");
1381 let mut tagged_count = 0usize;
1382 for (index, item) in items.iter().enumerate() {
1383 if matches!(item.value(), &RValue::List(_)) {
1384 let rd_tag = item.attributes().get("Rd_tag");
1385 if index == 0 {
1386 assert!(
1387 rd_tag.is_some(),
1388 "{name}_v{version}: first element missing Rd_tag"
1389 );
1390 }
1391 if let Some(rd_tag) = rd_tag {
1392 assert!(
1393 matches!(rd_tag.value(), &RValue::Character(_)),
1394 "{name}_v{version}: Rd_tag value is not a character vector"
1395 );
1396 tagged_count += 1;
1397 }
1398 }
1399 }
1400 assert!(
1401 tagged_count >= 1,
1402 "{name}_v{version}: no list element carries Rd_tag"
1403 );
1404 }
1405 }
1406 }
1407}