1pub(crate) mod cursor;
8pub(crate) mod emit;
9pub(crate) mod header_id;
10pub(crate) mod ops;
11pub(crate) mod rec;
12pub(crate) mod verify;
13
14use crate::LoadError;
15
16pub(crate) const MAGIC: u32 = 0x5645_4953;
17pub(crate) const FORMAT_VERSION: u16 = 1;
18pub(crate) const HEADER_LEN: usize = 40;
19pub(crate) const REC_LEN: usize = 16;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct Corrupt;
23
24pub(crate) type Decoded<T> = Result<T, Corrupt>;
25
26#[derive(Debug, Clone, Copy, Default)]
27pub(crate) struct Sections {
28 pub num_vars: u16,
29 pub num_match_vars: u16,
30 pub code: (usize, usize),
31 pub records: (usize, usize),
32 pub blob: (usize, usize),
33 pub header_names: (usize, usize),
34 pub globs: (usize, usize),
35 pub num_regexes: u32,
36}
37
38impl Sections {
39 pub(crate) fn parse(bytes: &[u8]) -> Result<Sections, LoadError> {
40 let head = bytes
41 .first_chunk::<HEADER_LEN>()
42 .ok_or(LoadError::Truncated)?;
43 let u16_at = |at: usize| u16::from_le_bytes([head[at], head[at + 1]]);
44 let u32_at =
45 |at: usize| u32::from_le_bytes([head[at], head[at + 1], head[at + 2], head[at + 3]]);
46 if u32_at(0) != MAGIC {
47 return Err(LoadError::Corrupted);
48 }
49 let version = u16_at(4);
50 if version != FORMAT_VERSION {
51 return Err(LoadError::UnsupportedVersion(version));
52 }
53 let mut start = HEADER_LEN;
54 let mut section = |len: u32| -> Result<(usize, usize), LoadError> {
55 let len = len as usize;
56 let end = start.checked_add(len).ok_or(LoadError::Corrupted)?;
57 if end > bytes.len() {
58 return Err(LoadError::Truncated);
59 }
60 let range = (start, end);
61 start = end;
62 Ok(range)
63 };
64 let code = section(u32_at(12))?;
65 let records = section(u32_at(16))?;
66 let blob = section(u32_at(20))?;
67 let header_names = section(u32_at(24))?;
68 let globs = section(u32_at(28))?;
69 let num_records = records.1 - records.0;
70 let num_regexes = u32_at(32);
71 if num_records % REC_LEN != 0 || num_regexes as usize > num_records / REC_LEN {
72 return Err(LoadError::Corrupted);
73 }
74 Ok(Sections {
75 num_vars: u16_at(8),
76 num_match_vars: u16_at(10),
77 code,
78 records,
79 blob,
80 header_names,
81 globs,
82 num_regexes,
83 })
84 }
85
86 pub(crate) fn write_header(&self, out: &mut Vec<u8>) {
87 out.extend_from_slice(&MAGIC.to_le_bytes());
88 out.extend_from_slice(&FORMAT_VERSION.to_le_bytes());
89 out.extend_from_slice(&0u16.to_le_bytes());
90 out.extend_from_slice(&self.num_vars.to_le_bytes());
91 out.extend_from_slice(&self.num_match_vars.to_le_bytes());
92 for (start, end) in [
93 self.code,
94 self.records,
95 self.blob,
96 self.header_names,
97 self.globs,
98 ] {
99 out.extend_from_slice(&((end - start) as u32).to_le_bytes());
100 }
101 out.extend_from_slice(&self.num_regexes.to_le_bytes());
102 out.extend_from_slice(&0u32.to_le_bytes());
103 }
104}