diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 4c77ebf..cc5fe12 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 848f7a2..8d00138 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -2,7 +2,6 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
-# Required
version: 2
build:
@@ -11,13 +10,11 @@ build:
python: "3.11"
sphinx:
- configuration: manual/conf.py
+ configuration: manual/conf.py
+ fail_on_warning: true
formats: all
-sphinx:
- fail_on_warning: true
-
python:
install:
- requirements: manual/requirements.txt
diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt
index 6b3cccf..029ed05 100644
--- a/fuzz/CMakeLists.txt
+++ b/fuzz/CMakeLists.txt
@@ -142,9 +142,6 @@ set(CORPUS_OTHER
70306b.fuzz
71624.fuzz
71689.fuzz
- 99999a.fuzz
- 99999b.fuzz
- 99999c.fuzz
99999d.fuzz
99999e.fuzz
369662293.fuzz
diff --git a/fuzz/qpdf_extra/99999a.fuzz b/fuzz/qpdf_extra/99999a.fuzz
deleted file mode 100644
index 026c742..0000000
--- a/fuzz/qpdf_extra/99999a.fuzz
+++ /dev/null
@@ -1,63 +0,0 @@
-%PDF-1.5
-%€€€€
-1 0 obj
-<<
- /Type /Catalog
- /Pages 2 0 R
->>
-endobj
-2 0 obj
-<<
- /Count 6 Ri
- 0K/ds [3 0 R]
- /Type /Pages
->>
-endobj
-3 0 obj
-<<
- /Resources <<
- /Font <<
- /F1 5 0 R
- >>
- >>
- /MediaBox [0 0 795 842]
- /Parent 2 0 R
- /Contents 4 0 R
- /Type /Page
-=>
-endobj
-4 0 obj
-<<444444444444444444444444 1 Tr /F1 30 Tf 350 750 Td (foobar) Tj ET
-endstream
-endobj
-5 0 obj
-<<
- /Name /F1
- /BaseFont /Helvetica
- /Type /Font
- /Subtype /Type1
->>
-e„dobj
-6 0 obj
-<< /Length 6 0 R >>
-stre444444444444444444444444444444<<>>
-endobj
-xref
-0 8
-0000000000 65535 f
-0000000015 00000 n
-0000000066 00000 n
-0000000130 00000 n
-0000000269 00000 n
-0000000362 00000 n
-000000ÎËËÉßÏÏÏ00 n
-0000000500 00000 n
-trailer
-<<
- /Size 713115528178535
- /Root 1 0 R
- /Info 7 0 R
->>
-startxref
-520
-%%EOF
\ No newline at end of file
diff --git a/fuzz/qpdf_extra/99999b.fuzz b/fuzz/qpdf_extra/99999b.fuzz
deleted file mode 100644
index 288a6b5..0000000
--- a/fuzz/qpdf_extra/99999b.fuzz
+++ /dev/null
diff --git a/fuzz/qpdf_extra/99999c.fuzz b/fuzz/qpdf_extra/99999c.fuzz
deleted file mode 100644
index c856648..0000000
--- a/fuzz/qpdf_extra/99999c.fuzz
+++ /dev/null
diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test
index efffdc6..cf38a63 100644
--- a/fuzz/qtest/fuzz.test
+++ b/fuzz/qtest/fuzz.test
@@ -11,7 +11,7 @@ my $td = new TestDriver('fuzz');
my $qpdf_corpus = $ENV{'QPDF_FUZZ_CORPUS'} || die "must set QPDF_FUZZ_CORPUS";
-my $n_qpdf_files = 87; # increment when adding new files
+my $n_qpdf_files = 84; # increment when adding new files
my @fuzzers = (
['ascii85' => 1],
diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh
index 756b22d..11bc807 100644
--- a/include/qpdf/QPDF.hh
+++ b/include/qpdf/QPDF.hh
@@ -391,7 +391,7 @@ class QPDF
void replaceObject(int objid, int generation, QPDFObjectHandle);
// Swap two objects given by ID. Prior to qpdf 10.2.1, existing QPDFObjectHandle instances that
- // reference the objects did not notice the swap, but this was fixed in 10.2.1.
+ // reference them objects not notice the swap, but this was fixed in 10.2.1.
QPDF_DLL
void swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2);
QPDF_DLL
@@ -645,7 +645,7 @@ class QPDF
QPDF_DLL
void fixDanglingReferences(bool force = false);
- // Return the approximate number of indirect objects. It is approximate because not all objects
+ // Return the approximate number of indirect objects. It is/ approximate because not all objects
// in the file are preserved in all cases, and gaps in object numbering are not preserved.
QPDF_DLL
size_t getObjectCount();
@@ -725,15 +725,165 @@ class QPDF
void removePage(QPDFObjectHandle page);
// End legacy page helpers
- // End of the public API. The following classes and methods are for qpdf internal use only.
+ // Writer class is restricted to QPDFWriter so that only it can call certain methods.
+ class Writer
+ {
+ friend class QPDFWriter;
+
+ private:
+ static void
+ optimize(
+ QPDF& qpdf,
+ QPDFWriter::ObjTable const& obj,
+ std::function skip_stream_parameters)
+ {
+ return qpdf.optimize(obj, skip_stream_parameters);
+ }
+
+ static void
+ getLinearizedParts(
+ QPDF& qpdf,
+ QPDFWriter::ObjTable const& obj,
+ std::vector& part4,
+ std::vector& part6,
+ std::vector& part7,
+ std::vector& part8,
+ std::vector& part9)
+ {
+ qpdf.getLinearizedParts(obj, part4, part6, part7, part8, part9);
+ }
+
+ static void
+ generateHintStream(
+ QPDF& qpdf,
+ QPDFWriter::NewObjTable const& new_obj,
+ QPDFWriter::ObjTable const& obj,
+ std::shared_ptr& hint_stream,
+ int& S,
+ int& O,
+ bool compressed)
+ {
+ return qpdf.generateHintStream(new_obj, obj, hint_stream, S, O, compressed);
+ }
+
+ static std::vector
+ getCompressibleObjGens(QPDF& qpdf)
+ {
+ return qpdf.getCompressibleObjVector();
+ }
+
+ static std::vector
+ getCompressibleObjSet(QPDF& qpdf)
+ {
+ return qpdf.getCompressibleObjSet();
+ }
+
+ static std::map const&
+ getXRefTable(QPDF& qpdf)
+ {
+ return qpdf.getXRefTableInternal();
+ }
+
+ static size_t
+ tableSize(QPDF& qpdf)
+ {
+ return qpdf.tableSize();
+ }
+ };
- class Writer;
- class Resolver;
- class StreamCopier;
- class Objects;
- class ParseGuard;
- class Pipe;
- class JobSetter;
+ // The Resolver class is restricted to QPDFObject so that only it can resolve indirect
+ // references.
+ class Resolver
+ {
+ friend class QPDFObject;
+ friend class QPDF_Unresolved;
+
+ private:
+ static QPDFObject*
+ resolved(QPDF* qpdf, QPDFObjGen og)
+ {
+ return qpdf->resolve(og);
+ }
+ };
+
+ // StreamCopier class is restricted to QPDFObjectHandle so it can copy stream data.
+ class StreamCopier
+ {
+ friend class QPDFObjectHandle;
+
+ private:
+ static void
+ copyStreamData(QPDF* qpdf, QPDFObjectHandle const& dest, QPDFObjectHandle const& src)
+ {
+ qpdf->copyStreamData(dest, src);
+ }
+ };
+
+ // The ParseGuard class allows QPDFParser to detect re-entrant parsing. It also provides
+ // special access to allow the parser to create unresolved objects and dangling references.
+ class ParseGuard
+ {
+ friend class QPDFParser;
+
+ private:
+ ParseGuard(QPDF* qpdf) :
+ qpdf(qpdf)
+ {
+ if (qpdf) {
+ qpdf->inParse(true);
+ }
+ }
+
+ static std::shared_ptr
+ getObject(QPDF* qpdf, int id, int gen, bool parse_pdf)
+ {
+ return qpdf->getObjectForParser(id, gen, parse_pdf);
+ }
+
+ ~ParseGuard()
+ {
+ if (qpdf) {
+ qpdf->inParse(false);
+ }
+ }
+ QPDF* qpdf;
+ };
+
+ // Pipe class is restricted to QPDF_Stream.
+ class Pipe
+ {
+ friend class QPDF_Stream;
+
+ private:
+ static bool
+ pipeStreamData(
+ QPDF* qpdf,
+ QPDFObjGen const& og,
+ qpdf_offset_t offset,
+ size_t length,
+ QPDFObjectHandle dict,
+ Pipeline* pipeline,
+ bool suppress_warnings,
+ bool will_retry)
+ {
+ return qpdf->pipeStreamData(
+ og, offset, length, dict, pipeline, suppress_warnings, will_retry);
+ }
+ };
+
+ // JobSetter class is restricted to QPDFJob.
+ class JobSetter
+ {
+ friend class QPDFJob;
+
+ private:
+ // Enable enhanced warnings for pdf file checking.
+ static void
+ setCheckMode(QPDF& qpdf, bool val)
+ {
+ qpdf.m->check_mode = val;
+ }
+ };
// For testing only -- do not add to DLL
static bool test_json_validators();
@@ -748,23 +898,194 @@ class QPDF
static std::string const qpdf_version;
- class ObjCopier;
- class EncryptionParameters;
- class ForeignStreamData;
- class CopiedStreamDataProvider;
- class StringDecrypter;
- class ResolveRecorder;
+ class ObjCache
+ {
+ public:
+ ObjCache() :
+ end_before_space(0),
+ end_after_space(0)
+ {
+ }
+ ObjCache(
+ std::shared_ptr object,
+ qpdf_offset_t end_before_space = 0,
+ qpdf_offset_t end_after_space = 0) :
+ object(object),
+ end_before_space(end_before_space),
+ end_after_space(end_after_space)
+ {
+ }
+
+ std::shared_ptr object;
+ qpdf_offset_t end_before_space;
+ qpdf_offset_t end_after_space;
+ };
+
+ class ObjCopier
+ {
+ public:
+ std::map object_map;
+ std::vector to_copy;
+ QPDFObjGen::set visiting;
+ };
+
+ class EncryptionParameters
+ {
+ friend class QPDF;
+
+ public:
+ EncryptionParameters();
+
+ private:
+ bool encrypted;
+ bool encryption_initialized;
+ int encryption_V;
+ int encryption_R;
+ bool encrypt_metadata;
+ std::map crypt_filters;
+ encryption_method_e cf_stream;
+ encryption_method_e cf_string;
+ encryption_method_e cf_file;
+ std::string provided_password;
+ std::string user_password;
+ std::string encryption_key;
+ std::string cached_object_encryption_key;
+ QPDFObjGen cached_key_og;
+ bool user_password_matched;
+ bool owner_password_matched;
+ };
+
+ class ForeignStreamData
+ {
+ friend class QPDF;
+
+ public:
+ ForeignStreamData(
+ std::shared_ptr encp,
+ std::shared_ptr file,
+ QPDFObjGen const& foreign_og,
+ qpdf_offset_t offset,
+ size_t length,
+ QPDFObjectHandle local_dict);
+
+ private:
+ std::shared_ptr encp;
+ std::shared_ptr file;
+ QPDFObjGen foreign_og;
+ qpdf_offset_t offset;
+ size_t length;
+ QPDFObjectHandle local_dict;
+ };
+
+ class CopiedStreamDataProvider: public QPDFObjectHandle::StreamDataProvider
+ {
+ public:
+ CopiedStreamDataProvider(QPDF& destination_qpdf);
+ ~CopiedStreamDataProvider() override = default;
+ bool provideStreamData(
+ QPDFObjGen const& og,
+ Pipeline* pipeline,
+ bool suppress_warnings,
+ bool will_retry) override;
+ void registerForeignStream(QPDFObjGen const& local_og, QPDFObjectHandle foreign_stream);
+ void registerForeignStream(QPDFObjGen const& local_og, std::shared_ptr);
+
+ private:
+ QPDF& destination_qpdf;
+ std::map foreign_streams;
+ std::map> foreign_stream_data;
+ };
+
+ class StringDecrypter: public QPDFObjectHandle::StringDecrypter
+ {
+ friend class QPDF;
+
+ public:
+ StringDecrypter(QPDF* qpdf, QPDFObjGen const& og);
+ ~StringDecrypter() override = default;
+ void decryptString(std::string& val) override;
+
+ private:
+ QPDF* qpdf;
+ QPDFObjGen og;
+ };
+
+ class ResolveRecorder
+ {
+ public:
+ ResolveRecorder(QPDF* qpdf, QPDFObjGen const& og) :
+ qpdf(qpdf),
+ iter(qpdf->m->resolving.insert(og).first)
+ {
+ }
+ virtual ~ResolveRecorder()
+ {
+ this->qpdf->m->resolving.erase(iter);
+ }
+
+ private:
+ QPDF* qpdf;
+ std::set::const_iterator iter;
+ };
+
class JSONReactor;
- inline Objects& objects() noexcept;
- inline Objects const& objects() const noexcept;
void parse(char const* password);
void inParse(bool);
+ void setTrailer(QPDFObjectHandle obj);
+ void read_xref(qpdf_offset_t offset);
+ bool resolveXRefTable();
+ void reconstruct_xref(QPDFExc& e);
+ bool parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes);
+ bool read_xrefEntry(qpdf_offset_t& f1, int& f2, char& type);
+ bool read_bad_xrefEntry(qpdf_offset_t& f1, int& f2, char& type);
+ qpdf_offset_t read_xrefTable(qpdf_offset_t offset);
+ qpdf_offset_t read_xrefStream(qpdf_offset_t offset);
+ qpdf_offset_t processXRefStream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream);
+ std::pair>
+ processXRefW(QPDFObjectHandle& dict, std::function damaged);
+ int processXRefSize(
+ QPDFObjectHandle& dict, int entry_size, std::function damaged);
+ std::pair>> processXRefIndex(
+ QPDFObjectHandle& dict,
+ int max_num_entries,
+ std::function damaged);
+ void insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2);
+ void insertFreeXrefEntry(QPDFObjGen);
+ void insertReconstructedXrefEntry(int obj, qpdf_offset_t f1, int f2);
void setLastObjectDescription(std::string const& description, QPDFObjGen const& og);
+ QPDFObjectHandle readTrailer();
+ QPDFObjectHandle readObject(std::string const& description, QPDFObjGen og);
+ void readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset);
+ void validateStreamLineEnd(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset);
+ QPDFObjectHandle readObjectInStream(std::shared_ptr& input, int obj);
+ size_t recoverStreamLength(
+ std::shared_ptr input, QPDFObjGen const& og, qpdf_offset_t stream_offset);
QPDFTokenizer::Token readToken(InputSource&, size_t max_len = 0);
+ QPDFObjectHandle readObjectAtOffset(
+ bool attempt_recovery,
+ qpdf_offset_t offset,
+ std::string const& description,
+ QPDFObjGen exp_og,
+ QPDFObjGen& og,
+ bool skip_cache_if_in_xref);
+ QPDFObject* resolve(QPDFObjGen og);
+ void resolveObjectsInStream(int obj_stream_number);
void stopOnError(std::string const& message);
+ QPDFObjGen nextObjGen();
QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr const&);
+ QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr const& obj);
+ bool isCached(QPDFObjGen const& og);
+ bool isUnresolved(QPDFObjGen const& og);
+ std::shared_ptr getObjectForParser(int id, int gen, bool parse_pdf);
+ std::shared_ptr getObjectForJSON(int id, int gen);
+ void removeObject(QPDFObjGen og);
+ void updateCache(
+ QPDFObjGen const& og,
+ std::shared_ptr const& object,
+ qpdf_offset_t end_before_space,
+ qpdf_offset_t end_after_space);
static QPDFExc damagedPDF(
InputSource& input,
std::string const& object,
@@ -801,6 +1122,7 @@ class QPDF
// For QPDFWriter:
+ std::map const& getXRefTableInternal();
template
void optimize_internal(
T const& object_stream_data,
@@ -809,7 +1131,7 @@ class QPDF
void optimize(
QPDFWriter::ObjTable const& obj,
std::function skip_stream_parameters);
- void optimize(Objects const& obj);
+ size_t tableSize();
// Get lists of all objects in order according to the part of a linearized file that they belong
// to.
@@ -829,6 +1151,12 @@ class QPDF
int& O,
bool compressed);
+ // Get a list of objects that would be permitted in an object stream.
+ template
+ std::vector getCompressibleObjGens();
+ std::vector getCompressibleObjVector();
+ std::vector getCompressibleObjSet();
+
// methods to support page handling
void getAllPagesInternal(
@@ -868,19 +1196,200 @@ class QPDF
replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top);
void copyStreamData(QPDFObjectHandle dest_stream, QPDFObjectHandle src_stream);
- struct HPageOffsetEntry;
- struct HPageOffset;
- struct HSharedObjectEntry;
- struct HSharedObject;
- struct HGeneric;
- struct LinParameters;
- struct CHPageOffsetEntry;
- struct CHPageOffset;
- struct CHSharedObjectEntry;
- struct CHSharedObject;
- class ObjUser;
- struct UpdateObjectMapsFrame;
- class PatternFinder;
+ // Linearization Hint table structures.
+ // Naming conventions:
+
+ // HSomething is the Something Hint Table or table header
+ // HSomethingEntry is an entry in the Something table
+
+ // delta_something + min_something = something
+ // nbits_something = number of bits required for something
+
+ // something_offset is the pre-adjusted offset in the file. If >=
+ // H0_offset, H0_length must be added to get an actual file
+ // offset.
+
+ // PDF 1.4: Table F.4
+ struct HPageOffsetEntry
+ {
+ int delta_nobjects{0}; // 1
+ qpdf_offset_t delta_page_length{0}; // 2
+ // vectors' sizes = nshared_objects
+ int nshared_objects{0}; // 3
+ std::vector shared_identifiers; // 4
+ std::vector shared_numerators; // 5
+ qpdf_offset_t delta_content_offset{0}; // 6
+ qpdf_offset_t delta_content_length{0}; // 7
+ };
+
+ // PDF 1.4: Table F.3
+ struct HPageOffset
+ {
+ int min_nobjects{0}; // 1
+ qpdf_offset_t first_page_offset{0}; // 2
+ int nbits_delta_nobjects{0}; // 3
+ int min_page_length{0}; // 4
+ int nbits_delta_page_length{0}; // 5
+ int min_content_offset{0}; // 6
+ int nbits_delta_content_offset{0}; // 7
+ int min_content_length{0}; // 8
+ int nbits_delta_content_length{0}; // 9
+ int nbits_nshared_objects{0}; // 10
+ int nbits_shared_identifier{0}; // 11
+ int nbits_shared_numerator{0}; // 12
+ int shared_denominator{0}; // 13
+ // vector size is npages
+ std::vector entries;
+ };
+
+ // PDF 1.4: Table F.6
+ struct HSharedObjectEntry
+ {
+ // Item 3 is a 128-bit signature (unsupported by Acrobat)
+ int delta_group_length{0}; // 1
+ int signature_present{0}; // 2 -- always 0
+ int nobjects_minus_one{0}; // 4 -- always 0
+ };
+
+ // PDF 1.4: Table F.5
+ struct HSharedObject
+ {
+ int first_shared_obj{0}; // 1
+ qpdf_offset_t first_shared_offset{0}; // 2
+ int nshared_first_page{0}; // 3
+ int nshared_total{0}; // 4
+ int nbits_nobjects{0}; // 5
+ int min_group_length{0}; // 6
+ int nbits_delta_group_length{0}; // 7
+ // vector size is nshared_total
+ std::vector entries;
+ };
+
+ // PDF 1.4: Table F.9
+ struct HGeneric
+ {
+ int first_object{0}; // 1
+ qpdf_offset_t first_object_offset{0}; // 2
+ int nobjects{0}; // 3
+ int group_length{0}; // 4
+ };
+
+ // Other linearization data structures
+
+ // Initialized from Linearization Parameter dictionary
+ struct LinParameters
+ {
+ qpdf_offset_t file_size{0}; // /L
+ int first_page_object{0}; // /O
+ qpdf_offset_t first_page_end{0}; // /E
+ int npages{0}; // /N
+ qpdf_offset_t xref_zero_offset{0}; // /T
+ int first_page{0}; // /P
+ qpdf_offset_t H_offset{0}; // offset of primary hint stream
+ qpdf_offset_t H_length{0}; // length of primary hint stream
+ };
+
+ // Computed hint table value data structures. These tables contain the computed values on which
+ // the hint table values are based. They exclude things like number of bits and store actual
+ // values instead of mins and deltas. File offsets are also absolute rather than being offset
+ // by the size of the primary hint table. We populate the hint table structures from these
+ // during writing and compare the hint table values with these during validation. We ignore
+ // some values for various reasons described in the code. Those values are omitted from these
+ // structures. Note also that object numbers are object numbers from the input file, not the
+ // output file.
+
+ // Naming convention: CHSomething is analogous to HSomething above. "CH" is computed hint.
+
+ struct CHPageOffsetEntry
+ {
+ int nobjects{0};
+ int nshared_objects{0};
+ // vectors' sizes = nshared_objects
+ std::vector shared_identifiers;
+ };
+
+ struct CHPageOffset
+ {
+ // vector size is npages
+ std::vector entries;
+ };
+
+ struct CHSharedObjectEntry
+ {
+ CHSharedObjectEntry(int object) :
+ object(object)
+ {
+ }
+
+ int object;
+ };
+
+ // PDF 1.4: Table F.5
+ struct CHSharedObject
+ {
+ int first_shared_obj{0};
+ int nshared_first_page{0};
+ int nshared_total{0};
+ // vector size is nshared_total
+ std::vector entries;
+ };
+
+ // No need for CHGeneric -- HGeneric is fine as is.
+
+ // Data structures to support optimization -- implemented in QPDF_optimization.cc
+
+ class ObjUser
+ {
+ public:
+ enum user_e { ou_bad, ou_page, ou_thumb, ou_trailer_key, ou_root_key, ou_root };
+
+ // type is set to ou_bad
+ ObjUser();
+
+ // type must be ou_root
+ ObjUser(user_e type);
+
+ // type must be one of ou_page or ou_thumb
+ ObjUser(user_e type, int pageno);
+
+ // type must be one of ou_trailer_key or ou_root_key
+ ObjUser(user_e type, std::string const& key);
+
+ bool operator<(ObjUser const&) const;
+
+ user_e ou_type;
+ int pageno; // if ou_page;
+ std::string key; // if ou_trailer_key or ou_root_key
+ };
+
+ struct UpdateObjectMapsFrame
+ {
+ UpdateObjectMapsFrame(ObjUser const& ou, QPDFObjectHandle oh, bool top);
+
+ ObjUser const& ou;
+ QPDFObjectHandle oh;
+ bool top;
+ };
+
+ class PatternFinder: public InputSource::Finder
+ {
+ public:
+ PatternFinder(QPDF& qpdf, bool (QPDF::*checker)()) :
+ qpdf(qpdf),
+ checker(checker)
+ {
+ }
+ ~PatternFinder() override = default;
+ bool
+ check() override
+ {
+ return (this->qpdf.*checker)();
+ }
+
+ private:
+ QPDF& qpdf;
+ bool (QPDF::*checker)();
+ };
// Methods to support pattern finding
static bool validatePDFVersion(char const*&, std::string& version);
@@ -902,7 +1411,6 @@ class QPDF
QPDFObjectHandle
getUncompressedObject(QPDFObjectHandle&, std::map const& object_stream_data);
QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, QPDFWriter::ObjTable const& obj);
- QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, Objects const& obj);
int lengthNextN(int first_object, int n);
void
checkHPageOffset(std::vector const& pages, std::map& idx_to_obj);
@@ -948,7 +1456,6 @@ class QPDF
std::function skip_stream_parameters);
void filterCompressedObjects(std::map const& object_stream_data);
void filterCompressedObjects(QPDFWriter::ObjTable const& object_stream_data);
- void filterCompressedObjects(Objects const& object_stream_data);
// JSON import
void importJSON(std::shared_ptr, bool must_be_complete);
@@ -979,7 +1486,90 @@ class QPDF
return QIntC::to_ulonglong(i);
}
- class Members;
+ class Members
+ {
+ friend class QPDF;
+ friend class ResolveRecorder;
+
+ public:
+ QPDF_DLL
+ ~Members() = default;
+
+ private:
+ Members();
+ Members(Members const&) = delete;
+
+ std::shared_ptr log;
+ unsigned long long unique_id{0};
+ QPDFTokenizer tokenizer;
+ std::shared_ptr file;
+ std::string last_object_description;
+ bool provided_password_is_hex_key{false};
+ bool ignore_xref_streams{false};
+ bool suppress_warnings{false};
+ size_t max_warnings{0};
+ bool attempt_recovery{true};
+ bool check_mode{false};
+ std::shared_ptr encp;
+ std::string pdf_version;
+ std::map xref_table;
+ // Various tables are indexed by object id, with potential size id + 1
+ int xref_table_max_id{std::numeric_limits::max() - 1};
+ qpdf_offset_t xref_table_max_offset{0};
+ std::set deleted_objects;
+ std::map obj_cache;
+ std::set resolving;
+ QPDFObjectHandle trailer;
+ std::vector all_pages;
+ bool invalid_page_found{false};
+ std::map pageobj_to_pages_pos;
+ bool pushed_inherited_attributes_to_pages{false};
+ bool ever_pushed_inherited_attributes_to_pages{false};
+ bool ever_called_get_all_pages{false};
+ std::vector warnings;
+ std::map object_copiers;
+ std::shared_ptr copied_streams;
+ // copied_stream_data_provider is owned by copied_streams
+ CopiedStreamDataProvider* copied_stream_data_provider{nullptr};
+ bool reconstructed_xref{false};
+ bool fixed_dangling_refs{false};
+ bool immediate_copy_from{false};
+ bool in_parse{false};
+ bool parsed{false};
+ std::set resolved_object_streams;
+
+ // Linearization data
+ qpdf_offset_t first_xref_item_offset{0}; // actual value from file
+ bool uncompressed_after_compressed{false};
+ bool linearization_warnings{false};
+
+ // Linearization parameter dictionary and hint table data: may be read from file or computed
+ // prior to writing a linearized file
+ QPDFObjectHandle lindict;
+ LinParameters linp;
+ HPageOffset page_offset_hints;
+ HSharedObject shared_object_hints;
+ HGeneric outline_hints;
+
+ // Computed linearization data: used to populate above tables during writing and to compare
+ // with them during validation. c_ means computed.
+ LinParameters c_linp;
+ CHPageOffset c_page_offset_data;
+ CHSharedObject c_shared_object_data;
+ HGeneric c_outline_data;
+
+ // Object ordering data for linearized files: initialized by calculateLinearizationData().
+ // Part numbers refer to the PDF 1.4 specification.
+ std::vector part4;
+ std::vector part6;
+ std::vector part7;
+ std::vector part8;
+ std::vector part9;
+
+ // Optimization data
+ std::map> obj_user_to_objects;
+ std::map> object_to_obj_users;
+ };
// Keep all member variables inside the Members object, which we dynamically allocate. This
// makes it possible to add new private members without breaking binary compatibility.
diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt
index 189e506..eb30b62 100644
--- a/libqpdf/CMakeLists.txt
+++ b/libqpdf/CMakeLists.txt
@@ -107,7 +107,6 @@ set(libqpdf_SOURCES
QPDF_encryption.cc
QPDF_json.cc
QPDF_linearization.cc
- QPDF_objects.cc
QPDF_optimization.cc
QPDF_pages.cc
QTC.cc
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index cc54db2..03ffb62 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -1,9 +1,11 @@
#include // include first for large file support
-#include
+#include
+#include
#include
#include
+#include
#include