1use super::model::{BitField, BlobInfo, DumpTree, Region, RegionKind};
8use crate::codecs::varint::parse_varint;
9use crate::utils::{parse_u8, take};
10use crate::{MltError, MltRefResult, MltResult, Parser};
11
12pub fn annotate_tile(buf: &[u8]) -> MltResult<DumpTree> {
16 let mut w = Walker {
17 buf,
18 out: Vec::new(),
19 depth: 0,
20 parser: Parser::default(),
21 };
22 w.walk_tile()?;
23 Ok(DumpTree {
24 buf_len: buf.len(),
25 regions: w.out,
26 })
27}
28
29pub(super) struct Walker<'a> {
30 pub(super) buf: &'a [u8],
31 pub(super) out: Vec<Region>,
32 pub(super) depth: usize,
33 pub(super) parser: Parser,
35}
36
37impl<'a> Walker<'a> {
38 pub(super) fn off(&self, s: &'a [u8]) -> usize {
40 self.buf
41 .subslice_range(s)
42 .expect("annotated slice must come from the tile buffer")
43 .start
44 }
45
46 pub(super) fn open(&mut self, at: &'a [u8], label: impl Into<String>) -> usize {
48 let idx = self.out.len();
49 self.out.push(Region {
50 offset: self.off(at),
51 len: 0,
52 depth: self.depth,
53 label: label.into(),
54 value: None,
55 bits: Vec::new(),
56 kind: RegionKind::Meta,
57 container: true,
58 blob: None,
59 });
60 self.depth += 1;
61 idx
62 }
63
64 pub(super) fn close(&mut self, idx: usize, after: &'a [u8]) {
66 self.depth -= 1;
67 let start = self.out[idx].offset;
68 self.out[idx].len = self.off(after) - start;
69 }
70
71 #[cfg(feature = "unstable-v2")]
73 pub(super) fn relabel(&mut self, idx: usize, label: impl Into<String>) {
74 self.out[idx].label = label.into();
75 }
76
77 pub(super) fn leaf(
78 &mut self,
79 before: &'a [u8],
80 after: &'a [u8],
81 label: impl Into<String>,
82 value: Option<String>,
83 ) {
84 self.out.push(Region {
85 offset: self.off(before),
86 len: before.len() - after.len(),
87 depth: self.depth,
88 label: label.into(),
89 value,
90 bits: Vec::new(),
91 kind: RegionKind::Meta,
92 container: false,
93 blob: None,
94 });
95 }
96
97 pub(super) fn leaf_bits(
99 &mut self,
100 before: &'a [u8],
101 after: &'a [u8],
102 label: impl Into<String>,
103 value: Option<String>,
104 bits: Vec<BitField>,
105 ) {
106 self.out.push(Region {
107 offset: self.off(before),
108 len: before.len() - after.len(),
109 depth: self.depth,
110 label: label.into(),
111 value,
112 bits,
113 kind: RegionKind::Meta,
114 container: false,
115 blob: None,
116 });
117 }
118
119 pub(super) fn field<T>(
121 &mut self,
122 before: &'a [u8],
123 label: &str,
124 parse: impl FnOnce(&'a [u8]) -> MltRefResult<'a, T>,
125 render: impl FnOnce(&T) -> Option<String>,
126 ) -> MltResult<(&'a [u8], T)> {
127 let (after, val) = parse(before)?;
128 let value = render(&val);
129 self.leaf(before, after, label, value);
130 Ok((after, val))
131 }
132
133 pub(super) fn byte_field(
135 &mut self,
136 before: &'a [u8],
137 label: &str,
138 value: impl FnOnce(u8) -> String,
139 bits: impl FnOnce(u8) -> Vec<BitField>,
140 ) -> MltResult<(&'a [u8], u8)> {
141 let (after, byte) = parse_u8(before)?;
142 self.leaf_bits(before, after, label, Some(value(byte)), bits(byte));
143 Ok((after, byte))
144 }
145
146 pub(super) fn raw_blob(&mut self, at: &'a [u8], len: usize, label: impl Into<String>) {
148 self.blob(at, len, label.into(), None);
149 }
150
151 pub(super) fn stream_blob(
153 &mut self,
154 at: &'a [u8],
155 len: usize,
156 label: impl Into<String>,
157 info: BlobInfo,
158 ) {
159 self.blob(at, len, label.into(), Some(info));
160 }
161
162 fn blob(&mut self, at: &'a [u8], len: usize, label: String, blob: Option<BlobInfo>) {
163 self.out.push(Region {
164 offset: self.off(at),
165 len,
166 depth: self.depth,
167 label,
168 value: None,
169 bits: Vec::new(),
170 kind: RegionKind::DataBlob,
171 container: false,
172 blob,
173 });
174 }
175
176 fn walk_tile(&mut self) -> MltResult<()> {
177 let mut input = self.buf;
178 let mut idx = 0;
179 while !input.is_empty() {
180 input = self.walk_layer(input, idx)?;
181 idx += 1;
182 }
183 Ok(())
184 }
185
186 fn walk_layer(&mut self, input: &'a [u8], idx: usize) -> MltResult<&'a [u8]> {
188 let ci = self.open(input, format!("layer[{idx}]"));
189
190 let (input, size) = self.field(
191 input,
192 "size",
193 |i| parse_varint::<u32>(i),
194 |v| Some(format!("{v} (varint) - tag + body")),
195 )?;
196 let (input, tag) = self.field(input, "tag", parse_u8, |t| Some(tag_label(*t)))?;
197
198 let body_len = size.checked_sub(1).ok_or(MltError::ZeroLayerSize)?;
199 let (rest, body) = take(input, body_len)?;
200
201 match tag {
202 1 => self.walk_layer01(body)?,
203 #[cfg(feature = "unstable-v2")]
204 2 => self.walk_layer02(body)?,
205 _ => self.raw_blob(body, body.len(), format!("value (Unknown tag 0x{tag:02X})")),
206 }
207
208 self.close(ci, rest);
209 Ok(rest)
210 }
211}
212
213fn tag_label(tag: u8) -> String {
215 match tag {
216 1 => "0x01 -> Tag01".into(),
217 #[cfg(feature = "unstable-v2")]
218 2 => "0x02 -> Tag02".into(),
219 other => format!("0x{other:02X} -> Unknown"),
220 }
221}