pdfboss_write/error.rs
1//! Error type for PDF creation. Writing is strict where reading is lenient:
2//! a writer that silently drops or corrupts content is worse than one that
3//! refuses, so every lossy situation is an error, never a skip.
4
5use pdfboss_core::ObjRef;
6
7/// Alias used across the crate.
8pub type Result<T> = std::result::Result<T, Error>;
9
10/// Any error raised while building or serializing a PDF.
11#[derive(Debug, thiserror::Error)]
12pub enum Error {
13 /// Underlying I/O failure while saving.
14 #[error("i/o error: {0}")]
15 Io(#[from] std::io::Error),
16 /// A reserved object was filled twice, or `fill` targeted a
17 /// never-reserved reference.
18 #[error("object {} {} already has a body", .0.num, .0.gen)]
19 AlreadyFilled(ObjRef),
20 /// `finish` found a reserved object that was never filled.
21 #[error("object {} {} was reserved but never filled", .0.num, .0.gen)]
22 Unfilled(ObjRef),
23 /// A `Stream` object appeared nested inside another object; streams are
24 /// only legal as indirect objects (ISO 32000 ยง7.3.8).
25 #[error("stream objects must be indirect, not nested")]
26 NestedStream,
27 /// A character has no code in the target font's encoding.
28 #[error("character {ch:?} is not encodable in {font}")]
29 Unencodable {
30 /// The character that failed to encode.
31 ch: char,
32 /// Base font name of the font that rejected it.
33 font: &'static str,
34 },
35 /// Image bytes could not be understood or are inconsistent.
36 #[error("invalid image: {0}")]
37 Image(String),
38 /// A locked import source (encrypted, with no working decryptor) is
39 /// refused: a copy would otherwise emit raw ciphertext into a plain
40 /// output with no `/Encrypt` of its own. A password-opened encrypted
41 /// source copies fine, since its content already reads as plaintext.
42 /// An append base is refused whenever it carries an `/Encrypt` entry at
43 /// all, password-opened or not: an appended update would need to
44 /// encrypt its own new strings and streams too, which is not yet
45 /// implemented.
46 #[error("cannot update an encrypted document, or copy from an encrypted document not opened with its password")]
47 EncryptedBase,
48 /// The base trailer names no `/Root` to build an update against.
49 #[error("trailer has no /Root")]
50 MissingRoot,
51 /// The base file carries no `startxref` to chain an appended section's
52 /// `/Prev` to.
53 #[error("no startxref in the base file")]
54 MissingStartxref,
55 /// An update section was asked for with no object set or put into it.
56 #[error("update has no changes")]
57 EmptyUpdate,
58 /// Anything else.
59 #[error("{0}")]
60 Other(String),
61}