mirror of
https://github.com/qpdf/qpdf.git
synced 2025-01-22 22:58:33 +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),
|
||||
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,6 +1113,16 @@ class QPDF
|
||||
std::set<QPDFObjGen>& visited, bool top);
|
||||
void filterCompressedObjects(std::map<int, int> const& object_stream_data);
|
||||
|
||||
class Members
|
||||
{
|
||||
friend class QPDF;
|
||||
|
||||
public:
|
||||
~Members();
|
||||
|
||||
private:
|
||||
Members();
|
||||
Members(Members const&);
|
||||
|
||||
QPDFTokenizer tokenizer;
|
||||
PointerHolder<InputSource> file;
|
||||
@ -1167,8 +1177,8 @@ class QPDF
|
||||
HGeneric outline_hints;
|
||||
|
||||
// Computed linearization data: used to populate above tables
|
||||
// during writing and to compare with them during validation. c_
|
||||
// means computed.
|
||||
// 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;
|
||||
@ -1188,4 +1198,10 @@ class QPDF
|
||||
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__
|
||||
|
510
libqpdf/QPDF.cc
510
libqpdf/QPDF.cc
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
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,
|
||||
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<int, int> 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<std::string> keys = this->trailer.getKeys();
|
||||
std::set<std::string> keys = this->m->trailer.getKeys();
|
||||
for (std::set<std::string>::iterator iter = keys.begin();
|
||||
iter != keys.end(); ++iter)
|
||||
{
|
||||
@ -107,7 +107,7 @@ QPDF::optimize(std::map<int, int> 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<int, int> 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<std::string, std::vector<QPDFObjectHandle> > 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<int, int> const& object_stream_data)
|
||||
std::map<QPDFObjGen, std::set<ObjUser> > t_object_to_obj_users;
|
||||
|
||||
for (std::map<ObjUser, std::set<QPDFObjGen> >::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<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 =
|
||||
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<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->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;
|
||||
}
|
||||
|
@ -44,12 +44,12 @@ std::vector<QPDFObjectHandle> 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<int>(this->all_pages.size())) ? 1 : // at end
|
||||
(pos == static_cast<int>(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<size_t>(pos) <= this->all_pages.size()));
|
||||
(static_cast<size_t>(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<size_t>(npages));
|
||||
this->m->all_pages.insert(this->m->all_pages.begin() + pos, newpage);
|
||||
assert(this->m->all_pages.size() == static_cast<size_t>(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<size_t>(npages));
|
||||
assert(this->m->pageobj_to_pages_pos.size() == static_cast<size_t>(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<int>(this->all_pages.size() - 1)) ? 1 : // end
|
||||
(pos == static_cast<int>(
|
||||
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<size_t>(npages));
|
||||
this->pageobj_to_pages_pos.erase(page.getObjGen());
|
||||
assert(this->pageobj_to_pages_pos.size() == static_cast<size_t>(npages));
|
||||
this->m->all_pages.erase(this->m->all_pages.begin() + pos);
|
||||
assert(this->m->all_pages.size() == static_cast<size_t>(npages));
|
||||
this->m->pageobj_to_pages_pos.erase(page.getObjGen());
|
||||
assert(this->m->pageobj_to_pages_pos.size() == static_cast<size_t>(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<QPDFObjGen, int>::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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user