1use crate::{Result, error};
6use primase_foundations::bytes::View;
7
8const MAX_DEPTH: usize = 32;
10const MAX_ABBREVS_PER_BLOCK: usize = 4096;
11const MAX_ABBREV_OPS: usize = 256;
12const MAX_TOTAL_OPERANDS: usize = 1 << 26;
13
14#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct Record {
17 pub code: u64,
19 pub operands: Vec<u64>,
21 pub blob: Option<Vec<u8>>,
23 pub at: usize,
25 pub end: usize,
28}
29#[derive(Clone, Debug, PartialEq, Eq)]
31pub enum Element {
32 Block(Block),
34 Record(Record),
36}
37#[derive(Clone, Debug, PartialEq, Eq)]
39pub struct Block {
40 pub id: u64,
42 pub elements: Vec<Element>,
44 pub at: usize,
46 pub end: usize,
49}
50impl Block {
51 pub fn blocks(&self) -> impl Iterator<Item = &Block> {
53 self.elements.iter().filter_map(|e| match e {
54 Element::Block(b) => Some(b),
55 Element::Record(_) => None,
56 })
57 }
58 pub fn records(&self) -> impl Iterator<Item = &Record> {
60 self.elements.iter().filter_map(|e| match e {
61 Element::Record(r) => Some(r),
62 Element::Block(_) => None,
63 })
64 }
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68enum Op {
69 Literal(u64),
70 Fixed(u32),
71 Vbr(u32),
72 Array,
73 Char6,
74 Blob,
75}
76type Abbrev = Vec<Op>;
77
78const CHAR6: &[u8; 64] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._";
80
81struct Bits<'a> {
82 data: &'a [u8],
83 pos: usize,
85}
86impl Bits<'_> {
87 fn remaining(&self) -> usize {
88 self.data.len().saturating_mul(8).saturating_sub(self.pos)
89 }
90 fn read(&mut self, width: u32) -> Result<u64> {
91 if width > 64 {
92 return Err(error(self.pos, "field wider than 64 bits"));
93 }
94 let n = width as usize;
95 if n > self.remaining() {
96 return Err(error(self.pos, "bitstream ends inside a field"));
97 }
98 let mut value = 0u64;
99 for i in 0..width {
100 let bit = self.pos.saturating_add(i as usize);
101 let byte = self.data.get(bit / 8).copied().unwrap_or(0);
102 let shift = u32::try_from(bit % 8).unwrap_or(0);
103 if byte.checked_shr(shift).unwrap_or(0) & 1 == 1 {
104 value |= 1u64.checked_shl(i).unwrap_or(0);
105 }
106 }
107 self.pos = self.pos.saturating_add(n);
108 Ok(value)
109 }
110 fn vbr(&mut self, width: u32) -> Result<u64> {
111 if !(2..=32).contains(&width) {
112 return Err(error(self.pos, "VBR width outside 2..32"));
113 }
114 let at = self.pos;
115 let high = 1u64.checked_shl(width.saturating_sub(1)).unwrap_or(0);
116 let mut value = 0u64;
117 let mut shift = 0u32;
118 loop {
119 let chunk = self.read(width)?;
120 let payload = chunk & high.saturating_sub(1);
121 if payload != 0 {
122 if shift >= 64 || payload.leading_zeros() < shift {
124 return Err(error(at, "VBR value exceeds 64 bits"));
125 }
126 value |= payload.checked_shl(shift).unwrap_or(0);
127 }
128 if chunk & high == 0 {
129 return Ok(value);
130 }
131 shift = shift.saturating_add(width.saturating_sub(1));
132 if shift > 64 + 32 {
133 return Err(error(at, "VBR value exceeds 64 bits"));
134 }
135 }
136 }
137 fn align32(&mut self) -> Result<()> {
138 let aligned = self
139 .pos
140 .div_ceil(32)
141 .checked_mul(32)
142 .filter(|&aligned| aligned <= self.data.len().saturating_mul(8))
143 .ok_or_else(|| error(self.pos, "bitstream ends before 32-bit alignment"))?;
144 self.pos = aligned;
145 Ok(())
146 }
147 fn vbr_usize(&mut self, width: u32) -> Result<usize> {
149 let at = self.pos;
150 let value = self.vbr(width)?;
151 usize::try_from(value).map_err(|_| error(at, format!("{value} does not fit the address space")))
152 }
153 fn vbr_u32(&mut self, width: u32) -> Result<u32> {
155 let at = self.pos;
156 let value = self.vbr(width)?;
157 u32::try_from(value).map_err(|_| error(at, format!("{value} does not fit 32 bits")))
158 }
159}
160
161struct Reader<'a> {
162 bits: Bits<'a>,
163 info: Vec<(u64, Vec<Abbrev>)>,
165 operands: usize,
166}
167
168fn char6(v: u64) -> u64 {
169 let [index, ..] = v.to_le_bytes();
170 u64::from(CHAR6.get(usize::from(index)).copied().unwrap_or(b'_'))
171}
172
173impl Reader<'_> {
174 fn count(&mut self, n: usize) -> Result<()> {
175 self.operands = self
176 .operands
177 .checked_add(n)
178 .filter(|&t| t <= MAX_TOTAL_OPERANDS)
179 .ok_or_else(|| error(self.bits.pos, "too many record operands"))?;
180 Ok(())
181 }
182 fn scalar(&mut self, op: Op) -> Result<u64> {
183 match op {
184 Op::Literal(v) => Ok(v),
185 Op::Fixed(w) => self.bits.read(w),
186 Op::Vbr(w) => self.bits.vbr(w),
187 Op::Char6 => Ok(char6(self.bits.read(6)?)),
188 Op::Array | Op::Blob => Err(error(self.bits.pos, "array or blob as an element")),
189 }
190 }
191 fn define_abbrev(&mut self) -> Result<Abbrev> {
192 let at = self.bits.pos;
193 let n = self.bits.vbr_usize(5)?;
194 if n == 0 || n > MAX_ABBREV_OPS {
195 return Err(error(at, "abbreviation operand count"));
196 }
197 let mut ops = Vec::with_capacity(n);
198 while ops.len() < n {
199 if self.bits.read(1)? == 1 {
200 ops.push(Op::Literal(self.bits.vbr(8)?));
201 continue;
202 }
203 ops.push(match self.bits.read(3)? {
204 1 => {
205 let w = self.bits.vbr(5)?;
206 if w > 64 {
207 return Err(error(at, "fixed width above 64"));
208 }
209 Op::Fixed(u32::try_from(w).map_err(|_| error(at, "fixed width above 64"))?)
210 }
211 2 => {
212 let w = self.bits.vbr(5)?;
213 if !(2..=32).contains(&w) {
214 return Err(error(at, "VBR width outside 2..32"));
215 }
216 Op::Vbr(u32::try_from(w).map_err(|_| error(at, "VBR width outside 2..32"))?)
217 }
218 3 => Op::Array,
219 4 => Op::Char6,
220 5 => Op::Blob,
221 other => return Err(error(at, format!("abbreviation encoding {other}"))),
222 });
223 }
224 let mut rest = ops.as_slice();
226 while let Some((op, tail)) = rest.split_first() {
227 match (op, tail) {
228 (Op::Array, [Op::Array | Op::Blob, ..]) => {
229 return Err(error(at, "array not followed by one element encoding"));
230 }
231 (Op::Array, [_]) => {}
232 (Op::Array, _) => {
233 return Err(error(at, "array not followed by one element encoding"));
234 }
235 (Op::Blob, [_, ..]) => return Err(error(at, "blob not last")),
236 _ => {}
237 }
238 rest = tail;
239 }
240 Ok(ops)
241 }
242 fn abbreviated(&mut self, abbrev: &Abbrev, at: usize) -> Result<Record> {
243 let mut values: Vec<u64> = Vec::new();
244 let mut blob = None;
245 let mut rest = abbrev.as_slice();
246 while let Some((&op, tail)) = rest.split_first() {
247 rest = tail;
248 match op {
249 Op::Array => {
250 let Some((&element, after)) = tail.split_first() else {
251 return Err(error(at, "array without its element encoding"));
252 };
253 rest = after;
254 let len = self.bits.vbr_usize(6)?;
255 let min_bits = match element {
259 Op::Literal(_) | Op::Fixed(0) => 1,
260 Op::Fixed(w) | Op::Vbr(w) => w as usize,
261 Op::Char6 => 6,
262 _ => 1,
263 };
264 if self
265 .bits
266 .remaining()
267 .checked_div(min_bits)
268 .is_none_or(|most| len > most)
269 {
270 return Err(error(at, "array longer than the bits that remain"));
271 }
272 self.count(len)?;
273 values.reserve(len);
274 for _ in 0..len {
275 values.push(self.scalar(element)?);
276 }
277 }
278 Op::Blob => {
279 let len = self.bits.vbr_usize(6)?;
280 self.bits.align32()?;
281 if len > self.bits.remaining() / 8 {
282 return Err(error(at, "blob longer than the bits that remain"));
283 }
284 let start = self.bits.pos / 8;
285 let bytes = View::new(self.bits.data)
286 .slice(start, len)
287 .map_err(|e| error(at, e.to_string()))?;
288 blob = Some(bytes.to_vec());
289 self.bits.pos = self.bits.pos.saturating_add(len.saturating_mul(8));
290 self.bits.align32()?;
291 }
292 op => {
293 self.count(1)?;
294 values.push(self.scalar(op)?);
295 }
296 }
297 }
298 if values.is_empty() {
299 return Err(error(at, "abbreviated record without a code"));
300 }
301 let code = values.remove(0);
302 Ok(Record {
303 code,
304 operands: values,
305 blob,
306 at,
307 end: self.bits.pos,
308 })
309 }
310 fn block(&mut self, id: u64, width: u32, end: usize, depth: usize, at: usize) -> Result<Block> {
312 if depth > MAX_DEPTH {
313 return Err(error(at, "blocks nested too deeply"));
314 }
315 let mut abbrevs: Vec<Abbrev> = self
316 .info
317 .iter()
318 .find(|(b, _)| *b == id)
319 .map(|(_, a)| a.clone())
320 .unwrap_or_default();
321 let mut elements = Vec::new();
322 let mut info_target: Option<u64> = None;
324 loop {
325 if self.bits.pos >= end {
326 return Err(error(at, "block ends without END_BLOCK"));
327 }
328 let here = self.bits.pos;
329 match self.bits.read(width)? {
330 0 => {
331 self.bits.align32()?;
332 if self.bits.pos != end {
333 return Err(error(here, "END_BLOCK before the declared block length"));
334 }
335 return Ok(Block {
336 id,
337 elements,
338 at,
339 end,
340 });
341 }
342 1 => {
343 let child = self.bits.vbr(8)?;
344 let child_width = self.bits.vbr_u32(4)?;
345 if !(1..=32).contains(&child_width) {
346 return Err(error(here, "abbreviation width outside 1..32"));
347 }
348 self.bits.align32()?;
349 let words = usize::try_from(self.bits.read(32)?)
350 .map_err(|_| error(here, "block longer than its parent"))?;
351 let child_end = words
352 .checked_mul(32)
353 .and_then(|b| b.checked_add(self.bits.pos))
354 .filter(|&e| e <= end)
355 .ok_or_else(|| error(here, "block longer than its parent"))?;
356 let b = self.block(child, child_width, child_end, depth.saturating_add(1), here)?;
357 elements.push(Element::Block(b));
358 }
359 2 => {
360 let abbrev = self.define_abbrev()?;
361 if id == 0 {
362 let target =
363 info_target.ok_or_else(|| error(here, "BLOCKINFO abbreviation before SETBID"))?;
364 let slot = match self.info.iter().position(|(b, _)| *b == target) {
365 Some(i) => i,
366 None => {
367 self.info.push((target, Vec::new()));
368 self.info.len().saturating_sub(1)
369 }
370 };
371 let Some((_, entry)) = self.info.get_mut(slot) else {
372 return Err(error(here, "BLOCKINFO abbreviation table"));
373 };
374 if entry.len() >= MAX_ABBREVS_PER_BLOCK {
375 return Err(error(here, "too many abbreviations"));
376 }
377 entry.push(abbrev);
378 } else {
379 if abbrevs.len() >= MAX_ABBREVS_PER_BLOCK {
380 return Err(error(here, "too many abbreviations"));
381 }
382 abbrevs.push(abbrev);
383 }
384 }
385 3 => {
386 let code = self.bits.vbr(6)?;
387 let n = self.bits.vbr_usize(6)?;
388 if n > self.bits.remaining() / 2 {
389 return Err(error(here, "record longer than the bits that remain"));
390 }
391 self.count(n)?;
392 let mut operands = Vec::with_capacity(n);
393 for _ in 0..n {
394 operands.push(self.bits.vbr(6)?);
395 }
396 if id == 0 && code == 1 {
397 info_target = Some(
398 *operands
399 .first()
400 .ok_or_else(|| error(here, "SETBID without a block id"))?,
401 );
402 }
403 elements.push(Element::Record(Record {
404 code,
405 operands,
406 blob: None,
407 at: here,
408 end: self.bits.pos,
409 }));
410 }
411 n => {
412 let abbrev = usize::try_from(n.saturating_sub(4))
413 .ok()
414 .and_then(|i| abbrevs.get(i))
415 .cloned()
416 .ok_or_else(|| error(here, format!("undefined abbreviation {n}")))?;
417 let record = self.abbreviated(&abbrev, here)?;
418 if id == 0 && record.code == 1 {
419 info_target = record.operands.first().copied();
420 }
421 elements.push(Element::Record(record));
422 }
423 }
424 }
425 }
426}
427
428pub fn read(data: &[u8], magic: [u8; 4]) -> Result<Vec<Block>> {
430 if data.get(..4) != Some(&magic[..]) || !data.len().is_multiple_of(4) {
431 return Err(error(0, "bitstream magic or length"));
432 }
433 let mut r = Reader {
434 bits: Bits { data, pos: 32 },
435 info: Vec::new(),
436 operands: 0,
437 };
438 let end = data.len().saturating_mul(8);
439 let mut blocks = Vec::new();
440 while r.bits.pos < end {
441 let here = r.bits.pos;
442 if data
444 .get(here / 8..)
445 .is_none_or(|tail| tail.iter().all(|&b| b == 0))
446 {
447 break;
448 }
449 if r.bits.read(2)? != 1 {
450 return Err(error(here, "top level holds only blocks"));
451 }
452 let id = r.bits.vbr(8)?;
453 let width = r.bits.vbr_u32(4)?;
454 if !(1..=32).contains(&width) {
455 return Err(error(here, "abbreviation width outside 1..32"));
456 }
457 r.bits.align32()?;
458 let words =
459 usize::try_from(r.bits.read(32)?).map_err(|_| error(here, "block longer than the stream"))?;
460 let block_end = words
461 .checked_mul(32)
462 .and_then(|b| b.checked_add(r.bits.pos))
463 .filter(|&e| e <= end)
464 .ok_or_else(|| error(here, "block longer than the stream"))?;
465 blocks.push(r.block(id, width, block_end, 1, here)?);
466 }
467 Ok(blocks)
468}