1use crate::diag::{DiagnosticKind, Diagnostics};
4use crate::error::{Error, Result};
5use crate::lexer::{Lexer, Token};
6use crate::limits::{LimitKind, Limits, Strictness};
7use crate::object::{Dict, ObjId, Object};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum ObjectEnd {
12 Endobj,
14 Stream {
16 data_start: usize,
18 },
19}
20
21pub struct Parser<'a, 'd> {
23 lexer: Lexer<'a>,
24 limits: &'d Limits,
25 strictness: Strictness,
26 diagnostics: Option<&'d Diagnostics>,
27 base: u64,
29}
30
31impl<'a, 'd> Parser<'a, 'd> {
32 pub fn new(buf: &'a [u8], base: u64, limits: &'d Limits, strictness: Strictness) -> Self {
34 Self {
35 lexer: Lexer::new(buf),
36 limits,
37 strictness,
38 diagnostics: None,
39 base,
40 }
41 }
42
43 pub fn with_diagnostics(mut self, diagnostics: &'d Diagnostics) -> Self {
45 self.diagnostics = Some(diagnostics);
46 self
47 }
48
49 pub fn lexer(&mut self) -> &mut Lexer<'a> {
51 &mut self.lexer
52 }
53
54 fn offset(&self) -> u64 {
55 self.base + self.lexer.pos() as u64
56 }
57
58 fn repair(&self, kind: DiagnosticKind, message: &'static str) -> Result<()> {
60 match self.strictness {
61 Strictness::Strict => Err(Error::syntax(self.offset(), message)),
62 Strictness::Lenient => {
63 if let Some(d) = self.diagnostics {
64 d.push(kind, Some(self.offset()), None);
65 }
66 Ok(())
67 }
68 }
69 }
70
71 pub fn parse_object(&mut self) -> Result<Object> {
73 let token = self.lexer.next_token()?;
74 self.object_from(token, 0)
75 }
76
77 fn object_from(&mut self, token: Token<'a>, depth: u32) -> Result<Object> {
78 if depth > self.limits.max_depth {
79 return Err(Error::Limit(LimitKind::Depth));
80 }
81 match token {
82 Token::Int(n) => self.int_or_ref(n),
83 Token::Real(r) => Ok(Object::Real(r)),
84 Token::String(s) => Ok(Object::String(s)),
85 Token::Name(n) => Ok(Object::Name(n)),
86 Token::ArrayStart => self.array(depth),
87 Token::DictStart => self.dict(depth).map(Object::Dict),
88 Token::Keyword(b"true") => Ok(Object::Bool(true)),
89 Token::Keyword(b"false") => Ok(Object::Bool(false)),
90 Token::Keyword(b"null") => Ok(Object::Null),
91 Token::Eof => Err(Error::UnexpectedEof),
92 _ => Err(Error::syntax(self.offset(), "expected an object")),
93 }
94 }
95
96 fn int_or_ref(&mut self, n: i64) -> Result<Object> {
98 let save = self.lexer.pos();
99 if let (Ok(num), Ok(Token::Int(g))) = (u32::try_from(n), self.lexer.next_token())
100 && let (Ok(generation), Ok(Token::Keyword(b"R"))) =
101 (u16::try_from(g), self.lexer.next_token())
102 {
103 return Ok(Object::Ref(ObjId::new(num, generation)));
104 }
105 self.lexer.set_pos(save);
106 Ok(Object::Int(n))
107 }
108
109 fn array(&mut self, depth: u32) -> Result<Object> {
110 let mut items = Vec::new();
111 loop {
112 let save = self.lexer.pos();
113 match self.lexer.next_token()? {
114 Token::ArrayEnd => return Ok(Object::Array(items)),
115 Token::Eof => return Err(Error::UnexpectedEof),
116 Token::Keyword(b"endobj" | b"stream" | b"endstream" | b"obj") => {
117 self.lexer.set_pos(save);
120 self.repair(DiagnosticKind::SyntaxError, "unterminated array")?;
121 return Ok(Object::Array(items));
122 }
123 Token::Keyword(k) if !matches!(k, b"true" | b"false" | b"null") => {
125 self.repair(DiagnosticKind::SyntaxError, "unexpected token in array")?;
126 }
127 Token::DictEnd | Token::BraceOpen | Token::BraceClose => {
128 self.repair(DiagnosticKind::SyntaxError, "unexpected token in array")?;
129 }
130 t => items.push(self.object_from(t, depth + 1)?),
131 }
132 }
133 }
134
135 fn dict(&mut self, depth: u32) -> Result<Dict> {
136 let mut dict = Dict::new();
137 loop {
138 let save = self.lexer.pos();
139 match self.lexer.next_token()? {
140 Token::DictEnd => return Ok(dict),
141 Token::Eof => return Err(Error::UnexpectedEof),
142 Token::Name(key) => {
143 let save_value = self.lexer.pos();
144 match self.lexer.next_token()? {
145 Token::DictEnd => {
146 self.repair(
147 DiagnosticKind::SyntaxError,
148 "dictionary key without value",
149 )?;
150 dict.insert(key, Object::Null);
151 return Ok(dict);
152 }
153 Token::Keyword(b"endobj" | b"stream" | b"endstream" | b"obj") => {
154 self.lexer.set_pos(save_value);
155 self.repair(DiagnosticKind::SyntaxError, "unterminated dictionary")?;
156 dict.insert(key, Object::Null);
157 return Ok(dict);
158 }
159 Token::Eof => return Err(Error::UnexpectedEof),
160 t => match self.object_from(t, depth + 1) {
161 Ok(v) => {
162 dict.insert(key, v);
163 }
164 Err(Error::Syntax { .. }) if self.strictness == Strictness::Lenient => {
165 self.repair(DiagnosticKind::SyntaxError, "bad dictionary value")?;
166 dict.insert(key, Object::Null);
167 }
168 Err(e) => return Err(e),
169 },
170 }
171 }
172 Token::Keyword(b"endobj" | b"stream" | b"endstream" | b"obj") => {
173 self.lexer.set_pos(save);
174 self.repair(DiagnosticKind::SyntaxError, "unterminated dictionary")?;
175 return Ok(dict);
176 }
177 _ => {
178 self.repair(DiagnosticKind::SyntaxError, "dictionary key is not a name")?;
179 }
180 }
181 }
182 }
183
184 pub fn parse_indirect(
187 &mut self,
188 expected: Option<ObjId>,
189 ) -> Result<(ObjId, Object, ObjectEnd)> {
190 let id = self.indirect_header()?;
191 if let Some(want) = expected {
192 if want.num != id.num {
193 return Err(Error::syntax(self.offset(), "object number mismatch"));
194 }
195 if want.generation != id.generation {
196 self.repair(DiagnosticKind::ObjectIdMismatch, "generation mismatch")?;
197 }
198 }
199 let object = self.parse_object_or_empty()?;
200 let save = self.lexer.pos();
201 let end = match self.lexer.next_token() {
202 Ok(Token::Keyword(b"endobj")) => ObjectEnd::Endobj,
203 Ok(Token::Keyword(b"stream")) => {
204 if !matches!(object, Object::Dict(_)) {
205 return Err(Error::syntax(self.offset(), "stream without dictionary"));
206 }
207 ObjectEnd::Stream {
208 data_start: self.stream_data_start(),
209 }
210 }
211 Err(Error::UnexpectedEof) | Ok(Token::Eof) => {
212 return Err(Error::UnexpectedEof);
213 }
214 _ => {
215 self.lexer.set_pos(save);
217 self.repair(DiagnosticKind::MissingEndobj, "missing endobj")?;
218 ObjectEnd::Endobj
219 }
220 };
221 Ok((id, object, end))
222 }
223
224 fn indirect_header(&mut self) -> Result<ObjId> {
226 let (Token::Int(num), Token::Int(generation), Token::Keyword(b"obj")) = (
227 self.lexer.next_token()?,
228 self.lexer.next_token()?,
229 self.lexer.next_token()?,
230 ) else {
231 return Err(Error::syntax(self.offset(), "expected `num gen obj`"));
232 };
233 match (u32::try_from(num), u16::try_from(generation)) {
234 (Ok(num), Ok(generation)) => Ok(ObjId::new(num, generation)),
235 _ => Err(Error::syntax(self.offset(), "object id out of range")),
236 }
237 }
238
239 fn parse_object_or_empty(&mut self) -> Result<Object> {
241 let save = self.lexer.pos();
242 let token = self.lexer.next_token()?;
243 if let Token::Keyword(b"endobj") = token {
244 self.lexer.set_pos(save);
245 self.repair(DiagnosticKind::SyntaxError, "empty object")?;
246 return Ok(Object::Null);
247 }
248 self.object_from(token, 0)
249 }
250
251 fn stream_data_start(&mut self) -> usize {
255 let buf = self.lexer.buffer();
256 let mut pos = self.lexer.pos();
257 while buf.get(pos) == Some(&b' ') {
258 pos += 1;
259 }
260 match (buf.get(pos), buf.get(pos + 1)) {
261 (Some(b'\r'), Some(b'\n')) => pos += 2,
262 (Some(b'\r' | b'\n'), _) => pos += 1,
263 _ => {}
264 }
265 self.lexer.set_pos(pos);
266 pos
267 }
268
269 pub fn parse_dict(&mut self) -> Result<Dict> {
271 match self.lexer.next_token()? {
272 Token::DictStart => self.dict(0),
273 Token::Eof => Err(Error::UnexpectedEof),
274 _ => Err(Error::syntax(self.offset(), "expected a dictionary")),
275 }
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282 use crate::object::{Name, PdfString};
283
284 fn name(bytes: &[u8]) -> Object {
285 Object::Name(Name(bytes.to_vec()))
286 }
287
288 fn parse(input: &[u8]) -> Result<Object> {
289 let limits = Limits::default();
290 Parser::new(input, 0, &limits, Strictness::Lenient).parse_object()
291 }
292
293 fn strict(input: &[u8]) -> Result<Object> {
294 let limits = Limits::default();
295 Parser::new(input, 0, &limits, Strictness::Strict).parse_object()
296 }
297
298 #[test]
299 fn scalars() {
300 assert_eq!(parse(b"true"), Ok(Object::Bool(true)));
301 assert_eq!(parse(b"false"), Ok(Object::Bool(false)));
302 assert_eq!(parse(b"null"), Ok(Object::Null));
303 assert_eq!(parse(b"42"), Ok(Object::Int(42)));
304 assert_eq!(parse(b"-1.5"), Ok(Object::Real(-1.5)));
305 assert_eq!(parse(b"/N"), Ok(name(b"N")));
306 assert_eq!(
307 parse(b"(s)"),
308 Ok(Object::String(PdfString::literal(b"s".to_vec())))
309 );
310 }
311
312 #[test]
313 fn references() {
314 assert_eq!(parse(b"12 0 R"), Ok(Object::Ref(ObjId::new(12, 0))));
315 assert_eq!(
316 parse(b"[1 2 R 3 4 5 R]"),
317 Ok(Object::Array(vec![
318 Object::Ref(ObjId::new(1, 2)),
319 Object::Int(3),
320 Object::Ref(ObjId::new(4, 5)),
321 ]))
322 );
323 assert_eq!(
325 parse(b"[-1 0 R]").unwrap().as_array().map(<[_]>::len),
326 Some(2)
327 );
328 assert_eq!(
329 parse(b"[1 70000 R]").unwrap().as_array().map(<[_]>::len),
330 Some(2)
331 );
332 }
333
334 #[test]
335 fn dictionaries() {
336 let obj = parse(b"<< /Type /Page /Kids [1 0 R] /Sub << /A 1 >> /N null >>").unwrap();
337 let d = obj.as_dict().unwrap();
338 assert!(d.is_type(b"Page"));
339 assert_eq!(d.get_dict(b"Sub").unwrap().get_int(b"A"), Some(1));
340 assert!(d.get(b"N").is_none());
341 }
342
343 #[test]
344 fn lenient_dictionary_repairs() {
345 let d = parse(b"<< /A 1 /B >>").unwrap();
346 assert_eq!(d.as_dict().unwrap().get_int(b"A"), Some(1));
347 let d = parse(b"<< /A 1 2 /B 3 >>").unwrap();
348 assert_eq!(d.as_dict().unwrap().get_int(b"B"), Some(3));
349 assert!(strict(b"<< /A 1 /B >>").is_err());
350 assert!(strict(b"<< 1 /B 3 >>").is_err());
351 }
352
353 #[test]
354 fn keyword_objects_in_arrays() {
355 assert_eq!(
356 strict(b"[true false null 1]"),
357 Ok(Object::Array(vec![
358 Object::Bool(true),
359 Object::Bool(false),
360 Object::Null,
361 Object::Int(1),
362 ]))
363 );
364 }
365
366 #[test]
367 fn lenient_array_repairs() {
368 assert_eq!(
369 parse(b"[1 foo 2]"),
370 Ok(Object::Array(vec![Object::Int(1), Object::Int(2)]))
371 );
372 assert!(strict(b"[1 foo 2]").is_err());
373 }
374
375 #[test]
376 fn unterminated_containers() {
377 assert_eq!(parse(b"[1 2"), Err(Error::UnexpectedEof));
378 assert_eq!(parse(b"<< /A 1"), Err(Error::UnexpectedEof));
379 assert_eq!(parse(b""), Err(Error::UnexpectedEof));
380 }
381
382 #[test]
383 fn depth_limit() {
384 let mut deep = vec![b'['; 300];
385 deep.extend(vec![b']'; 300]);
386 assert_eq!(parse(&deep), Err(Error::Limit(LimitKind::Depth)));
387 let mut ok = vec![b'['; 200];
388 ok.extend(vec![b']'; 200]);
389 assert!(parse(&ok).is_ok());
390 }
391
392 fn indirect(input: &[u8], mode: Strictness) -> Result<(ObjId, Object, ObjectEnd)> {
393 let limits = Limits::default();
394 Parser::new(input, 0, &limits, mode).parse_indirect(None)
395 }
396
397 #[test]
398 fn indirect_objects() {
399 let (id, obj, end) = indirect(b"3 0 obj\n<< /A 1 >>\nendobj", Strictness::Strict).unwrap();
400 assert_eq!(id, ObjId::new(3, 0));
401 assert!(obj.as_dict().is_some());
402 assert_eq!(end, ObjectEnd::Endobj);
403 }
404
405 #[test]
406 fn stream_start() {
407 for (input, start) in [
408 (&b"1 0 obj << /Length 3 >> stream\r\nabc"[..], 32),
409 (b"1 0 obj << /Length 3 >> stream\nabc", 31),
410 (b"1 0 obj << /Length 3 >> stream\rabc", 31),
411 (b"1 0 obj << /Length 3 >> stream \nabc", 33),
412 ] {
413 let (_, _, end) = indirect(input, Strictness::Lenient).unwrap();
414 assert_eq!(end, ObjectEnd::Stream { data_start: start });
415 assert_eq!(&input[start..], b"abc");
416 }
417 assert!(indirect(b"1 0 obj 5 stream\nabc", Strictness::Lenient).is_err());
418 }
419
420 #[test]
421 fn missing_endobj() {
422 let diags = Diagnostics::default();
423 let limits = Limits::default();
424 let (_, obj, end) = Parser::new(b"1 0 obj 5 2 0 obj", 0, &limits, Strictness::Lenient)
425 .with_diagnostics(&diags)
426 .parse_indirect(None)
427 .unwrap();
428 assert_eq!(obj, Object::Int(5));
429 assert_eq!(end, ObjectEnd::Endobj);
430 assert_eq!(diags.snapshot()[0].kind, DiagnosticKind::MissingEndobj);
431 assert!(indirect(b"1 0 obj 5 2 0 obj", Strictness::Strict).is_err());
432 }
433
434 #[test]
435 fn empty_object_is_null() {
436 let (_, obj, _) = indirect(b"1 0 obj endobj", Strictness::Lenient).unwrap();
437 assert_eq!(obj, Object::Null);
438 }
439
440 #[test]
441 fn id_checks() {
442 let limits = Limits::default();
443 let mut p = Parser::new(b"4 0 obj 1 endobj", 0, &limits, Strictness::Lenient);
444 assert!(p.parse_indirect(Some(ObjId::new(5, 0))).is_err());
445 let mut p = Parser::new(b"4 1 obj 1 endobj", 0, &limits, Strictness::Lenient);
446 assert!(p.parse_indirect(Some(ObjId::new(4, 0))).is_ok());
447 let mut p = Parser::new(b"4 1 obj 1 endobj", 0, &limits, Strictness::Strict);
448 assert!(p.parse_indirect(Some(ObjId::new(4, 0))).is_err());
449 assert!(indirect(b"x 0 obj", Strictness::Lenient).is_err());
450 assert!(indirect(b"99999999999 0 obj 1 endobj", Strictness::Lenient).is_err());
451 }
452
453 #[test]
454 fn trailer_dict() {
455 let limits = Limits::default();
456 let mut p = Parser::new(b" << /Size 3 >>", 0, &limits, Strictness::Strict);
457 assert_eq!(p.parse_dict().unwrap().get_int(b"Size"), Some(3));
458 let mut p = Parser::new(b" 5", 0, &limits, Strictness::Strict);
459 assert!(p.parse_dict().is_err());
460 }
461}