1use 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::{DataMode, DataSegment, MemIdx};
15
16pub fn parse_data_section<'a>(
17 section: &RawSection<'a>,
18) -> Result<Vec<DataSegment<'a>>, DecodeError> {
19 let mut cursor = Cursor::new(section.data);
20 let count = decode_u32_in_section(&mut cursor, section.offset)?;
21
22 let mut segments = Vec::with_capacity(cursor.capacity_hint(count));
23 for _ in 0..count {
24 segments.push(parse_data_segment(&mut cursor, section.offset)?);
25 }
26
27 if !cursor.is_empty() {
28 return Err(DecodeError {
29 offset: ByteOffset(section.offset + cursor.position()),
30 context: DecodeContext::DataSection,
31 kind: DecodeErrorKind::SectionSizeMismatch {
32 expected: section.data.len() as u32,
33 consumed: cursor.position() as u32,
34 },
35 });
36 }
37
38 Ok(segments)
39}
40
41pub fn parse_data_count_section(section: &RawSection<'_>) -> Result<u32, DecodeError> {
42 let mut cursor = Cursor::new(section.data);
43 let count = leb128::decode_u32(&mut cursor).map_err(|mut e| {
44 e.context = DecodeContext::DataCountSection;
45 e.offset = ByteOffset(section.offset + e.offset.0);
46 e
47 })?;
48
49 if !cursor.is_empty() {
50 return Err(DecodeError {
51 offset: ByteOffset(section.offset + cursor.position()),
52 context: DecodeContext::DataCountSection,
53 kind: DecodeErrorKind::SectionSizeMismatch {
54 expected: section.data.len() as u32,
55 consumed: cursor.position() as u32,
56 },
57 });
58 }
59
60 Ok(count)
61}
62
63fn parse_data_segment<'a>(
64 cursor: &mut Cursor<'a>,
65 base_offset: usize,
66) -> Result<DataSegment<'a>, DecodeError> {
67 let flag = decode_u32_in_section(cursor, base_offset)?;
68 match flag {
69 0 => {
70 let offset_offset = base_offset + cursor.position();
71 let offset_expr = parse_init_expr(cursor, base_offset)?;
72 let init = parse_byte_vec(cursor, base_offset)?;
73 let init_offset = base_offset + cursor.position() - init.len();
74 Ok(DataSegment {
75 mode: DataMode::Active {
76 memory: MemIdx(0),
77 offset_expr,
78 offset_offset,
79 },
80 init,
81 init_offset,
82 })
83 }
84 1 => {
85 let init = parse_byte_vec(cursor, base_offset)?;
86 let init_offset = base_offset + cursor.position() - init.len();
87 Ok(DataSegment {
88 mode: DataMode::Passive,
89 init,
90 init_offset,
91 })
92 }
93 2 => {
94 let memory = MemIdx(decode_u32_in_section(cursor, base_offset)?);
95 let offset_offset = base_offset + cursor.position();
96 let offset_expr = parse_init_expr(cursor, base_offset)?;
97 let init = parse_byte_vec(cursor, base_offset)?;
98 let init_offset = base_offset + cursor.position() - init.len();
99 Ok(DataSegment {
100 mode: DataMode::Active {
101 memory,
102 offset_expr,
103 offset_offset,
104 },
105 init,
106 init_offset,
107 })
108 }
109 _ => Err(DecodeError {
110 offset: ByteOffset(base_offset),
111 context: DecodeContext::DataSection,
112 kind: DecodeErrorKind::UnexpectedByte {
113 expected: 0x00,
114 found: flag as u8,
115 },
116 }),
117 }
118}
119
120fn parse_init_expr<'a>(
121 cursor: &mut Cursor<'a>,
122 base_offset: usize,
123) -> Result<&'a [u8], DecodeError> {
124 let start = cursor.position();
125 loop {
126 let pos = cursor.position();
127 let byte = cursor.read_byte().map_err(|_| DecodeError {
128 offset: ByteOffset(base_offset + pos),
129 context: DecodeContext::DataSection,
130 kind: DecodeErrorKind::UnexpectedEof,
131 })?;
132 if byte == 0x0B {
133 return Ok(&cursor.original()[start..cursor.position()]);
134 }
135 }
136}
137
138fn parse_byte_vec<'a>(
139 cursor: &mut Cursor<'a>,
140 base_offset: usize,
141) -> Result<&'a [u8], DecodeError> {
142 let len = decode_u32_in_section(cursor, base_offset)? as usize;
143 let pos = cursor.position();
144 cursor.read_bytes(len).map_err(|_| DecodeError {
145 offset: ByteOffset(base_offset + pos),
146 context: DecodeContext::DataSection,
147 kind: DecodeErrorKind::UnexpectedEof,
148 })
149}
150
151fn decode_u32_in_section(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<u32, DecodeError> {
152 leb128::decode_u32(cursor).map_err(|mut e| {
153 e.context = DecodeContext::DataSection;
154 e.offset = ByteOffset(base_offset + e.offset.0);
155 e
156 })
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use crate::binary::section::SectionId;
163
164 fn raw_data_section(data: &[u8]) -> RawSection<'_> {
165 RawSection {
166 id: SectionId::Data,
167 offset: 40,
168 data,
169 }
170 }
171
172 #[test]
173 fn parse_passive_data_segment() {
174 let section = raw_data_section(&[0x01, 0x01, 0x03, b'a', b'b', b'c']);
175 let segments = parse_data_section(§ion).unwrap();
176 assert_eq!(segments.len(), 1);
177 assert!(matches!(segments[0].mode, DataMode::Passive));
178 assert_eq!(segments[0].init, b"abc");
179 }
180
181 #[test]
182 fn parse_active_data_segment() {
183 let section = raw_data_section(&[0x01, 0x00, 0x41, 0x00, 0x0B, 0x02, 0xAA, 0xBB]);
184 let segments = parse_data_section(§ion).unwrap();
185 assert_eq!(segments.len(), 1);
186 match &segments[0].mode {
187 DataMode::Active {
188 memory,
189 offset_expr,
190 ..
191 } => {
192 assert_eq!(*memory, MemIdx(0));
193 assert_eq!(*offset_expr, &[0x41, 0x00, 0x0B]);
194 }
195 DataMode::Passive => panic!("expected active"),
196 }
197 assert_eq!(segments[0].init, &[0xAA, 0xBB]);
198 }
199}