mirror of
https://github.com/qpdf/qpdf.git
synced 2025-02-02 11:58:25 +00:00
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.
This commit is contained in:
parent
8288a4eb3a
commit
a8c93bd324
@ -635,11 +635,11 @@ class QPDF
|
|||||||
qpdf(qpdf),
|
qpdf(qpdf),
|
||||||
og(og)
|
og(og)
|
||||||
{
|
{
|
||||||
qpdf->resolving.insert(og);
|
qpdf->m->resolving.insert(og);
|
||||||
}
|
}
|
||||||
virtual ~ResolveRecorder()
|
virtual ~ResolveRecorder()
|
||||||
{
|
{
|
||||||
this->qpdf->resolving.erase(og);
|
this->qpdf->m->resolving.erase(og);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
QPDF* qpdf;
|
QPDF* qpdf;
|
||||||
@ -1113,79 +1113,95 @@ class QPDF
|
|||||||
std::set<QPDFObjGen>& visited, bool top);
|
std::set<QPDFObjGen>& visited, bool top);
|
||||||
void filterCompressedObjects(std::map<int, int> const& object_stream_data);
|
void filterCompressedObjects(std::map<int, int> const& object_stream_data);
|
||||||
|
|
||||||
|
class Members
|
||||||
|
{
|
||||||
|
friend class QPDF;
|
||||||
|
|
||||||
QPDFTokenizer tokenizer;
|
public:
|
||||||
PointerHolder<InputSource> file;
|
~Members();
|
||||||
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<std::string, encryption_method_e> 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<QPDFObjGen, QPDFXRefEntry> xref_table;
|
|
||||||
std::set<int> deleted_objects;
|
|
||||||
std::map<QPDFObjGen, ObjCache> obj_cache;
|
|
||||||
std::set<QPDFObjGen> resolving;
|
|
||||||
QPDFObjectHandle trailer;
|
|
||||||
std::vector<QPDFObjectHandle> all_pages;
|
|
||||||
std::map<QPDFObjGen, int> pageobj_to_pages_pos;
|
|
||||||
bool pushed_inherited_attributes_to_pages;
|
|
||||||
std::vector<QPDFExc> warnings;
|
|
||||||
std::map<QPDF*, ObjCopier> object_copiers;
|
|
||||||
PointerHolder<QPDFObjectHandle::StreamDataProvider> copied_streams;
|
|
||||||
// copied_stream_data_provider is owned by copied_streams
|
|
||||||
CopiedStreamDataProvider* copied_stream_data_provider;
|
|
||||||
std::set<QPDFObjGen> attachment_streams;
|
|
||||||
bool reconstructed_xref;
|
|
||||||
|
|
||||||
// Linearization data
|
private:
|
||||||
qpdf_offset_t first_xref_item_offset; // actual value from file
|
Members();
|
||||||
bool uncompressed_after_compressed;
|
Members(Members const&);
|
||||||
|
|
||||||
// Linearization parameter dictionary and hint table data: may be
|
QPDFTokenizer tokenizer;
|
||||||
// read from file or computed prior to writing a linearized file
|
PointerHolder<InputSource> file;
|
||||||
QPDFObjectHandle lindict;
|
std::string last_object_description;
|
||||||
LinParameters linp;
|
bool encrypted;
|
||||||
HPageOffset page_offset_hints;
|
bool encryption_initialized;
|
||||||
HSharedObject shared_object_hints;
|
bool ignore_xref_streams;
|
||||||
HGeneric outline_hints;
|
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<std::string, encryption_method_e> 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<QPDFObjGen, QPDFXRefEntry> xref_table;
|
||||||
|
std::set<int> deleted_objects;
|
||||||
|
std::map<QPDFObjGen, ObjCache> obj_cache;
|
||||||
|
std::set<QPDFObjGen> resolving;
|
||||||
|
QPDFObjectHandle trailer;
|
||||||
|
std::vector<QPDFObjectHandle> all_pages;
|
||||||
|
std::map<QPDFObjGen, int> pageobj_to_pages_pos;
|
||||||
|
bool pushed_inherited_attributes_to_pages;
|
||||||
|
std::vector<QPDFExc> warnings;
|
||||||
|
std::map<QPDF*, ObjCopier> object_copiers;
|
||||||
|
PointerHolder<QPDFObjectHandle::StreamDataProvider> copied_streams;
|
||||||
|
// copied_stream_data_provider is owned by copied_streams
|
||||||
|
CopiedStreamDataProvider* copied_stream_data_provider;
|
||||||
|
std::set<QPDFObjGen> attachment_streams;
|
||||||
|
bool reconstructed_xref;
|
||||||
|
|
||||||
// Computed linearization data: used to populate above tables
|
// Linearization data
|
||||||
// during writing and to compare with them during validation. c_
|
qpdf_offset_t first_xref_item_offset; // actual value from file
|
||||||
// means computed.
|
bool uncompressed_after_compressed;
|
||||||
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
|
// Linearization parameter dictionary and hint table data: may be
|
||||||
// calculateLinearizationData(). Part numbers refer to the PDF
|
// read from file or computed prior to writing a linearized file
|
||||||
// 1.4 specification.
|
QPDFObjectHandle lindict;
|
||||||
std::vector<QPDFObjectHandle> part4;
|
LinParameters linp;
|
||||||
std::vector<QPDFObjectHandle> part6;
|
HPageOffset page_offset_hints;
|
||||||
std::vector<QPDFObjectHandle> part7;
|
HSharedObject shared_object_hints;
|
||||||
std::vector<QPDFObjectHandle> part8;
|
HGeneric outline_hints;
|
||||||
std::vector<QPDFObjectHandle> part9;
|
|
||||||
|
|
||||||
// Optimization data
|
// Computed linearization data: used to populate above tables
|
||||||
std::map<ObjUser, std::set<QPDFObjGen> > obj_user_to_objects;
|
// during writing and to compare with them during validation.
|
||||||
std::map<QPDFObjGen, std::set<ObjUser> > object_to_obj_users;
|
// 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<QPDFObjectHandle> part4;
|
||||||
|
std::vector<QPDFObjectHandle> part6;
|
||||||
|
std::vector<QPDFObjectHandle> part7;
|
||||||
|
std::vector<QPDFObjectHandle> part8;
|
||||||
|
std::vector<QPDFObjectHandle> part9;
|
||||||
|
|
||||||
|
// Optimization data
|
||||||
|
std::map<ObjUser, std::set<QPDFObjGen> > obj_user_to_objects;
|
||||||
|
std::map<QPDFObjGen, std::set<ObjUser> > 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<Members> m;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __QPDF_HH__
|
#endif // __QPDF_HH__
|
||||||
|
512
libqpdf/QPDF.cc
512
libqpdf/QPDF.cc
File diff suppressed because it is too large
Load Diff
@ -760,9 +760,9 @@ QPDF::interpretCF(QPDFObjectHandle cf)
|
|||||||
if (cf.isName())
|
if (cf.isName())
|
||||||
{
|
{
|
||||||
std::string filter = cf.getName();
|
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")
|
else if (filter == "/Identity")
|
||||||
{
|
{
|
||||||
@ -783,29 +783,29 @@ QPDF::interpretCF(QPDFObjectHandle cf)
|
|||||||
void
|
void
|
||||||
QPDF::initializeEncryption()
|
QPDF::initializeEncryption()
|
||||||
{
|
{
|
||||||
if (this->encryption_initialized)
|
if (this->m->encryption_initialized)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->encryption_initialized = true;
|
this->m->encryption_initialized = true;
|
||||||
|
|
||||||
// After we initialize encryption parameters, we must used stored
|
// After we initialize encryption parameters, we must used stored
|
||||||
// key information and never look at /Encrypt again. Otherwise,
|
// key information and never look at /Encrypt again. Otherwise,
|
||||||
// things could go wrong if someone mutates the encryption
|
// things could go wrong if someone mutates the encryption
|
||||||
// dictionary.
|
// dictionary.
|
||||||
|
|
||||||
if (! this->trailer.hasKey("/Encrypt"))
|
if (! this->m->trailer.hasKey("/Encrypt"))
|
||||||
{
|
{
|
||||||
return;
|
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
|
// will return true even if there were errors reading the
|
||||||
// encryption dictionary.
|
// encryption dictionary.
|
||||||
this->encrypted = true;
|
this->m->encrypted = true;
|
||||||
|
|
||||||
std::string id1;
|
std::string id1;
|
||||||
QPDFObjectHandle id_obj = this->trailer.getKey("/ID");
|
QPDFObjectHandle id_obj = this->m->trailer.getKey("/ID");
|
||||||
if ((id_obj.isArray() &&
|
if ((id_obj.isArray() &&
|
||||||
(id_obj.getArrayNItems() == 2) &&
|
(id_obj.getArrayNItems() == 2) &&
|
||||||
id_obj.getArrayItem(0).isString()))
|
id_obj.getArrayItem(0).isString()))
|
||||||
@ -817,31 +817,31 @@ QPDF::initializeEncryption()
|
|||||||
// Treating a missing ID as the empty string enables qpdf to
|
// Treating a missing ID as the empty string enables qpdf to
|
||||||
// decrypt some invalid encrypted files with no /ID that
|
// decrypt some invalid encrypted files with no /ID that
|
||||||
// poppler can read but Adobe Reader can't.
|
// poppler can read but Adobe Reader can't.
|
||||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
"trailer", this->file->getLastOffset(),
|
"trailer", this->m->file->getLastOffset(),
|
||||||
"invalid /ID in trailer dictionary"));
|
"invalid /ID in trailer dictionary"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDFObjectHandle encryption_dict = this->trailer.getKey("/Encrypt");
|
QPDFObjectHandle encryption_dict = this->m->trailer.getKey("/Encrypt");
|
||||||
if (! encryption_dict.isDictionary())
|
if (! encryption_dict.isDictionary())
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
this->last_object_description,
|
this->m->last_object_description,
|
||||||
this->file->getLastOffset(),
|
this->m->file->getLastOffset(),
|
||||||
"/Encrypt in trailer dictionary is not a dictionary");
|
"/Encrypt in trailer dictionary is not a dictionary");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! (encryption_dict.getKey("/Filter").isName() &&
|
if (! (encryption_dict.getKey("/Filter").isName() &&
|
||||||
(encryption_dict.getKey("/Filter").getName() == "/Standard")))
|
(encryption_dict.getKey("/Filter").getName() == "/Standard")))
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary", this->m->file->getLastOffset(),
|
||||||
"unsupported encryption filter");
|
"unsupported encryption filter");
|
||||||
}
|
}
|
||||||
if (! encryption_dict.getKey("/SubFilter").isNull())
|
if (! encryption_dict.getKey("/SubFilter").isNull())
|
||||||
{
|
{
|
||||||
warn(QPDFExc(qpdf_e_unsupported, this->file->getName(),
|
warn(QPDFExc(qpdf_e_unsupported, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary", this->m->file->getLastOffset(),
|
||||||
"file uses encryption SubFilters,"
|
"file uses encryption SubFilters,"
|
||||||
" which qpdf does not support"));
|
" which qpdf does not support"));
|
||||||
}
|
}
|
||||||
@ -852,8 +852,8 @@ QPDF::initializeEncryption()
|
|||||||
encryption_dict.getKey("/U").isString() &&
|
encryption_dict.getKey("/U").isString() &&
|
||||||
encryption_dict.getKey("/P").isInteger()))
|
encryption_dict.getKey("/P").isInteger()))
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary", this->m->file->getLastOffset(),
|
||||||
"some encryption dictionary parameters are missing "
|
"some encryption dictionary parameters are missing "
|
||||||
"or the wrong type");
|
"or the wrong type");
|
||||||
}
|
}
|
||||||
@ -869,15 +869,15 @@ QPDF::initializeEncryption()
|
|||||||
if (! (((R >= 2) && (R <= 6)) &&
|
if (! (((R >= 2) && (R <= 6)) &&
|
||||||
((V == 1) || (V == 2) || (V == 4) || (V == 5))))
|
((V == 1) || (V == 2) || (V == 4) || (V == 5))))
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_unsupported, this->file->getName(),
|
throw QPDFExc(qpdf_e_unsupported, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary", this->m->file->getLastOffset(),
|
||||||
"Unsupported /R or /V in encryption dictionary; R = " +
|
"Unsupported /R or /V in encryption dictionary; R = " +
|
||||||
QUtil::int_to_string(R) + " (max 6), V = " +
|
QUtil::int_to_string(R) + " (max 6), V = " +
|
||||||
QUtil::int_to_string(V) + " (max 5)");
|
QUtil::int_to_string(V) + " (max 5)");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->encryption_V = V;
|
this->m->encryption_V = V;
|
||||||
this->encryption_R = R;
|
this->m->encryption_R = R;
|
||||||
|
|
||||||
// OE, UE, and Perms are only present if V >= 5.
|
// OE, UE, and Perms are only present if V >= 5.
|
||||||
std::string OE;
|
std::string OE;
|
||||||
@ -890,8 +890,9 @@ QPDF::initializeEncryption()
|
|||||||
pad_short_parameter(U, key_bytes);
|
pad_short_parameter(U, key_bytes);
|
||||||
if (! ((O.length() == key_bytes) && (U.length() == key_bytes)))
|
if (! ((O.length() == key_bytes) && (U.length() == key_bytes)))
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary",
|
||||||
|
this->m->file->getLastOffset(),
|
||||||
"incorrect length for /O and/or /U in "
|
"incorrect length for /O and/or /U in "
|
||||||
"encryption dictionary");
|
"encryption dictionary");
|
||||||
}
|
}
|
||||||
@ -902,8 +903,9 @@ QPDF::initializeEncryption()
|
|||||||
encryption_dict.getKey("/UE").isString() &&
|
encryption_dict.getKey("/UE").isString() &&
|
||||||
encryption_dict.getKey("/Perms").isString()))
|
encryption_dict.getKey("/Perms").isString()))
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary",
|
||||||
|
this->m->file->getLastOffset(),
|
||||||
"some V=5 encryption dictionary parameters are "
|
"some V=5 encryption dictionary parameters are "
|
||||||
"missing or the wrong type");
|
"missing or the wrong type");
|
||||||
}
|
}
|
||||||
@ -922,8 +924,9 @@ QPDF::initializeEncryption()
|
|||||||
(UE.length() < OUE_key_bytes_V5) ||
|
(UE.length() < OUE_key_bytes_V5) ||
|
||||||
(Perms.length() < Perms_key_bytes_V5))
|
(Perms.length() < Perms_key_bytes_V5))
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary",
|
||||||
|
this->m->file->getLastOffset(),
|
||||||
"incorrect length for some of"
|
"incorrect length for some of"
|
||||||
" /O, /U, /OE, /UE, or /Perms in"
|
" /O, /U, /OE, /UE, or /Perms in"
|
||||||
" encryption dictionary");
|
" encryption dictionary");
|
||||||
@ -936,16 +939,17 @@ QPDF::initializeEncryption()
|
|||||||
Length = encryption_dict.getKey("/Length").getIntValue();
|
Length = encryption_dict.getKey("/Length").getIntValue();
|
||||||
if ((Length % 8) || (Length < 40) || (Length > 256))
|
if ((Length % 8) || (Length < 40) || (Length > 256))
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary",
|
||||||
|
this->m->file->getLastOffset(),
|
||||||
"invalid /Length value in encryption dictionary");
|
"invalid /Length value in encryption dictionary");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->encrypt_metadata = true;
|
this->m->encrypt_metadata = true;
|
||||||
if ((V >= 4) && (encryption_dict.getKey("/EncryptMetadata").isBool()))
|
if ((V >= 4) && (encryption_dict.getKey("/EncryptMetadata").isBool()))
|
||||||
{
|
{
|
||||||
this->encrypt_metadata =
|
this->m->encrypt_metadata =
|
||||||
encryption_dict.getKey("/EncryptMetadata").getBoolValue();
|
encryption_dict.getKey("/EncryptMetadata").getBoolValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -986,40 +990,40 @@ QPDF::initializeEncryption()
|
|||||||
method = e_unknown;
|
method = e_unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->crypt_filters[filter] = method;
|
this->m->crypt_filters[filter] = method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDFObjectHandle StmF = encryption_dict.getKey("/StmF");
|
QPDFObjectHandle StmF = encryption_dict.getKey("/StmF");
|
||||||
QPDFObjectHandle StrF = encryption_dict.getKey("/StrF");
|
QPDFObjectHandle StrF = encryption_dict.getKey("/StrF");
|
||||||
QPDFObjectHandle EFF = encryption_dict.getKey("/EFF");
|
QPDFObjectHandle EFF = encryption_dict.getKey("/EFF");
|
||||||
this->cf_stream = interpretCF(StmF);
|
this->m->cf_stream = interpretCF(StmF);
|
||||||
this->cf_string = interpretCF(StrF);
|
this->m->cf_string = interpretCF(StrF);
|
||||||
if (EFF.isName())
|
if (EFF.isName())
|
||||||
{
|
{
|
||||||
this->cf_file = interpretCF(EFF);
|
this->m->cf_file = interpretCF(EFF);
|
||||||
}
|
}
|
||||||
else
|
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,
|
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(
|
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
|
// password supplied was owner password; user_password has
|
||||||
// been initialized for V < 5
|
// 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
|
else
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_password, this->file->getName(),
|
throw QPDFExc(qpdf_e_password, this->m->file->getName(),
|
||||||
"", 0, "invalid password");
|
"", 0, "invalid password");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1028,8 +1032,8 @@ QPDF::initializeEncryption()
|
|||||||
// For V < 5, the user password is encrypted with the owner
|
// For V < 5, the user password is encrypted with the owner
|
||||||
// password, and the user password is always used for
|
// password, and the user password is always used for
|
||||||
// computing the encryption key.
|
// computing the encryption key.
|
||||||
this->encryption_key = compute_encryption_key(
|
this->m->encryption_key = compute_encryption_key(
|
||||||
this->user_password, data);
|
this->m->user_password, data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1037,12 +1041,13 @@ QPDF::initializeEncryption()
|
|||||||
// compute the encryption key, and neither password can be
|
// compute the encryption key, and neither password can be
|
||||||
// used to recover the other.
|
// used to recover the other.
|
||||||
bool perms_valid;
|
bool perms_valid;
|
||||||
this->encryption_key = recover_encryption_key_with_password(
|
this->m->encryption_key = recover_encryption_key_with_password(
|
||||||
this->provided_password, data, perms_valid);
|
this->m->provided_password, data, perms_valid);
|
||||||
if (! perms_valid)
|
if (! perms_valid)
|
||||||
{
|
{
|
||||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
"encryption dictionary", this->file->getLastOffset(),
|
"encryption dictionary",
|
||||||
|
this->m->file->getLastOffset(),
|
||||||
"/Perms field in encryption dictionary"
|
"/Perms field in encryption dictionary"
|
||||||
" doesn't match expected value"));
|
" doesn't match expected value"));
|
||||||
}
|
}
|
||||||
@ -1052,23 +1057,24 @@ QPDF::initializeEncryption()
|
|||||||
std::string
|
std::string
|
||||||
QPDF::getKeyForObject(int objid, int generation, bool use_aes)
|
QPDF::getKeyForObject(int objid, int generation, bool use_aes)
|
||||||
{
|
{
|
||||||
if (! this->encrypted)
|
if (! this->m->encrypted)
|
||||||
{
|
{
|
||||||
throw std::logic_error(
|
throw std::logic_error(
|
||||||
"request for encryption key in non-encrypted PDF");
|
"request for encryption key in non-encrypted PDF");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! ((objid == this->cached_key_objid) &&
|
if (! ((objid == this->m->cached_key_objid) &&
|
||||||
(generation == this->cached_key_generation)))
|
(generation == this->m->cached_key_generation)))
|
||||||
{
|
{
|
||||||
this->cached_object_encryption_key =
|
this->m->cached_object_encryption_key =
|
||||||
compute_data_key(this->encryption_key, objid, generation,
|
compute_data_key(this->m->encryption_key, objid, generation,
|
||||||
use_aes, this->encryption_V, this->encryption_R);
|
use_aes, this->m->encryption_V,
|
||||||
this->cached_key_objid = objid;
|
this->m->encryption_R);
|
||||||
this->cached_key_generation = generation;
|
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
|
void
|
||||||
@ -1079,9 +1085,9 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool use_aes = false;
|
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:
|
case e_none:
|
||||||
return;
|
return;
|
||||||
@ -1098,15 +1104,15 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
this->last_object_description,
|
this->m->last_object_description,
|
||||||
this->file->getLastOffset(),
|
this->m->file->getLastOffset(),
|
||||||
"unknown encryption filter for strings"
|
"unknown encryption filter for strings"
|
||||||
" (check /StrF in /Encrypt dictionary);"
|
" (check /StrF in /Encrypt dictionary);"
|
||||||
" strings may be decrypted improperly"));
|
" strings may be decrypted improperly"));
|
||||||
// To avoid repeated warnings, reset cf_string. Assume
|
// To avoid repeated warnings, reset cf_string. Assume
|
||||||
// we'd want to use AES if V == 4.
|
// we'd want to use AES if V == 4.
|
||||||
this->cf_string = e_aes;
|
this->m->cf_string = e_aes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1145,9 +1151,9 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
|||||||
}
|
}
|
||||||
catch (std::runtime_error& e)
|
catch (std::runtime_error& e)
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
this->last_object_description,
|
this->m->last_object_description,
|
||||||
this->file->getLastOffset(),
|
this->m->file->getLastOffset(),
|
||||||
"error decrypting string for object " +
|
"error decrypting string for object " +
|
||||||
QUtil::int_to_string(objid) + " " +
|
QUtil::int_to_string(objid) + " " +
|
||||||
QUtil::int_to_string(generation) + ": " + e.what());
|
QUtil::int_to_string(generation) + ": " + e.what());
|
||||||
@ -1170,7 +1176,7 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool use_aes = false;
|
bool use_aes = false;
|
||||||
if (this->encryption_V >= 4)
|
if (this->m->encryption_V >= 4)
|
||||||
{
|
{
|
||||||
encryption_method_e method = e_unknown;
|
encryption_method_e method = e_unknown;
|
||||||
std::string method_source = "/StmF from /Encrypt dictionary";
|
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 (method == e_unknown)
|
||||||
{
|
{
|
||||||
if ((! this->encrypt_metadata) && (type == "/Metadata"))
|
if ((! this->m->encrypt_metadata) && (type == "/Metadata"))
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF_encryption cleartext metadata");
|
QTC::TC("qpdf", "QPDF_encryption cleartext metadata");
|
||||||
method = e_none;
|
method = e_none;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (this->attachment_streams.count(
|
if (this->m->attachment_streams.count(
|
||||||
QPDFObjGen(objid, generation)) > 0)
|
QPDFObjGen(objid, generation)) > 0)
|
||||||
{
|
{
|
||||||
method = this->cf_file;
|
method = this->m->cf_file;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
method = this->cf_stream;
|
method = this->m->cf_stream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1259,15 +1265,15 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
// filter local to this stream.
|
// filter local to this stream.
|
||||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
this->last_object_description,
|
this->m->last_object_description,
|
||||||
this->file->getLastOffset(),
|
this->m->file->getLastOffset(),
|
||||||
"unknown encryption filter for streams"
|
"unknown encryption filter for streams"
|
||||||
" (check " + method_source + ");"
|
" (check " + method_source + ");"
|
||||||
" streams may be decrypted improperly"));
|
" streams may be decrypted improperly"));
|
||||||
// To avoid repeated warnings, reset cf_stream. Assume
|
// To avoid repeated warnings, reset cf_stream. Assume
|
||||||
// we'd want to use AES if V == 4.
|
// we'd want to use AES if V == 4.
|
||||||
this->cf_stream = e_aes;
|
this->m->cf_stream = e_aes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1331,13 +1337,13 @@ QPDF::compute_encryption_parameters_V5(
|
|||||||
std::string const&
|
std::string const&
|
||||||
QPDF::getPaddedUserPassword() const
|
QPDF::getPaddedUserPassword() const
|
||||||
{
|
{
|
||||||
return this->user_password;
|
return this->m->user_password;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
QPDF::getTrimmedUserPassword() const
|
QPDF::getTrimmedUserPassword() const
|
||||||
{
|
{
|
||||||
std::string result = this->user_password;
|
std::string result = this->m->user_password;
|
||||||
trim_user_password(result);
|
trim_user_password(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1345,13 +1351,13 @@ QPDF::getTrimmedUserPassword() const
|
|||||||
std::string
|
std::string
|
||||||
QPDF::getEncryptionKey() const
|
QPDF::getEncryptionKey() const
|
||||||
{
|
{
|
||||||
return this->encryption_key;
|
return this->m->encryption_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
QPDF::isEncrypted() const
|
QPDF::isEncrypted() const
|
||||||
{
|
{
|
||||||
return this->encrypted;
|
return this->m->encrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -1368,7 +1374,7 @@ QPDF::isEncrypted(int& R, int& P, int& V,
|
|||||||
encryption_method_e& string_method,
|
encryption_method_e& string_method,
|
||||||
encryption_method_e& file_method)
|
encryption_method_e& file_method)
|
||||||
{
|
{
|
||||||
if (this->encrypted)
|
if (this->m->encrypted)
|
||||||
{
|
{
|
||||||
QPDFObjectHandle trailer = getTrailer();
|
QPDFObjectHandle trailer = getTrailer();
|
||||||
QPDFObjectHandle encrypt = trailer.getKey("/Encrypt");
|
QPDFObjectHandle encrypt = trailer.getKey("/Encrypt");
|
||||||
@ -1378,9 +1384,9 @@ QPDF::isEncrypted(int& R, int& P, int& V,
|
|||||||
P = Pkey.getIntValue();
|
P = Pkey.getIntValue();
|
||||||
R = Rkey.getIntValue();
|
R = Rkey.getIntValue();
|
||||||
V = Vkey.getIntValue();
|
V = Vkey.getIntValue();
|
||||||
stream_method = this->cf_stream;
|
stream_method = this->m->cf_stream;
|
||||||
string_method = this->cf_stream;
|
string_method = this->m->cf_stream;
|
||||||
file_method = this->cf_file;
|
file_method = this->m->cf_file;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -62,7 +62,7 @@ void
|
|||||||
QPDF::optimize(std::map<int, int> const& object_stream_data,
|
QPDF::optimize(std::map<int, int> const& object_stream_data,
|
||||||
bool allow_changes)
|
bool allow_changes)
|
||||||
{
|
{
|
||||||
if (! this->obj_user_to_objects.empty())
|
if (! this->m->obj_user_to_objects.empty())
|
||||||
{
|
{
|
||||||
// already optimized
|
// already optimized
|
||||||
return;
|
return;
|
||||||
@ -83,19 +83,19 @@ QPDF::optimize(std::map<int, int> const& object_stream_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Traverse pages tree pushing all inherited resources down to the
|
// 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);
|
pushInheritedAttributesToPage(allow_changes, false);
|
||||||
|
|
||||||
// Traverse pages
|
// Traverse pages
|
||||||
int n = this->all_pages.size();
|
int n = this->m->all_pages.size();
|
||||||
for (int pageno = 0; pageno < n; ++pageno)
|
for (int pageno = 0; pageno < n; ++pageno)
|
||||||
{
|
{
|
||||||
updateObjectMaps(ObjUser(ObjUser::ou_page, pageno),
|
updateObjectMaps(ObjUser(ObjUser::ou_page, pageno),
|
||||||
this->all_pages.at(pageno));
|
this->m->all_pages.at(pageno));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverse document-level items
|
// Traverse document-level items
|
||||||
std::set<std::string> keys = this->trailer.getKeys();
|
std::set<std::string> keys = this->m->trailer.getKeys();
|
||||||
for (std::set<std::string>::iterator iter = keys.begin();
|
for (std::set<std::string>::iterator iter = keys.begin();
|
||||||
iter != keys.end(); ++iter)
|
iter != keys.end(); ++iter)
|
||||||
{
|
{
|
||||||
@ -107,7 +107,7 @@ QPDF::optimize(std::map<int, int> const& object_stream_data,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
updateObjectMaps(ObjUser(ObjUser::ou_trailer_key, key),
|
updateObjectMaps(ObjUser(ObjUser::ou_trailer_key, key),
|
||||||
this->trailer.getKey(key));
|
this->m->trailer.getKey(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,8 +129,8 @@ QPDF::optimize(std::map<int, int> const& object_stream_data,
|
|||||||
|
|
||||||
ObjUser root_ou = ObjUser(ObjUser::ou_root);
|
ObjUser root_ou = ObjUser(ObjUser::ou_root);
|
||||||
QPDFObjGen root_og = QPDFObjGen(root.getObjGen());
|
QPDFObjGen root_og = QPDFObjGen(root.getObjGen());
|
||||||
obj_user_to_objects[root_ou].insert(root_og);
|
this->m->obj_user_to_objects[root_ou].insert(root_og);
|
||||||
object_to_obj_users[root_og].insert(root_ou);
|
this->m->object_to_obj_users[root_og].insert(root_ou);
|
||||||
|
|
||||||
filterCompressedObjects(object_stream_data);
|
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
|
// The record of whether we've done this is cleared by
|
||||||
// updateAllPagesCache(). If we're warning for skipped keys,
|
// updateAllPagesCache(). If we're warning for skipped keys,
|
||||||
// re-traverse unconditionally.
|
// 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;
|
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
|
// key_ancestors is a mapping of page attribute keys to a stack of
|
||||||
// Pages nodes that contain values for them.
|
// Pages nodes that contain values for them.
|
||||||
std::map<std::string, std::vector<QPDFObjectHandle> > key_ancestors;
|
std::map<std::string, std::vector<QPDFObjectHandle> > key_ancestors;
|
||||||
this->all_pages.clear();
|
this->m->all_pages.clear();
|
||||||
pushInheritedAttributesToPageInternal(
|
pushInheritedAttributesToPageInternal(
|
||||||
this->trailer.getKey("/Root").getKey("/Pages"),
|
this->m->trailer.getKey("/Root").getKey("/Pages"),
|
||||||
key_ancestors, this->all_pages, allow_changes, warn_skipped_keys);
|
key_ancestors, this->m->all_pages, allow_changes, warn_skipped_keys);
|
||||||
assert(key_ancestors.empty());
|
assert(key_ancestors.empty());
|
||||||
this->pushed_inherited_attributes_to_pages = true;
|
this->m->pushed_inherited_attributes_to_pages = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -192,8 +192,8 @@ QPDF::pushInheritedAttributesToPageInternal2(
|
|||||||
if (visited.count(this_og) > 0)
|
if (visited.count(this_og) > 0)
|
||||||
{
|
{
|
||||||
throw QPDFExc(
|
throw QPDFExc(
|
||||||
qpdf_e_pages, this->file->getName(),
|
qpdf_e_pages, this->m->file->getName(),
|
||||||
this->last_object_description, 0,
|
this->m->last_object_description, 0,
|
||||||
"Loop detected in /Pages structure (inherited attributes)");
|
"Loop detected in /Pages structure (inherited attributes)");
|
||||||
}
|
}
|
||||||
visited.insert(this_og);
|
visited.insert(this_og);
|
||||||
@ -219,9 +219,9 @@ QPDF::pushInheritedAttributesToPageInternal2(
|
|||||||
{
|
{
|
||||||
if (! allow_changes)
|
if (! allow_changes)
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_internal, this->file->getName(),
|
throw QPDFExc(qpdf_e_internal, this->m->file->getName(),
|
||||||
this->last_object_description,
|
this->m->last_object_description,
|
||||||
this->file->getLastOffset(),
|
this->m->file->getLastOffset(),
|
||||||
"optimize detected an "
|
"optimize detected an "
|
||||||
"inheritable attribute when called "
|
"inheritable attribute when called "
|
||||||
"in no-change mode");
|
"in no-change mode");
|
||||||
@ -269,8 +269,8 @@ QPDF::pushInheritedAttributesToPageInternal2(
|
|||||||
setLastObjectDescription("Pages object",
|
setLastObjectDescription("Pages object",
|
||||||
cur_pages.getObjectID(),
|
cur_pages.getObjectID(),
|
||||||
cur_pages.getGeneration());
|
cur_pages.getGeneration());
|
||||||
warn(QPDFExc(qpdf_e_pages, this->file->getName(),
|
warn(QPDFExc(qpdf_e_pages, this->m->file->getName(),
|
||||||
this->last_object_description, 0,
|
this->m->last_object_description, 0,
|
||||||
"Unknown key " + key + " in /Pages object"
|
"Unknown key " + key + " in /Pages object"
|
||||||
" is being discarded as a result of"
|
" is being discarded as a result of"
|
||||||
" flattening the /Pages tree"));
|
" flattening the /Pages tree"));
|
||||||
@ -337,9 +337,9 @@ QPDF::pushInheritedAttributesToPageInternal2(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
this->last_object_description,
|
this->m->last_object_description,
|
||||||
this->file->getLastOffset(),
|
this->m->file->getLastOffset(),
|
||||||
"invalid Type " + type + " in page tree");
|
"invalid Type " + type + " in page tree");
|
||||||
}
|
}
|
||||||
visited.erase(this_og);
|
visited.erase(this_og);
|
||||||
@ -382,8 +382,8 @@ QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh,
|
|||||||
QTC::TC("qpdf", "QPDF opt loop detected");
|
QTC::TC("qpdf", "QPDF opt loop detected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->obj_user_to_objects[ou].insert(og);
|
this->m->obj_user_to_objects[ou].insert(og);
|
||||||
this->object_to_obj_users[og].insert(ou);
|
this->m->object_to_obj_users[og].insert(ou);
|
||||||
visited.insert(og);
|
visited.insert(og);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,8 +445,8 @@ QPDF::filterCompressedObjects(std::map<int, int> const& object_stream_data)
|
|||||||
std::map<QPDFObjGen, std::set<ObjUser> > t_object_to_obj_users;
|
std::map<QPDFObjGen, std::set<ObjUser> > t_object_to_obj_users;
|
||||||
|
|
||||||
for (std::map<ObjUser, std::set<QPDFObjGen> >::iterator i1 =
|
for (std::map<ObjUser, std::set<QPDFObjGen> >::iterator i1 =
|
||||||
this->obj_user_to_objects.begin();
|
this->m->obj_user_to_objects.begin();
|
||||||
i1 != this->obj_user_to_objects.end(); ++i1)
|
i1 != this->m->obj_user_to_objects.end(); ++i1)
|
||||||
{
|
{
|
||||||
ObjUser const& ou = (*i1).first;
|
ObjUser const& ou = (*i1).first;
|
||||||
std::set<QPDFObjGen> const& objects = (*i1).second;
|
std::set<QPDFObjGen> const& objects = (*i1).second;
|
||||||
@ -468,8 +468,8 @@ QPDF::filterCompressedObjects(std::map<int, int> const& object_stream_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (std::map<QPDFObjGen, std::set<ObjUser> >::iterator i1 =
|
for (std::map<QPDFObjGen, std::set<ObjUser> >::iterator i1 =
|
||||||
this->object_to_obj_users.begin();
|
this->m->object_to_obj_users.begin();
|
||||||
i1 != this->object_to_obj_users.end(); ++i1)
|
i1 != this->m->object_to_obj_users.end(); ++i1)
|
||||||
{
|
{
|
||||||
QPDFObjGen const& og = (*i1).first;
|
QPDFObjGen const& og = (*i1).first;
|
||||||
std::set<ObjUser> const& objusers = (*i1).second;
|
std::set<ObjUser> const& objusers = (*i1).second;
|
||||||
@ -490,6 +490,6 @@ QPDF::filterCompressedObjects(std::map<int, int> const& object_stream_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->obj_user_to_objects = t_obj_user_to_objects;
|
this->m->obj_user_to_objects = t_obj_user_to_objects;
|
||||||
this->object_to_obj_users = t_object_to_obj_users;
|
this->m->object_to_obj_users = t_object_to_obj_users;
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,12 @@ std::vector<QPDFObjectHandle> const&
|
|||||||
QPDF::getAllPages()
|
QPDF::getAllPages()
|
||||||
{
|
{
|
||||||
// Note that pushInheritedAttributesToPage may also be used to
|
// Note that pushInheritedAttributesToPage may also be used to
|
||||||
// initialize this->all_pages.
|
// initialize this->m->all_pages.
|
||||||
if (this->all_pages.empty())
|
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
|
void
|
||||||
@ -69,8 +69,8 @@ QPDF::getAllPagesInternal2(QPDFObjectHandle cur_pages,
|
|||||||
if (visited.count(this_og) > 0)
|
if (visited.count(this_og) > 0)
|
||||||
{
|
{
|
||||||
throw QPDFExc(
|
throw QPDFExc(
|
||||||
qpdf_e_pages, this->file->getName(),
|
qpdf_e_pages, this->m->file->getName(),
|
||||||
this->last_object_description, 0,
|
this->m->last_object_description, 0,
|
||||||
"Loop detected in /Pages structure (getAllPages)");
|
"Loop detected in /Pages structure (getAllPages)");
|
||||||
}
|
}
|
||||||
visited.insert(this_og);
|
visited.insert(this_og);
|
||||||
@ -103,9 +103,9 @@ QPDF::getAllPagesInternal2(QPDFObjectHandle cur_pages,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
||||||
this->last_object_description,
|
this->m->last_object_description,
|
||||||
this->file->getLastOffset(),
|
this->m->file->getLastOffset(),
|
||||||
"invalid Type " + type + " in page tree");
|
"invalid Type " + type + " in page tree");
|
||||||
}
|
}
|
||||||
visited.erase(this_og);
|
visited.erase(this_og);
|
||||||
@ -119,9 +119,9 @@ QPDF::updateAllPagesCache()
|
|||||||
// it that they got from calls to getAllPages(). We can defer
|
// it that they got from calls to getAllPages(). We can defer
|
||||||
// recalculation of pageobj_to_pages_pos until needed.
|
// recalculation of pageobj_to_pages_pos until needed.
|
||||||
QTC::TC("qpdf", "QPDF updateAllPagesCache");
|
QTC::TC("qpdf", "QPDF updateAllPagesCache");
|
||||||
this->all_pages.clear();
|
this->m->all_pages.clear();
|
||||||
this->pageobj_to_pages_pos.clear();
|
this->m->pageobj_to_pages_pos.clear();
|
||||||
this->pushed_inherited_attributes_to_pages = false;
|
this->m->pushed_inherited_attributes_to_pages = false;
|
||||||
getAllPages();
|
getAllPages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,26 +131,26 @@ QPDF::flattenPagesTree()
|
|||||||
// If not already done, flatten the /Pages structure and
|
// If not already done, flatten the /Pages structure and
|
||||||
// initialize pageobj_to_pages_pos.
|
// initialize pageobj_to_pages_pos.
|
||||||
|
|
||||||
if (! this->pageobj_to_pages_pos.empty())
|
if (! this->m->pageobj_to_pages_pos.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push inherited objects down to the /Page level. As a side
|
// 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);
|
pushInheritedAttributesToPage(true, true);
|
||||||
|
|
||||||
QPDFObjectHandle pages = getRoot().getKey("/Pages");
|
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)
|
for (int pos = 0; pos < len; ++pos)
|
||||||
{
|
{
|
||||||
// populate pageobj_to_pages_pos and fix parent pointer
|
// populate pageobj_to_pages_pos and fix parent pointer
|
||||||
insertPageobjToPage(this->all_pages.at(pos), pos, true);
|
insertPageobjToPage(this->m->all_pages.at(pos), pos, true);
|
||||||
this->all_pages.at(pos).replaceKey("/Parent", pages);
|
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
|
// /Count has not changed
|
||||||
if (pages.getKey("/Count").getIntValue() != len)
|
if (pages.getKey("/Count").getIntValue() != len)
|
||||||
{
|
{
|
||||||
@ -165,21 +165,22 @@ QPDF::insertPageobjToPage(QPDFObjectHandle const& obj, int pos,
|
|||||||
QPDFObjGen og(obj.getObjGen());
|
QPDFObjGen og(obj.getObjGen());
|
||||||
if (check_duplicate)
|
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");
|
QTC::TC("qpdf", "QPDF duplicate page reference");
|
||||||
setLastObjectDescription("page " + QUtil::int_to_string(pos) +
|
setLastObjectDescription("page " + QUtil::int_to_string(pos) +
|
||||||
" (numbered from zero)",
|
" (numbered from zero)",
|
||||||
og.getObj(), og.getGen());
|
og.getObj(), og.getGen());
|
||||||
throw QPDFExc(qpdf_e_pages, this->file->getName(),
|
throw QPDFExc(qpdf_e_pages, this->m->file->getName(),
|
||||||
this->last_object_description, 0,
|
this->m->last_object_description, 0,
|
||||||
"duplicate page reference found;"
|
"duplicate page reference found;"
|
||||||
" this would cause loss of data");
|
" this would cause loss of data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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())
|
if (! newpage.isIndirect())
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF insert non-indirect page");
|
QTC::TC("qpdf", "QPDF insert non-indirect page");
|
||||||
newpage = this->makeIndirectObject(newpage);
|
newpage = makeIndirectObject(newpage);
|
||||||
}
|
}
|
||||||
else if (newpage.getOwningQPDF() != this)
|
else if (newpage.getOwningQPDF() != this)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF insert foreign page");
|
QTC::TC("qpdf", "QPDF insert foreign page");
|
||||||
newpage.getOwningQPDF()->pushInheritedAttributesToPage();
|
newpage.getOwningQPDF()->pushInheritedAttributesToPage();
|
||||||
newpage = this->copyForeignObject(newpage, true);
|
newpage = copyForeignObject(newpage, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -210,26 +211,26 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos)
|
|||||||
|
|
||||||
QTC::TC("qpdf", "QPDF insert page",
|
QTC::TC("qpdf", "QPDF insert page",
|
||||||
(pos == 0) ? 0 : // insert at beginning
|
(pos == 0) ? 0 : // insert at beginning
|
||||||
(pos == static_cast<int>(this->all_pages.size())) ? 1 : // at end
|
(pos == static_cast<int>(this->m->all_pages.size())) ? 1 : // at end
|
||||||
2); // insert in middle
|
2); // insert in middle
|
||||||
|
|
||||||
QPDFObjectHandle pages = getRoot().getKey("/Pages");
|
QPDFObjectHandle pages = getRoot().getKey("/Pages");
|
||||||
QPDFObjectHandle kids = pages.getKey("/Kids");
|
QPDFObjectHandle kids = pages.getKey("/Kids");
|
||||||
assert ((pos >= 0) &&
|
assert ((pos >= 0) &&
|
||||||
(static_cast<size_t>(pos) <= this->all_pages.size()));
|
(static_cast<size_t>(pos) <= this->m->all_pages.size()));
|
||||||
|
|
||||||
newpage.replaceKey("/Parent", pages);
|
newpage.replaceKey("/Parent", pages);
|
||||||
kids.insertItem(pos, newpage);
|
kids.insertItem(pos, newpage);
|
||||||
int npages = kids.getArrayNItems();
|
int npages = kids.getArrayNItems();
|
||||||
pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages));
|
pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages));
|
||||||
this->all_pages.insert(this->all_pages.begin() + pos, newpage);
|
this->m->all_pages.insert(this->m->all_pages.begin() + pos, newpage);
|
||||||
assert(this->all_pages.size() == static_cast<size_t>(npages));
|
assert(this->m->all_pages.size() == static_cast<size_t>(npages));
|
||||||
for (int i = pos + 1; i < npages; ++i)
|
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);
|
insertPageobjToPage(newpage, pos, true);
|
||||||
assert(this->pageobj_to_pages_pos.size() == static_cast<size_t>(npages));
|
assert(this->m->pageobj_to_pages_pos.size() == static_cast<size_t>(npages));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -238,7 +239,8 @@ QPDF::removePage(QPDFObjectHandle page)
|
|||||||
int pos = findPage(page); // also ensures flat /Pages
|
int pos = findPage(page); // also ensures flat /Pages
|
||||||
QTC::TC("qpdf", "QPDF remove page",
|
QTC::TC("qpdf", "QPDF remove page",
|
||||||
(pos == 0) ? 0 : // remove at beginning
|
(pos == 0) ? 0 : // remove at beginning
|
||||||
(pos == static_cast<int>(this->all_pages.size() - 1)) ? 1 : // end
|
(pos == static_cast<int>(
|
||||||
|
this->m->all_pages.size() - 1)) ? 1 : // end
|
||||||
2); // remove in middle
|
2); // remove in middle
|
||||||
|
|
||||||
QPDFObjectHandle pages = getRoot().getKey("/Pages");
|
QPDFObjectHandle pages = getRoot().getKey("/Pages");
|
||||||
@ -247,13 +249,13 @@ QPDF::removePage(QPDFObjectHandle page)
|
|||||||
kids.eraseItem(pos);
|
kids.eraseItem(pos);
|
||||||
int npages = kids.getArrayNItems();
|
int npages = kids.getArrayNItems();
|
||||||
pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages));
|
pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages));
|
||||||
this->all_pages.erase(this->all_pages.begin() + pos);
|
this->m->all_pages.erase(this->m->all_pages.begin() + pos);
|
||||||
assert(this->all_pages.size() == static_cast<size_t>(npages));
|
assert(this->m->all_pages.size() == static_cast<size_t>(npages));
|
||||||
this->pageobj_to_pages_pos.erase(page.getObjGen());
|
this->m->pageobj_to_pages_pos.erase(page.getObjGen());
|
||||||
assert(this->pageobj_to_pages_pos.size() == static_cast<size_t>(npages));
|
assert(this->m->pageobj_to_pages_pos.size() == static_cast<size_t>(npages));
|
||||||
for (int i = pos; i < npages; ++i)
|
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();
|
flattenPagesTree();
|
||||||
std::map<QPDFObjGen, int>::iterator it =
|
std::map<QPDFObjGen, int>::iterator it =
|
||||||
this->pageobj_to_pages_pos.find(og);
|
this->m->pageobj_to_pages_pos.find(og);
|
||||||
if (it == this->pageobj_to_pages_pos.end())
|
if (it == this->m->pageobj_to_pages_pos.end())
|
||||||
{
|
{
|
||||||
setLastObjectDescription("page object", og.getObj(), og.getGen());
|
setLastObjectDescription("page object", og.getObj(), og.getGen());
|
||||||
throw QPDFExc(qpdf_e_pages, this->file->getName(),
|
throw QPDFExc(qpdf_e_pages, this->m->file->getName(),
|
||||||
this->last_object_description, 0,
|
this->m->last_object_description, 0,
|
||||||
"page object not referenced in /Pages tree");
|
"page object not referenced in /Pages tree");
|
||||||
}
|
}
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user