From a8c93bd324d0362a26c1e6591eead5c52f865c0d Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Mon, 21 Aug 2017 21:33:44 -0400 Subject: [PATCH] Push QPDF member variables into a nested class Pushing member variables into a nested class enables addition of new member variables without breaking binary compatibility. --- include/qpdf/QPDF.hh | 154 +++++----- libqpdf/QPDF.cc | 512 ++++++++++++++++++---------------- libqpdf/QPDF_encryption.cc | 176 ++++++------ libqpdf/QPDF_linearization.cc | 438 +++++++++++++++-------------- libqpdf/QPDF_optimization.cc | 62 ++-- libqpdf/QPDF_pages.cc | 82 +++--- 6 files changed, 737 insertions(+), 687 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index af38c32e..72e02754 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -635,11 +635,11 @@ class QPDF qpdf(qpdf), og(og) { - qpdf->resolving.insert(og); + qpdf->m->resolving.insert(og); } virtual ~ResolveRecorder() { - this->qpdf->resolving.erase(og); + this->qpdf->m->resolving.erase(og); } private: QPDF* qpdf; @@ -1113,79 +1113,95 @@ class QPDF std::set& visited, bool top); void filterCompressedObjects(std::map const& object_stream_data); + class Members + { + friend class QPDF; - QPDFTokenizer tokenizer; - PointerHolder file; - std::string last_object_description; - bool encrypted; - bool encryption_initialized; - bool ignore_xref_streams; - bool suppress_warnings; - std::ostream* out_stream; - std::ostream* err_stream; - bool attempt_recovery; - 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; - int cached_key_objid; - int cached_key_generation; - std::string pdf_version; - std::map xref_table; - std::set deleted_objects; - std::map obj_cache; - std::set resolving; - QPDFObjectHandle trailer; - std::vector all_pages; - std::map pageobj_to_pages_pos; - bool pushed_inherited_attributes_to_pages; - std::vector warnings; - std::map object_copiers; - PointerHolder copied_streams; - // copied_stream_data_provider is owned by copied_streams - CopiedStreamDataProvider* copied_stream_data_provider; - std::set attachment_streams; - bool reconstructed_xref; + public: + ~Members(); - // Linearization data - qpdf_offset_t first_xref_item_offset; // actual value from file - bool uncompressed_after_compressed; + private: + Members(); + Members(Members const&); - // 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; + QPDFTokenizer tokenizer; + PointerHolder file; + std::string last_object_description; + bool encrypted; + bool encryption_initialized; + bool ignore_xref_streams; + bool suppress_warnings; + std::ostream* out_stream; + std::ostream* err_stream; + bool attempt_recovery; + 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; + int cached_key_objid; + int cached_key_generation; + std::string pdf_version; + std::map xref_table; + std::set deleted_objects; + std::map obj_cache; + std::set resolving; + QPDFObjectHandle trailer; + std::vector all_pages; + std::map pageobj_to_pages_pos; + bool pushed_inherited_attributes_to_pages; + std::vector warnings; + std::map object_copiers; + PointerHolder copied_streams; + // copied_stream_data_provider is owned by copied_streams + CopiedStreamDataProvider* copied_stream_data_provider; + std::set attachment_streams; + bool reconstructed_xref; - // 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; + // Linearization data + qpdf_offset_t first_xref_item_offset; // actual value from file + bool uncompressed_after_compressed; - // 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; + // 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; - // Optimization data - std::map > obj_user_to_objects; - std::map > object_to_obj_users; + // 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. + PointerHolder m; }; #endif // __QPDF_HH__ diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 9c79fc3a..f6e62546 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -74,7 +74,7 @@ QPDF::QPDFVersion() return QPDF::qpdf_version; } -QPDF::QPDF() : +QPDF::Members::Members() : encrypted(false), encryption_initialized(false), ignore_xref_streams(false), @@ -98,6 +98,15 @@ QPDF::QPDF() : { } +QPDF::Members::~Members() +{ +} + +QPDF::QPDF() : + m(new Members()) +{ +} + QPDF::~QPDF() { // If two objects are mutually referential (through each object @@ -114,10 +123,10 @@ QPDF::~QPDF() // reference will reread the object from the file, which would // have the effect of undoing any modifications that may have been // made to any of the objects. - this->xref_table.clear(); + this->m->xref_table.clear(); for (std::map::iterator iter = - this->obj_cache.begin(); - iter != obj_cache.end(); ++iter) + this->m->obj_cache.begin(); + iter != this->m->obj_cache.end(); ++iter) { QPDFObject::ObjAccessor::releaseResolved( (*iter).second.object.getPointer()); @@ -158,7 +167,7 @@ void QPDF::processInputSource(PointerHolder source, char const* password) { - this->file = source; + this->m->file = source; parse(password); } @@ -171,41 +180,41 @@ QPDF::emptyPDF() void QPDF::setIgnoreXRefStreams(bool val) { - this->ignore_xref_streams = val; + this->m->ignore_xref_streams = val; } void QPDF::setOutputStreams(std::ostream* out, std::ostream* err) { - this->out_stream = out ? out : &std::cout; - this->err_stream = err ? err : &std::cerr; + this->m->out_stream = out ? out : &std::cout; + this->m->err_stream = err ? err : &std::cerr; } void QPDF::setSuppressWarnings(bool val) { - this->suppress_warnings = val; + this->m->suppress_warnings = val; } void QPDF::setAttemptRecovery(bool val) { - this->attempt_recovery = val; + this->m->attempt_recovery = val; } std::vector QPDF::getWarnings() { - std::vector result = this->warnings; - this->warnings.clear(); + std::vector result = this->m->warnings; + this->m->warnings.clear(); return result; } bool QPDF::findHeader() { - qpdf_offset_t global_offset = this->file->tell(); - std::string line = this->file->readLine(1024); + qpdf_offset_t global_offset = this->m->file->tell(); + std::string line = this->m->file->readLine(1024); char const* p = line.c_str(); if (strncmp(p, "%PDF-", 5) != 0) { @@ -239,7 +248,7 @@ QPDF::findHeader() } if (valid) { - this->pdf_version = version; + this->m->pdf_version = version; if (global_offset != 0) { // Empirical evidence strongly suggests that when there is @@ -247,7 +256,7 @@ QPDF::findHeader() // offsets in the file are such that 0 points to the // beginning of the header. QTC::TC("qpdf", "QPDF global offset"); - this->file = new OffsetInputSource(this->file, global_offset); + this->m->file = new OffsetInputSource(this->m->file, global_offset); } } return valid; @@ -256,14 +265,14 @@ QPDF::findHeader() bool QPDF::findStartxref() { - QPDFTokenizer::Token t = readToken(this->file, true); + QPDFTokenizer::Token t = readToken(this->m->file, true); if (t == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "startxref")) { - t = readToken(this->file, true); + t = readToken(this->m->file, true); if (t.getType() == QPDFTokenizer::tt_integer) { // Position in front of offset token - this->file->seek(this->file->getLastOffset(), SEEK_SET); + this->m->file->seek(this->m->file->getLastOffset(), SEEK_SET); return true; } } @@ -275,37 +284,37 @@ QPDF::parse(char const* password) { if (password) { - this->provided_password = password; + this->m->provided_password = password; } // Find the header anywhere in the first 1024 bytes of the file. PatternFinder hf(*this, &QPDF::findHeader); - if (! this->file->findFirst("%PDF-", 0, 1024, hf)) + if (! this->m->file->findFirst("%PDF-", 0, 1024, hf)) { QTC::TC("qpdf", "QPDF not a pdf file"); - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, "can't find PDF header")); // QPDFWriter writes files that usually require at least // version 1.2 for /FlateDecode - this->pdf_version = "1.2"; + this->m->pdf_version = "1.2"; } - if (atof(this->pdf_version.c_str()) < 1.2) + if (atof(this->m->pdf_version.c_str()) < 1.2) { - this->tokenizer.allowPoundAnywhereInName(); + this->m->tokenizer.allowPoundAnywhereInName(); } // PDF spec says %%EOF must be found within the last 1024 bytes of // the file. We add an extra 30 characters to leave room for the // startxref stuff. - this->file->seek(0, SEEK_END); - qpdf_offset_t end_offset = this->file->tell(); + this->m->file->seek(0, SEEK_END); + qpdf_offset_t end_offset = this->m->file->tell(); qpdf_offset_t start_offset = (end_offset > 1054 ? end_offset - 1054 : 0); PatternFinder sf(*this, &QPDF::findStartxref); qpdf_offset_t xref_offset = 0; - if (this->file->findLast("startxref", start_offset, 0, sf)) + if (this->m->file->findLast("startxref", start_offset, 0, sf)) { xref_offset = QUtil::string_to_ll( - readToken(this->file).getValue().c_str()); + readToken(this->m->file).getValue().c_str()); } try @@ -313,14 +322,14 @@ QPDF::parse(char const* password) if (xref_offset == 0) { QTC::TC("qpdf", "QPDF can't find startxref"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0, + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, "can't find startxref"); } read_xref(xref_offset); } catch (QPDFExc& e) { - if (this->attempt_recovery) + if (this->m->attempt_recovery) { reconstruct_xref(e); QTC::TC("qpdf", "QPDF reconstructed xref table"); @@ -338,28 +347,29 @@ QPDF::parse(char const* password) void QPDF::warn(QPDFExc const& e) { - this->warnings.push_back(e); - if (! this->suppress_warnings) + this->m->warnings.push_back(e); + if (! this->m->suppress_warnings) { - *err_stream << "WARNING: " - << this->warnings.back().what() << std::endl; + *this->m->err_stream + << "WARNING: " + << this->m->warnings.back().what() << std::endl; } } void QPDF::setTrailer(QPDFObjectHandle obj) { - if (this->trailer.isInitialized()) + if (this->m->trailer.isInitialized()) { return; } - this->trailer = obj; + this->m->trailer = obj; } void QPDF::reconstruct_xref(QPDFExc& e) { - if (this->reconstructed_xref) + if (this->m->reconstructed_xref) { // Avoid xref reconstruction infinite loops. This is getting // very hard to reproduce because qpdf is throwing many fewer @@ -367,19 +377,19 @@ QPDF::reconstruct_xref(QPDFExc& e) throw e; } - this->reconstructed_xref = true; + this->m->reconstructed_xref = true; - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0, + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, "file is damaged")); warn(e); - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0, + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, "Attempting to reconstruct cross-reference table")); // Delete all references to type 1 (uncompressed) objects std::set to_delete; for (std::map::iterator iter = - this->xref_table.begin(); - iter != this->xref_table.end(); ++iter) + this->m->xref_table.begin(); + iter != this->m->xref_table.end(); ++iter) { if (((*iter).second).getType() == 1) { @@ -389,21 +399,22 @@ QPDF::reconstruct_xref(QPDFExc& e) for (std::set::iterator iter = to_delete.begin(); iter != to_delete.end(); ++iter) { - this->xref_table.erase(*iter); + this->m->xref_table.erase(*iter); } - this->file->seek(0, SEEK_END); - qpdf_offset_t eof = this->file->tell(); - this->file->seek(0, SEEK_SET); + this->m->file->seek(0, SEEK_END); + qpdf_offset_t eof = this->m->file->tell(); + this->m->file->seek(0, SEEK_SET); bool in_obj = false; qpdf_offset_t line_start = 0; - while (this->file->tell() < eof) + while (this->m->file->tell() < eof) { - this->file->findAndSkipNextEOL(); - qpdf_offset_t next_line_start = this->file->tell(); - this->file->seek(line_start, SEEK_SET); - QPDFTokenizer::Token t1 = readToken(this->file, true); - qpdf_offset_t token_start = this->file->tell() - t1.getValue().length(); + this->m->file->findAndSkipNextEOL(); + qpdf_offset_t next_line_start = this->m->file->tell(); + this->m->file->seek(line_start, SEEK_SET); + QPDFTokenizer::Token t1 = readToken(this->m->file, true); + qpdf_offset_t token_start = + this->m->file->tell() - t1.getValue().length(); if (token_start >= next_line_start) { // don't process yet @@ -419,8 +430,8 @@ QPDF::reconstruct_xref(QPDFExc& e) { if (t1.getType() == QPDFTokenizer::tt_integer) { - QPDFTokenizer::Token t2 = readToken(this->file, true); - QPDFTokenizer::Token t3 = readToken(this->file, true); + QPDFTokenizer::Token t2 = readToken(this->m->file, true); + QPDFTokenizer::Token t3 = readToken(this->m->file, true); if ((t2.getType() == QPDFTokenizer::tt_integer) && (t3 == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "obj"))) { @@ -430,11 +441,12 @@ QPDF::reconstruct_xref(QPDFExc& e) insertXrefEntry(obj, 1, token_start, gen, true); } } - else if ((! this->trailer.isInitialized()) && - (t1 == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "trailer"))) + else if ((! this->m->trailer.isInitialized()) && + (t1 == QPDFTokenizer::Token( + QPDFTokenizer::tt_word, "trailer"))) { QPDFObjectHandle t = - readObject(this->file, "trailer", 0, 0, false); + readObject(this->m->file, "trailer", 0, 0, false); if (! t.isDictionary()) { // Oh well. It was worth a try. @@ -445,11 +457,11 @@ QPDF::reconstruct_xref(QPDFExc& e) } } } - this->file->seek(next_line_start, SEEK_SET); + this->m->file->seek(next_line_start, SEEK_SET); line_start = next_line_start; } - if (! this->trailer.isInitialized()) + if (! this->m->trailer.isInitialized()) { // We could check the last encountered object to see if it was // an xref stream. If so, we could try to get the trailer @@ -457,7 +469,7 @@ QPDF::reconstruct_xref(QPDFExc& e) // with bad startxref pointers even when they have object // streams. - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0, + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, "unable to find trailer " "dictionary while recovering damaged file"); } @@ -479,8 +491,8 @@ QPDF::read_xref(qpdf_offset_t xref_offset) { char buf[7]; memset(buf, 0, sizeof(buf)); - this->file->seek(xref_offset, SEEK_SET); - this->file->read(buf, sizeof(buf) - 1); + this->m->file->seek(xref_offset, SEEK_SET); + this->m->file->read(buf, sizeof(buf) - 1); // The PDF spec says xref must be followed by a line // terminator, but files exist in the wild where it is // terminated by arbitrary whitespace. @@ -506,25 +518,25 @@ QPDF::read_xref(qpdf_offset_t xref_offset) } } - if (! this->trailer.isInitialized()) + if (! this->m->trailer.isInitialized()) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0, + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, "unable to find trailer while reading xref"); } - int size = this->trailer.getKey("/Size").getIntValue(); + int size = this->m->trailer.getKey("/Size").getIntValue(); int max_obj = 0; - if (! xref_table.empty()) + if (! this->m->xref_table.empty()) { - max_obj = (*(xref_table.rbegin())).first.getObj(); + max_obj = (*(this->m->xref_table.rbegin())).first.getObj(); } - if (! this->deleted_objects.empty()) + if (! this->m->deleted_objects.empty()) { - max_obj = std::max(max_obj, *(this->deleted_objects.rbegin())); + max_obj = std::max(max_obj, *(this->m->deleted_objects.rbegin())); } if (size != max_obj + 1) { QTC::TC("qpdf", "QPDF xref size mismatch"); - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0, + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, std::string("reported number of objects (") + QUtil::int_to_string(size) + ") inconsistent with actual number of objects (" + @@ -533,7 +545,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) // We no longer need the deleted_objects table, so go ahead and // clear it out to make sure we never depend on its being set. - this->deleted_objects.clear(); + this->m->deleted_objects.clear(); } bool @@ -677,9 +689,9 @@ QPDF::parse_xrefEntry(std::string const& line, if (invalid) { - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "xref table", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "accepting invalid xref table entry")); } @@ -694,13 +706,13 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) { std::vector deleted_items; - this->file->seek(xref_offset, SEEK_SET); + this->m->file->seek(xref_offset, SEEK_SET); bool done = false; while (! done) { char linebuf[51]; memset(linebuf, 0, sizeof(linebuf)); - this->file->read(linebuf, sizeof(linebuf) - 1); + this->m->file->read(linebuf, sizeof(linebuf) - 1); std::string line = linebuf; int obj = 0; int num = 0; @@ -708,19 +720,19 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) if (! parse_xrefFirst(line, obj, num, bytes)) { QTC::TC("qpdf", "QPDF invalid xref"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "xref table", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "xref table", this->m->file->getLastOffset(), "xref syntax invalid"); } - this->file->seek(this->file->getLastOffset() + bytes, SEEK_SET); + this->m->file->seek(this->m->file->getLastOffset() + bytes, SEEK_SET); for (int i = obj; i < obj + num; ++i) { if (i == 0) { // This is needed by checkLinearization() - this->first_xref_item_offset = this->file->tell(); + this->m->first_xref_item_offset = this->m->file->tell(); } - std::string xref_entry = this->file->readLine(30); + std::string xref_entry = this->m->file->readLine(30); // For xref_table, these will always be small enough to be ints qpdf_offset_t f1 = 0; int f2 = 0; @@ -729,8 +741,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) { QTC::TC("qpdf", "QPDF invalid xref entry"); throw QPDFExc( - qpdf_e_damaged_pdf, this->file->getName(), - "xref table", this->file->getLastOffset(), + qpdf_e_damaged_pdf, this->m->file->getName(), + "xref table", this->m->file->getLastOffset(), "invalid xref entry (obj=" + QUtil::int_to_string(i) + ")"); } @@ -745,45 +757,45 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) insertXrefEntry(i, 1, f1, f2); } } - qpdf_offset_t pos = this->file->tell(); - QPDFTokenizer::Token t = readToken(this->file); + qpdf_offset_t pos = this->m->file->tell(); + QPDFTokenizer::Token t = readToken(this->m->file); if (t == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "trailer")) { done = true; } else { - this->file->seek(pos, SEEK_SET); + this->m->file->seek(pos, SEEK_SET); } } // Set offset to previous xref table if any QPDFObjectHandle cur_trailer = - readObject(this->file, "trailer", 0, 0, false); + readObject(this->m->file, "trailer", 0, 0, false); if (! cur_trailer.isDictionary()) { QTC::TC("qpdf", "QPDF missing trailer"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "", this->m->file->getLastOffset(), "expected trailer dictionary"); } - if (! this->trailer.isInitialized()) + if (! this->m->trailer.isInitialized()) { setTrailer(cur_trailer); - if (! this->trailer.hasKey("/Size")) + if (! this->m->trailer.hasKey("/Size")) { QTC::TC("qpdf", "QPDF trailer lacks size"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "trailer", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "trailer", this->m->file->getLastOffset(), "trailer dictionary lacks /Size key"); } - if (! this->trailer.getKey("/Size").isInteger()) + if (! this->m->trailer.getKey("/Size").isInteger()) { QTC::TC("qpdf", "QPDF trailer size not integer"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "trailer", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "trailer", this->m->file->getLastOffset(), "/Size key in trailer dictionary is not " "an integer"); } @@ -791,7 +803,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) if (cur_trailer.hasKey("/XRefStm")) { - if (this->ignore_xref_streams) + if (this->m->ignore_xref_streams) { QTC::TC("qpdf", "QPDF ignoring XRefStm in trailer"); } @@ -807,7 +819,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) } else { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "xref stream", xref_offset, "invalid /XRefStm"); } @@ -827,8 +839,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) if (! cur_trailer.getKey("/Prev").isInteger()) { QTC::TC("qpdf", "QPDF trailer prev not integer"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "trailer", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "trailer", this->m->file->getLastOffset(), "/Prev key in trailer dictionary is not " "an integer"); } @@ -847,7 +859,7 @@ qpdf_offset_t QPDF::read_xrefStream(qpdf_offset_t xref_offset) { bool found = false; - if (! this->ignore_xref_streams) + if (! this->m->ignore_xref_streams) { int xobj; int xgen; @@ -875,7 +887,7 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset) if (! found) { QTC::TC("qpdf", "QPDF can't find xref"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", xref_offset, "xref not found"); } @@ -896,7 +908,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) dict.getKey("/Size").isInteger() && (Index_obj.isArray() || Index_obj.isNull()))) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "xref stream", xref_offset, "Cross-reference stream does not have" " proper /W and /Index keys"); @@ -910,7 +922,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) W[i] = W_obj.getArrayItem(i).getIntValue(); if (W[i] > max_bytes) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "xref stream", xref_offset, "Cross-reference stream's /W contains" " impossibly large values"); @@ -919,7 +931,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) } if (entry_size == 0) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "xref stream", xref_offset, "Cross-reference stream's /W indicates" " entry size of 0"); @@ -933,7 +945,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) int n_index = Index_obj.getArrayNItems(); if ((n_index % 2) || (n_index < 2)) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "xref stream", xref_offset, "Cross-reference stream's /Index has an" " invalid number of values"); @@ -946,7 +958,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) } else { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "xref stream", xref_offset, "Cross-reference stream's /Index's item " + QUtil::int_to_string(i) + @@ -969,7 +981,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) { if (indx.at(i) > max_num_entries - num_entries) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "xref stream", xref_offset, "Cross-reference stream claims to contain" " too many entries: " + @@ -989,7 +1001,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) if (expected_size != actual_size) { - QPDFExc x(qpdf_e_damaged_pdf, this->file->getName(), + QPDFExc x(qpdf_e_damaged_pdf, this->m->file->getName(), "xref stream", xref_offset, "Cross-reference stream data has the wrong size;" " expected = " + QUtil::int_to_string(expected_size) + @@ -1050,7 +1062,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) { if (fields[0] != 2) { - this->uncompressed_after_compressed = true; + this->m->uncompressed_after_compressed = true; } } else if (fields[0] == 2) @@ -1060,13 +1072,13 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) if (obj == 0) { // This is needed by checkLinearization() - this->first_xref_item_offset = xref_offset; + this->m->first_xref_item_offset = xref_offset; } insertXrefEntry(obj, static_cast(fields[0]), fields[1], static_cast(fields[2])); } - if (! this->trailer.isInitialized()) + if (! this->m->trailer.isInitialized()) { setTrailer(dict); } @@ -1075,8 +1087,8 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) { if (! dict.getKey("/Prev").isInteger()) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "xref stream", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "xref stream", this->m->file->getLastOffset(), "/Prev key in xref stream dictionary is not " "an integer"); } @@ -1108,12 +1120,12 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite) { // private scope int gen = (f0 == 2 ? 0 : f2); QPDFObjGen og(obj, gen); - if (this->xref_table.count(og)) + if (this->m->xref_table.count(og)) { if (overwrite) { QTC::TC("qpdf", "QPDF xref overwrite object"); - this->xref_table.erase(og); + this->m->xref_table.erase(og); } else { @@ -1121,7 +1133,7 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite) return; } } - if (this->deleted_objects.count(obj)) + if (this->m->deleted_objects.count(obj)) { QTC::TC("qpdf", "QPDF xref deleted object"); return; @@ -1131,22 +1143,22 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite) switch (f0) { case 0: - this->deleted_objects.insert(obj); + this->m->deleted_objects.insert(obj); break; case 1: // f2 is generation QTC::TC("qpdf", "QPDF xref gen > 0", ((f2 > 0) ? 1 : 0)); - this->xref_table[QPDFObjGen(obj, f2)] = QPDFXRefEntry(f0, f1, f2); + this->m->xref_table[QPDFObjGen(obj, f2)] = QPDFXRefEntry(f0, f1, f2); break; case 2: - this->xref_table[QPDFObjGen(obj, 0)] = QPDFXRefEntry(f0, f1, f2); + this->m->xref_table[QPDFObjGen(obj, 0)] = QPDFXRefEntry(f0, f1, f2); break; default: - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "xref stream", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "xref stream", this->m->file->getLastOffset(), "unknown xref stream entry type " + QUtil::int_to_string(f0)); break; @@ -1157,21 +1169,24 @@ void QPDF::showXRefTable() { for (std::map::iterator iter = - this->xref_table.begin(); - iter != this->xref_table.end(); ++iter) + this->m->xref_table.begin(); + iter != this->m->xref_table.end(); ++iter) { QPDFObjGen const& og = (*iter).first; QPDFXRefEntry const& entry = (*iter).second; - *out_stream << og.getObj() << "/" << og.getGen() << ": "; + *this->m->out_stream << og.getObj() << "/" << og.getGen() << ": "; switch (entry.getType()) { case 1: - *out_stream << "uncompressed; offset = " << entry.getOffset(); + *this->m->out_stream + << "uncompressed; offset = " << entry.getOffset(); break; case 2: - *out_stream << "compressed; stream = " << entry.getObjStreamNumber() - << ", index = " << entry.getObjStreamIndex(); + *this->m->out_stream + << "compressed; stream = " + << entry.getObjStreamNumber() + << ", index = " << entry.getObjStreamIndex(); break; default: @@ -1179,7 +1194,7 @@ QPDF::showXRefTable() " showing xref_table"); break; } - *out_stream << std::endl; + *this->m->out_stream << std::endl; } } @@ -1188,8 +1203,8 @@ QPDF::getAllObjects() { std::vector result; for (std::map::iterator iter = - this->xref_table.begin(); - iter != this->xref_table.end(); ++iter) + this->m->xref_table.begin(); + iter != this->m->xref_table.end(); ++iter) { QPDFObjGen const& og = (*iter).first; @@ -1203,18 +1218,18 @@ void QPDF::setLastObjectDescription(std::string const& description, int objid, int generation) { - this->last_object_description.clear(); + this->m->last_object_description.clear(); if (! description.empty()) { - this->last_object_description += description; + this->m->last_object_description += description; if (objid > 0) { - this->last_object_description += ": "; + this->m->last_object_description += ": "; } } if (objid > 0) { - this->last_object_description += "object " + + this->m->last_object_description += "object " + QUtil::int_to_string(objid) + " " + QUtil::int_to_string(generation); } @@ -1231,20 +1246,20 @@ QPDF::readObject(PointerHolder input, bool empty = false; PointerHolder decrypter_ph; StringDecrypter* decrypter = 0; - if (this->encrypted && (! in_object_stream)) + if (this->m->encrypted && (! in_object_stream)) { decrypter_ph = new StringDecrypter(this, objid, generation); decrypter = decrypter_ph.getPointer(); } QPDFObjectHandle object = QPDFObjectHandle::parse( - input, description, this->tokenizer, empty, decrypter, this); + input, description, this->m->tokenizer, empty, decrypter, this); if (empty) { // Nothing in the PDF spec appears to allow empty objects, but // they have been encountered in actual PDF files and Adobe // Reader appears to ignore them. warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, + this->m->last_object_description, input->getLastOffset(), "empty object treated as null")); } @@ -1299,7 +1314,7 @@ QPDF::readObject(PointerHolder input, warn(QPDFExc( qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, + this->m->last_object_description, input->tell(), "stream keyword followed" " by carriage return only")); @@ -1315,7 +1330,7 @@ QPDF::readObject(PointerHolder input, input->unreadCh(ch); } warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, + this->m->last_object_description, input->tell(), "stream keyword not followed" " by proper line terminator")); @@ -1337,7 +1352,7 @@ QPDF::readObject(PointerHolder input, { QTC::TC("qpdf", "QPDF stream without length"); throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, offset, + this->m->last_object_description, offset, "stream dictionary lacks /Length key"); } @@ -1346,7 +1361,7 @@ QPDF::readObject(PointerHolder input, { QTC::TC("qpdf", "QPDF stream length not integer"); throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, offset, + this->m->last_object_description, offset, "/Length key in stream dictionary is not " "an integer"); } @@ -1359,14 +1374,14 @@ QPDF::readObject(PointerHolder input, { QTC::TC("qpdf", "QPDF missing endstream"); throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, + this->m->last_object_description, input->getLastOffset(), "expected endstream"); } } catch (QPDFExc& e) { - if (this->attempt_recovery) + if (this->m->attempt_recovery) { warn(e); length = recoverStreamLength( @@ -1396,12 +1411,12 @@ bool QPDF::findEndstream() { // Find endstream or endobj. Position the input at that token. - QPDFTokenizer::Token t = readToken(this->file, true); + QPDFTokenizer::Token t = readToken(this->m->file, true); if ((t.getType() == QPDFTokenizer::tt_word) && ((t.getValue() == "endobj") || (t.getValue() == "endstream"))); { - this->file->seek(this->file->getLastOffset(), SEEK_SET); + this->m->file->seek(this->m->file->getLastOffset(), SEEK_SET); return true; } return false; @@ -1415,19 +1430,19 @@ QPDF::recoverStreamLength(PointerHolder input, // Try to reconstruct stream length by looking for // endstream or endobj warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, stream_offset, + this->m->last_object_description, stream_offset, "attempting to recover stream length")); PatternFinder ef(*this, &QPDF::findEndstream); size_t length = 0; - if (this->file->findFirst("end", stream_offset, 0, ef)) + if (this->m->file->findFirst("end", stream_offset, 0, ef)) { - length = this->file->tell() - stream_offset; + length = this->m->file->tell() - stream_offset; // Reread endstream but, if it was endobj, don't skip that. - QPDFTokenizer::Token t = readToken(this->file); + QPDFTokenizer::Token t = readToken(this->m->file); if (t.getValue() == "endobj") { - this->file->seek(this->file->getLastOffset(), SEEK_SET); + this->m->file->seek(this->m->file->getLastOffset(), SEEK_SET); } } @@ -1438,8 +1453,8 @@ QPDF::recoverStreamLength(PointerHolder input, // Make sure this is inside this object for (std::map::iterator iter = - this->xref_table.begin(); - iter != this->xref_table.end(); ++iter) + this->m->xref_table.begin(); + iter != this->m->xref_table.end(); ++iter) { QPDFObjGen const& og = (*iter).first; QPDFXRefEntry const& entry = (*iter).second; @@ -1472,13 +1487,14 @@ QPDF::recoverStreamLength(PointerHolder input, if (length == 0) { warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, stream_offset, - "unable to recover stream data; treating stream as empty")); + this->m->last_object_description, stream_offset, + "unable to recover stream data;" + " treating stream as empty")); } else { warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, stream_offset, + this->m->last_object_description, stream_offset, "recovered stream length: " + QUtil::int_to_string(length))); } @@ -1490,8 +1506,8 @@ QPDF::recoverStreamLength(PointerHolder input, QPDFTokenizer::Token QPDF::readToken(PointerHolder input, bool allow_bad) { - return this->tokenizer.readToken( - input, this->last_object_description, allow_bad); + return this->m->tokenizer.readToken( + input, this->m->last_object_description, allow_bad); } QPDFObjectHandle @@ -1500,7 +1516,7 @@ QPDF::readObjectAtOffset(bool try_recovery, int exp_objid, int exp_generation, int& objid, int& generation) { - if (! this->attempt_recovery) + if (! this->m->attempt_recovery) { try_recovery = false; } @@ -1514,17 +1530,17 @@ QPDF::readObjectAtOffset(bool try_recovery, if (offset == 0) { QTC::TC("qpdf", "QPDF bogus 0 offset", 0); - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, 0, + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, 0, "object has offset 0")); return QPDFObjectHandle::newNull(); } - this->file->seek(offset, SEEK_SET); + this->m->file->seek(offset, SEEK_SET); - QPDFTokenizer::Token tobjid = readToken(this->file); - QPDFTokenizer::Token tgen = readToken(this->file); - QPDFTokenizer::Token tobj = readToken(this->file); + QPDFTokenizer::Token tobjid = readToken(this->m->file); + QPDFTokenizer::Token tgen = readToken(this->m->file); + QPDFTokenizer::Token tobj = readToken(this->m->file); bool objidok = (tobjid.getType() == QPDFTokenizer::tt_integer); int genok = (tgen.getType() == QPDFTokenizer::tt_integer); @@ -1539,8 +1555,8 @@ QPDF::readObjectAtOffset(bool try_recovery, if (! (objidok && genok && objok)) { QTC::TC("qpdf", "QPDF expected n n obj"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, offset, + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, offset, "expected n n obj"); } objid = atoi(tobjid.getValue().c_str()); @@ -1549,8 +1565,8 @@ QPDF::readObjectAtOffset(bool try_recovery, if (objid == 0) { QTC::TC("qpdf", "QPDF object id 0"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, offset, + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, offset, "object with ID 0"); } @@ -1558,8 +1574,8 @@ QPDF::readObjectAtOffset(bool try_recovery, (! ((objid == exp_objid) && (generation == exp_generation)))) { QTC::TC("qpdf", "QPDF err wrong objid/generation"); - QPDFExc e(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, offset, + QPDFExc e(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, offset, std::string("expected ") + QUtil::int_to_string(exp_objid) + " " + QUtil::int_to_string(exp_generation) + " obj"); @@ -1583,10 +1599,10 @@ QPDF::readObjectAtOffset(bool try_recovery, // Try again after reconstructing xref table reconstruct_xref(e); QPDFObjGen og(exp_objid, exp_generation); - if (this->xref_table.count(og) && - (this->xref_table[og].getType() == 1)) + if (this->m->xref_table.count(og) && + (this->m->xref_table[og].getType() == 1)) { - qpdf_offset_t new_offset = this->xref_table[og].getOffset(); + qpdf_offset_t new_offset = this->m->xref_table[og].getOffset(); QPDFObjectHandle result = readObjectAtOffset( false, new_offset, description, exp_objid, exp_generation, objid, generation); @@ -1597,7 +1613,7 @@ QPDF::readObjectAtOffset(bool try_recovery, { QTC::TC("qpdf", "QPDF object gone after xref reconstruction"); warn(QPDFExc( - qpdf_e_damaged_pdf, this->file->getName(), + qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, std::string( "object " + @@ -1616,19 +1632,20 @@ QPDF::readObjectAtOffset(bool try_recovery, } QPDFObjectHandle oh = readObject( - this->file, description, objid, generation, false); + this->m->file, description, objid, generation, false); - if (! (readToken(this->file) == + if (! (readToken(this->m->file) == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj"))) { QTC::TC("qpdf", "QPDF err expected endobj"); - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, this->file->getLastOffset(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "expected endobj")); } QPDFObjGen og(objid, generation); - if (! this->obj_cache.count(og)) + if (! this->m->obj_cache.count(og)) { // Store the object in the cache here so it gets cached // whether we first know the offset or whether we first know @@ -1640,30 +1657,30 @@ QPDF::readObjectAtOffset(bool try_recovery, // linearization hint tables. Offsets and lengths of objects // may imply the end of an object to be anywhere between these // values. - qpdf_offset_t end_before_space = this->file->tell(); + qpdf_offset_t end_before_space = this->m->file->tell(); // skip over spaces while (true) { char ch; - if (this->file->read(&ch, 1)) + if (this->m->file->read(&ch, 1)) { if (! isspace(static_cast(ch))) { - this->file->seek(-1, SEEK_CUR); + this->m->file->seek(-1, SEEK_CUR); break; } } else { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, offset, + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, offset, "EOF after endobj"); } } - qpdf_offset_t end_after_space = this->file->tell(); + qpdf_offset_t end_after_space = this->m->file->tell(); - this->obj_cache[og] = + this->m->obj_cache[og] = ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), end_before_space, end_after_space); } @@ -1678,14 +1695,14 @@ QPDF::resolve(int objid, int generation) // to insert things into the object cache that don't actually // exist in the file. QPDFObjGen og(objid, generation); - if (this->resolving.count(og)) + if (this->m->resolving.count(og)) { // This can happen if an object references itself directly or // indirectly in some key that has to be resolved during // object parsing, such as stream length. QTC::TC("qpdf", "QPDF recursion loop in resolve"); - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "", this->file->getLastOffset(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "", this->m->file->getLastOffset(), "loop detected resolving object " + QUtil::int_to_string(objid) + " " + QUtil::int_to_string(generation))); @@ -1693,15 +1710,15 @@ QPDF::resolve(int objid, int generation) } ResolveRecorder rr(this, og); - if (! this->obj_cache.count(og)) + if (! this->m->obj_cache.count(og)) { - if (! this->xref_table.count(og)) + if (! this->m->xref_table.count(og)) { // PDF spec says unknown objects resolve to the null object. return new QPDF_Null; } - QPDFXRefEntry const& entry = this->xref_table[og]; + QPDFXRefEntry const& entry = this->m->xref_table[og]; bool success = false; try { @@ -1724,7 +1741,8 @@ QPDF::resolve(int objid, int generation) break; default: - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0, + throw QPDFExc(qpdf_e_damaged_pdf, + this->m->file->getName(), "", 0, "object " + QUtil::int_to_string(objid) + "/" + QUtil::int_to_string(generation) + @@ -1738,7 +1756,7 @@ QPDF::resolve(int objid, int generation) } catch (std::exception& e) { - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0, + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "", 0, "object " + QUtil::int_to_string(objid) + "/" + QUtil::int_to_string(generation) + @@ -1748,12 +1766,12 @@ QPDF::resolve(int objid, int generation) { QTC::TC("qpdf", "QPDF resolve failure to null"); QPDFObjectHandle oh = QPDFObjectHandle::newNull(); - this->obj_cache[og] = + this->m->obj_cache[og] = ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); } } - return this->obj_cache[og].object; + return this->m->obj_cache[og].object; } void @@ -1763,9 +1781,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number) QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0); if (! obj_stream.isStream()) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "supposed object stream " + QUtil::int_to_string(obj_stream_number) + " is not a stream"); @@ -1775,18 +1793,18 @@ QPDF::resolveObjectsInStream(int obj_stream_number) // object stream for the objects in the stream. QPDFObjGen stream_og(obj_stream_number, 0); qpdf_offset_t end_before_space = - this->obj_cache[stream_og].end_before_space; + this->m->obj_cache[stream_og].end_before_space; qpdf_offset_t end_after_space = - this->obj_cache[stream_og].end_after_space; + this->m->obj_cache[stream_og].end_after_space; QPDFObjectHandle dict = obj_stream.getDict(); if (! (dict.getKey("/Type").isName() && dict.getKey("/Type").getName() == "/ObjStm")) { QTC::TC("qpdf", "QPDF ERR object stream with wrong type"); - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "supposed object stream " + QUtil::int_to_string(obj_stream_number) + " has wrong type"); @@ -1795,9 +1813,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number) if (! (dict.getKey("/N").isInteger() && dict.getKey("/First").isInteger())) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "object stream " + QUtil::int_to_string(obj_stream_number) + " has incorrect keys"); @@ -1821,7 +1839,8 @@ QPDF::resolveObjectsInStream(int obj_stream_number) (toffset.getType() == QPDFTokenizer::tt_integer))) { throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - this->last_object_description, input->getLastOffset(), + this->m->last_object_description, + input->getLastOffset(), "expected integer in object stream header"); } @@ -1840,14 +1859,14 @@ QPDF::resolveObjectsInStream(int obj_stream_number) { int obj = (*iter).first; QPDFObjGen og(obj, 0); - QPDFXRefEntry const& entry = this->xref_table[og]; + QPDFXRefEntry const& entry = this->m->xref_table[og]; if ((entry.getType() == 2) && (entry.getObjStreamNumber() == obj_stream_number)) { int offset = (*iter).second; input->seek(offset, SEEK_SET); QPDFObjectHandle oh = readObject(input, "", obj, 0, true); - this->obj_cache[og] = + this->m->obj_cache[og] = ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), end_before_space, end_after_space); } @@ -1862,16 +1881,16 @@ QPDFObjectHandle QPDF::makeIndirectObject(QPDFObjectHandle oh) { QPDFObjGen o1(0, 0); - if (! this->obj_cache.empty()) + if (! this->m->obj_cache.empty()) { - o1 = (*(this->obj_cache.rbegin())).first; + o1 = (*(this->m->obj_cache.rbegin())).first; } - QPDFObjGen o2 = (*(this->xref_table.rbegin())).first; + QPDFObjGen o2 = (*(this->m->xref_table.rbegin())).first; QTC::TC("qpdf", "QPDF indirect last obj from xref", (o2.getObj() > o1.getObj()) ? 1 : 0); int max_objid = std::max(o1.getObj(), o2.getObj()); QPDFObjGen next(max_objid + 1, 0); - this->obj_cache[next] = + this->m->obj_cache[next] = ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); return QPDFObjectHandle::Factory::newIndirect( this, next.getObj(), next.getGen()); @@ -1910,7 +1929,7 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh) // Replace the object in the object cache QPDFObjGen og(objid, generation); - this->obj_cache[og] = + this->m->obj_cache[og] = ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); } @@ -1946,7 +1965,7 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign, bool allow_page) "QPDF::copyForeign called with object from this QPDF"); } - ObjCopier& obj_copier = this->object_copiers[other]; + ObjCopier& obj_copier = this->m->object_copiers[other]; if (! obj_copier.visiting.empty()) { throw std::logic_error("obj_copier.visiting is not empty" @@ -2016,7 +2035,8 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, QTC::TC("qpdf", "QPDF loop reserving objects"); return; } - if (obj_copier.object_map.find(foreign_og) != obj_copier.object_map.end()) + if (obj_copier.object_map.find(foreign_og) != + obj_copier.object_map.end()) { QTC::TC("qpdf", "QPDF already reserved object"); return; @@ -2139,15 +2159,16 @@ QPDF::replaceForeignIndirectObjects( replaceForeignIndirectObjects( old_dict.getKey(*iter), obj_copier, false)); } - if (this->copied_stream_data_provider == 0) + if (this->m->copied_stream_data_provider == 0) { - this->copied_stream_data_provider = new CopiedStreamDataProvider(); - this->copied_streams = this->copied_stream_data_provider; + this->m->copied_stream_data_provider = + new CopiedStreamDataProvider(); + this->m->copied_streams = this->m->copied_stream_data_provider; } QPDFObjGen local_og(result.getObjGen()); - this->copied_stream_data_provider->registerForeignStream( + this->m->copied_stream_data_provider->registerForeignStream( local_og, foreign); - result.replaceStreamData(this->copied_streams, + result.replaceStreamData(this->m->copied_streams, dict.getKey("/Filter"), dict.getKey("/DecodeParms")); } @@ -2181,21 +2202,21 @@ QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2) resolve(objid2, generation2); QPDFObjGen og1(objid1, generation1); QPDFObjGen og2(objid2, generation2); - ObjCache t = this->obj_cache[og1]; - this->obj_cache[og1] = this->obj_cache[og2]; - this->obj_cache[og2] = t; + ObjCache t = this->m->obj_cache[og1]; + this->m->obj_cache[og1] = this->m->obj_cache[og2]; + this->m->obj_cache[og2] = t; } std::string QPDF::getFilename() const { - return this->file->getName(); + return this->m->file->getName(); } std::string QPDF::getPDFVersion() const { - return this->pdf_version; + return this->m->pdf_version; } int @@ -2225,17 +2246,17 @@ QPDF::getExtensionLevel() QPDFObjectHandle QPDF::getTrailer() { - return this->trailer; + return this->m->trailer; } QPDFObjectHandle QPDF::getRoot() { - QPDFObjectHandle root = this->trailer.getKey("/Root"); + QPDFObjectHandle root = this->m->trailer.getKey("/Root"); if (! root.isDictionary()) { - throw QPDFExc(qpdf_e_damaged_pdf, file->getName(), - "", file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "", this->m->file->getLastOffset(), "unable to find /Root dictionary"); } return root; @@ -2245,8 +2266,8 @@ void QPDF::getObjectStreamData(std::map& omap) { for (std::map::iterator iter = - this->xref_table.begin(); - iter != this->xref_table.end(); ++iter) + this->m->xref_table.begin(); + iter != this->m->xref_table.end(); ++iter) { QPDFObjGen const& og = (*iter).first; QPDFXRefEntry const& entry = (*iter).second; @@ -2270,12 +2291,13 @@ QPDF::getCompressibleObjGens() // orphaned items. // Exclude encryption dictionary, if any - QPDFObjectHandle encryption_dict = trailer.getKey("/Encrypt"); + QPDFObjectHandle encryption_dict = + this->m->trailer.getKey("/Encrypt"); QPDFObjGen encryption_dict_og = encryption_dict.getObjGen(); std::set visited; std::list queue; - queue.push_front(this->trailer); + queue.push_front(this->m->trailer); std::vector result; while (! queue.empty()) { @@ -2353,25 +2375,25 @@ QPDF::pipeStreamData(int objid, int generation, { bool success = false; std::vector > to_delete; - if (this->encrypted) + if (this->m->encrypted) { decryptStream(pipeline, objid, generation, stream_dict, to_delete); } try { - this->file->seek(offset, SEEK_SET); + this->m->file->seek(offset, SEEK_SET); char buf[10240]; while (length > 0) { size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length); - size_t len = this->file->read(buf, to_read); + size_t len = this->m->file->read(buf, to_read); if (len == 0) { throw QPDFExc(qpdf_e_damaged_pdf, - this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "unexpected EOF reading stream data"); } length -= len; @@ -2392,8 +2414,8 @@ QPDF::pipeStreamData(int objid, int generation, if (! suppress_warnings) { QTC::TC("qpdf", "QPDF decoding error warning"); - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "", this->file->getLastOffset(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "", this->m->file->getLastOffset(), "error decoding stream data for object " + QUtil::int_to_string(objid) + " " + QUtil::int_to_string(generation) + ": " + e.what())); @@ -2442,7 +2464,7 @@ QPDF::findAttachmentStreams() item.getKey("/EF").getKey("/F").isStream()) { QPDFObjectHandle stream = item.getKey("/EF").getKey("/F"); - this->attachment_streams.insert(stream.getObjGen()); + this->m->attachment_streams.insert(stream.getObjGen()); } } } diff --git a/libqpdf/QPDF_encryption.cc b/libqpdf/QPDF_encryption.cc index 6c0c97ef..81325591 100644 --- a/libqpdf/QPDF_encryption.cc +++ b/libqpdf/QPDF_encryption.cc @@ -760,9 +760,9 @@ QPDF::interpretCF(QPDFObjectHandle cf) if (cf.isName()) { std::string filter = cf.getName(); - if (this->crypt_filters.count(filter) != 0) + if (this->m->crypt_filters.count(filter) != 0) { - return this->crypt_filters[filter]; + return this->m->crypt_filters[filter]; } else if (filter == "/Identity") { @@ -783,29 +783,29 @@ QPDF::interpretCF(QPDFObjectHandle cf) void QPDF::initializeEncryption() { - if (this->encryption_initialized) + if (this->m->encryption_initialized) { return; } - this->encryption_initialized = true; + this->m->encryption_initialized = true; // After we initialize encryption parameters, we must used stored // key information and never look at /Encrypt again. Otherwise, // things could go wrong if someone mutates the encryption // dictionary. - if (! this->trailer.hasKey("/Encrypt")) + if (! this->m->trailer.hasKey("/Encrypt")) { return; } - // Go ahead and set this->encryption here. That way, isEncrypted + // Go ahead and set this->m->encrypted here. That way, isEncrypted // will return true even if there were errors reading the // encryption dictionary. - this->encrypted = true; + this->m->encrypted = true; std::string id1; - QPDFObjectHandle id_obj = this->trailer.getKey("/ID"); + QPDFObjectHandle id_obj = this->m->trailer.getKey("/ID"); if ((id_obj.isArray() && (id_obj.getArrayNItems() == 2) && id_obj.getArrayItem(0).isString())) @@ -817,31 +817,31 @@ QPDF::initializeEncryption() // Treating a missing ID as the empty string enables qpdf to // decrypt some invalid encrypted files with no /ID that // poppler can read but Adobe Reader can't. - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "trailer", this->file->getLastOffset(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "trailer", this->m->file->getLastOffset(), "invalid /ID in trailer dictionary")); } - QPDFObjectHandle encryption_dict = this->trailer.getKey("/Encrypt"); + QPDFObjectHandle encryption_dict = this->m->trailer.getKey("/Encrypt"); if (! encryption_dict.isDictionary()) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "/Encrypt in trailer dictionary is not a dictionary"); } if (! (encryption_dict.getKey("/Filter").isName() && (encryption_dict.getKey("/Filter").getName() == "/Standard"))) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "encryption dictionary", this->m->file->getLastOffset(), "unsupported encryption filter"); } if (! encryption_dict.getKey("/SubFilter").isNull()) { - warn(QPDFExc(qpdf_e_unsupported, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + warn(QPDFExc(qpdf_e_unsupported, this->m->file->getName(), + "encryption dictionary", this->m->file->getLastOffset(), "file uses encryption SubFilters," " which qpdf does not support")); } @@ -852,8 +852,8 @@ QPDF::initializeEncryption() encryption_dict.getKey("/U").isString() && encryption_dict.getKey("/P").isInteger())) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "encryption dictionary", this->m->file->getLastOffset(), "some encryption dictionary parameters are missing " "or the wrong type"); } @@ -869,15 +869,15 @@ QPDF::initializeEncryption() if (! (((R >= 2) && (R <= 6)) && ((V == 1) || (V == 2) || (V == 4) || (V == 5)))) { - throw QPDFExc(qpdf_e_unsupported, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_unsupported, this->m->file->getName(), + "encryption dictionary", this->m->file->getLastOffset(), "Unsupported /R or /V in encryption dictionary; R = " + QUtil::int_to_string(R) + " (max 6), V = " + QUtil::int_to_string(V) + " (max 5)"); } - this->encryption_V = V; - this->encryption_R = R; + this->m->encryption_V = V; + this->m->encryption_R = R; // OE, UE, and Perms are only present if V >= 5. std::string OE; @@ -890,8 +890,9 @@ QPDF::initializeEncryption() pad_short_parameter(U, key_bytes); if (! ((O.length() == key_bytes) && (U.length() == key_bytes))) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "encryption dictionary", + this->m->file->getLastOffset(), "incorrect length for /O and/or /U in " "encryption dictionary"); } @@ -902,8 +903,9 @@ QPDF::initializeEncryption() encryption_dict.getKey("/UE").isString() && encryption_dict.getKey("/Perms").isString())) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "encryption dictionary", + this->m->file->getLastOffset(), "some V=5 encryption dictionary parameters are " "missing or the wrong type"); } @@ -922,8 +924,9 @@ QPDF::initializeEncryption() (UE.length() < OUE_key_bytes_V5) || (Perms.length() < Perms_key_bytes_V5)) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "encryption dictionary", + this->m->file->getLastOffset(), "incorrect length for some of" " /O, /U, /OE, /UE, or /Perms in" " encryption dictionary"); @@ -936,16 +939,17 @@ QPDF::initializeEncryption() Length = encryption_dict.getKey("/Length").getIntValue(); if ((Length % 8) || (Length < 40) || (Length > 256)) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "encryption dictionary", + this->m->file->getLastOffset(), "invalid /Length value in encryption dictionary"); } } - this->encrypt_metadata = true; + this->m->encrypt_metadata = true; if ((V >= 4) && (encryption_dict.getKey("/EncryptMetadata").isBool())) { - this->encrypt_metadata = + this->m->encrypt_metadata = encryption_dict.getKey("/EncryptMetadata").getBoolValue(); } @@ -986,40 +990,40 @@ QPDF::initializeEncryption() method = e_unknown; } } - this->crypt_filters[filter] = method; + this->m->crypt_filters[filter] = method; } } QPDFObjectHandle StmF = encryption_dict.getKey("/StmF"); QPDFObjectHandle StrF = encryption_dict.getKey("/StrF"); QPDFObjectHandle EFF = encryption_dict.getKey("/EFF"); - this->cf_stream = interpretCF(StmF); - this->cf_string = interpretCF(StrF); + this->m->cf_stream = interpretCF(StmF); + this->m->cf_string = interpretCF(StrF); if (EFF.isName()) { - this->cf_file = interpretCF(EFF); + this->m->cf_file = interpretCF(EFF); } else { - this->cf_file = this->cf_stream; + this->m->cf_file = this->m->cf_stream; } } EncryptionData data(V, R, Length / 8, P, O, U, OE, UE, Perms, - id1, this->encrypt_metadata); + id1, this->m->encrypt_metadata); if (check_owner_password( - this->user_password, this->provided_password, data)) + this->m->user_password, this->m->provided_password, data)) { // password supplied was owner password; user_password has // been initialized for V < 5 } - else if (check_user_password(this->provided_password, data)) + else if (check_user_password(this->m->provided_password, data)) { - this->user_password = this->provided_password; + this->m->user_password = this->m->provided_password; } else { - throw QPDFExc(qpdf_e_password, this->file->getName(), + throw QPDFExc(qpdf_e_password, this->m->file->getName(), "", 0, "invalid password"); } @@ -1028,8 +1032,8 @@ QPDF::initializeEncryption() // For V < 5, the user password is encrypted with the owner // password, and the user password is always used for // computing the encryption key. - this->encryption_key = compute_encryption_key( - this->user_password, data); + this->m->encryption_key = compute_encryption_key( + this->m->user_password, data); } else { @@ -1037,12 +1041,13 @@ QPDF::initializeEncryption() // compute the encryption key, and neither password can be // used to recover the other. bool perms_valid; - this->encryption_key = recover_encryption_key_with_password( - this->provided_password, data, perms_valid); + this->m->encryption_key = recover_encryption_key_with_password( + this->m->provided_password, data, perms_valid); if (! perms_valid) { - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - "encryption dictionary", this->file->getLastOffset(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "encryption dictionary", + this->m->file->getLastOffset(), "/Perms field in encryption dictionary" " doesn't match expected value")); } @@ -1052,23 +1057,24 @@ QPDF::initializeEncryption() std::string QPDF::getKeyForObject(int objid, int generation, bool use_aes) { - if (! this->encrypted) + if (! this->m->encrypted) { throw std::logic_error( "request for encryption key in non-encrypted PDF"); } - if (! ((objid == this->cached_key_objid) && - (generation == this->cached_key_generation))) + if (! ((objid == this->m->cached_key_objid) && + (generation == this->m->cached_key_generation))) { - this->cached_object_encryption_key = - compute_data_key(this->encryption_key, objid, generation, - use_aes, this->encryption_V, this->encryption_R); - this->cached_key_objid = objid; - this->cached_key_generation = generation; + this->m->cached_object_encryption_key = + compute_data_key(this->m->encryption_key, objid, generation, + use_aes, this->m->encryption_V, + this->m->encryption_R); + this->m->cached_key_objid = objid; + this->m->cached_key_generation = generation; } - return this->cached_object_encryption_key; + return this->m->cached_object_encryption_key; } void @@ -1079,9 +1085,9 @@ QPDF::decryptString(std::string& str, int objid, int generation) return; } bool use_aes = false; - if (this->encryption_V >= 4) + if (this->m->encryption_V >= 4) { - switch (this->cf_string) + switch (this->m->cf_string) { case e_none: return; @@ -1098,15 +1104,15 @@ QPDF::decryptString(std::string& str, int objid, int generation) break; default: - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "unknown encryption filter for strings" " (check /StrF in /Encrypt dictionary);" " strings may be decrypted improperly")); // To avoid repeated warnings, reset cf_string. Assume // we'd want to use AES if V == 4. - this->cf_string = e_aes; + this->m->cf_string = e_aes; break; } } @@ -1145,9 +1151,9 @@ QPDF::decryptString(std::string& str, int objid, int generation) } catch (std::runtime_error& e) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "error decrypting string for object " + QUtil::int_to_string(objid) + " " + QUtil::int_to_string(generation) + ": " + e.what()); @@ -1170,7 +1176,7 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation, return; } bool use_aes = false; - if (this->encryption_V >= 4) + if (this->m->encryption_V >= 4) { encryption_method_e method = e_unknown; std::string method_source = "/StmF from /Encrypt dictionary"; @@ -1221,21 +1227,21 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation, if (method == e_unknown) { - if ((! this->encrypt_metadata) && (type == "/Metadata")) + if ((! this->m->encrypt_metadata) && (type == "/Metadata")) { QTC::TC("qpdf", "QPDF_encryption cleartext metadata"); method = e_none; } else { - if (this->attachment_streams.count( + if (this->m->attachment_streams.count( QPDFObjGen(objid, generation)) > 0) { - method = this->cf_file; + method = this->m->cf_file; } else { - method = this->cf_stream; + method = this->m->cf_stream; } } } @@ -1259,15 +1265,15 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation, default: // filter local to this stream. - warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "unknown encryption filter for streams" " (check " + method_source + ");" " streams may be decrypted improperly")); // To avoid repeated warnings, reset cf_stream. Assume // we'd want to use AES if V == 4. - this->cf_stream = e_aes; + this->m->cf_stream = e_aes; break; } } @@ -1331,13 +1337,13 @@ QPDF::compute_encryption_parameters_V5( std::string const& QPDF::getPaddedUserPassword() const { - return this->user_password; + return this->m->user_password; } std::string QPDF::getTrimmedUserPassword() const { - std::string result = this->user_password; + std::string result = this->m->user_password; trim_user_password(result); return result; } @@ -1345,13 +1351,13 @@ QPDF::getTrimmedUserPassword() const std::string QPDF::getEncryptionKey() const { - return this->encryption_key; + return this->m->encryption_key; } bool QPDF::isEncrypted() const { - return this->encrypted; + return this->m->encrypted; } bool @@ -1368,7 +1374,7 @@ QPDF::isEncrypted(int& R, int& P, int& V, encryption_method_e& string_method, encryption_method_e& file_method) { - if (this->encrypted) + if (this->m->encrypted) { QPDFObjectHandle trailer = getTrailer(); QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); @@ -1378,9 +1384,9 @@ QPDF::isEncrypted(int& R, int& P, int& V, P = Pkey.getIntValue(); R = Rkey.getIntValue(); V = Vkey.getIntValue(); - stream_method = this->cf_stream; - string_method = this->cf_stream; - file_method = this->cf_file; + stream_method = this->m->cf_stream; + string_method = this->m->cf_stream; + file_method = this->m->cf_file; return true; } else diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc index b05b1d4c..3d04ab90 100644 --- a/libqpdf/QPDF_linearization.cc +++ b/libqpdf/QPDF_linearization.cc @@ -72,7 +72,7 @@ QPDF::checkLinearization() } catch (QPDFExc& e) { - *out_stream << e.what() << std::endl; + *this->m->out_stream << e.what() << std::endl; } return result; } @@ -82,7 +82,7 @@ QPDF::isLinearized() { // If the first object in the file is a dictionary with a suitable // /Linearized key and has an /L key that accurately indicates the - // file size, initialize this->lindict and return true. + // file size, initialize this->m->lindict and return true. // A linearized PDF spec's first object will be contained within // the first 1024 bytes of the file and will be a dictionary with @@ -95,10 +95,10 @@ QPDF::isLinearized() static int const tbuf_size = 1025; char* buf = new char[tbuf_size]; - this->file->seek(0, SEEK_SET); + this->m->file->seek(0, SEEK_SET); PointerHolder b(true, buf); memset(buf, '\0', tbuf_size); - this->file->read(buf, tbuf_size - 1); + this->m->file->read(buf, tbuf_size - 1); int lindict_obj = -1; char* p = buf; @@ -115,16 +115,16 @@ QPDF::isLinearized() } // Seek to the digit. Then skip over digits for a potential // next iteration. - this->file->seek(p - buf, SEEK_SET); + this->m->file->seek(p - buf, SEEK_SET); while (((p - buf) < tbuf_size) && QUtil::is_digit(*p)) { ++p; } - QPDFTokenizer::Token t1 = readToken(this->file, true); - QPDFTokenizer::Token t2 = readToken(this->file, true); - QPDFTokenizer::Token t3 = readToken(this->file, true); - QPDFTokenizer::Token t4 = readToken(this->file, true); + QPDFTokenizer::Token t1 = readToken(this->m->file, true); + QPDFTokenizer::Token t2 = readToken(this->m->file, true); + QPDFTokenizer::Token t3 = readToken(this->m->file, true); + QPDFTokenizer::Token t4 = readToken(this->m->file, true); if ((t1.getType() == QPDFTokenizer::tt_integer) && (t2.getType() == QPDFTokenizer::tt_integer) && (t3 == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "obj")) && @@ -158,19 +158,19 @@ QPDF::isLinearized() if (L.isInteger()) { qpdf_offset_t Li = L.getIntValue(); - this->file->seek(0, SEEK_END); - if (Li != this->file->tell()) + this->m->file->seek(0, SEEK_END); + if (Li != this->m->file->tell()) { QTC::TC("qpdf", "QPDF /L mismatch"); return false; } else { - this->linp.file_size = Li; + this->m->linp.file_size = Li; } } - this->lindict = candidate; + this->m->lindict = candidate; return true; } @@ -191,12 +191,12 @@ QPDF::readLinearizationData() } // /L is read and stored in linp by isLinearized() - QPDFObjectHandle H = lindict.getKey("/H"); - QPDFObjectHandle O = lindict.getKey("/O"); - QPDFObjectHandle E = lindict.getKey("/E"); - QPDFObjectHandle N = lindict.getKey("/N"); - QPDFObjectHandle T = lindict.getKey("/T"); - QPDFObjectHandle P = lindict.getKey("/P"); + QPDFObjectHandle H = this->m->lindict.getKey("/H"); + QPDFObjectHandle O = this->m->lindict.getKey("/O"); + QPDFObjectHandle E = this->m->lindict.getKey("/E"); + QPDFObjectHandle N = this->m->lindict.getKey("/N"); + QPDFObjectHandle T = this->m->lindict.getKey("/T"); + QPDFObjectHandle P = this->m->lindict.getKey("/P"); if (! (H.isArray() && O.isInteger() && @@ -205,9 +205,9 @@ QPDF::readLinearizationData() T.isInteger() && (P.isInteger() || P.isNull()))) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "linearization dictionary", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "some keys in linearization dictionary are of " "the wrong type"); } @@ -216,9 +216,9 @@ QPDF::readLinearizationData() unsigned int n_H_items = H.getArrayNItems(); if (! ((n_H_items == 2) || (n_H_items == 4))) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "linearization dictionary", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "H has the wrong number of items"); } @@ -232,9 +232,9 @@ QPDF::readLinearizationData() } else { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "linearization dictionary", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "some H items are of the wrong type"); } } @@ -272,20 +272,20 @@ QPDF::readLinearizationData() // accurate and bail right now if it's not. if (N.getIntValue() != static_cast(getAllPages().size())) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "linearization hint table", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "/N does not match number of pages"); } // file_size initialized by isLinearized() - this->linp.first_page_object = O.getIntValue(); - this->linp.first_page_end = E.getIntValue(); - this->linp.npages = N.getIntValue(); - this->linp.xref_zero_offset = T.getIntValue(); - this->linp.first_page = first_page; - this->linp.H_offset = H0_offset; - this->linp.H_length = H0_length; + this->m->linp.first_page_object = O.getIntValue(); + this->m->linp.first_page_end = E.getIntValue(); + this->m->linp.npages = N.getIntValue(); + this->m->linp.xref_zero_offset = T.getIntValue(); + this->m->linp.first_page = first_page; + this->m->linp.H_offset = H0_offset; + this->m->linp.H_length = H0_length; // Read hint streams @@ -320,9 +320,9 @@ QPDF::readLinearizationData() int HSi = HS.getIntValue(); if ((HSi < 0) || (HSi >= h_size)) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "linearization hint table", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "/S (shared object) offset is out of bounds"); } readHSharedObject(BitStream(h_buf + HSi, h_size - HSi)); @@ -332,13 +332,13 @@ QPDF::readLinearizationData() int HOi = HO.getIntValue(); if ((HOi < 0) || (HOi >= h_size)) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "linearization hint table", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "/O (outline) offset is out of bounds"); } readHGeneric(BitStream(h_buf + HOi, h_size - HOi), - this->outline_hints); + this->m->outline_hints); } } @@ -349,14 +349,14 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) int gen; QPDFObjectHandle H = readObjectAtOffset( false, offset, "linearization hint stream", -1, 0, obj, gen); - ObjCache& oc = this->obj_cache[QPDFObjGen(obj, gen)]; + ObjCache& oc = this->m->obj_cache[QPDFObjGen(obj, gen)]; qpdf_offset_t min_end_offset = oc.end_before_space; qpdf_offset_t max_end_offset = oc.end_after_space; if (! H.isStream()) { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "linearization dictionary", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "hint table is not a stream"); } @@ -373,7 +373,7 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) QTC::TC("qpdf", "QPDF hint table length indirect"); // Force resolution (void) length_obj.getIntValue(); - ObjCache& oc = this->obj_cache[length_obj.getObjGen()]; + ObjCache& oc = this->m->obj_cache[length_obj.getObjGen()]; min_end_offset = oc.end_before_space; max_end_offset = oc.end_after_space; } @@ -385,12 +385,12 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) if ((computed_end < min_end_offset) || (computed_end > max_end_offset)) { - *out_stream << "expected = " << computed_end - << "; actual = " << min_end_offset << ".." - << max_end_offset << std::endl; - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), + *this->m->out_stream << "expected = " << computed_end + << "; actual = " << min_end_offset << ".." + << max_end_offset << std::endl; + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), "linearization dictionary", - this->file->getLastOffset(), + this->m->file->getLastOffset(), "hint table length mismatch"); } H.pipeStreamData(&pl, 0, qpdf_dl_specialized); @@ -403,7 +403,7 @@ QPDF::readHPageOffset(BitStream h) // All comments referring to the PDF spec refer to the spec for // version 1.4. - HPageOffset& t = this->page_offset_hints; + HPageOffset& t = this->m->page_offset_hints; t.min_nobjects = h.getBits(32); // 1 t.first_page_offset = h.getBits(32); // 2 @@ -421,7 +421,7 @@ QPDF::readHPageOffset(BitStream h) std::vector& entries = t.entries; entries.clear(); - unsigned int nitems = this->linp.npages; + unsigned int nitems = this->m->linp.npages; load_vector_int(h, nitems, entries, t.nbits_delta_nobjects, &HPageOffsetEntry::delta_nobjects); @@ -450,7 +450,7 @@ QPDF::readHPageOffset(BitStream h) void QPDF::readHSharedObject(BitStream h) { - HSharedObject& t = this->shared_object_hints; + HSharedObject& t = this->m->shared_object_hints; t.first_shared_obj = h.getBits(32); // 1 t.first_shared_offset = h.getBits(32); // 2 @@ -509,7 +509,7 @@ QPDF::checkLinearizationInternal() // Check all values in linearization parameter dictionary - LinParameters& p = this->linp; + LinParameters& p = this->m->linp; // L: file size in bytes -- checked by isLinearized @@ -533,7 +533,7 @@ QPDF::checkLinearizationInternal() { QPDFObjectHandle const& page = pages.at(i); QPDFObjGen og(page.getObjGen()); - if (this->xref_table[og].getType() == 2) + if (this->m->xref_table[og].getType() == 2) { errors.push_back("page dictionary for page " + QUtil::int_to_string(i) + " is compressed"); @@ -541,25 +541,25 @@ QPDF::checkLinearizationInternal() } // T: offset of whitespace character preceding xref entry for object 0 - this->file->seek(p.xref_zero_offset, SEEK_SET); + this->m->file->seek(p.xref_zero_offset, SEEK_SET); while (1) { char ch; - this->file->read(&ch, 1); + this->m->file->read(&ch, 1); if (! ((ch == ' ') || (ch == '\r') || (ch == '\n'))) { - this->file->seek(-1, SEEK_CUR); + this->m->file->seek(-1, SEEK_CUR); break; } } - if (this->file->tell() != this->first_xref_item_offset) + if (this->m->file->tell() != this->m->first_xref_item_offset) { QTC::TC("qpdf", "QPDF err /T mismatch"); errors.push_back("space before first xref item (/T) mismatch " "(computed = " + - QUtil::int_to_string(this->first_xref_item_offset) + + QUtil::int_to_string(this->m->first_xref_item_offset) + "; file = " + - QUtil::int_to_string(this->file->tell())); + QUtil::int_to_string(this->m->file->tell())); } // P: first page number -- Implementation note 124 says Acrobat @@ -570,7 +570,7 @@ QPDF::checkLinearizationInternal() // at the end of the containing xref section if any object streams // are in use. - if (this->uncompressed_after_compressed) + if (this->m->uncompressed_after_compressed) { errors.push_back("linearized file contains an uncompressed object" " after a compressed one in a cross-reference stream"); @@ -584,8 +584,8 @@ QPDF::checkLinearizationInternal() { // local scope std::map object_stream_data; for (std::map::const_iterator iter = - this->xref_table.begin(); - iter != this->xref_table.end(); ++iter) + this->m->xref_table.begin(); + iter != this->m->xref_table.end(); ++iter) { QPDFObjGen const& og = (*iter).first; QPDFXRefEntry const& entry = (*iter).second; @@ -609,22 +609,22 @@ QPDF::checkLinearizationInternal() // agree with pdlin. As of this writing, the test suite doesn't // contain any files with threads. - if (this->part6.empty()) + if (this->m->part6.empty()) { throw std::logic_error("linearization part 6 unexpectedly empty"); } qpdf_offset_t min_E = -1; qpdf_offset_t max_E = -1; - for (std::vector::iterator iter = this->part6.begin(); - iter != this->part6.end(); ++iter) + for (std::vector::iterator iter = this->m->part6.begin(); + iter != this->m->part6.end(); ++iter) { QPDFObjGen og((*iter).getObjGen()); - if (this->obj_cache.count(og) == 0) + if (this->m->obj_cache.count(og) == 0) { // All objects have to have been dereferenced to be classified. throw std::logic_error("linearization part6 object not in cache"); } - ObjCache const& oc = this->obj_cache[og]; + ObjCache const& oc = this->m->obj_cache[og]; min_E = std::max(min_E, oc.end_before_space); max_E = std::max(max_E, oc.end_after_space); } @@ -655,7 +655,7 @@ QPDF::checkLinearizationInternal() for (std::list::iterator iter = errors.begin(); iter != errors.end(); ++iter) { - *out_stream << "ERROR: " << (*iter) << std::endl; + *this->m->out_stream << "ERROR: " << (*iter) << std::endl; } } @@ -665,7 +665,7 @@ QPDF::checkLinearizationInternal() for (std::list::iterator iter = warnings.begin(); iter != warnings.end(); ++iter) { - *out_stream << "WARNING: " << (*iter) << std::endl; + *this->m->out_stream << "WARNING: " << (*iter) << std::endl; } } @@ -675,15 +675,15 @@ QPDF::checkLinearizationInternal() qpdf_offset_t QPDF::maxEnd(ObjUser const& ou) { - assert(this->obj_user_to_objects.count(ou) > 0); - std::set const& ogs = this->obj_user_to_objects[ou]; + assert(this->m->obj_user_to_objects.count(ou) > 0); + std::set const& ogs = this->m->obj_user_to_objects[ou]; qpdf_offset_t end = 0; for (std::set::const_iterator iter = ogs.begin(); iter != ogs.end(); ++iter) { QPDFObjGen const& og = *iter; - assert(this->obj_cache.count(og) > 0); - end = std::max(end, this->obj_cache[og].end_after_space); + assert(this->m->obj_cache.count(og) > 0); + end = std::max(end, this->m->obj_cache[og].end_after_space); } return end; } @@ -691,7 +691,7 @@ QPDF::maxEnd(ObjUser const& ou) qpdf_offset_t QPDF::getLinearizationOffset(QPDFObjGen const& og) { - QPDFXRefEntry entry = this->xref_table[og]; + QPDFXRefEntry entry = this->m->xref_table[og]; qpdf_offset_t result = 0; switch (entry.getType()) { @@ -737,7 +737,7 @@ QPDF::lengthNextN(int first_object, int n, for (int i = 0; i < n; ++i) { QPDFObjGen og(first_object + i, 0); - if (this->xref_table.count(og) == 0) + if (this->m->xref_table.count(og) == 0) { errors.push_back( "no xref table entry for " + @@ -745,8 +745,8 @@ QPDF::lengthNextN(int first_object, int n, } else { - assert(this->obj_cache.count(og) > 0); - length += this->obj_cache[og].end_after_space - + assert(this->m->obj_cache.count(og) > 0); + length += this->m->obj_cache[og].end_after_space - getLinearizationOffset(og); } } @@ -778,9 +778,9 @@ QPDF::checkHPageOffset(std::list& errors, unsigned int npages = pages.size(); int table_offset = adjusted_offset( - this->page_offset_hints.first_page_offset); + this->m->page_offset_hints.first_page_offset); QPDFObjGen first_page_og(pages.at(0).getObjGen()); - assert(this->xref_table.count(first_page_og) > 0); + assert(this->m->xref_table.count(first_page_og) > 0); int offset = getLinearizationOffset(first_page_og); if (table_offset != offset) { @@ -791,13 +791,13 @@ QPDF::checkHPageOffset(std::list& errors, { QPDFObjGen page_og(pages.at(pageno).getObjGen()); int first_object = page_og.getObj(); - assert(this->xref_table.count(page_og) > 0); + assert(this->m->xref_table.count(page_og) > 0); offset = getLinearizationOffset(page_og); - HPageOffsetEntry& he = this->page_offset_hints.entries.at(pageno); - CHPageOffsetEntry& ce = this->c_page_offset_data.entries.at(pageno); + HPageOffsetEntry& he = this->m->page_offset_hints.entries.at(pageno); + CHPageOffsetEntry& ce = this->m->c_page_offset_data.entries.at(pageno); int h_nobjects = he.delta_nobjects + - this->page_offset_hints.min_nobjects; + this->m->page_offset_hints.min_nobjects; if (h_nobjects != ce.nobjects) { // This happens with pdlin when there are thumbnails. @@ -812,7 +812,7 @@ QPDF::checkHPageOffset(std::list& errors, // computed value if there is a discrepancy. int length = lengthNextN(first_object, h_nobjects, errors); int h_length = he.delta_page_length + - this->page_offset_hints.min_page_length; + this->m->page_offset_hints.min_page_length; if (length != h_length) { // This condition almost certainly indicates a bad hint @@ -853,12 +853,12 @@ QPDF::checkHPageOffset(std::list& errors, for (int i = 0; i < ce.nshared_objects; ++i) { int idx = ce.shared_identifiers.at(i); - if (idx >= this->c_shared_object_data.nshared_total) + if (idx >= this->m->c_shared_object_data.nshared_total) { throw std::logic_error( "index out of bounds for shared object hint table"); } - int obj = this->c_shared_object_data.entries.at(idx).object; + int obj = this->m->c_shared_object_data.entries.at(idx).object; computed_shared.insert(obj); } @@ -916,7 +916,7 @@ QPDF::checkHSharedObject(std::list& errors, // these whenever there are no shared objects not referenced by // the first page (i.e., nshared_total == nshared_first_page). - HSharedObject& so = this->shared_object_hints; + HSharedObject& so = this->m->shared_object_hints; if (so.nshared_total < so.nshared_first_page) { errors.push_back("shared object hint table: ntotal < nfirst_page"); @@ -932,7 +932,7 @@ QPDF::checkHSharedObject(std::list& errors, if (i == so.nshared_first_page) { QTC::TC("qpdf", "QPDF lin check shared past first page"); - if (this->part8.empty()) + if (this->m->part8.empty()) { errors.push_back( "part 8 is empty but nshared_total > " @@ -940,7 +940,7 @@ QPDF::checkHSharedObject(std::list& errors, } else { - int obj = this->part8.at(0).getObjectID(); + int obj = this->m->part8.at(0).getObjectID(); if (obj != so.first_shared_obj) { errors.push_back( @@ -955,7 +955,7 @@ QPDF::checkHSharedObject(std::list& errors, cur_object = so.first_shared_obj; QPDFObjGen og(cur_object, 0); - assert(this->xref_table.count(og) > 0); + assert(this->m->xref_table.count(og) > 0); int offset = getLinearizationOffset(og); int h_offset = adjusted_offset(so.first_shared_offset); if (offset != h_offset) @@ -996,15 +996,15 @@ QPDF::checkHOutlines(std::list& warnings) // wrong starting place). pdlin appears to generate correct // values in those cases. - if (this->c_outline_data.nobjects == this->outline_hints.nobjects) + if (this->m->c_outline_data.nobjects == this->m->outline_hints.nobjects) { - if (this->c_outline_data.nobjects == 0) + if (this->m->c_outline_data.nobjects == 0) { return; } - if (this->c_outline_data.first_object == - this->outline_hints.first_object) + if (this->m->c_outline_data.first_object == + this->m->outline_hints.first_object) { // Check length and offset. Acrobat gets these wrong. QPDFObjectHandle outlines = getRoot().getKey("/Outlines"); @@ -1018,12 +1018,12 @@ QPDF::checkHOutlines(std::list& warnings) return; } QPDFObjGen og(outlines.getObjGen()); - assert(this->xref_table.count(og) > 0); + assert(this->m->xref_table.count(og) > 0); int offset = getLinearizationOffset(og); ObjUser ou(ObjUser::ou_root_key, "/Outlines"); int length = maxEnd(ou) - offset; int table_offset = - adjusted_offset(this->outline_hints.first_object_offset); + adjusted_offset(this->m->outline_hints.first_object_offset); if (offset != table_offset) { warnings.push_back( @@ -1031,7 +1031,7 @@ QPDF::checkHOutlines(std::list& warnings) QUtil::int_to_string(table_offset) + "; computed = " + QUtil::int_to_string(offset)); } - int table_length = this->outline_hints.group_length; + int table_length = this->m->outline_hints.group_length; if (length != table_length) { warnings.push_back( @@ -1063,41 +1063,42 @@ QPDF::showLinearizationData() } catch (QPDFExc& e) { - *out_stream << e.what() << std::endl; + *this->m->out_stream << e.what() << std::endl; } } void QPDF::dumpLinearizationDataInternal() { - *out_stream << this->file->getName() << ": linearization data:" << std::endl - << std::endl; + *this->m->out_stream + << this->m->file->getName() << ": linearization data:" << std::endl + << std::endl; - *out_stream - << "file_size: " << this->linp.file_size << std::endl - << "first_page_object: " << this->linp.first_page_object << std::endl - << "first_page_end: " << this->linp.first_page_end << std::endl - << "npages: " << this->linp.npages << std::endl - << "xref_zero_offset: " << this->linp.xref_zero_offset << std::endl - << "first_page: " << this->linp.first_page << std::endl - << "H_offset: " << this->linp.H_offset << std::endl - << "H_length: " << this->linp.H_length << std::endl + *this->m->out_stream + << "file_size: " << this->m->linp.file_size << std::endl + << "first_page_object: " << this->m->linp.first_page_object << std::endl + << "first_page_end: " << this->m->linp.first_page_end << std::endl + << "npages: " << this->m->linp.npages << std::endl + << "xref_zero_offset: " << this->m->linp.xref_zero_offset << std::endl + << "first_page: " << this->m->linp.first_page << std::endl + << "H_offset: " << this->m->linp.H_offset << std::endl + << "H_length: " << this->m->linp.H_length << std::endl << std::endl; - *out_stream << "Page Offsets Hint Table" << std::endl - << std::endl; + *this->m->out_stream << "Page Offsets Hint Table" << std::endl + << std::endl; dumpHPageOffset(); - *out_stream << std::endl - << "Shared Objects Hint Table" << std::endl - << std::endl; + *this->m->out_stream << std::endl + << "Shared Objects Hint Table" << std::endl + << std::endl; dumpHSharedObject(); - if (this->outline_hints.nobjects > 0) + if (this->m->outline_hints.nobjects > 0) { - *out_stream << std::endl - << "Outlines Hint Table" << std::endl - << std::endl; - dumpHGeneric(this->outline_hints); + *this->m->out_stream << std::endl + << "Outlines Hint Table" << std::endl + << std::endl; + dumpHGeneric(this->m->outline_hints); } } @@ -1107,9 +1108,9 @@ QPDF::adjusted_offset(int offset) // All offsets >= H_offset have to be increased by H_length // since all hint table location values disregard the hint table // itself. - if (offset >= this->linp.H_offset) + if (offset >= this->m->linp.H_offset) { - return offset + this->linp.H_length; + return offset + this->m->linp.H_length; } return offset; } @@ -1118,8 +1119,8 @@ QPDF::adjusted_offset(int offset) void QPDF::dumpHPageOffset() { - HPageOffset& t = this->page_offset_hints; - *out_stream + HPageOffset& t = this->m->page_offset_hints; + *this->m->out_stream << "min_nobjects: " << t.min_nobjects << std::endl << "first_page_offset: " << adjusted_offset(t.first_page_offset) @@ -1147,10 +1148,10 @@ QPDF::dumpHPageOffset() << "shared_denominator: " << t.shared_denominator << std::endl; - for (int i1 = 0; i1 < this->linp.npages; ++i1) + for (int i1 = 0; i1 < this->m->linp.npages; ++i1) { HPageOffsetEntry& pe = t.entries.at(i1); - *out_stream + *this->m->out_stream << "Page " << i1 << ":" << std::endl << " nobjects: " << pe.delta_nobjects + t.min_nobjects << std::endl @@ -1164,10 +1165,10 @@ QPDF::dumpHPageOffset() << " nshared_objects: " << pe.nshared_objects << std::endl; for (int i2 = 0; i2 < pe.nshared_objects; ++i2) { - *out_stream << " identifier " << i2 << ": " - << pe.shared_identifiers.at(i2) << std::endl; - *out_stream << " numerator " << i2 << ": " - << pe.shared_numerators.at(i2) << std::endl; + *this->m->out_stream << " identifier " << i2 << ": " + << pe.shared_identifiers.at(i2) << std::endl; + *this->m->out_stream << " numerator " << i2 << ": " + << pe.shared_numerators.at(i2) << std::endl; } } } @@ -1175,8 +1176,8 @@ QPDF::dumpHPageOffset() void QPDF::dumpHSharedObject() { - HSharedObject& t = this->shared_object_hints; - *out_stream + HSharedObject& t = this->m->shared_object_hints; + *this->m->out_stream << "first_shared_obj: " << t.first_shared_obj << std::endl << "first_shared_offset: " << adjusted_offset(t.first_shared_offset) @@ -1195,19 +1196,20 @@ QPDF::dumpHSharedObject() for (int i = 0; i < t.nshared_total; ++i) { HSharedObjectEntry& se = t.entries.at(i); - *out_stream << "Shared Object " << i << ":" << std::endl; - *out_stream << " group length: " - << se.delta_group_length + t.min_group_length << std::endl; + *this->m->out_stream + << "Shared Object " << i << ":" << std::endl + << " group length: " + << se.delta_group_length + t.min_group_length << std::endl; // PDF spec says signature present nobjects_minus_one are // always 0, so print them only if they have a non-zero value. if (se.signature_present) { - *out_stream << " signature present" << std::endl; + *this->m->out_stream << " signature present" << std::endl; } if (se.nobjects_minus_one != 0) { - *out_stream << " nobjects: " - << se.nobjects_minus_one + 1 << std::endl; + *this->m->out_stream << " nobjects: " + << se.nobjects_minus_one + 1 << std::endl; } } } @@ -1215,7 +1217,7 @@ QPDF::dumpHSharedObject() void QPDF::dumpHGeneric(HGeneric& t) { - *out_stream + *this->m->out_stream << "first_object: " << t.first_object << std::endl << "first_object_offset: " << adjusted_offset(t.first_object_offset) @@ -1242,7 +1244,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) // this function. Note that actual offsets and lengths are not // computed here, but anything related to object ordering is. - if (this->object_to_obj_users.empty()) + if (this->m->object_to_obj_users.empty()) { // Note that we can't call optimize here because we don't know // whether it should be called with or without allow changes. @@ -1298,15 +1300,15 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) // * outlines: part 6 or 9 - this->part4.clear(); - this->part6.clear(); - this->part7.clear(); - this->part8.clear(); - this->part9.clear(); - this->c_linp = LinParameters(); - this->c_page_offset_data = CHPageOffset(); - this->c_shared_object_data = CHSharedObject(); - this->c_outline_data = HGeneric(); + this->m->part4.clear(); + this->m->part6.clear(); + this->m->part7.clear(); + this->m->part8.clear(); + this->m->part9.clear(); + this->m->c_linp = LinParameters(); + this->m->c_page_offset_data = CHPageOffset(); + this->m->c_shared_object_data = CHSharedObject(); + this->m->c_outline_data = HGeneric(); QPDFObjectHandle root = getRoot(); bool outlines_in_first_page = false; @@ -1349,8 +1351,8 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) std::set lc_root; for (std::map >::iterator oiter = - this->object_to_obj_users.begin(); - oiter != this->object_to_obj_users.end(); ++oiter) + this->m->object_to_obj_users.begin(); + oiter != this->m->object_to_obj_users.end(); ++oiter) { QPDFObjGen const& og = (*oiter).first; @@ -1505,17 +1507,18 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) // npages is the size of the existing pages vector, which has been // created by traversing the pages tree, and as such is a // reasonable size. - this->c_linp.npages = npages; - this->c_page_offset_data.entries = std::vector(npages); + this->m->c_linp.npages = npages; + this->m->c_page_offset_data.entries = + std::vector(npages); // Part 4: open document objects. We don't care about the order. assert(lc_root.size() == 1); - this->part4.push_back(objGenToIndirect(*(lc_root.begin()))); + this->m->part4.push_back(objGenToIndirect(*(lc_root.begin()))); for (std::set::iterator iter = lc_open_document.begin(); iter != lc_open_document.end(); ++iter) { - this->part4.push_back(objGenToIndirect(*iter)); + this->m->part4.push_back(objGenToIndirect(*iter)); } // Part 6: first page objects. Note: implementation note 124 @@ -1533,8 +1536,8 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) "object not in lc_first_page_private"); } lc_first_page_private.erase(first_page_og); - this->c_linp.first_page_object = pages.at(0).getObjectID(); - this->part6.push_back(pages.at(0)); + this->m->c_linp.first_page_object = pages.at(0).getObjectID(); + this->m->part6.push_back(pages.at(0)); // The PDF spec "recommends" an order for the rest of the objects, // but we are going to disregard it except to the extent that it @@ -1544,19 +1547,19 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) for (std::set::iterator iter = lc_first_page_private.begin(); iter != lc_first_page_private.end(); ++iter) { - this->part6.push_back(objGenToIndirect(*iter)); + this->m->part6.push_back(objGenToIndirect(*iter)); } for (std::set::iterator iter = lc_first_page_shared.begin(); iter != lc_first_page_shared.end(); ++iter) { - this->part6.push_back(objGenToIndirect(*iter)); + this->m->part6.push_back(objGenToIndirect(*iter)); } // Place the outline dictionary if it goes in the first page section. if (outlines_in_first_page) { - pushOutlinesToPart(this->part6, lc_outlines, object_stream_data); + pushOutlinesToPart(this->m->part6, lc_outlines, object_stream_data); } // Fill in page offset hint table information for the first page. @@ -1565,7 +1568,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) // in garbage values for all the shared object identifiers on the // first page. - this->c_page_offset_data.entries.at(0).nobjects = this->part6.size(); + this->m->c_page_offset_data.entries.at(0).nobjects = this->m->part6.size(); // Part 7: other pages' private objects @@ -1583,16 +1586,16 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) QUtil::int_to_string(i) + " not in lc_other_page_private"); } lc_other_page_private.erase(page_og); - this->part7.push_back(pages.at(i)); + this->m->part7.push_back(pages.at(i)); // Place all non-shared objects referenced by this page, // updating the page object count for the hint table. - this->c_page_offset_data.entries.at(i).nobjects = 1; + this->m->c_page_offset_data.entries.at(i).nobjects = 1; ObjUser ou(ObjUser::ou_page, i); - assert(this->obj_user_to_objects.count(ou) > 0); - std::set ogs = this->obj_user_to_objects[ou]; + assert(this->m->obj_user_to_objects.count(ou) > 0); + std::set ogs = this->m->obj_user_to_objects[ou]; for (std::set::iterator iter = ogs.begin(); iter != ogs.end(); ++iter) { @@ -1600,8 +1603,8 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) if (lc_other_page_private.count(og)) { lc_other_page_private.erase(og); - this->part7.push_back(objGenToIndirect(og)); - ++this->c_page_offset_data.entries.at(i).nobjects; + this->m->part7.push_back(objGenToIndirect(og)); + ++this->m->c_page_offset_data.entries.at(i).nobjects; } } } @@ -1620,7 +1623,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) for (std::set::iterator iter = lc_other_page_shared.begin(); iter != lc_other_page_shared.end(); ++iter) { - this->part8.push_back(objGenToIndirect(*iter)); + this->m->part8.push_back(objGenToIndirect(*iter)); } // Part 9: other objects @@ -1634,7 +1637,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) // Place the pages tree. std::set pages_ogs = - this->obj_user_to_objects[ObjUser(ObjUser::ou_root_key, "/Pages")]; + this->m->obj_user_to_objects[ObjUser(ObjUser::ou_root_key, "/Pages")]; assert(! pages_ogs.empty()); for (std::set::iterator iter = pages_ogs.begin(); iter != pages_ogs.end(); ++iter) @@ -1643,7 +1646,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) if (lc_other.count(og)) { lc_other.erase(og); - this->part9.push_back(objGenToIndirect(og)); + this->m->part9.push_back(objGenToIndirect(og)); } } @@ -1661,7 +1664,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) if (lc_thumbnail_private.count(thumb_og)) { lc_thumbnail_private.erase(thumb_og); - this->part9.push_back(thumb); + this->m->part9.push_back(thumb); } else { @@ -1673,7 +1676,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) // lc_thumbnail_private. } std::set& ogs = - this->obj_user_to_objects[ObjUser(ObjUser::ou_thumb, i)]; + this->m->obj_user_to_objects[ObjUser(ObjUser::ou_thumb, i)]; for (std::set::iterator iter = ogs.begin(); iter != ogs.end(); ++iter) { @@ -1681,7 +1684,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) if (lc_thumbnail_private.count(og)) { lc_thumbnail_private.erase(og); - this->part9.push_back(objGenToIndirect(og)); + this->m->part9.push_back(objGenToIndirect(og)); } } } @@ -1698,28 +1701,28 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) for (std::set::iterator iter = lc_thumbnail_shared.begin(); iter != lc_thumbnail_shared.end(); ++iter) { - this->part9.push_back(objGenToIndirect(*iter)); + this->m->part9.push_back(objGenToIndirect(*iter)); } // Place outlines unless in first page if (! outlines_in_first_page) { - pushOutlinesToPart(this->part9, lc_outlines, object_stream_data); + pushOutlinesToPart(this->m->part9, lc_outlines, object_stream_data); } // Place all remaining objects for (std::set::iterator iter = lc_other.begin(); iter != lc_other.end(); ++iter) { - this->part9.push_back(objGenToIndirect(*iter)); + this->m->part9.push_back(objGenToIndirect(*iter)); } // Make sure we got everything exactly once. unsigned int num_placed = - this->part4.size() + this->part6.size() + this->part7.size() + - this->part8.size() + this->part9.size(); - unsigned int num_wanted = this->object_to_obj_users.size(); + this->m->part4.size() + this->m->part6.size() + this->m->part7.size() + + this->m->part8.size() + this->m->part9.size(); + unsigned int num_wanted = this->m->object_to_obj_users.size(); if (num_placed != num_wanted) { throw std::logic_error( @@ -1743,28 +1746,29 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) // can map from object number only without regards to generation. std::map obj_to_index; - this->c_shared_object_data.nshared_first_page = this->part6.size(); - this->c_shared_object_data.nshared_total = - this->c_shared_object_data.nshared_first_page + this->part8.size(); + this->m->c_shared_object_data.nshared_first_page = this->m->part6.size(); + this->m->c_shared_object_data.nshared_total = + this->m->c_shared_object_data.nshared_first_page + + this->m->part8.size(); std::vector& shared = - this->c_shared_object_data.entries; - for (std::vector::iterator iter = this->part6.begin(); - iter != this->part6.end(); ++iter) + this->m->c_shared_object_data.entries; + for (std::vector::iterator iter = this->m->part6.begin(); + iter != this->m->part6.end(); ++iter) { QPDFObjectHandle& oh = *iter; int obj = oh.getObjectID(); obj_to_index[obj] = shared.size(); shared.push_back(CHSharedObjectEntry(obj)); } - QTC::TC("qpdf", "QPDF lin part 8 empty", this->part8.empty() ? 1 : 0); - if (! this->part8.empty()) + QTC::TC("qpdf", "QPDF lin part 8 empty", this->m->part8.empty() ? 1 : 0); + if (! this->m->part8.empty()) { - this->c_shared_object_data.first_shared_obj = - this->part8.at(0).getObjectID(); + this->m->c_shared_object_data.first_shared_obj = + this->m->part8.at(0).getObjectID(); for (std::vector::iterator iter = - this->part8.begin(); - iter != this->part8.end(); ++iter) + this->m->part8.begin(); + iter != this->m->part8.end(); ++iter) { QPDFObjectHandle& oh = *iter; int obj = oh.getObjectID(); @@ -1772,8 +1776,8 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) shared.push_back(CHSharedObjectEntry(obj)); } } - if (static_cast(this->c_shared_object_data.nshared_total) != - this->c_shared_object_data.entries.size()) + if (static_cast(this->m->c_shared_object_data.nshared_total) != + this->m->c_shared_object_data.entries.size()) { throw std::logic_error( "shared object hint table has wrong number of entries"); @@ -1784,15 +1788,15 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) for (unsigned int i = 1; i < npages; ++i) { - CHPageOffsetEntry& pe = this->c_page_offset_data.entries.at(i); + CHPageOffsetEntry& pe = this->m->c_page_offset_data.entries.at(i); ObjUser ou(ObjUser::ou_page, i); - assert(this->obj_user_to_objects.count(ou) > 0); - std::set const& ogs = this->obj_user_to_objects[ou]; + assert(this->m->obj_user_to_objects.count(ou) > 0); + std::set const& ogs = this->m->obj_user_to_objects[ou]; for (std::set::const_iterator iter = ogs.begin(); iter != ogs.end(); ++iter) { QPDFObjGen const& og = *iter; - if ((this->object_to_obj_users[og].size() > 1) && + if ((this->m->object_to_obj_users[og].size() > 1) && (obj_to_index.count(og.getObj()) > 0)) { int idx = obj_to_index[og.getObj()]; @@ -1818,18 +1822,18 @@ QPDF::pushOutlinesToPart( outlines = getUncompressedObject(outlines, object_stream_data); QPDFObjGen outlines_og(outlines.getObjGen()); QTC::TC("qpdf", "QPDF lin outlines in part", - ((&part == (&this->part6)) ? 0 - : (&part == (&this->part9)) ? 1 + ((&part == (&this->m->part6)) ? 0 + : (&part == (&this->m->part9)) ? 1 : 9999)); // can't happen - this->c_outline_data.first_object = outlines_og.getObj(); - this->c_outline_data.nobjects = 1; + this->m->c_outline_data.first_object = outlines_og.getObj(); + this->m->c_outline_data.nobjects = 1; lc_outlines.erase(outlines_og); part.push_back(outlines); for (std::set::iterator iter = lc_outlines.begin(); iter != lc_outlines.end(); ++iter) { part.push_back(objGenToIndirect(*iter)); - ++this->c_outline_data.nobjects; + ++this->m->c_outline_data.nobjects; } } @@ -1843,11 +1847,11 @@ QPDF::getLinearizedParts( std::vector& part9) { calculateLinearizationData(object_stream_data); - part4 = this->part4; - part6 = this->part6; - part7 = this->part7; - part8 = this->part8; - part9 = this->part9; + part4 = this->m->part4; + part6 = this->m->part6; + part7 = this->m->part7; + part8 = this->m->part8; + part9 = this->m->part9; } static inline int nbits(int val) @@ -1889,7 +1893,7 @@ QPDF::calculateHPageOffset( std::vector const& pages = getAllPages(); unsigned int npages = pages.size(); - CHPageOffset& cph = this->c_page_offset_data; + CHPageOffset& cph = this->m->c_page_offset_data; std::vector& cphe = cph.entries; // Calculate minimum and maximum values for number of objects per @@ -1902,7 +1906,7 @@ QPDF::calculateHPageOffset( int max_length = min_length; int max_shared = cphe.at(0).nshared_objects; - HPageOffset& ph = this->page_offset_hints; + HPageOffset& ph = this->m->page_offset_hints; std::vector& phe = ph.entries; // npages is the size of the existing pages array. phe = std::vector(npages); @@ -1940,7 +1944,7 @@ QPDF::calculateHPageOffset( ph.nbits_delta_page_length = nbits(max_length - min_length); ph.nbits_nshared_objects = nbits(max_shared); ph.nbits_shared_identifier = - nbits(this->c_shared_object_data.nshared_total); + nbits(this->m->c_shared_object_data.nshared_total); ph.shared_denominator = 4; // doesn't matter // It isn't clear how to compute content offset and content @@ -1975,9 +1979,9 @@ QPDF::calculateHSharedObject( std::map const& lengths, std::map const& obj_renumber) { - CHSharedObject& cso = this->c_shared_object_data; + CHSharedObject& cso = this->m->c_shared_object_data; std::vector& csoe = cso.entries; - HSharedObject& so = this->shared_object_hints; + HSharedObject& so = this->m->shared_object_hints; std::vector& soe = so.entries; soe.clear(); @@ -2026,14 +2030,14 @@ QPDF::calculateHOutline( std::map const& lengths, std::map const& obj_renumber) { - HGeneric& cho = this->c_outline_data; + HGeneric& cho = this->m->c_outline_data; if (cho.nobjects == 0) { return; } - HGeneric& ho = this->outline_hints; + HGeneric& ho = this->m->outline_hints; ho.first_object = (*(obj_renumber.find(cho.first_object))).second; @@ -2083,7 +2087,7 @@ write_vector_vector(BitWriter& w, void QPDF::writeHPageOffset(BitWriter& w) { - HPageOffset& t = this->page_offset_hints; + HPageOffset& t = this->m->page_offset_hints; w.writeBits(t.min_nobjects, 32); // 1 w.writeBits(t.first_page_offset, 32); // 2 @@ -2130,7 +2134,7 @@ QPDF::writeHPageOffset(BitWriter& w) void QPDF::writeHSharedObject(BitWriter& w) { - HSharedObject& t = this->shared_object_hints; + HSharedObject& t = this->m->shared_object_hints; w.writeBits(t.first_shared_obj, 32); // 1 w.writeBits(t.first_shared_offset, 32); // 2 @@ -2193,10 +2197,10 @@ QPDF::generateHintStream(std::map const& xref, S = c.getCount(); writeHSharedObject(w); O = 0; - if (this->outline_hints.nobjects > 0) + if (this->m->outline_hints.nobjects > 0) { O = c.getCount(); - writeHGeneric(w, this->outline_hints); + writeHGeneric(w, this->m->outline_hints); } c.finish(); diff --git a/libqpdf/QPDF_optimization.cc b/libqpdf/QPDF_optimization.cc index fad710d0..1e42865c 100644 --- a/libqpdf/QPDF_optimization.cc +++ b/libqpdf/QPDF_optimization.cc @@ -62,7 +62,7 @@ void QPDF::optimize(std::map const& object_stream_data, bool allow_changes) { - if (! this->obj_user_to_objects.empty()) + if (! this->m->obj_user_to_objects.empty()) { // already optimized return; @@ -83,19 +83,19 @@ QPDF::optimize(std::map const& object_stream_data, } // Traverse pages tree pushing all inherited resources down to the - // page level. This also initializes this->all_pages. + // page level. This also initializes this->m->all_pages. pushInheritedAttributesToPage(allow_changes, false); // Traverse pages - int n = this->all_pages.size(); + int n = this->m->all_pages.size(); for (int pageno = 0; pageno < n; ++pageno) { updateObjectMaps(ObjUser(ObjUser::ou_page, pageno), - this->all_pages.at(pageno)); + this->m->all_pages.at(pageno)); } // Traverse document-level items - std::set keys = this->trailer.getKeys(); + std::set keys = this->m->trailer.getKeys(); for (std::set::iterator iter = keys.begin(); iter != keys.end(); ++iter) { @@ -107,7 +107,7 @@ QPDF::optimize(std::map const& object_stream_data, else { updateObjectMaps(ObjUser(ObjUser::ou_trailer_key, key), - this->trailer.getKey(key)); + this->m->trailer.getKey(key)); } } @@ -129,8 +129,8 @@ QPDF::optimize(std::map const& object_stream_data, ObjUser root_ou = ObjUser(ObjUser::ou_root); QPDFObjGen root_og = QPDFObjGen(root.getObjGen()); - obj_user_to_objects[root_ou].insert(root_og); - object_to_obj_users[root_og].insert(root_ou); + this->m->obj_user_to_objects[root_ou].insert(root_og); + this->m->object_to_obj_users[root_og].insert(root_ou); filterCompressedObjects(object_stream_data); } @@ -151,7 +151,7 @@ QPDF::pushInheritedAttributesToPage(bool allow_changes, bool warn_skipped_keys) // The record of whether we've done this is cleared by // updateAllPagesCache(). If we're warning for skipped keys, // re-traverse unconditionally. - if (this->pushed_inherited_attributes_to_pages && (! warn_skipped_keys)) + if (this->m->pushed_inherited_attributes_to_pages && (! warn_skipped_keys)) { return; } @@ -159,12 +159,12 @@ QPDF::pushInheritedAttributesToPage(bool allow_changes, bool warn_skipped_keys) // key_ancestors is a mapping of page attribute keys to a stack of // Pages nodes that contain values for them. std::map > key_ancestors; - this->all_pages.clear(); + this->m->all_pages.clear(); pushInheritedAttributesToPageInternal( - this->trailer.getKey("/Root").getKey("/Pages"), - key_ancestors, this->all_pages, allow_changes, warn_skipped_keys); + this->m->trailer.getKey("/Root").getKey("/Pages"), + key_ancestors, this->m->all_pages, allow_changes, warn_skipped_keys); assert(key_ancestors.empty()); - this->pushed_inherited_attributes_to_pages = true; + this->m->pushed_inherited_attributes_to_pages = true; } void @@ -192,8 +192,8 @@ QPDF::pushInheritedAttributesToPageInternal2( if (visited.count(this_og) > 0) { throw QPDFExc( - qpdf_e_pages, this->file->getName(), - this->last_object_description, 0, + qpdf_e_pages, this->m->file->getName(), + this->m->last_object_description, 0, "Loop detected in /Pages structure (inherited attributes)"); } visited.insert(this_og); @@ -219,9 +219,9 @@ QPDF::pushInheritedAttributesToPageInternal2( { if (! allow_changes) { - throw QPDFExc(qpdf_e_internal, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + throw QPDFExc(qpdf_e_internal, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "optimize detected an " "inheritable attribute when called " "in no-change mode"); @@ -269,8 +269,8 @@ QPDF::pushInheritedAttributesToPageInternal2( setLastObjectDescription("Pages object", cur_pages.getObjectID(), cur_pages.getGeneration()); - warn(QPDFExc(qpdf_e_pages, this->file->getName(), - this->last_object_description, 0, + warn(QPDFExc(qpdf_e_pages, this->m->file->getName(), + this->m->last_object_description, 0, "Unknown key " + key + " in /Pages object" " is being discarded as a result of" " flattening the /Pages tree")); @@ -337,9 +337,9 @@ QPDF::pushInheritedAttributesToPageInternal2( } else { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "invalid Type " + type + " in page tree"); } visited.erase(this_og); @@ -382,8 +382,8 @@ QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh, QTC::TC("qpdf", "QPDF opt loop detected"); return; } - this->obj_user_to_objects[ou].insert(og); - this->object_to_obj_users[og].insert(ou); + this->m->obj_user_to_objects[ou].insert(og); + this->m->object_to_obj_users[og].insert(ou); visited.insert(og); } @@ -445,8 +445,8 @@ QPDF::filterCompressedObjects(std::map const& object_stream_data) std::map > t_object_to_obj_users; for (std::map >::iterator i1 = - this->obj_user_to_objects.begin(); - i1 != this->obj_user_to_objects.end(); ++i1) + this->m->obj_user_to_objects.begin(); + i1 != this->m->obj_user_to_objects.end(); ++i1) { ObjUser const& ou = (*i1).first; std::set const& objects = (*i1).second; @@ -468,8 +468,8 @@ QPDF::filterCompressedObjects(std::map const& object_stream_data) } for (std::map >::iterator i1 = - this->object_to_obj_users.begin(); - i1 != this->object_to_obj_users.end(); ++i1) + this->m->object_to_obj_users.begin(); + i1 != this->m->object_to_obj_users.end(); ++i1) { QPDFObjGen const& og = (*i1).first; std::set const& objusers = (*i1).second; @@ -490,6 +490,6 @@ QPDF::filterCompressedObjects(std::map const& object_stream_data) } } - this->obj_user_to_objects = t_obj_user_to_objects; - this->object_to_obj_users = t_object_to_obj_users; + this->m->obj_user_to_objects = t_obj_user_to_objects; + this->m->object_to_obj_users = t_object_to_obj_users; } diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index f9b421c6..31307e4e 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -44,12 +44,12 @@ std::vector const& QPDF::getAllPages() { // Note that pushInheritedAttributesToPage may also be used to - // initialize this->all_pages. - if (this->all_pages.empty()) + // initialize this->m->all_pages. + if (this->m->all_pages.empty()) { - getAllPagesInternal(getRoot().getKey("/Pages"), this->all_pages); + getAllPagesInternal(getRoot().getKey("/Pages"), this->m->all_pages); } - return this->all_pages; + return this->m->all_pages; } void @@ -69,8 +69,8 @@ QPDF::getAllPagesInternal2(QPDFObjectHandle cur_pages, if (visited.count(this_og) > 0) { throw QPDFExc( - qpdf_e_pages, this->file->getName(), - this->last_object_description, 0, + qpdf_e_pages, this->m->file->getName(), + this->m->last_object_description, 0, "Loop detected in /Pages structure (getAllPages)"); } visited.insert(this_og); @@ -103,9 +103,9 @@ QPDF::getAllPagesInternal2(QPDFObjectHandle cur_pages, } else { - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), - this->last_object_description, - this->file->getLastOffset(), + throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + this->m->last_object_description, + this->m->file->getLastOffset(), "invalid Type " + type + " in page tree"); } visited.erase(this_og); @@ -119,9 +119,9 @@ QPDF::updateAllPagesCache() // it that they got from calls to getAllPages(). We can defer // recalculation of pageobj_to_pages_pos until needed. QTC::TC("qpdf", "QPDF updateAllPagesCache"); - this->all_pages.clear(); - this->pageobj_to_pages_pos.clear(); - this->pushed_inherited_attributes_to_pages = false; + this->m->all_pages.clear(); + this->m->pageobj_to_pages_pos.clear(); + this->m->pushed_inherited_attributes_to_pages = false; getAllPages(); } @@ -131,26 +131,26 @@ QPDF::flattenPagesTree() // If not already done, flatten the /Pages structure and // initialize pageobj_to_pages_pos. - if (! this->pageobj_to_pages_pos.empty()) + if (! this->m->pageobj_to_pages_pos.empty()) { return; } // Push inherited objects down to the /Page level. As a side - // effect this->all_pages will also be generated. + // effect this->m->all_pages will also be generated. pushInheritedAttributesToPage(true, true); QPDFObjectHandle pages = getRoot().getKey("/Pages"); - int const len = this->all_pages.size(); + int const len = this->m->all_pages.size(); for (int pos = 0; pos < len; ++pos) { // populate pageobj_to_pages_pos and fix parent pointer - insertPageobjToPage(this->all_pages.at(pos), pos, true); - this->all_pages.at(pos).replaceKey("/Parent", pages); + insertPageobjToPage(this->m->all_pages.at(pos), pos, true); + this->m->all_pages.at(pos).replaceKey("/Parent", pages); } - pages.replaceKey("/Kids", QPDFObjectHandle::newArray(this->all_pages)); + pages.replaceKey("/Kids", QPDFObjectHandle::newArray(this->m->all_pages)); // /Count has not changed if (pages.getKey("/Count").getIntValue() != len) { @@ -165,21 +165,22 @@ QPDF::insertPageobjToPage(QPDFObjectHandle const& obj, int pos, QPDFObjGen og(obj.getObjGen()); if (check_duplicate) { - if (! this->pageobj_to_pages_pos.insert(std::make_pair(og, pos)).second) + if (! this->m->pageobj_to_pages_pos.insert( + std::make_pair(og, pos)).second) { QTC::TC("qpdf", "QPDF duplicate page reference"); setLastObjectDescription("page " + QUtil::int_to_string(pos) + " (numbered from zero)", og.getObj(), og.getGen()); - throw QPDFExc(qpdf_e_pages, this->file->getName(), - this->last_object_description, 0, + throw QPDFExc(qpdf_e_pages, this->m->file->getName(), + this->m->last_object_description, 0, "duplicate page reference found;" " this would cause loss of data"); } } else { - this->pageobj_to_pages_pos[og] = pos; + this->m->pageobj_to_pages_pos[og] = pos; } } @@ -195,13 +196,13 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) if (! newpage.isIndirect()) { QTC::TC("qpdf", "QPDF insert non-indirect page"); - newpage = this->makeIndirectObject(newpage); + newpage = makeIndirectObject(newpage); } else if (newpage.getOwningQPDF() != this) { QTC::TC("qpdf", "QPDF insert foreign page"); newpage.getOwningQPDF()->pushInheritedAttributesToPage(); - newpage = this->copyForeignObject(newpage, true); + newpage = copyForeignObject(newpage, true); } else { @@ -210,26 +211,26 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) QTC::TC("qpdf", "QPDF insert page", (pos == 0) ? 0 : // insert at beginning - (pos == static_cast(this->all_pages.size())) ? 1 : // at end + (pos == static_cast(this->m->all_pages.size())) ? 1 : // at end 2); // insert in middle QPDFObjectHandle pages = getRoot().getKey("/Pages"); QPDFObjectHandle kids = pages.getKey("/Kids"); assert ((pos >= 0) && - (static_cast(pos) <= this->all_pages.size())); + (static_cast(pos) <= this->m->all_pages.size())); newpage.replaceKey("/Parent", pages); kids.insertItem(pos, newpage); int npages = kids.getArrayNItems(); pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); - this->all_pages.insert(this->all_pages.begin() + pos, newpage); - assert(this->all_pages.size() == static_cast(npages)); + this->m->all_pages.insert(this->m->all_pages.begin() + pos, newpage); + assert(this->m->all_pages.size() == static_cast(npages)); for (int i = pos + 1; i < npages; ++i) { - insertPageobjToPage(this->all_pages.at(i), i, false); + insertPageobjToPage(this->m->all_pages.at(i), i, false); } insertPageobjToPage(newpage, pos, true); - assert(this->pageobj_to_pages_pos.size() == static_cast(npages)); + assert(this->m->pageobj_to_pages_pos.size() == static_cast(npages)); } void @@ -238,7 +239,8 @@ QPDF::removePage(QPDFObjectHandle page) int pos = findPage(page); // also ensures flat /Pages QTC::TC("qpdf", "QPDF remove page", (pos == 0) ? 0 : // remove at beginning - (pos == static_cast(this->all_pages.size() - 1)) ? 1 : // end + (pos == static_cast( + this->m->all_pages.size() - 1)) ? 1 : // end 2); // remove in middle QPDFObjectHandle pages = getRoot().getKey("/Pages"); @@ -247,13 +249,13 @@ QPDF::removePage(QPDFObjectHandle page) kids.eraseItem(pos); int npages = kids.getArrayNItems(); pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); - this->all_pages.erase(this->all_pages.begin() + pos); - assert(this->all_pages.size() == static_cast(npages)); - this->pageobj_to_pages_pos.erase(page.getObjGen()); - assert(this->pageobj_to_pages_pos.size() == static_cast(npages)); + this->m->all_pages.erase(this->m->all_pages.begin() + pos); + assert(this->m->all_pages.size() == static_cast(npages)); + this->m->pageobj_to_pages_pos.erase(page.getObjGen()); + assert(this->m->pageobj_to_pages_pos.size() == static_cast(npages)); for (int i = pos; i < npages; ++i) { - insertPageobjToPage(this->all_pages.at(i), i, false); + insertPageobjToPage(this->m->all_pages.at(i), i, false); } } @@ -295,12 +297,12 @@ QPDF::findPage(QPDFObjGen const& og) { flattenPagesTree(); std::map::iterator it = - this->pageobj_to_pages_pos.find(og); - if (it == this->pageobj_to_pages_pos.end()) + this->m->pageobj_to_pages_pos.find(og); + if (it == this->m->pageobj_to_pages_pos.end()) { setLastObjectDescription("page object", og.getObj(), og.getGen()); - throw QPDFExc(qpdf_e_pages, this->file->getName(), - this->last_object_description, 0, + throw QPDFExc(qpdf_e_pages, this->m->file->getName(), + this->m->last_object_description, 0, "page object not referenced in /Pages tree"); } return (*it).second;