1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use std::fmt;
use crate::encryption;

#[derive(Debug)]
pub enum Error {
    /// Could not decode content.
    ContentDecode,
    /// Dictionary key was not found.
    DictKey,
    /// Invalid file header
    Header,
    /// IO error
    IO(std::io::Error),
    /// Found Object ID does not match Expected Object ID.
    ObjectIdMismatch,
    /// The Object ID was not found.
    ObjectNotFound,
    /// Offset in file is invalid.
    Offset(usize),
    /// Page number was not found in document.
    PageNumberNotFound(u32),
    /// Invalid object while parsing at offset.
    Parse { offset: usize },
    /// Dereferencing object reached the limit.
    /// This might indicate a reference loop.
    ReferenceLimit,
    /// Brackets limit reached.
    /// To many brackets nested.
    // TODO: This does not seem to be used.
    BracketLimit,
    /// The file trailer was invalid.
    Trailer,
    /// The object does not have the expected type.
    Type,
    /// Decoding byte vector to UTF8 String failed.
    UTF8,
    /// Syntax error while parsing the file.
    Syntax(String),
    /// Error while parsing cross reference table.
    Xref(XrefError),
    /// Invalid command.
    Invalid(String),
    /// PDF document has no Outlines.
    NoOutlines,
    /// Error when handling images.
    #[cfg(feature = "embed_image")]
    Image(image::ImageError),
    /// Error when decrypting the contents of the file
    Decryption(encryption::DecryptionError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::ContentDecode => write!(f, "Could not decode content"),
            Error::DictKey => write!(f, "A required dictionary key was not found"),
            Error::Header => write!(f, "Invalid file header"),
            Error::IO(e) => e.fmt(f),
            Error::ObjectIdMismatch => write!(f, "The object id found did not match the requested object"),
            Error::ObjectNotFound => write!(f, "A required object was not found"),
            Error::Offset(o) => write!(f, "Invalid file offset: {}", o),
            Error::PageNumberNotFound(p) => write!(f, "Page number {} could not be found", p),
            Error::Parse { offset, .. } => write!(f, "Invalid object at byte {}", offset),
            Error::ReferenceLimit => write!(f, "Could not dereference an object; possible reference loop"),
            Error::BracketLimit => write!(f, "Too deep embedding of ()'s."),
            Error::Trailer => write!(f, "Invalid file trailer"),
            Error::Type => write!(f, "An object does not have the expected type"),
            Error::UTF8 => write!(f, "UTF-8 error"),
            Error::Syntax(msg) => write!(f, "Syntax error: {}", msg),
            Error::Xref(e) => write!(f, "Invalid cross-reference table ({})", e),
            Error::Invalid(msg) => write!(f, "Invalid command: {}", msg),
            Error::NoOutlines => write!(f, "PDF document has no Outlines"),
            #[cfg(feature = "embed_image")]
            Error::Image(e) => e.fmt(f),
            Error::Decryption(d) => d.fmt(f),
        }
    }
}

impl std::error::Error for Error {}

#[derive(Debug)]
pub enum XrefError {
    /// Could not parse cross reference table.
    Parse,
    /// Could not find start of cross reference table.
    Start,
    /// The trailer's "Prev" field was invalid.
    PrevStart,
    /// The trailer's "XRefStm" field was invalid.
    StreamStart,
}

impl fmt::Display for XrefError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            XrefError::Parse => write!(f, "could not parse xref"),
            XrefError::Start => write!(f, "invalid start value"),
            XrefError::PrevStart => write!(f, "invalid start value in Prev field"),
            XrefError::StreamStart => write!(f, "invalid stream start value"),
        }
    }
}

impl std::error::Error for XrefError {}

pub type Result<T> = std::result::Result<T, Error>;

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Self {
        Error::IO(err)
    }
}

impl From<std::string::FromUtf8Error> for Error {
    fn from(_err: std::string::FromUtf8Error) -> Self {
        Error::UTF8
    }
}

impl From<std::str::Utf8Error> for Error {
    fn from(_err: std::str::Utf8Error) -> Self {
        Error::UTF8
    }
}

#[cfg(feature = "embed_image")]
impl From<image::ImageError> for Error {
    fn from(err: image::ImageError) -> Self {
        Error::Image(err)
    }
}

impl From<encryption::DecryptionError> for Error {
    fn from(_err: encryption::DecryptionError) -> Self {
        Error::Decryption(_err)
    }
}