///|
/// Object data state during parsing or decryption.
pub(all) enum ObjectData {
Parsed(PdfObject)
ParsedAlreadyDecrypted(PdfObject)
ToParse
ToParseFromObjectStream(
Map[Int, Array[Int]],
Int,
Int,
(Int, Array[Int]) -> Array[(Int, (Ref[ObjectData], Int))]
)
}
///|
type PdfObjMapKey = Int
///|
type PdfObjMapEntry = (Ref[ObjectData], Int)
///|
pub type PdfObjMap = Map[Int, (Ref[ObjectData], Int)]
///|
/// Container for document objects.
pub(all) struct PdfObjects {
mut max_obj_num : Int
parse : ((PdfObjMapKey) -> PdfObject)?
objects : PdfObjMap
object_stream_ids : Map[Int, Int]
}
///|
/// In-memory PDF document.
pub(all) struct Pdf {
major : Int
minor : Int
root : Int
objects : PdfObjects
mut trailerdict : PdfObject
was_linearized : Bool
mut saved_encryption : SavedEncryption?
}
///|
pub fn pdfobjmap_empty() -> PdfObjMap {
Map::new()
}
///|
pub fn pdfobjmap_find(
key : PdfObjMapKey,
map : PdfObjMap,
) -> PdfObjMapEntry raise {
match map.get(key) {
Some(entry) => entry
None => fail("Not_found")
}
}
///|
pub fn pdfobjmap_bindings(
map : PdfObjMap,
) -> Array[(PdfObjMapKey, PdfObjMapEntry)] {
map.to_array()
}
///|
/// The empty document (PDF 2.0, no objects, no root, empty trailer dictionary).
pub fn Pdf::empty() -> Pdf {
{
major: 2,
minor: 0,
root: 0,
objects: {
max_obj_num: 0,
parse: None,
objects: pdfobjmap_empty(),
object_stream_ids: Map::new(),
},
trailerdict: Dictionary([]),
was_linearized: false,
saved_encryption: None,
}
}
///|
/// Return the size of the object map.
pub fn Pdf::objcard(self : Pdf) -> Int {
self.objects.objects.length()
}
///|
/// Return the object numbers in ascending order.
pub fn Pdf::objnumbers(self : Pdf) -> Array[Int] {
let entries = self.objects.objects.to_array()
entries.sort_by((a, b) => a.0 - b.0)
entries.map(pair => pair.0)
}
///|
/// Remove the given object.
pub fn Pdf::removeobj(self : Pdf, objnum : Int) -> Unit {
self.objects.objects.remove(objnum)
}
///|
/// Add an object. Returns the number chosen.
pub fn Pdf::addobj(self : Pdf, obj : PdfObject) -> Int {
let next = self.objects.max_obj_num + 1
self.addobj_given_num((next, obj))
next
}
///|
/// Same as addobj, but pick a number ourselves.
pub fn Pdf::addobj_given_num(self : Pdf, pair : (Int, PdfObject)) -> Unit {
let (num, obj) = pair
if num > self.objects.max_obj_num {
self.objects.max_obj_num = num
}
self.objects.objects.set(num, ({ val: Parsed(obj) }, 0))
}
///|
/// Return the document catalog.
pub fn Pdf::catalog_of_pdf(self : Pdf) -> PdfObject raise {
let obj = self.lookup_obj(self.root)
match obj {
Null => raise PdfError::Msg("No catalog")
_ => obj
}
}
///|
fn deep_copy_pdfobjects(from : Pdf) -> PdfObjMap {
let out : PdfObjMap = Map::new(capacity=from.objects.objects.length())
for objnum, entry in from.objects.objects {
let (obj_ref, gen) = entry
out.set(objnum, (Ref::new(deep_copy_objdata(obj_ref.val)), gen))
}
out
}