WIP
This commit is contained in:
parent
5247d69ebd
commit
5fbfaa8053
8 changed files with 2975 additions and 958 deletions
68
Cargo.lock
generated
68
Cargo.lock
generated
|
|
@ -5,71 +5,3 @@ version = 4
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parse_powerisa_pdf"
|
name = "parse_powerisa_pdf"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.103"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.42"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.228"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
|
||||||
dependencies = [
|
|
||||||
"serde_core",
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_core"
|
|
||||||
version = "1.0.228"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
|
||||||
dependencies = [
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.228"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.111"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,4 @@ edition = "2024"
|
||||||
license = "LGPL-3.0-or-later"
|
license = "LGPL-3.0-or-later"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,5 @@
|
||||||
mod pdf;
|
#[doc(hidden)]
|
||||||
mod util;
|
pub use std as __std;
|
||||||
|
|
||||||
|
pub mod pdf;
|
||||||
|
pub mod util;
|
||||||
|
|
|
||||||
45
src/main.rs
Normal file
45
src/main.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
use parse_powerisa_pdf::pdf::{Pdf, PdfTrailer};
|
||||||
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
io::{IsTerminal, Read},
|
||||||
|
process::ExitCode,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<ExitCode, Box<dyn Error>> {
|
||||||
|
let args: Vec<_> = std::env::args_os().collect();
|
||||||
|
if args
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.any(|v| v.as_encoded_bytes().starts_with(b"-") && v != "-")
|
||||||
|
|| args.len() > 2
|
||||||
|
|| (args.len() == 1 && std::io::stdin().is_terminal())
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
"Usage: {} [<path/to/file.pdf>]\n\
|
||||||
|
Reads the PDF file passed on the command line,\n\
|
||||||
|
Reads stdin if no arguments are passed or if the file name is just a dash `-`.\n\
|
||||||
|
If stdin is a terminal, you have to pass `-` explicitly to read from it.",
|
||||||
|
args[0].display()
|
||||||
|
);
|
||||||
|
return Ok(ExitCode::FAILURE);
|
||||||
|
}
|
||||||
|
let file_path = args.get(1).filter(|v| *v != "-");
|
||||||
|
let input = if let Some(file_path) = file_path {
|
||||||
|
std::fs::read(file_path)?
|
||||||
|
} else {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
std::io::stdin().lock().read_to_end(&mut buf)?;
|
||||||
|
buf
|
||||||
|
};
|
||||||
|
let pdf = Pdf::parse(input)?;
|
||||||
|
if let PdfTrailer::Stream {
|
||||||
|
xref_stream,
|
||||||
|
start_xref,
|
||||||
|
} = pdf.trailer
|
||||||
|
{
|
||||||
|
dbg!(xref_stream.dictionary());
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!();
|
||||||
|
Ok(ExitCode::SUCCESS)
|
||||||
|
}
|
||||||
1746
src/pdf.rs
1746
src/pdf.rs
File diff suppressed because it is too large
Load diff
1111
src/pdf/object.rs
Normal file
1111
src/pdf/object.rs
Normal file
File diff suppressed because it is too large
Load diff
953
src/pdf/parse.rs
Normal file
953
src/pdf/parse.rs
Normal file
|
|
@ -0,0 +1,953 @@
|
||||||
|
use crate::pdf::object::{
|
||||||
|
MaybeArray, PdfInteger, PdfName, PdfNull, PdfObject, PdfObjectDirect, PdfObjectIdentifier,
|
||||||
|
PdfObjectIndirect, PdfObjectNonNull, PdfReal,
|
||||||
|
};
|
||||||
|
use std::{any::Any, borrow::Cow, fmt, mem, num::NonZero, sync::Arc};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
|
||||||
|
pub struct PdfInputPosition(Option<usize>);
|
||||||
|
|
||||||
|
impl fmt::Debug for PdfInputPosition {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("PdfInputPosition")
|
||||||
|
.field(&format_args!("{self}"))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PdfInputPosition {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if let Some(pos) = self.0 {
|
||||||
|
write!(f, "{pos:#x}")
|
||||||
|
} else {
|
||||||
|
f.write_str("<unknown>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfInputPosition {
|
||||||
|
pub const fn new(pos: usize) -> Self {
|
||||||
|
Self(Some(pos))
|
||||||
|
}
|
||||||
|
pub const fn empty() -> PdfInputPosition {
|
||||||
|
Self(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GetPdfInputPosition {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + GetPdfInputPosition> GetPdfInputPosition for &'_ T {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
T::get_pdf_input_position(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + GetPdfInputPosition> GetPdfInputPosition for &'_ mut T {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
T::get_pdf_input_position(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + GetPdfInputPosition> GetPdfInputPosition for Box<T> {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
T::get_pdf_input_position(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetPdfInputPosition for PdfInputPosition {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetPdfInputPosition for bool {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
PdfInputPosition::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetPdfInputPosition for i128 {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
PdfInputPosition::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetPdfInputPosition for f64 {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
PdfInputPosition::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
pub struct PdfInputPositionNoCompare(pub PdfInputPosition);
|
||||||
|
|
||||||
|
impl PdfInputPositionNoCompare {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self(PdfInputPosition::empty())
|
||||||
|
}
|
||||||
|
pub const fn new(pos: usize) -> Self {
|
||||||
|
Self(PdfInputPosition::new(pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetPdfInputPosition for PdfInputPositionNoCompare {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PdfInputPosition> for PdfInputPositionNoCompare {
|
||||||
|
fn from(value: PdfInputPosition) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for PdfInputPositionNoCompare {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("PdfInputPositionNoCompare")
|
||||||
|
.field(&format_args!("{self}"))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PdfInputPositionNoCompare {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for PdfInputPositionNoCompare {
|
||||||
|
fn cmp(&self, _other: &Self) -> std::cmp::Ordering {
|
||||||
|
std::cmp::Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for PdfInputPositionNoCompare {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for PdfInputPositionNoCompare {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {
|
||||||
|
// don't hash anything since Self always compares equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for PdfInputPositionNoCompare {}
|
||||||
|
|
||||||
|
impl PartialEq for PdfInputPositionNoCompare {
|
||||||
|
fn eq(&self, _other: &Self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum PdfParseError {
|
||||||
|
Custom(String),
|
||||||
|
InvalidType {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
ty: &'static str,
|
||||||
|
expected_ty: &'static str,
|
||||||
|
},
|
||||||
|
InvalidName {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
name: PdfName,
|
||||||
|
expected_ty: &'static str,
|
||||||
|
},
|
||||||
|
NotAPdfFile,
|
||||||
|
TruncatedFile {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
InvalidObjectNumber {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
InvalidGenerationNumber {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
InvalidNumber {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
InvalidStringEscape {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
InvalidHexStringDigit {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
DuplicateIndirectObjectDefinition {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
id: PdfObjectIdentifier,
|
||||||
|
},
|
||||||
|
MissingObj {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
MissingEndObj {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
InvalidDictionaryClosingDoubleRAngle {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
DuplicateDictionaryKey {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
name: PdfName,
|
||||||
|
},
|
||||||
|
InvalidNameEscape {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
InvalidOrMissingEolAfterStreamKeyword {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
MissingEndStreamKeyword {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
IntegerOutOfRange {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
MissingTrailer {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
WrongArrayLength {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
len: usize,
|
||||||
|
expected_len: usize,
|
||||||
|
},
|
||||||
|
MissingStartXRefKeyword {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
MissingStartXRefValue {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
MissingEofComment {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
},
|
||||||
|
UnexpectedByte {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
byte: u8,
|
||||||
|
},
|
||||||
|
InvalidStartXRefValue {
|
||||||
|
pos: PdfInputPosition,
|
||||||
|
start_xref: usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::convert::Infallible> for PdfParseError {
|
||||||
|
fn from(value: std::convert::Infallible) -> Self {
|
||||||
|
match value {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetPdfInputPosition for PdfParseError {
|
||||||
|
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||||
|
match *self {
|
||||||
|
PdfParseError::Custom(_) | PdfParseError::NotAPdfFile => PdfInputPosition::empty(),
|
||||||
|
PdfParseError::InvalidType { pos, .. }
|
||||||
|
| PdfParseError::InvalidName { pos, .. }
|
||||||
|
| PdfParseError::TruncatedFile { pos }
|
||||||
|
| PdfParseError::InvalidObjectNumber { pos }
|
||||||
|
| PdfParseError::InvalidGenerationNumber { pos }
|
||||||
|
| PdfParseError::InvalidNumber { pos }
|
||||||
|
| PdfParseError::InvalidStringEscape { pos }
|
||||||
|
| PdfParseError::InvalidHexStringDigit { pos }
|
||||||
|
| PdfParseError::DuplicateIndirectObjectDefinition { pos, .. }
|
||||||
|
| PdfParseError::MissingObj { pos }
|
||||||
|
| PdfParseError::MissingEndObj { pos }
|
||||||
|
| PdfParseError::InvalidDictionaryClosingDoubleRAngle { pos }
|
||||||
|
| PdfParseError::DuplicateDictionaryKey { pos, .. }
|
||||||
|
| PdfParseError::InvalidNameEscape { pos }
|
||||||
|
| PdfParseError::InvalidOrMissingEolAfterStreamKeyword { pos }
|
||||||
|
| PdfParseError::MissingEndStreamKeyword { pos }
|
||||||
|
| PdfParseError::IntegerOutOfRange { pos }
|
||||||
|
| PdfParseError::MissingTrailer { pos }
|
||||||
|
| PdfParseError::WrongArrayLength { pos, .. }
|
||||||
|
| PdfParseError::MissingStartXRefKeyword { pos }
|
||||||
|
| PdfParseError::MissingStartXRefValue { pos }
|
||||||
|
| PdfParseError::MissingEofComment { pos }
|
||||||
|
| PdfParseError::UnexpectedByte { pos, .. }
|
||||||
|
| PdfParseError::InvalidStartXRefValue { pos, .. } => pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PdfParseError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
PdfParseError::Custom(ref v) => f.write_str(v),
|
||||||
|
PdfParseError::InvalidType {
|
||||||
|
pos,
|
||||||
|
ty,
|
||||||
|
expected_ty,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"at {pos}: invalid type: expected {expected_ty}, got {ty}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidName {
|
||||||
|
pos,
|
||||||
|
ref name,
|
||||||
|
expected_ty,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"at {pos}: invalid name: expected a(n) {expected_ty}, got {name}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PdfParseError::NotAPdfFile => f.write_str("Not a PDF file"),
|
||||||
|
PdfParseError::TruncatedFile { pos } => {
|
||||||
|
write!(f, "at {pos}: PDF file is truncated too early")
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidObjectNumber { pos } => {
|
||||||
|
write!(f, "at {pos}: PDF object number is invalid")
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidGenerationNumber { pos } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"at {pos}: PDF object identifier's generation number is invalid"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidNumber { pos } => {
|
||||||
|
write!(f, "at {pos}: invalid number")
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidStringEscape { pos } => {
|
||||||
|
write!(f, "at {pos}: invalid string escape")
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidHexStringDigit { pos } => {
|
||||||
|
write!(f, "at {pos}: invalid hex string digit")
|
||||||
|
}
|
||||||
|
PdfParseError::DuplicateIndirectObjectDefinition { pos, id } => {
|
||||||
|
write!(f, "at {pos}: duplicate indirect object definition: {id:?}")
|
||||||
|
}
|
||||||
|
PdfParseError::MissingObj { pos } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"at {pos}: indirect object definition is missing `obj` keyword"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PdfParseError::MissingEndObj { pos } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"at {pos}: indirect object definition is missing `endobj` keyword"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidDictionaryClosingDoubleRAngle { pos } => {
|
||||||
|
write!(f, "at {pos}: dictionary has an invalid closing `>>` symbol")
|
||||||
|
}
|
||||||
|
PdfParseError::DuplicateDictionaryKey { pos, ref name } => {
|
||||||
|
write!(f, "at {pos}: duplicate dictionary key: {name}")
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidNameEscape { pos } => {
|
||||||
|
write!(f, "at {pos}: invalid name escape")
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidOrMissingEolAfterStreamKeyword { pos } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"at {pos}: invalid or missing end-of-line after `stream` keyword"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PdfParseError::MissingEndStreamKeyword { pos } => {
|
||||||
|
write!(f, "at {pos}: missing `endstream` keyword")
|
||||||
|
}
|
||||||
|
PdfParseError::IntegerOutOfRange { pos } => {
|
||||||
|
write!(f, "at {pos}: integer out of range")
|
||||||
|
}
|
||||||
|
PdfParseError::MissingTrailer { pos } => {
|
||||||
|
write!(f, "at {pos}: missing `trailer` keyword")
|
||||||
|
}
|
||||||
|
PdfParseError::WrongArrayLength {
|
||||||
|
pos,
|
||||||
|
len,
|
||||||
|
expected_len,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"at {pos}: wrong array length: expected {expected_len}, got {len}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PdfParseError::MissingStartXRefKeyword { pos } => {
|
||||||
|
write!(f, "at {pos}: missing `startxref` keyword")
|
||||||
|
}
|
||||||
|
PdfParseError::MissingStartXRefValue { pos } => {
|
||||||
|
write!(f, "at {pos}: missing `startxref` value")
|
||||||
|
}
|
||||||
|
PdfParseError::MissingEofComment { pos } => {
|
||||||
|
write!(f, "at {pos}: missing `%%EOF` comment")
|
||||||
|
}
|
||||||
|
PdfParseError::UnexpectedByte { pos, byte } => {
|
||||||
|
write!(f, "at {pos}: unexpected byte {}", byte.escape_ascii())
|
||||||
|
}
|
||||||
|
PdfParseError::InvalidStartXRefValue { pos, start_xref } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"at {pos}: invalid `startxref` value: {start_xref} ({start_xref:#x})"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for PdfParseError {}
|
||||||
|
|
||||||
|
pub trait PdfParse: Sized + 'static {
|
||||||
|
fn type_name() -> Cow<'static, str>;
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError>;
|
||||||
|
fn parse_option(object: PdfObject) -> Result<Option<Self>, PdfParseError> {
|
||||||
|
match object {
|
||||||
|
PdfObject::Null(_) => Ok(None),
|
||||||
|
PdfObject::Indirect(ref v) if v.get().is_null() => Ok(None),
|
||||||
|
PdfObject::Boolean(_)
|
||||||
|
| PdfObject::Integer(_)
|
||||||
|
| PdfObject::Real(_)
|
||||||
|
| PdfObject::String(_)
|
||||||
|
| PdfObject::Name(_)
|
||||||
|
| PdfObject::Array(_)
|
||||||
|
| PdfObject::Dictionary(_)
|
||||||
|
| PdfObject::Stream(_)
|
||||||
|
| PdfObject::Indirect(_) => Self::parse(object).map(Some),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PdfParse> PdfParse for Option<T> {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
T::type_name()
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
T::parse_option(object)
|
||||||
|
}
|
||||||
|
fn parse_option(object: PdfObject) -> Result<Option<Self>, PdfParseError> {
|
||||||
|
if matches!(object, PdfObject::Null(_)) {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Self::parse(object).map(Some)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_pdf_parse_prim_int {
|
||||||
|
($ty:ident) => {
|
||||||
|
impl PdfParse for $ty {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed(stringify!($ty))
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
let v: PdfInteger = PdfParse::parse(object)?;
|
||||||
|
v.value()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| PdfParseError::IntegerOutOfRange { pos: v.pos() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PdfParse for NonZero<$ty> {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed(concat!("NonZero<", stringify!($ty), ">"))
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
let v: PdfInteger = PdfParse::parse(object)?;
|
||||||
|
v.value()
|
||||||
|
.try_into()
|
||||||
|
.ok()
|
||||||
|
.and_then(NonZero::new)
|
||||||
|
.ok_or(PdfParseError::IntegerOutOfRange { pos: v.pos() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_pdf_parse_prim_int!(u8);
|
||||||
|
impl_pdf_parse_prim_int!(i8);
|
||||||
|
impl_pdf_parse_prim_int!(u16);
|
||||||
|
impl_pdf_parse_prim_int!(i16);
|
||||||
|
impl_pdf_parse_prim_int!(u32);
|
||||||
|
impl_pdf_parse_prim_int!(i32);
|
||||||
|
impl_pdf_parse_prim_int!(u64);
|
||||||
|
impl_pdf_parse_prim_int!(i64);
|
||||||
|
impl_pdf_parse_prim_int!(u128);
|
||||||
|
impl_pdf_parse_prim_int!(usize);
|
||||||
|
impl_pdf_parse_prim_int!(isize);
|
||||||
|
|
||||||
|
impl PdfParse for i128 {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("i128")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
let v: PdfInteger = PdfParse::parse(object)?;
|
||||||
|
Ok(v.value().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfParse for NonZero<i128> {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("NonZero<i128>")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
let v: PdfInteger = PdfParse::parse(object)?;
|
||||||
|
NonZero::new(v.value().into()).ok_or(PdfParseError::IntegerOutOfRange { pos: v.pos() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfParse for f64 {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("f64")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
Ok(<PdfReal as PdfParse>::parse(object)?.value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfParse for f32 {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("f32")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
Ok(<f64 as PdfParse>::parse(object)? as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfParse for PdfNull {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("null")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
match PdfObjectDirect::from(object) {
|
||||||
|
PdfObjectDirect::Null(v) => Ok(v),
|
||||||
|
object => Err(PdfParseError::InvalidType {
|
||||||
|
pos: object.pos(),
|
||||||
|
ty: object.type_name(),
|
||||||
|
expected_ty: "null",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_option(object: PdfObject) -> Result<Option<Self>, PdfParseError> {
|
||||||
|
Self::parse(object).map(Some)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfParse for PdfObjectNonNull {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("non-null")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
Option::<PdfObjectNonNull>::from(object).ok_or(PdfParseError::InvalidType {
|
||||||
|
pos: PdfInputPosition::empty(),
|
||||||
|
ty: "null",
|
||||||
|
expected_ty: "non-null",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn parse_option(object: PdfObject) -> Result<Option<Self>, PdfParseError> {
|
||||||
|
Ok(object.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfParse for PdfObjectDirect {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("direct object")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
Ok(object.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfParse for PdfObject {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("object")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
Ok(object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PdfParse for PdfObjectIndirect {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Borrowed("indirect object")
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
match object {
|
||||||
|
PdfObject::Indirect(v) => Ok(v),
|
||||||
|
_ => Err(PdfParseError::InvalidType {
|
||||||
|
pos: object.pos(),
|
||||||
|
ty: object.type_name(),
|
||||||
|
expected_ty: "indirect object",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_option(object: PdfObject) -> Result<Option<Self>, PdfParseError> {
|
||||||
|
match object {
|
||||||
|
PdfObject::Indirect(v) => Ok(Some(v)),
|
||||||
|
PdfObject::Null(_) => Ok(None),
|
||||||
|
_ => Err(PdfParseError::InvalidType {
|
||||||
|
pos: object.pos(),
|
||||||
|
ty: object.type_name(),
|
||||||
|
expected_ty: "indirect object",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PdfParse, const N: usize> PdfParse for [T; N] {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Owned(format!("[{}; {N}]", T::type_name()))
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
match PdfObjectDirect::from(object) {
|
||||||
|
PdfObjectDirect::Array(array) => {
|
||||||
|
let array_pos = array.pos();
|
||||||
|
let elements = array.into_elements();
|
||||||
|
let mut elements: Arc<[PdfObject; N]> =
|
||||||
|
elements.try_into().map_err(|elements: Arc<[PdfObject]>| {
|
||||||
|
PdfParseError::WrongArrayLength {
|
||||||
|
pos: array_pos,
|
||||||
|
len: elements.len(),
|
||||||
|
expected_len: N,
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
let elements: Box<[T]> = if let Some(elements) = Arc::get_mut(&mut elements) {
|
||||||
|
Result::from_iter(elements.iter_mut().map(|v| T::parse(mem::take(v))))?
|
||||||
|
} else {
|
||||||
|
Result::from_iter(elements.iter().map(|v| T::parse(v.clone())))?
|
||||||
|
};
|
||||||
|
Ok(*Box::<[T; N]>::try_from(elements)
|
||||||
|
.ok()
|
||||||
|
.expect("already checked length"))
|
||||||
|
}
|
||||||
|
object => Err(PdfParseError::InvalidType {
|
||||||
|
pos: object.pos(),
|
||||||
|
ty: object.type_name(),
|
||||||
|
expected_ty: "array",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PdfParse> PdfParse for Arc<[T]> {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Owned(format!("Arc<[{}]>", T::type_name()))
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
match PdfObjectDirect::from(object) {
|
||||||
|
PdfObjectDirect::Array(array) => {
|
||||||
|
let mut elements = array.into_elements();
|
||||||
|
if let Some(retval) = <dyn Any>::downcast_ref::<Self>(&elements) {
|
||||||
|
return Ok(retval.clone());
|
||||||
|
}
|
||||||
|
if let Some(elements) = Arc::get_mut(&mut elements) {
|
||||||
|
Result::from_iter(elements.iter_mut().map(|v| T::parse(mem::take(v))))
|
||||||
|
} else {
|
||||||
|
Result::from_iter(elements.iter().map(|v| T::parse(v.clone())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PdfObjectDirect::Null(_) => Ok(Self::default()),
|
||||||
|
object => Err(PdfParseError::InvalidType {
|
||||||
|
pos: object.pos(),
|
||||||
|
ty: object.type_name(),
|
||||||
|
expected_ty: "array",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PdfParse> PdfParse for MaybeArray<T> {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
Cow::Owned(format!("MaybeArray<{}>", T::type_name()))
|
||||||
|
}
|
||||||
|
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||||
|
match PdfObjectDirect::from(object) {
|
||||||
|
PdfObjectDirect::Null(_) => Ok(Self::default()),
|
||||||
|
PdfObjectDirect::Array(object) => Ok(Self(PdfParse::parse(object.into())?)),
|
||||||
|
object => Ok(Self(Arc::new([PdfParse::parse(object.into())?]))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pdf_parse {
|
||||||
|
(
|
||||||
|
$(#[$($struct_meta:tt)*])*
|
||||||
|
$struct_vis:vis struct $Struct:ident$(<$($StructParam:ident $(: $StructBound:tt)? $(= $StructParamDefault:ty)?),* $(,)?>)? {
|
||||||
|
$(#[pdf $($pdf_meta:tt)*]
|
||||||
|
$(#[$($field_meta:tt)*])*
|
||||||
|
$field_vis:vis $field_name:ident: $field_ty:ty,)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$(#[$($struct_meta)*])*
|
||||||
|
$struct_vis struct $Struct$(<$($StructParam $(: $StructBound)? $(= $StructParamDefault)?),*>)? {
|
||||||
|
$($(#[$($field_meta)*])*
|
||||||
|
$field_vis $field_name: $field_ty,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
$crate::pdf::parse::pdf_parse! {
|
||||||
|
@impl
|
||||||
|
struct $Struct$(<$($StructParam $(: $StructBound)?),*>)? {
|
||||||
|
$(#[pdf $($pdf_meta)*]
|
||||||
|
$(#[$($field_meta)*])*
|
||||||
|
$field_name: $field_ty,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl
|
||||||
|
struct $Struct:ident$(<$($StructParam:ident $(: $StructBound:tt)?),* $(,)?>)? {
|
||||||
|
$($(#[$($field_meta:tt)*])*
|
||||||
|
$field_name:ident: $field_ty:ty,)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
impl$(<$($StructParam: $crate::pdf::parse::PdfParse $(+ $StructBound)?),*>)? $crate::pdf::parse::PdfParse for $Struct$(<$($StructParam),*>)? {
|
||||||
|
fn type_name() -> $crate::__std::borrow::Cow<'static, $crate::__std::primitive::str> {
|
||||||
|
let args: &[$crate::__std::borrow::Cow<'static, $crate::__std::primitive::str>] = &[
|
||||||
|
$($(<$StructParam as $crate::pdf::parse::PdfParse>::type_name()),*)?
|
||||||
|
];
|
||||||
|
if args.is_empty() {
|
||||||
|
$crate::__std::borrow::Cow::Borrowed($crate::__std::stringify!($Struct))
|
||||||
|
} else {
|
||||||
|
let mut retval = $crate::__std::string::String::new();
|
||||||
|
retval.push_str($crate::__std::stringify!($Struct));
|
||||||
|
retval.push_str("<");
|
||||||
|
let mut first = true;
|
||||||
|
for arg in args {
|
||||||
|
if first {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
retval.push_str(", ");
|
||||||
|
}
|
||||||
|
retval.push_str(arg);
|
||||||
|
}
|
||||||
|
retval.push_str(">");
|
||||||
|
$crate::__std::borrow::Cow::Owned(retval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse(object: $crate::pdf::object::PdfObject) -> $crate::__std::result::Result<Self, $crate::pdf::parse::PdfParseError> {
|
||||||
|
let object = $crate::__std::convert::From::from(object);
|
||||||
|
let $crate::pdf::object::PdfObjectDirect::Dictionary(object) = object else {
|
||||||
|
return $crate::__std::result::Result::Err($crate::pdf::parse::PdfParseError::InvalidType {
|
||||||
|
pos: object.pos(),
|
||||||
|
ty: object.type_name(),
|
||||||
|
expected_ty: $crate::__std::stringify!($Struct),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let pos = object.pos();
|
||||||
|
let mut object = object.into_fields();
|
||||||
|
let object_mut = $crate::__std::sync::Arc::make_mut(&mut object);
|
||||||
|
let _ = object_mut;
|
||||||
|
$($crate::pdf::parse::pdf_parse! {
|
||||||
|
@impl_struct_field(pos, object, object_mut)
|
||||||
|
[]
|
||||||
|
$(#[$($field_meta)*])*
|
||||||
|
$field_name: $field_ty
|
||||||
|
})*
|
||||||
|
$crate::__std::result::Result::Ok(Self {
|
||||||
|
$($field_name,)*
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl_struct_field($pos:ident, $object:ident, $object_mut:ident)
|
||||||
|
[$(#[$($prev_field_meta:tt)*])*]
|
||||||
|
#[pdf $pdf_meta:tt]
|
||||||
|
$(#[$($field_meta:tt)*])*
|
||||||
|
$field_name:ident: $field_ty:ty
|
||||||
|
) => {
|
||||||
|
$crate::pdf::parse::pdf_parse! {
|
||||||
|
@impl_struct_field($pos, $object, $object_mut, pdf $pdf_meta)
|
||||||
|
[$(#[$($prev_field_meta)*])*]
|
||||||
|
$(#[$($field_meta)*])*
|
||||||
|
$field_name: $field_ty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl_struct_field($pos:ident, $object:ident, $object_mut:ident $($pdf_meta:tt)*)
|
||||||
|
[$(#[$($prev_field_meta:tt)*])*]
|
||||||
|
#[$($next_field_meta:tt)*]
|
||||||
|
$(#[$($field_meta:tt)*])*
|
||||||
|
$field_name:ident: $field_ty:ty
|
||||||
|
) => {
|
||||||
|
$crate::pdf::parse::pdf_parse! {
|
||||||
|
@impl_struct_field($pos, $object, $object_mut $($pdf_meta)*)
|
||||||
|
[$(#[$($prev_field_meta)*])* #[$($next_field_meta)*]]
|
||||||
|
$(#[$($field_meta)*])*
|
||||||
|
$field_name: $field_ty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl_struct_field($pos:ident, $object:ident, $object_mut:ident, pdf(flatten))
|
||||||
|
[$(#[$($field_meta:tt)*])*]
|
||||||
|
$field_name:ident: $field_ty:ty
|
||||||
|
) => {
|
||||||
|
let $field_name = <$field_ty as $crate::pdf::parse::PdfParse>::parse(
|
||||||
|
$crate::pdf::object::PdfObject::Dictionary(
|
||||||
|
$crate::pdf::object::PdfDictionary::from_fields($pos, $object),
|
||||||
|
),
|
||||||
|
)?;
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl_struct_field($pos:ident, $object:ident, $object_mut:ident, pdf(name = $name:expr))
|
||||||
|
[$(#[$($field_meta:tt)*])*]
|
||||||
|
$field_name:ident: $field_ty:ty
|
||||||
|
) => {
|
||||||
|
let $field_name = $crate::pdf::object::PdfName::new_static(
|
||||||
|
$crate::__std::convert::AsRef::<[u8]>::as_ref($name),
|
||||||
|
);
|
||||||
|
let $field_name = <$field_ty as $crate::pdf::parse::PdfParse>::parse(
|
||||||
|
$object_mut
|
||||||
|
.remove(&$field_name)
|
||||||
|
.unwrap_or($crate::pdf::object::PdfObject::Null($crate::pdf::object::PdfNull::new($pos))),
|
||||||
|
)?;
|
||||||
|
};
|
||||||
|
(
|
||||||
|
$(#[$($enum_meta:tt)*])*
|
||||||
|
$enum_vis:vis enum $Enum:ident {
|
||||||
|
$(#[pdf $($pdf_meta:tt)*]
|
||||||
|
$(#[$($variant_meta:tt)*])*
|
||||||
|
$VariantName:ident $(($($variant_paren_body:tt)*))? $({$($variant_brace_body:tt)*})?,)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$(#[$($enum_meta)*])*
|
||||||
|
$enum_vis enum $Enum {
|
||||||
|
$($(#[$($variant_meta)*])*
|
||||||
|
$VariantName $(($($variant_paren_body)*))? $({$($variant_brace_body)*})?,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
$crate::pdf::parse::pdf_parse! {
|
||||||
|
@impl
|
||||||
|
$(#[$($enum_meta)*])*
|
||||||
|
enum $Enum {
|
||||||
|
$(#[pdf $($pdf_meta)*]
|
||||||
|
$(#[$($variant_meta)*])*
|
||||||
|
$VariantName $(($($variant_paren_body)*))? $({$($variant_brace_body)*})?,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl
|
||||||
|
$(#[$($enum_meta:tt)*])*
|
||||||
|
enum $Enum:ident {
|
||||||
|
$(#[pdf(name = $name:expr)]
|
||||||
|
$(#[$($variant_meta:tt)*])*
|
||||||
|
$VariantName:ident,)*
|
||||||
|
$(#[pdf(other)]
|
||||||
|
$(#[$($variant_meta_other:tt)*])*
|
||||||
|
$VariantNameOther:ident($($PdfName:tt)*),)?
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
impl $crate::__std::convert::From<$Enum> for $crate::pdf::object::PdfName {
|
||||||
|
fn from(value: $Enum) -> Self {
|
||||||
|
match value {
|
||||||
|
$($Enum::$VariantName => $crate::pdf::object::PdfName::new_static(
|
||||||
|
$crate::__std::convert::AsRef::<[u8]>::as_ref($name),
|
||||||
|
),)*
|
||||||
|
$($Enum::$VariantNameOther(v) => $crate::__std::convert::Into::into(v),)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$crate::pdf::parse::pdf_parse! {
|
||||||
|
@impl_try_from
|
||||||
|
$(#[$($enum_meta)*])*
|
||||||
|
enum $Enum {
|
||||||
|
$(#[pdf(name = $name)]
|
||||||
|
$(#[$($variant_meta)*])*
|
||||||
|
$VariantName,)*
|
||||||
|
$(#[pdf(other)]
|
||||||
|
$(#[$($variant_meta_other)*])*
|
||||||
|
$VariantNameOther($($PdfName)*),)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::pdf::parse::PdfParse for $Enum {
|
||||||
|
fn type_name() -> $crate::__std::borrow::Cow<'static, $crate::__std::primitive::str> {
|
||||||
|
$crate::__std::borrow::Cow::Borrowed($crate::__std::stringify!($Struct))
|
||||||
|
}
|
||||||
|
fn parse(object: $crate::pdf::object::PdfObject) -> $crate::__std::result::Result<Self, $crate::pdf::parse::PdfParseError> {
|
||||||
|
let object = $crate::__std::convert::From::from(object);
|
||||||
|
let $crate::pdf::object::PdfObjectDirect::Name(name) = object else {
|
||||||
|
return $crate::__std::result::Result::Err($crate::pdf::parse::PdfParseError::InvalidType {
|
||||||
|
pos: object.pos(),
|
||||||
|
ty: object.type_name(),
|
||||||
|
expected_ty: $crate::__std::stringify!($Struct),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
$crate::__std::result::Result::Ok($crate::__std::convert::TryInto::<$Enum>::try_into(name)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl_try_from
|
||||||
|
$(#[$($enum_meta:tt)*])*
|
||||||
|
enum $Enum:ident {
|
||||||
|
$(#[pdf(name = $name:expr)]
|
||||||
|
$(#[$($variant_meta:tt)*])*
|
||||||
|
$VariantName:ident,)*
|
||||||
|
#[pdf(other)]
|
||||||
|
$(#[$($variant_meta_other:tt)*])*
|
||||||
|
$VariantNameOther:ident(PdfName),
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
impl $crate::__std::convert::From<$crate::pdf::object::PdfName> for $Enum {
|
||||||
|
fn from(name: $crate::pdf::object::PdfName) -> Self {
|
||||||
|
$(if name == $crate::pdf::object::PdfName::new_static(
|
||||||
|
$crate::__std::convert::AsRef::<[u8]>::as_ref($name),
|
||||||
|
) {
|
||||||
|
$Enum::$VariantName
|
||||||
|
} else)* {
|
||||||
|
$Enum::$VariantNameOther(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl_try_from
|
||||||
|
$(#[$($enum_meta:tt)*])*
|
||||||
|
enum $Enum:ident {
|
||||||
|
$(#[pdf(name = $name:expr)]
|
||||||
|
$(#[$($variant_meta:tt)*])*
|
||||||
|
$VariantName:ident,)*
|
||||||
|
#[pdf(other)]
|
||||||
|
$(#[$($variant_meta_other:tt)*])*
|
||||||
|
$VariantNameOther:ident($PdfName:ty),
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
impl $crate::__std::convert::TryFrom<$crate::pdf::object::PdfName> for $Enum {
|
||||||
|
type Error = $crate::pdf::parse::PdfParseError;
|
||||||
|
|
||||||
|
fn try_from(name: $crate::pdf::object::PdfName) -> $crate::__std::result::Result<Self, $crate::pdf::parse::PdfParseError> {
|
||||||
|
$(if name == $crate::pdf::object::PdfName::new_static(
|
||||||
|
$crate::__std::convert::AsRef::<[u8]>::as_ref($name),
|
||||||
|
) {
|
||||||
|
$crate::__std::result::Result::Ok($Enum::$VariantName)
|
||||||
|
} else)* {
|
||||||
|
$crate::__std::result::Result::Ok($Enum::$VariantNameOther($crate::__std::convert::TryInto::<$PdfName>::try_into(name)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl_try_from
|
||||||
|
$(#[$($enum_meta:tt)*])*
|
||||||
|
enum $Enum:ident {
|
||||||
|
$(#[pdf(name = $name:expr)]
|
||||||
|
$(#[$($variant_meta:tt)*])*
|
||||||
|
$VariantName:ident,)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
impl $crate::__std::convert::TryFrom<$crate::pdf::object::PdfName> for $Enum {
|
||||||
|
type Error = $crate::pdf::parse::PdfParseError;
|
||||||
|
|
||||||
|
fn try_from(name: $crate::pdf::object::PdfName) -> $crate::__std::result::Result<Self, $crate::pdf::parse::PdfParseError> {
|
||||||
|
$(if name == $crate::pdf::object::PdfName::new_static(
|
||||||
|
$crate::__std::convert::AsRef::<[u8]>::as_ref($name),
|
||||||
|
) {
|
||||||
|
$crate::__std::result::Result::Ok($Enum::$VariantName)
|
||||||
|
} else)* {
|
||||||
|
$crate::__std::result::Result::Err($crate::pdf::parse::PdfParseError::InvalidName {
|
||||||
|
pos: name.pos(),
|
||||||
|
name,
|
||||||
|
expected_ty: $crate::__std::stringify!($Struct),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use pdf_parse;
|
||||||
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) enum ArcOrRef<'a, T: ?Sized> {
|
pub enum ArcOrRef<'a, T: ?Sized> {
|
||||||
Arc(Arc<T>),
|
Arc(Arc<T>),
|
||||||
Ref(&'a T),
|
Ref(&'a T),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue