baedeker_core/binary/
memorysec.rs1use alloc::vec::Vec;
10
11use crate::binary::leb128::{self, Cursor};
12use crate::binary::section::RawSection;
13use crate::error::{ByteOffset, DecodeContext, DecodeError, DecodeErrorKind};
14use crate::types::{Limits, MemType};
15
16pub fn parse_memory_section(section: &RawSection<'_>) -> Result<Vec<MemType>, DecodeError> {
17 let mut cursor = Cursor::new(section.data);
18 let count = decode_u32_in_section(&mut cursor, section.offset)?;
19
20 let mut memories = Vec::with_capacity(cursor.capacity_hint(count));
21 for _ in 0..count {
22 memories.push(MemType {
23 limits: parse_limits(&mut cursor, section.offset)?,
24 });
25 }
26
27 if !cursor.is_empty() {
28 return Err(DecodeError {
29 offset: ByteOffset(section.offset + cursor.position()),
30 context: DecodeContext::MemorySection,
31 kind: DecodeErrorKind::SectionSizeMismatch {
32 expected: section.data.len() as u32,
33 consumed: cursor.position() as u32,
34 },
35 });
36 }
37
38 Ok(memories)
39}
40
41fn parse_limits(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<Limits, DecodeError> {
42 let tag_offset = cursor.position();
43 let tag = cursor.read_byte().map_err(|_| DecodeError {
44 offset: ByteOffset(base_offset + tag_offset),
45 context: DecodeContext::MemorySection,
46 kind: DecodeErrorKind::UnexpectedEof,
47 })?;
48
49 match tag {
50 0x00 => {
51 let min = decode_u32_in_section(cursor, base_offset)?;
52 Ok(Limits { min, max: None })
53 }
54 0x01 => {
55 let min = decode_u32_in_section(cursor, base_offset)?;
56 let max = decode_u32_in_section(cursor, base_offset)?;
57 Ok(Limits {
58 min,
59 max: Some(max),
60 })
61 }
62 _ => Err(DecodeError {
63 offset: ByteOffset(base_offset + tag_offset),
64 context: DecodeContext::MemorySection,
65 kind: DecodeErrorKind::UnexpectedByte {
66 expected: 0x00,
67 found: tag,
68 },
69 }),
70 }
71}
72
73fn decode_u32_in_section(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<u32, DecodeError> {
74 leb128::decode_u32(cursor).map_err(|mut e| {
75 e.context = DecodeContext::MemorySection;
76 e.offset = ByteOffset(base_offset + e.offset.0);
77 e
78 })
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::binary::section::SectionId;
85
86 fn raw_memory_section(data: &[u8]) -> RawSection<'_> {
87 RawSection {
88 id: SectionId::Memory,
89 offset: 24,
90 data,
91 }
92 }
93
94 #[test]
95 fn parse_empty_memory_section() {
96 let section = raw_memory_section(&[0x00]);
97 let memories = parse_memory_section(§ion).unwrap();
98 assert!(memories.is_empty());
99 }
100
101 #[test]
102 fn parse_single_min_only_memory() {
103 let section = raw_memory_section(&[0x01, 0x00, 0x02]);
104 let memories = parse_memory_section(§ion).unwrap();
105 assert_eq!(memories.len(), 1);
106 assert_eq!(memories[0].limits.min, 2);
107 assert_eq!(memories[0].limits.max, None);
108 }
109
110 #[test]
111 fn parse_single_bounded_memory() {
112 let section = raw_memory_section(&[0x01, 0x01, 0x01, 0x03]);
113 let memories = parse_memory_section(§ion).unwrap();
114 assert_eq!(memories.len(), 1);
115 assert_eq!(memories[0].limits.min, 1);
116 assert_eq!(memories[0].limits.max, Some(3));
117 }
118
119 #[test]
120 fn reject_invalid_limits_tag() {
121 let section = raw_memory_section(&[0x01, 0x02, 0x01]);
122 let err = parse_memory_section(§ion).unwrap_err();
123 assert!(matches!(
124 err.kind,
125 DecodeErrorKind::UnexpectedByte {
126 expected: 0x00,
127 found: 0x02
128 }
129 ));
130 }
131}