mirror of
https://github.com/qpdf/qpdf.git
synced 2025-02-02 11:58:25 +00:00
Make a static version of QPDF::pipeStreamData
This is in preparation of being able to pipe a stream's data without keeping a copy of its containing qpdf object.
This commit is contained in:
parent
7588cac295
commit
fbbb0ee016
@ -692,6 +692,30 @@ class QPDF
|
|||||||
};
|
};
|
||||||
friend class ResolveRecorder;
|
friend class ResolveRecorder;
|
||||||
|
|
||||||
|
class EncryptionParameters
|
||||||
|
{
|
||||||
|
friend class QPDF;
|
||||||
|
public:
|
||||||
|
EncryptionParameters();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool encrypted;
|
||||||
|
bool encryption_initialized;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
void parse(char const* password);
|
void parse(char const* password);
|
||||||
void warn(QPDFExc const& e);
|
void warn(QPDFExc const& e);
|
||||||
void setTrailer(QPDFObjectHandle obj);
|
void setTrailer(QPDFObjectHandle obj);
|
||||||
@ -735,6 +759,16 @@ class QPDF
|
|||||||
Pipeline* pipeline,
|
Pipeline* pipeline,
|
||||||
bool suppress_warnings,
|
bool suppress_warnings,
|
||||||
bool will_retry);
|
bool will_retry);
|
||||||
|
static bool pipeStreamData(PointerHolder<QPDF::EncryptionParameters> encp,
|
||||||
|
PointerHolder<InputSource> file,
|
||||||
|
QPDF& qpdf_for_warning,
|
||||||
|
int objid, int generation,
|
||||||
|
qpdf_offset_t offset, size_t length,
|
||||||
|
QPDFObjectHandle dict,
|
||||||
|
bool is_attachment_stream,
|
||||||
|
Pipeline* pipeline,
|
||||||
|
bool suppress_warnings,
|
||||||
|
bool will_retry);
|
||||||
|
|
||||||
// For QPDFWriter:
|
// For QPDFWriter:
|
||||||
|
|
||||||
@ -776,9 +810,12 @@ class QPDF
|
|||||||
bool check_duplicate);
|
bool check_duplicate);
|
||||||
|
|
||||||
// methods to support encryption -- implemented in QPDF_encryption.cc
|
// methods to support encryption -- implemented in QPDF_encryption.cc
|
||||||
encryption_method_e interpretCF(QPDFObjectHandle);
|
static encryption_method_e interpretCF(
|
||||||
|
PointerHolder<EncryptionParameters> encp, QPDFObjectHandle);
|
||||||
void initializeEncryption();
|
void initializeEncryption();
|
||||||
std::string getKeyForObject(int objid, int generation, bool use_aes);
|
static std::string getKeyForObject(
|
||||||
|
PointerHolder<EncryptionParameters> encp,
|
||||||
|
int objid, int generation, bool use_aes);
|
||||||
void decryptString(std::string&, int objid, int generation);
|
void decryptString(std::string&, int objid, int generation);
|
||||||
static std::string compute_encryption_key_from_password(
|
static std::string compute_encryption_key_from_password(
|
||||||
std::string const& password, EncryptionData const& data);
|
std::string const& password, EncryptionData const& data);
|
||||||
@ -787,9 +824,12 @@ class QPDF
|
|||||||
static std::string recover_encryption_key_with_password(
|
static std::string recover_encryption_key_with_password(
|
||||||
std::string const& password, EncryptionData const& data,
|
std::string const& password, EncryptionData const& data,
|
||||||
bool& perms_valid);
|
bool& perms_valid);
|
||||||
void decryptStream(
|
static void decryptStream(
|
||||||
Pipeline*& pipeline, int objid, int generation,
|
PointerHolder<EncryptionParameters> encp,
|
||||||
QPDFObjectHandle& stream_dict,
|
PointerHolder<InputSource> file,
|
||||||
|
QPDF& qpdf_for_warning, Pipeline*& pipeline,
|
||||||
|
int objid, int generation,
|
||||||
|
QPDFObjectHandle& stream_dict, bool is_attachment_stream,
|
||||||
std::vector<PointerHolder<Pipeline> >& heap);
|
std::vector<PointerHolder<Pipeline> >& heap);
|
||||||
|
|
||||||
// Methods to support object copying
|
// Methods to support object copying
|
||||||
@ -1160,30 +1200,6 @@ 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 EncryptionParameters
|
|
||||||
{
|
|
||||||
friend class QPDF;
|
|
||||||
public:
|
|
||||||
EncryptionParameters();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool encrypted;
|
|
||||||
bool encryption_initialized;
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Members
|
class Members
|
||||||
{
|
{
|
||||||
friend class QPDF;
|
friend class QPDF;
|
||||||
|
@ -2512,34 +2512,40 @@ QPDF::getCompressibleObjGens()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
QPDF::pipeStreamData(int objid, int generation,
|
QPDF::pipeStreamData(PointerHolder<EncryptionParameters> encp,
|
||||||
|
PointerHolder<InputSource> file,
|
||||||
|
QPDF& qpdf_for_warning,
|
||||||
|
int objid, int generation,
|
||||||
qpdf_offset_t offset, size_t length,
|
qpdf_offset_t offset, size_t length,
|
||||||
QPDFObjectHandle stream_dict,
|
QPDFObjectHandle stream_dict,
|
||||||
|
bool is_attachment_stream,
|
||||||
Pipeline* pipeline,
|
Pipeline* pipeline,
|
||||||
bool suppress_warnings,
|
bool suppress_warnings,
|
||||||
bool will_retry)
|
bool will_retry)
|
||||||
{
|
{
|
||||||
bool success = false;
|
|
||||||
std::vector<PointerHolder<Pipeline> > to_delete;
|
std::vector<PointerHolder<Pipeline> > to_delete;
|
||||||
if (this->m->encp->encrypted)
|
if (encp->encrypted)
|
||||||
{
|
{
|
||||||
decryptStream(pipeline, objid, generation, stream_dict, to_delete);
|
decryptStream(encp, file, qpdf_for_warning,
|
||||||
|
pipeline, objid, generation,
|
||||||
|
stream_dict, is_attachment_stream, to_delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this->m->file->seek(offset, SEEK_SET);
|
file->seek(offset, SEEK_SET);
|
||||||
char buf[10240];
|
char buf[10240];
|
||||||
while (length > 0)
|
while (length > 0)
|
||||||
{
|
{
|
||||||
size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length);
|
size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length);
|
||||||
size_t len = this->m->file->read(buf, to_read);
|
size_t len = file->read(buf, to_read);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
throw QPDFExc(qpdf_e_damaged_pdf,
|
throw QPDFExc(qpdf_e_damaged_pdf,
|
||||||
this->m->file->getName(),
|
file->getName(),
|
||||||
this->m->last_object_description,
|
"",
|
||||||
this->m->file->getLastOffset(),
|
file->getLastOffset(),
|
||||||
"unexpected EOF reading stream data");
|
"unexpected EOF reading stream data");
|
||||||
}
|
}
|
||||||
length -= len;
|
length -= len;
|
||||||
@ -2552,7 +2558,7 @@ QPDF::pipeStreamData(int objid, int generation,
|
|||||||
{
|
{
|
||||||
if (! suppress_warnings)
|
if (! suppress_warnings)
|
||||||
{
|
{
|
||||||
warn(e);
|
qpdf_for_warning.warn(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
@ -2560,17 +2566,19 @@ QPDF::pipeStreamData(int objid, int generation,
|
|||||||
if (! suppress_warnings)
|
if (! suppress_warnings)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF decoding error warning");
|
QTC::TC("qpdf", "QPDF decoding error warning");
|
||||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
qpdf_for_warning.warn(
|
||||||
"", this->m->file->getLastOffset(),
|
QPDFExc(qpdf_e_damaged_pdf, file->getName(),
|
||||||
"error decoding stream data for object " +
|
"", file->getLastOffset(),
|
||||||
QUtil::int_to_string(objid) + " " +
|
"error decoding stream data for object " +
|
||||||
QUtil::int_to_string(generation) + ": " + e.what()));
|
QUtil::int_to_string(objid) + " " +
|
||||||
|
QUtil::int_to_string(generation) + ": " + e.what()));
|
||||||
if (will_retry)
|
if (will_retry)
|
||||||
{
|
{
|
||||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
|
qpdf_for_warning.warn(
|
||||||
"", this->m->file->getLastOffset(),
|
QPDFExc(qpdf_e_damaged_pdf, file->getName(),
|
||||||
"stream will be re-processed without"
|
"", file->getLastOffset(),
|
||||||
" filtering to avoid data loss"));
|
"stream will be re-processed without"
|
||||||
|
" filtering to avoid data loss"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2588,6 +2596,23 @@ QPDF::pipeStreamData(int objid, int generation,
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
QPDF::pipeStreamData(int objid, int generation,
|
||||||
|
qpdf_offset_t offset, size_t length,
|
||||||
|
QPDFObjectHandle stream_dict,
|
||||||
|
Pipeline* pipeline,
|
||||||
|
bool suppress_warnings,
|
||||||
|
bool will_retry)
|
||||||
|
{
|
||||||
|
bool is_attachment_stream = this->m->attachment_streams.count(
|
||||||
|
QPDFObjGen(objid, generation));
|
||||||
|
return pipeStreamData(
|
||||||
|
this->m->encp, this->m->file, *this,
|
||||||
|
objid, generation, offset, length,
|
||||||
|
stream_dict, is_attachment_stream,
|
||||||
|
pipeline, suppress_warnings, will_retry);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QPDF::findAttachmentStreams()
|
QPDF::findAttachmentStreams()
|
||||||
{
|
{
|
||||||
|
@ -764,14 +764,15 @@ QPDF::recover_encryption_key_with_password(
|
|||||||
}
|
}
|
||||||
|
|
||||||
QPDF::encryption_method_e
|
QPDF::encryption_method_e
|
||||||
QPDF::interpretCF(QPDFObjectHandle cf)
|
QPDF::interpretCF(
|
||||||
|
PointerHolder<EncryptionParameters> encp, QPDFObjectHandle cf)
|
||||||
{
|
{
|
||||||
if (cf.isName())
|
if (cf.isName())
|
||||||
{
|
{
|
||||||
std::string filter = cf.getName();
|
std::string filter = cf.getName();
|
||||||
if (this->m->encp->crypt_filters.count(filter) != 0)
|
if (encp->crypt_filters.count(filter) != 0)
|
||||||
{
|
{
|
||||||
return this->m->encp->crypt_filters[filter];
|
return encp->crypt_filters[filter];
|
||||||
}
|
}
|
||||||
else if (filter == "/Identity")
|
else if (filter == "/Identity")
|
||||||
{
|
{
|
||||||
@ -1000,11 +1001,11 @@ QPDF::initializeEncryption()
|
|||||||
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->m->encp->cf_stream = interpretCF(StmF);
|
this->m->encp->cf_stream = interpretCF(this->m->encp, StmF);
|
||||||
this->m->encp->cf_string = interpretCF(StrF);
|
this->m->encp->cf_string = interpretCF(this->m->encp, StrF);
|
||||||
if (EFF.isName())
|
if (EFF.isName())
|
||||||
{
|
{
|
||||||
this->m->encp->cf_file = interpretCF(EFF);
|
this->m->encp->cf_file = interpretCF(this->m->encp, EFF);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1068,26 +1069,28 @@ QPDF::initializeEncryption()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
QPDF::getKeyForObject(int objid, int generation, bool use_aes)
|
QPDF::getKeyForObject(
|
||||||
|
PointerHolder<EncryptionParameters> encp,
|
||||||
|
int objid, int generation, bool use_aes)
|
||||||
{
|
{
|
||||||
if (! this->m->encp->encrypted)
|
if (! encp->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->m->encp->cached_key_objid) &&
|
if (! ((objid == encp->cached_key_objid) &&
|
||||||
(generation == this->m->encp->cached_key_generation)))
|
(generation == encp->cached_key_generation)))
|
||||||
{
|
{
|
||||||
this->m->encp->cached_object_encryption_key =
|
encp->cached_object_encryption_key =
|
||||||
compute_data_key(this->m->encp->encryption_key, objid, generation,
|
compute_data_key(encp->encryption_key, objid, generation,
|
||||||
use_aes, this->m->encp->encryption_V,
|
use_aes, encp->encryption_V,
|
||||||
this->m->encp->encryption_R);
|
encp->encryption_R);
|
||||||
this->m->encp->cached_key_objid = objid;
|
encp->cached_key_objid = objid;
|
||||||
this->m->encp->cached_key_generation = generation;
|
encp->cached_key_generation = generation;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->m->encp->cached_object_encryption_key;
|
return encp->cached_object_encryption_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1131,7 +1134,8 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string key = getKeyForObject(objid, generation, use_aes);
|
std::string key = getKeyForObject(
|
||||||
|
this->m->encp, objid, generation, use_aes);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (use_aes)
|
if (use_aes)
|
||||||
@ -1175,8 +1179,12 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
QPDF::decryptStream(PointerHolder<EncryptionParameters> encp,
|
||||||
|
PointerHolder<InputSource> file,
|
||||||
|
QPDF& qpdf_for_warning, Pipeline*& pipeline,
|
||||||
|
int objid, int generation,
|
||||||
QPDFObjectHandle& stream_dict,
|
QPDFObjectHandle& stream_dict,
|
||||||
|
bool is_attachment_stream,
|
||||||
std::vector<PointerHolder<Pipeline> >& heap)
|
std::vector<PointerHolder<Pipeline> >& heap)
|
||||||
{
|
{
|
||||||
std::string type;
|
std::string type;
|
||||||
@ -1190,7 +1198,7 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool use_aes = false;
|
bool use_aes = false;
|
||||||
if (this->m->encp->encryption_V >= 4)
|
if (encp->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";
|
||||||
@ -1206,7 +1214,7 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
|||||||
"/CryptFilterDecodeParms"))
|
"/CryptFilterDecodeParms"))
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF_encryption stream crypt filter");
|
QTC::TC("qpdf", "QPDF_encryption stream crypt filter");
|
||||||
method = interpretCF(decode_parms.getKey("/Name"));
|
method = interpretCF(encp, decode_parms.getKey("/Name"));
|
||||||
method_source = "stream's Crypt decode parameters";
|
method_source = "stream's Crypt decode parameters";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1229,7 +1237,7 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
|||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF_encrypt crypt array");
|
QTC::TC("qpdf", "QPDF_encrypt crypt array");
|
||||||
method = interpretCF(
|
method = interpretCF(
|
||||||
crypt_params.getKey("/Name"));
|
encp, crypt_params.getKey("/Name"));
|
||||||
method_source = "stream's Crypt "
|
method_source = "stream's Crypt "
|
||||||
"decode parameters (array)";
|
"decode parameters (array)";
|
||||||
}
|
}
|
||||||
@ -1241,21 +1249,21 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
|||||||
|
|
||||||
if (method == e_unknown)
|
if (method == e_unknown)
|
||||||
{
|
{
|
||||||
if ((! this->m->encp->encrypt_metadata) && (type == "/Metadata"))
|
if ((! encp->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->m->attachment_streams.count(
|
if (is_attachment_stream)
|
||||||
QPDFObjGen(objid, generation)) > 0)
|
|
||||||
{
|
{
|
||||||
method = this->m->encp->cf_file;
|
QTC::TC("qpdf", "QPDF_encryption attachment stream");
|
||||||
|
method = encp->cf_file;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
method = this->m->encp->cf_stream;
|
method = encp->cf_stream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1279,19 +1287,20 @@ 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->m->file->getName(),
|
qpdf_for_warning.warn(
|
||||||
this->m->last_object_description,
|
QPDFExc(qpdf_e_damaged_pdf, file->getName(),
|
||||||
this->m->file->getLastOffset(),
|
"", 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->m->encp->cf_stream = e_aes;
|
encp->cf_stream = e_aes;
|
||||||
|
use_aes = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string key = getKeyForObject(objid, generation, use_aes);
|
std::string key = getKeyForObject(encp, objid, generation, use_aes);
|
||||||
if (use_aes)
|
if (use_aes)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF_encryption aes decode stream");
|
QTC::TC("qpdf", "QPDF_encryption aes decode stream");
|
||||||
|
@ -406,3 +406,4 @@ qpdf image optimize no pipeline 0
|
|||||||
qpdf image optimize no shrink 0
|
qpdf image optimize no shrink 0
|
||||||
qpdf image optimize too small 0
|
qpdf image optimize too small 0
|
||||||
QPDFFormFieldObjectHelper WinAnsi 0
|
QPDFFormFieldObjectHelper WinAnsi 0
|
||||||
|
QPDF_encryption attachment stream 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user