Skip to main content

sieve/bytecode/
mod.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
5 */
6
7pub(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}