Skip to main content

hayro_postscript/
array.rs

1use crate::error::{Error, Result};
2use crate::object;
3use crate::reader::Reader;
4use crate::string;
5
6/// A PostScript array object.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct Array<'a> {
9    data: &'a [u8],
10}
11
12impl<'a> Array<'a> {
13    pub(crate) fn new(data: &'a [u8]) -> Self {
14        Self { data }
15    }
16
17    /// Return a [`Scanner`](crate::Scanner) that iterates over the objects inside
18    /// this array.
19    pub fn objects(&self) -> crate::Scanner<'a> {
20        crate::Scanner::new(self.data)
21    }
22}
23
24pub(crate) fn parse<'a>(r: &mut Reader<'a>) -> Result<&'a [u8]> {
25    r.forward_tag(b"[").ok_or(Error::SyntaxError)?;
26
27    let start = r.offset();
28    skip_array(r)?;
29    let end = r.offset() - 1;
30
31    r.range(start..end).ok_or(Error::SyntaxError)
32}
33
34fn skip_array(r: &mut Reader<'_>) -> Result<()> {
35    let mut depth = 1_u32;
36
37    while depth > 0 {
38        match r.peek_byte().ok_or(Error::SyntaxError)? {
39            b'[' => {
40                r.forward();
41                depth += 1;
42            }
43            b']' => {
44                r.forward();
45                depth -= 1;
46            }
47            b'(' => {
48                let _ = string::parse_literal(r).ok_or(Error::SyntaxError)?;
49            }
50            b'<' => {
51                if r.peek_bytes(2) == Some(b"<~") {
52                    let _ = string::parse_ascii85(r).ok_or(Error::SyntaxError)?;
53                } else if r.peek_bytes(2) == Some(b"<<") {
54                    r.forward();
55                    r.forward();
56                } else {
57                    let _ = string::parse_hex(r).ok_or(Error::SyntaxError)?;
58                }
59            }
60            b'%' => object::skip_whitespace_and_comments(r),
61            _ => {
62                r.forward();
63            }
64        }
65    }
66
67    Ok(())
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    fn parse_array(input: &[u8]) -> Result<&[u8]> {
75        let mut r = Reader::new(input);
76        parse(&mut r)
77    }
78
79    #[test]
80    fn empty() {
81        assert_eq!(parse_array(b"[]").unwrap(), b"");
82    }
83
84    #[test]
85    fn simple() {
86        assert_eq!(parse_array(b"[1 2 3]").unwrap(), b"1 2 3");
87    }
88
89    #[test]
90    fn nested() {
91        assert_eq!(parse_array(b"[1 [2 3] 4]").unwrap(), b"1 [2 3] 4");
92    }
93
94    #[test]
95    fn with_string() {
96        // The ']' inside the string should not close the array.
97        assert_eq!(parse_array(b"[1 (str]) 2]").unwrap(), b"1 (str]) 2");
98    }
99
100    #[test]
101    fn with_hex_string() {
102        assert_eq!(parse_array(b"[<48> /name]").unwrap(), b"<48> /name");
103    }
104
105    #[test]
106    fn with_ascii85_string() {
107        assert_eq!(parse_array(b"[<~87cURDZ~> 1]").unwrap(), b"<~87cURDZ~> 1");
108    }
109
110    #[test]
111    fn with_comment() {
112        assert_eq!(
113            parse_array(b"[1 % comment with ]\n2]").unwrap(),
114            b"1 % comment with ]\n2"
115        );
116    }
117
118    #[test]
119    fn unterminated() {
120        assert_eq!(parse_array(b"[1 2"), Err(Error::SyntaxError));
121    }
122
123    #[test]
124    fn not_an_array() {
125        assert_eq!(parse_array(b"1 2]"), Err(Error::SyntaxError));
126    }
127}