Skip to main content

fixed_json/
validator.rs

1use crate::{Error, Result, number::hex_val};
2
3pub fn validate_json(input: &[u8]) -> Result<usize> {
4    let mut validator = JsonValidator {
5        bytes: input,
6        depth: 0,
7    };
8    let end = validator.parse_value(validator.skip_ws(0))?;
9    let end = validator.skip_ws(end);
10    if end == input.len() {
11        Ok(end)
12    } else {
13        Err(Error::BadTrail)
14    }
15}
16
17pub(crate) struct JsonValidator<'a> {
18    pub(crate) bytes: &'a [u8],
19    pub(crate) depth: usize,
20}
21
22impl JsonValidator<'_> {
23    const MAX_DEPTH: usize = 1024;
24
25    #[inline]
26    fn parse_value(&mut self, i: usize) -> Result<usize> {
27        if i >= self.bytes.len() {
28            return Err(Error::BadTrail);
29        }
30        match self.bytes[i] {
31            b'{' => self.parse_object(i),
32            b'[' => self.parse_array(i),
33            b'"' => self.parse_string(i),
34            b't' => self.parse_literal(i, b"true"),
35            b'f' => self.parse_literal(i, b"false"),
36            b'n' => self.parse_literal(i, b"null"),
37            b'-' | b'0'..=b'9' => self.parse_number(i),
38            _ => Err(Error::BadTrail),
39        }
40    }
41
42    fn parse_object(&mut self, mut i: usize) -> Result<usize> {
43        self.enter()?;
44        i += 1;
45        i = self.skip_ws(i);
46        if i < self.bytes.len() && self.bytes[i] == b'}' {
47            self.leave();
48            return Ok(i + 1);
49        }
50        loop {
51            if i >= self.bytes.len() || self.bytes[i] != b'"' {
52                self.leave();
53                return Err(Error::AttrStart);
54            }
55            i = self.parse_string(i)?;
56            i = self.skip_ws(i);
57            if i >= self.bytes.len() || self.bytes[i] != b':' {
58                self.leave();
59                return Err(Error::BadTrail);
60            }
61            i = self.parse_value(self.skip_ws(i + 1))?;
62            i = self.skip_ws(i);
63            if i >= self.bytes.len() {
64                self.leave();
65                return Err(Error::BadTrail);
66            }
67            match self.bytes[i] {
68                b',' => i = self.skip_ws(i + 1),
69                b'}' => {
70                    self.leave();
71                    return Ok(i + 1);
72                }
73                _ => {
74                    self.leave();
75                    return Err(Error::BadTrail);
76                }
77            }
78        }
79    }
80
81    fn parse_array(&mut self, mut i: usize) -> Result<usize> {
82        self.enter()?;
83        i += 1;
84        i = self.skip_ws(i);
85        if i < self.bytes.len() && self.bytes[i] == b']' {
86            self.leave();
87            return Ok(i + 1);
88        }
89        loop {
90            i = self.parse_value(i)?;
91            i = self.skip_ws(i);
92            if i >= self.bytes.len() {
93                self.leave();
94                return Err(Error::BadTrail);
95            }
96            match self.bytes[i] {
97                b',' => i = self.skip_ws(i + 1),
98                b']' => {
99                    self.leave();
100                    return Ok(i + 1);
101                }
102                _ => {
103                    self.leave();
104                    return Err(Error::BadTrail);
105                }
106            }
107        }
108    }
109
110    pub(crate) fn parse_string(&self, mut i: usize) -> Result<usize> {
111        i += 1;
112        let mut raw_start = i;
113        while i < self.bytes.len() {
114            match self.bytes[i] {
115                b'"' => {
116                    core::str::from_utf8(&self.bytes[raw_start..i])
117                        .map_err(|_| Error::BadString)?;
118                    return Ok(i + 1);
119                }
120                b'\\' => {
121                    core::str::from_utf8(&self.bytes[raw_start..i])
122                        .map_err(|_| Error::BadString)?;
123                    i += 1;
124                    if i >= self.bytes.len() {
125                        return Err(Error::BadString);
126                    }
127                    match self.bytes[i] {
128                        b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't' => {
129                            i += 1;
130                        }
131                        b'u' => {
132                            i += 1;
133                            for _ in 0..4 {
134                                if i >= self.bytes.len() || hex_val(self.bytes[i]).is_none() {
135                                    return Err(Error::BadString);
136                                }
137                                i += 1;
138                            }
139                        }
140                        _ => return Err(Error::BadString),
141                    }
142                    raw_start = i;
143                }
144                0x00..=0x1f => return Err(Error::BadString),
145                _ => i += 1,
146            }
147        }
148        Err(Error::BadString)
149    }
150
151    #[inline]
152    fn parse_literal(&self, i: usize, literal: &[u8]) -> Result<usize> {
153        if self.bytes[i..].starts_with(literal) {
154            Ok(i + literal.len())
155        } else {
156            Err(Error::BadTrail)
157        }
158    }
159
160    pub(crate) fn parse_number(&self, mut i: usize) -> Result<usize> {
161        if i < self.bytes.len() && self.bytes[i] == b'-' {
162            i += 1;
163        }
164        if i >= self.bytes.len() {
165            return Err(Error::BadNum);
166        }
167        if self.bytes[i] == b'0' {
168            i += 1;
169            if i < self.bytes.len() && self.bytes[i].is_ascii_digit() {
170                return Err(Error::BadNum);
171            }
172        } else if self.bytes[i].is_ascii_digit() {
173            while i < self.bytes.len() && self.bytes[i].is_ascii_digit() {
174                i += 1;
175            }
176        } else {
177            return Err(Error::BadNum);
178        }
179        if i < self.bytes.len() && self.bytes[i] == b'.' {
180            i += 1;
181            let start = i;
182            while i < self.bytes.len() && self.bytes[i].is_ascii_digit() {
183                i += 1;
184            }
185            if i == start {
186                return Err(Error::BadNum);
187            }
188        }
189        if i < self.bytes.len() && matches!(self.bytes[i], b'e' | b'E') {
190            i += 1;
191            if i < self.bytes.len() && matches!(self.bytes[i], b'+' | b'-') {
192                i += 1;
193            }
194            let start = i;
195            while i < self.bytes.len() && self.bytes[i].is_ascii_digit() {
196                i += 1;
197            }
198            if i == start {
199                return Err(Error::BadNum);
200            }
201        }
202        Ok(i)
203    }
204
205    #[inline]
206    pub(crate) fn skip_ws(&self, mut i: usize) -> usize {
207        while i < self.bytes.len() && matches!(self.bytes[i], b' ' | b'\t' | b'\n' | b'\r') {
208            i += 1;
209        }
210        i
211    }
212
213    #[inline]
214    fn enter(&mut self) -> Result<()> {
215        self.depth += 1;
216        if self.depth > Self::MAX_DEPTH {
217            return Err(Error::SubTooLong);
218        }
219        Ok(())
220    }
221
222    #[inline]
223    fn leave(&mut self) {
224        self.depth -= 1;
225    }
226}