2
1
mirror of https://github.com/qpdf/qpdf.git synced 2025-02-08 14:48:24 +00:00

Merge pull request #731 from m-holger/og_unparse

Tidy QPDFObjGen related code
This commit is contained in:
Jay Berkenbilt 2022-07-24 14:41:33 -04:00 committed by GitHub
commit 5696a507b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 294 additions and 393 deletions

View File

@ -29,8 +29,7 @@ class ImageProvider: public QPDFObjectHandle::StreamDataProvider
public: public:
ImageProvider(std::string const& color_space, std::string const& filter); ImageProvider(std::string const& color_space, std::string const& filter);
virtual ~ImageProvider() = default; virtual ~ImageProvider() = default;
virtual void virtual void provideStreamData(QPDFObjGen const&, Pipeline* pipeline);
provideStreamData(int objid, int generation, Pipeline* pipeline);
size_t getWidth() const; size_t getWidth() const;
size_t getHeight() const; size_t getHeight() const;
@ -93,7 +92,7 @@ ImageProvider::getHeight() const
} }
void void
ImageProvider::provideStreamData(int objid, int generation, Pipeline* pipeline) ImageProvider::provideStreamData(QPDFObjGen const&, Pipeline* pipeline)
{ {
std::vector<std::shared_ptr<Pipeline>> to_delete; std::vector<std::shared_ptr<Pipeline>> to_delete;
Pipeline* p = pipeline; Pipeline* p = pipeline;
@ -292,7 +291,7 @@ check(
ImageProvider* p = new ImageProvider(desired_color_space, "null"); ImageProvider* p = new ImageProvider(desired_color_space, "null");
std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider(p); std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider(p);
Pl_Buffer b_p("get image data"); Pl_Buffer b_p("get image data");
provider->provideStreamData(0, 0, &b_p); provider->provideStreamData(QPDFObjGen(), &b_p);
std::shared_ptr<Buffer> desired_data(b_p.getBuffer()); std::shared_ptr<Buffer> desired_data(b_p.getBuffer());
if (desired_data->getSize() != actual_data->getSize()) { if (desired_data->getSize() != actual_data->getSize()) {

View File

@ -201,7 +201,7 @@ class StreamReplacer: public QPDFObjectHandle::StreamDataProvider
StreamReplacer(QPDF* pdf); StreamReplacer(QPDF* pdf);
virtual ~StreamReplacer() = default; virtual ~StreamReplacer() = default;
virtual void virtual void
provideStreamData(int objid, int generation, Pipeline* pipeline) override; provideStreamData(QPDFObjGen const& og, Pipeline* pipeline) override;
void registerStream( void registerStream(
QPDFObjectHandle stream, QPDFObjectHandle stream,
@ -384,9 +384,8 @@ StreamReplacer::registerStream(
} }
void void
StreamReplacer::provideStreamData(int objid, int generation, Pipeline* pipeline) StreamReplacer::provideStreamData(QPDFObjGen const& og, Pipeline* pipeline)
{ {
QPDFObjGen og(objid, generation);
QPDFObjectHandle orig = this->copied_streams[og]; QPDFObjectHandle orig = this->copied_streams[og];
// call maybeReplace again, this time with the pipeline and no // call maybeReplace again, this time with the pipeline and no
// dict_updates. In this mode, maybeReplace doesn't make any // dict_updates. In this mode, maybeReplace doesn't make any

View File

@ -35,7 +35,7 @@ class ImageInverter: public QPDFObjectHandle::StreamDataProvider
public: public:
virtual ~ImageInverter() = default; virtual ~ImageInverter() = default;
virtual void virtual void
provideStreamData(int objid, int generation, Pipeline* pipeline) override; provideStreamData(QPDFObjGen const& og, Pipeline* pipeline) override;
void registerImage( void registerImage(
QPDFObjectHandle image, QPDFObjectHandle image,
@ -82,12 +82,11 @@ ImageInverter::registerImage(
} }
void void
ImageInverter::provideStreamData(int objid, int generation, Pipeline* pipeline) ImageInverter::provideStreamData(QPDFObjGen const& og, Pipeline* pipeline)
{ {
// Use the object and generation number supplied to look up the // Use the object and generation number supplied to look up the
// image data. Then invert the image data and write the inverted // image data. Then invert the image data and write the inverted
// data to the pipeline. // data to the pipeline.
QPDFObjGen og(objid, generation);
std::shared_ptr<Buffer> data = std::shared_ptr<Buffer> data =
this->copied_images[og].getStreamData(qpdf_dl_all); this->copied_images[og].getStreamData(qpdf_dl_all);
size_t size = data->getSize(); size_t size = data->getSize();

View File

@ -815,9 +815,9 @@ class QPDF
private: private:
static std::shared_ptr<QPDFObject> static std::shared_ptr<QPDFObject>
resolve(QPDF* qpdf, int objid, int generation) resolve(QPDF* qpdf, QPDFObjGen const& og)
{ {
return qpdf->resolve(objid, generation); return qpdf->resolve(og);
} }
static bool static bool
objectChanged( objectChanged(
@ -879,8 +879,7 @@ class QPDF
static bool static bool
pipeStreamData( pipeStreamData(
QPDF* qpdf, QPDF* qpdf,
int objid, QPDFObjGen const& og,
int generation,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length, size_t length,
QPDFObjectHandle dict, QPDFObjectHandle dict,
@ -889,8 +888,7 @@ class QPDF
bool will_retry) bool will_retry)
{ {
return qpdf->pipeStreamData( return qpdf->pipeStreamData(
objid, og,
generation,
offset, offset,
length, length,
dict, dict,
@ -959,8 +957,7 @@ class QPDF
std::string user_password; std::string user_password;
std::string encryption_key; std::string encryption_key;
std::string cached_object_encryption_key; std::string cached_object_encryption_key;
int cached_key_objid; QPDFObjGen cached_key_og;
int cached_key_generation;
bool user_password_matched; bool user_password_matched;
bool owner_password_matched; bool owner_password_matched;
}; };
@ -973,8 +970,7 @@ class QPDF
ForeignStreamData( ForeignStreamData(
std::shared_ptr<EncryptionParameters> encp, std::shared_ptr<EncryptionParameters> encp,
std::shared_ptr<InputSource> file, std::shared_ptr<InputSource> file,
int foreign_objid, QPDFObjGen const& foreign_og,
int foreign_generation,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length, size_t length,
QPDFObjectHandle local_dict); QPDFObjectHandle local_dict);
@ -982,8 +978,7 @@ class QPDF
private: private:
std::shared_ptr<EncryptionParameters> encp; std::shared_ptr<EncryptionParameters> encp;
std::shared_ptr<InputSource> file; std::shared_ptr<InputSource> file;
int foreign_objid; QPDFObjGen foreign_og;
int foreign_generation;
qpdf_offset_t offset; qpdf_offset_t offset;
size_t length; size_t length;
QPDFObjectHandle local_dict; QPDFObjectHandle local_dict;
@ -995,8 +990,7 @@ class QPDF
CopiedStreamDataProvider(QPDF& destination_qpdf); CopiedStreamDataProvider(QPDF& destination_qpdf);
virtual ~CopiedStreamDataProvider() = default; virtual ~CopiedStreamDataProvider() = default;
virtual bool provideStreamData( virtual bool provideStreamData(
int objid, QPDFObjGen const& og,
int generation,
Pipeline* pipeline, Pipeline* pipeline,
bool suppress_warnings, bool suppress_warnings,
bool will_retry) override; bool will_retry) override;
@ -1017,14 +1011,13 @@ class QPDF
friend class QPDF; friend class QPDF;
public: public:
StringDecrypter(QPDF* qpdf, int objid, int gen); StringDecrypter(QPDF* qpdf, QPDFObjGen const& og);
virtual ~StringDecrypter() = default; virtual ~StringDecrypter() = default;
virtual void decryptString(std::string& val); virtual void decryptString(std::string& val);
private: private:
QPDF* qpdf; QPDF* qpdf;
int objid; QPDFObjGen og;
int gen;
}; };
class ResolveRecorder class ResolveRecorder
@ -1127,17 +1120,15 @@ class QPDF
void insertXrefEntry( void insertXrefEntry(
int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite = false); int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite = false);
void setLastObjectDescription( void setLastObjectDescription(
std::string const& description, int objid, int generation); std::string const& description, QPDFObjGen const& og);
QPDFObjectHandle readObject( QPDFObjectHandle readObject(
std::shared_ptr<InputSource>, std::shared_ptr<InputSource>,
std::string const& description, std::string const& description,
int objid, QPDFObjGen const& og,
int generation,
bool in_object_stream); bool in_object_stream);
size_t recoverStreamLength( size_t recoverStreamLength(
std::shared_ptr<InputSource> input, std::shared_ptr<InputSource> input,
int objid, QPDFObjGen const& og,
int generation,
qpdf_offset_t stream_offset); qpdf_offset_t stream_offset);
QPDFTokenizer::Token QPDFTokenizer::Token
readToken(std::shared_ptr<InputSource>, size_t max_len = 0); readToken(std::shared_ptr<InputSource>, size_t max_len = 0);
@ -1146,21 +1137,18 @@ class QPDF
bool attempt_recovery, bool attempt_recovery,
qpdf_offset_t offset, qpdf_offset_t offset,
std::string const& description, std::string const& description,
int exp_objid, QPDFObjGen const& exp_og,
int exp_generation, QPDFObjGen& og);
int& act_objid,
int& act_generation);
bool objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph); bool objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph);
std::shared_ptr<QPDFObject> resolve(int objid, int generation); std::shared_ptr<QPDFObject> resolve(QPDFObjGen const& og);
void resolveObjectsInStream(int obj_stream_number); void resolveObjectsInStream(int obj_stream_number);
void stopOnError(std::string const& message); void stopOnError(std::string const& message);
QPDFObjectHandle reserveObjectIfNotExists(int objid, int gen); QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
QPDFObjectHandle reserveStream(int objid, int gen); QPDFObjectHandle reserveStream(QPDFObjGen const& og);
// Calls finish() on the pipeline when done but does not delete it // Calls finish() on the pipeline when done but does not delete it
bool pipeStreamData( bool pipeStreamData(
int objid, QPDFObjGen const& og,
int generation,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length, size_t length,
QPDFObjectHandle dict, QPDFObjectHandle dict,
@ -1176,8 +1164,7 @@ class QPDF
std::shared_ptr<QPDF::EncryptionParameters> encp, std::shared_ptr<QPDF::EncryptionParameters> encp,
std::shared_ptr<InputSource> file, std::shared_ptr<InputSource> file,
QPDF& qpdf_for_warning, QPDF& qpdf_for_warning,
int objid, QPDFObjGen const& og,
int generation,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length, size_t length,
QPDFObjectHandle dict, QPDFObjectHandle dict,
@ -1230,10 +1217,9 @@ class QPDF
void initializeEncryption(); void initializeEncryption();
static std::string getKeyForObject( static std::string getKeyForObject(
std::shared_ptr<EncryptionParameters> encp, std::shared_ptr<EncryptionParameters> encp,
int objid, QPDFObjGen const& og,
int generation,
bool use_aes); bool use_aes);
void decryptString(std::string&, int objid, int generation); void decryptString(std::string&, QPDFObjGen const& og);
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);
static std::string recover_encryption_key_with_password( static std::string recover_encryption_key_with_password(
@ -1247,8 +1233,7 @@ class QPDF
std::shared_ptr<InputSource> file, std::shared_ptr<InputSource> file,
QPDF& qpdf_for_warning, QPDF& qpdf_for_warning,
Pipeline*& pipeline, Pipeline*& pipeline,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle& stream_dict, QPDFObjectHandle& stream_dict,
std::vector<std::shared_ptr<Pipeline>>& heap); std::vector<std::shared_ptr<Pipeline>>& heap);
@ -1571,7 +1556,6 @@ class QPDF
void dumpHSharedObject(); void dumpHSharedObject();
void dumpHGeneric(HGeneric&); void dumpHGeneric(HGeneric&);
qpdf_offset_t adjusted_offset(qpdf_offset_t offset); qpdf_offset_t adjusted_offset(qpdf_offset_t offset);
QPDFObjectHandle objGenToIndirect(QPDFObjGen const&);
void void
calculateLinearizationData(std::map<int, int> const& object_stream_data); calculateLinearizationData(std::map<int, int> const& object_stream_data);
void pushOutlinesToPart( void pushOutlinesToPart(

View File

@ -23,7 +23,6 @@
#define QPDFOBJGEN_HH #define QPDFOBJGEN_HH
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/QUtil.hh>
#include <iostream> #include <iostream>
// This class represents an object ID and generation pair. It is // This class represents an object ID and generation pair. It is
@ -39,7 +38,7 @@ class QPDFObjGen
{ {
} }
QPDF_DLL QPDF_DLL
QPDFObjGen(int obj, int gen) : explicit QPDFObjGen(int obj, int gen) :
obj(obj), obj(obj),
gen(gen) gen(gen)
{ {
@ -48,13 +47,19 @@ class QPDFObjGen
bool bool
operator<(QPDFObjGen const& rhs) const operator<(QPDFObjGen const& rhs) const
{ {
return ((obj < rhs.obj) || ((obj == rhs.obj) && (gen < rhs.gen))); return (obj < rhs.obj) || ((obj == rhs.obj) && (gen < rhs.gen));
} }
QPDF_DLL QPDF_DLL
bool bool
operator==(QPDFObjGen const& rhs) const operator==(QPDFObjGen const& rhs) const
{ {
return ((obj == rhs.obj) && (gen == rhs.gen)); return (obj == rhs.obj) && (gen == rhs.gen);
}
QPDF_DLL
bool
operator!=(QPDFObjGen const& rhs) const
{
return (obj != rhs.obj) || (gen != rhs.gen);
} }
QPDF_DLL QPDF_DLL
int int
@ -69,18 +74,15 @@ class QPDFObjGen
return gen; return gen;
} }
QPDF_DLL QPDF_DLL
std::string bool
unparse() const isIndirect() const
{ {
return QUtil::int_to_string(obj) + "," + QUtil::int_to_string(gen); return obj != 0;
} }
QPDF_DLL QPDF_DLL
friend std::ostream& std::string unparse(char separator = ',') const;
operator<<(std::ostream& os, const QPDFObjGen& og) QPDF_DLL
{ friend std::ostream& operator<<(std::ostream& os, const QPDFObjGen& og);
os << og.obj << "," << og.gen;
return os;
}
private: private:
// This class does not use the Members pattern to avoid a memory // This class does not use the Members pattern to avoid a memory

View File

@ -116,9 +116,16 @@ class QPDFObjectHandle
// indicating whether it ran without errors. // indicating whether it ran without errors.
QPDF_DLL QPDF_DLL
virtual void virtual void
provideStreamData(int objid, int generation, Pipeline* pipeline); provideStreamData(QPDFObjGen const& og, Pipeline* pipeline);
QPDF_DLL QPDF_DLL
virtual bool provideStreamData( virtual bool provideStreamData(
QPDFObjGen const& og,
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry);
QPDF_DLL virtual void
provideStreamData(int objid, int generation, Pipeline* pipeline);
QPDF_DLL virtual bool provideStreamData(
int objid, int objid,
int generation, int generation,
Pipeline* pipeline, Pipeline* pipeline,
@ -1429,21 +1436,20 @@ class QPDFObjectHandle
private: private:
static QPDFObjectHandle static QPDFObjectHandle
newIndirect(QPDF* qpdf, int objid, int generation) newIndirect(QPDF* qpdf, QPDFObjGen const& og)
{ {
return QPDFObjectHandle::newIndirect(qpdf, objid, generation); return QPDFObjectHandle::newIndirect(qpdf, og);
} }
static QPDFObjectHandle static QPDFObjectHandle
newStream( newStream(
QPDF* qpdf, QPDF* qpdf,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length) size_t length)
{ {
return QPDFObjectHandle::newStream( return QPDFObjectHandle::newStream(
qpdf, objid, generation, stream_dict, offset, length); qpdf, og, stream_dict, offset, length);
} }
// Reserve an object with a specific ID // Reserve an object with a specific ID
static QPDFObjectHandle static QPDFObjectHandle
@ -1550,7 +1556,7 @@ class QPDFObjectHandle
bool isImage(bool exclude_imagemask = true); bool isImage(bool exclude_imagemask = true);
private: private:
QPDFObjectHandle(QPDF*, int objid, int generation); QPDFObjectHandle(QPDF*, QPDFObjGen const& og);
QPDFObjectHandle(std::shared_ptr<QPDFObject> const&); QPDFObjectHandle(std::shared_ptr<QPDFObject> const&);
enum parser_state_e { enum parser_state_e {
@ -1563,11 +1569,10 @@ class QPDFObjectHandle
}; };
// Private object factory methods // Private object factory methods
static QPDFObjectHandle newIndirect(QPDF*, int objid, int generation); static QPDFObjectHandle newIndirect(QPDF*, QPDFObjGen const& og);
static QPDFObjectHandle newStream( static QPDFObjectHandle newStream(
QPDF* qpdf, QPDF* qpdf,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length); size_t length);
@ -1584,7 +1589,6 @@ class QPDFObjectHandle
bool stop_at_streams); bool stop_at_streams);
void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only); void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only);
void releaseResolved(); void releaseResolved();
std::string getObjGenAsStr() const;
static void setObjectDescriptionFromInput( static void setObjectDescriptionFromInput(
QPDFObjectHandle, QPDFObjectHandle,
QPDF*, QPDF*,
@ -1618,8 +1622,7 @@ class QPDFObjectHandle
// a substantial performance penalty since QPDFObjectHandle // a substantial performance penalty since QPDFObjectHandle
// objects are copied around so frequently. // objects are copied around so frequently.
QPDF* qpdf; QPDF* qpdf;
int objid; // 0 for direct object QPDFObjGen og;
int generation;
std::shared_ptr<QPDFObject> obj; std::shared_ptr<QPDFObject> obj;
bool reserved; bool reserved;
}; };

View File

@ -74,6 +74,7 @@ set(libqpdf_SOURCES
QPDFNumberTreeObjectHelper.cc QPDFNumberTreeObjectHelper.cc
QPDFObject.cc QPDFObject.cc
QPDFObjectHandle.cc QPDFObjectHandle.cc
QPDFObjGen.cc
QPDFOutlineDocumentHelper.cc QPDFOutlineDocumentHelper.cc
QPDFOutlineObjectHelper.cc QPDFOutlineObjectHelper.cc
QPDFPageDocumentHelper.cc QPDFPageDocumentHelper.cc

View File

@ -113,15 +113,13 @@ namespace
QPDF::ForeignStreamData::ForeignStreamData( QPDF::ForeignStreamData::ForeignStreamData(
std::shared_ptr<EncryptionParameters> encp, std::shared_ptr<EncryptionParameters> encp,
std::shared_ptr<InputSource> file, std::shared_ptr<InputSource> file,
int foreign_objid, QPDFObjGen const& foreign_og,
int foreign_generation,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length, size_t length,
QPDFObjectHandle local_dict) : QPDFObjectHandle local_dict) :
encp(encp), encp(encp),
file(file), file(file),
foreign_objid(foreign_objid), foreign_og(foreign_og),
foreign_generation(foreign_generation),
offset(offset), offset(offset),
length(length), length(length),
local_dict(local_dict) local_dict(local_dict)
@ -137,22 +135,19 @@ QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider(
bool bool
QPDF::CopiedStreamDataProvider::provideStreamData( QPDF::CopiedStreamDataProvider::provideStreamData(
int objid, QPDFObjGen const& og,
int generation,
Pipeline* pipeline, Pipeline* pipeline,
bool suppress_warnings, bool suppress_warnings,
bool will_retry) bool will_retry)
{ {
std::shared_ptr<ForeignStreamData> foreign_data = std::shared_ptr<ForeignStreamData> foreign_data = foreign_stream_data[og];
this->foreign_stream_data[QPDFObjGen(objid, generation)];
bool result = false; bool result = false;
if (foreign_data.get()) { if (foreign_data.get()) {
result = destination_qpdf.pipeForeignStreamData( result = destination_qpdf.pipeForeignStreamData(
foreign_data, pipeline, suppress_warnings, will_retry); foreign_data, pipeline, suppress_warnings, will_retry);
QTC::TC("qpdf", "QPDF copy foreign with data", result ? 0 : 1); QTC::TC("qpdf", "QPDF copy foreign with data", result ? 0 : 1);
} else { } else {
QPDFObjectHandle foreign_stream = auto foreign_stream = foreign_streams[og];
this->foreign_streams[QPDFObjGen(objid, generation)];
result = foreign_stream.pipeStreamData( result = foreign_stream.pipeStreamData(
pipeline, nullptr, 0, qpdf_dl_none, suppress_warnings, will_retry); pipeline, nullptr, 0, qpdf_dl_none, suppress_warnings, will_retry);
QTC::TC( QTC::TC(
@ -176,17 +171,16 @@ QPDF::CopiedStreamDataProvider::registerForeignStream(
this->foreign_stream_data[local_og] = foreign_stream; this->foreign_stream_data[local_og] = foreign_stream;
} }
QPDF::StringDecrypter::StringDecrypter(QPDF* qpdf, int objid, int gen) : QPDF::StringDecrypter::StringDecrypter(QPDF* qpdf, QPDFObjGen const& og) :
qpdf(qpdf), qpdf(qpdf),
objid(objid), og(og)
gen(gen)
{ {
} }
void void
QPDF::StringDecrypter::decryptString(std::string& val) QPDF::StringDecrypter::decryptString(std::string& val)
{ {
qpdf->decryptString(val, objid, gen); qpdf->decryptString(val, og);
} }
std::string const& std::string const&
@ -205,8 +199,6 @@ QPDF::EncryptionParameters::EncryptionParameters() :
cf_stream(e_none), cf_stream(e_none),
cf_string(e_none), cf_string(e_none),
cf_file(e_none), cf_file(e_none),
cached_key_objid(0),
cached_key_generation(0),
user_password_matched(false), user_password_matched(false),
owner_password_matched(false) owner_password_matched(false)
{ {
@ -631,7 +623,7 @@ QPDF::reconstruct_xref(QPDFExc& e)
(!this->m->trailer.isInitialized()) && (!this->m->trailer.isInitialized()) &&
(t1 == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "trailer"))) { (t1 == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "trailer"))) {
QPDFObjectHandle t = QPDFObjectHandle t =
readObject(this->m->file, "trailer", 0, 0, false); readObject(this->m->file, "trailer", QPDFObjGen(), false);
if (!t.isDictionary()) { if (!t.isDictionary()) {
// Oh well. It was worth a try. // Oh well. It was worth a try.
} else { } else {
@ -969,7 +961,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
// Set offset to previous xref table if any // Set offset to previous xref table if any
QPDFObjectHandle cur_trailer = QPDFObjectHandle cur_trailer =
readObject(this->m->file, "trailer", 0, 0, false); readObject(this->m->file, "trailer", QPDFObjGen(), false);
if (!cur_trailer.isDictionary()) { if (!cur_trailer.isDictionary()) {
QTC::TC("qpdf", "QPDF missing trailer"); QTC::TC("qpdf", "QPDF missing trailer");
throw QPDFExc( throw QPDFExc(
@ -1055,12 +1047,11 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset)
{ {
bool found = false; bool found = false;
if (!this->m->ignore_xref_streams) { if (!this->m->ignore_xref_streams) {
int xobj; QPDFObjGen x_og;
int xgen;
QPDFObjectHandle xref_obj; QPDFObjectHandle xref_obj;
try { try {
xref_obj = readObjectAtOffset( xref_obj = readObjectAtOffset(
false, xref_offset, "xref stream", 0, 0, xobj, xgen); false, xref_offset, "xref stream", QPDFObjGen(0, 0), x_og);
} catch (QPDFExc&) { } catch (QPDFExc&) {
// ignore -- report error below // ignore -- report error below
} }
@ -1363,7 +1354,7 @@ QPDF::showXRefTable()
for (auto const& iter: this->m->xref_table) { for (auto const& iter: this->m->xref_table) {
QPDFObjGen const& og = iter.first; QPDFObjGen const& og = iter.first;
QPDFXRefEntry const& entry = iter.second; QPDFXRefEntry const& entry = iter.second;
cout << og.getObj() << "/" << og.getGen() << ": "; cout << og.unparse('/') << ": ";
switch (entry.getType()) { switch (entry.getType()) {
case 1: case 1:
cout << "uncompressed; offset = " << entry.getOffset(); cout << "uncompressed; offset = " << entry.getOffset();
@ -1405,9 +1396,8 @@ QPDF::fixDanglingReferences(bool force)
// For each non-scalar item to process, put it in the queue. // For each non-scalar item to process, put it in the queue.
std::list<QPDFObjectHandle> queue; std::list<QPDFObjectHandle> queue;
queue.push_back(this->m->trailer); queue.push_back(this->m->trailer);
for (auto const& iter: to_process) { for (auto const& og: to_process) {
QPDFObjectHandle obj = QPDFObjectHandle::Factory::newIndirect( QPDFObjectHandle obj = QPDFObjectHandle::Factory::newIndirect(this, og);
this, iter.getObj(), iter.getGen());
if (obj.isDictionary() || obj.isArray()) { if (obj.isDictionary() || obj.isArray()) {
queue.push_back(obj); queue.push_back(obj);
} else if (obj.isStream()) { } else if (obj.isStream()) {
@ -1473,29 +1463,24 @@ QPDF::getAllObjects()
std::vector<QPDFObjectHandle> result; std::vector<QPDFObjectHandle> result;
for (auto const& iter: this->m->obj_cache) { for (auto const& iter: this->m->obj_cache) {
QPDFObjGen const& og = iter.first; QPDFObjGen const& og = iter.first;
result.push_back( result.push_back(QPDFObjectHandle::Factory::newIndirect(this, og));
// line-break
QPDFObjectHandle::Factory::newIndirect(
this, og.getObj(), og.getGen()));
} }
return result; return result;
} }
void void
QPDF::setLastObjectDescription( QPDF::setLastObjectDescription(
std::string const& description, int objid, int generation) std::string const& description, QPDFObjGen const& og)
{ {
this->m->last_object_description.clear(); this->m->last_object_description.clear();
if (!description.empty()) { if (!description.empty()) {
this->m->last_object_description += description; this->m->last_object_description += description;
if (objid > 0) { if (og.isIndirect()) {
this->m->last_object_description += ": "; this->m->last_object_description += ": ";
} }
} }
if (objid > 0) { if (og.isIndirect()) {
this->m->last_object_description += "object " + this->m->last_object_description += "object " + og.unparse(' ');
QUtil::int_to_string(objid) + " " +
QUtil::int_to_string(generation);
} }
} }
@ -1503,19 +1488,17 @@ QPDFObjectHandle
QPDF::readObject( QPDF::readObject(
std::shared_ptr<InputSource> input, std::shared_ptr<InputSource> input,
std::string const& description, std::string const& description,
int objid, QPDFObjGen const& og,
int generation,
bool in_object_stream) bool in_object_stream)
{ {
setLastObjectDescription(description, objid, generation); setLastObjectDescription(description, og);
qpdf_offset_t offset = input->tell(); qpdf_offset_t offset = input->tell();
bool empty = false; bool empty = false;
std::shared_ptr<StringDecrypter> decrypter_ph; std::shared_ptr<StringDecrypter> decrypter_ph;
StringDecrypter* decrypter = 0; StringDecrypter* decrypter = 0;
if (this->m->encp->encrypted && (!in_object_stream)) { if (this->m->encp->encrypted && (!in_object_stream)) {
decrypter_ph = decrypter_ph = std::make_shared<StringDecrypter>(this, og);
std::make_shared<StringDecrypter>(this, objid, generation);
decrypter = decrypter_ph.get(); decrypter = decrypter_ph.get();
} }
QPDFObjectHandle object = QPDFObjectHandle::parse( QPDFObjectHandle object = QPDFObjectHandle::parse(
@ -1657,14 +1640,13 @@ QPDF::readObject(
} catch (QPDFExc& e) { } catch (QPDFExc& e) {
if (this->m->attempt_recovery) { if (this->m->attempt_recovery) {
warn(e); warn(e);
length = recoverStreamLength( length = recoverStreamLength(input, og, stream_offset);
input, objid, generation, stream_offset);
} else { } else {
throw e; throw e;
} }
} }
object = QPDFObjectHandle::Factory::newStream( object = QPDFObjectHandle::Factory::newStream(
this, objid, generation, object, stream_offset, length); this, og, object, stream_offset, length);
} else { } else {
input->seek(cur_offset, SEEK_SET); input->seek(cur_offset, SEEK_SET);
} }
@ -1692,8 +1674,7 @@ QPDF::findEndstream()
size_t size_t
QPDF::recoverStreamLength( QPDF::recoverStreamLength(
std::shared_ptr<InputSource> input, std::shared_ptr<InputSource> input,
int objid, QPDFObjGen const& og,
int generation,
qpdf_offset_t stream_offset) qpdf_offset_t stream_offset)
{ {
// Try to reconstruct stream length by looking for // Try to reconstruct stream length by looking for
@ -1718,11 +1699,10 @@ QPDF::recoverStreamLength(
if (length) { if (length) {
qpdf_offset_t this_obj_offset = 0; qpdf_offset_t this_obj_offset = 0;
QPDFObjGen this_obj(0, 0); QPDFObjGen this_og;
// Make sure this is inside this object // Make sure this is inside this object
for (auto const& iter: this->m->xref_table) { for (auto const& iter: this->m->xref_table) {
QPDFObjGen const& og = iter.first;
QPDFXRefEntry const& entry = iter.second; QPDFXRefEntry const& entry = iter.second;
if (entry.getType() == 1) { if (entry.getType() == 1) {
qpdf_offset_t obj_offset = entry.getOffset(); qpdf_offset_t obj_offset = entry.getOffset();
@ -1730,12 +1710,11 @@ QPDF::recoverStreamLength(
((this_obj_offset == 0) || ((this_obj_offset == 0) ||
(this_obj_offset > obj_offset))) { (this_obj_offset > obj_offset))) {
this_obj_offset = obj_offset; this_obj_offset = obj_offset;
this_obj = og; this_og = iter.first;
} }
} }
} }
if (this_obj_offset && (this_obj.getObj() == objid) && if (this_obj_offset && (this_og == og)) {
(this_obj.getGen() == generation)) {
// Well, we found endstream\nendobj within the space // Well, we found endstream\nendobj within the space
// allowed for this object, so we're probably in good // allowed for this object, so we're probably in good
// shape. // shape.
@ -1777,13 +1756,11 @@ QPDF::readObjectAtOffset(
bool try_recovery, bool try_recovery,
qpdf_offset_t offset, qpdf_offset_t offset,
std::string const& description, std::string const& description,
int exp_objid, QPDFObjGen const& exp_og,
int exp_generation, QPDFObjGen& og)
int& objid,
int& generation)
{ {
bool check_og = true; bool check_og = true;
if (exp_objid == 0) { if (exp_og.getObj() == 0) {
// This method uses an expect object ID of 0 to indicate that // This method uses an expect object ID of 0 to indicate that
// we don't know or don't care what the actual object ID is at // we don't know or don't care what the actual object ID is at
// this offset. This is true when we read the xref stream and // this offset. This is true when we read the xref stream and
@ -1795,7 +1772,7 @@ QPDF::readObjectAtOffset(
check_og = false; check_og = false;
try_recovery = false; try_recovery = false;
} else { } else {
setLastObjectDescription(description, exp_objid, exp_generation); setLastObjectDescription(description, exp_og);
} }
if (!this->m->attempt_recovery) { if (!this->m->attempt_recovery) {
@ -1841,9 +1818,9 @@ QPDF::readObjectAtOffset(
offset, offset,
"expected n n obj"); "expected n n obj");
} }
objid = QUtil::string_to_int(tobjid.getValue().c_str()); int objid = QUtil::string_to_int(tobjid.getValue().c_str());
generation = QUtil::string_to_int(tgen.getValue().c_str()); int generation = QUtil::string_to_int(tgen.getValue().c_str());
og = QPDFObjGen(objid, generation);
if (objid == 0) { if (objid == 0) {
QTC::TC("qpdf", "QPDF object id 0"); QTC::TC("qpdf", "QPDF object id 0");
throw QPDFExc( throw QPDFExc(
@ -1853,17 +1830,14 @@ QPDF::readObjectAtOffset(
offset, offset,
"object with ID 0"); "object with ID 0");
} }
if (check_og && (exp_og != og)) {
if (check_og &&
(!((objid == exp_objid) && (generation == exp_generation)))) {
QTC::TC("qpdf", "QPDF err wrong objid/generation"); QTC::TC("qpdf", "QPDF err wrong objid/generation");
QPDFExc e( QPDFExc e(
qpdf_e_damaged_pdf, qpdf_e_damaged_pdf,
this->m->file->getName(), this->m->file->getName(),
this->m->last_object_description, this->m->last_object_description,
offset, offset,
(std::string("expected ") + QUtil::int_to_string(exp_objid) + (std::string("expected ") + exp_og.unparse(' ') + " obj"));
" " + QUtil::int_to_string(exp_generation) + " obj"));
if (try_recovery) { if (try_recovery) {
// Will be retried below // Will be retried below
throw e; throw e;
@ -1877,18 +1851,12 @@ QPDF::readObjectAtOffset(
if (try_recovery) { if (try_recovery) {
// Try again after reconstructing xref table // Try again after reconstructing xref table
reconstruct_xref(e); reconstruct_xref(e);
QPDFObjGen og(exp_objid, exp_generation); if (this->m->xref_table.count(exp_og) &&
if (this->m->xref_table.count(og) && (this->m->xref_table[exp_og].getType() == 1)) {
(this->m->xref_table[og].getType() == 1)) { qpdf_offset_t new_offset =
qpdf_offset_t new_offset = this->m->xref_table[og].getOffset(); this->m->xref_table[exp_og].getOffset();
QPDFObjectHandle result = readObjectAtOffset( QPDFObjectHandle result = readObjectAtOffset(
false, false, new_offset, description, exp_og, og);
new_offset,
description,
exp_objid,
exp_generation,
objid,
generation);
QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset"); QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
return result; return result;
} else { } else {
@ -1898,8 +1866,7 @@ QPDF::readObjectAtOffset(
"", "",
0, 0,
std::string( std::string(
"object " + QUtil::int_to_string(exp_objid) + " " + "object " + exp_og.unparse(' ') +
QUtil::int_to_string(exp_generation) +
" not found in file after regenerating" " not found in file after regenerating"
" cross reference table")); " cross reference table"));
return QPDFObjectHandle::newNull(); return QPDFObjectHandle::newNull();
@ -1909,8 +1876,7 @@ QPDF::readObjectAtOffset(
} }
} }
QPDFObjectHandle oh = QPDFObjectHandle oh = readObject(this->m->file, description, og, false);
readObject(this->m->file, description, objid, generation, false);
if (!(readToken(this->m->file) == if (!(readToken(this->m->file) ==
QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj"))) { QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj"))) {
@ -1922,7 +1888,6 @@ QPDF::readObjectAtOffset(
"expected endobj"); "expected endobj");
} }
QPDFObjGen og(objid, generation);
if (!this->m->obj_cache.count(og)) { if (!this->m->obj_cache.count(og)) {
// Store the object in the cache here so it gets cached // Store the object in the cache here so it gets cached
// whether we first know the offset or whether we first know // whether we first know the offset or whether we first know
@ -1987,12 +1952,11 @@ QPDF::objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph)
} }
std::shared_ptr<QPDFObject> std::shared_ptr<QPDFObject>
QPDF::resolve(int objid, int generation) QPDF::resolve(QPDFObjGen const& og)
{ {
// Check object cache before checking xref table. This allows us // Check object cache before checking xref table. This allows us
// to insert things into the object cache that don't actually // to insert things into the object cache that don't actually
// exist in the file. // exist in the file.
QPDFObjGen og(objid, generation);
if (this->m->resolving.count(og)) { if (this->m->resolving.count(og)) {
// This can happen if an object references itself directly or // This can happen if an object references itself directly or
// indirectly in some key that has to be resolved during // indirectly in some key that has to be resolved during
@ -2002,8 +1966,7 @@ QPDF::resolve(int objid, int generation)
qpdf_e_damaged_pdf, qpdf_e_damaged_pdf,
"", "",
this->m->file->getLastOffset(), this->m->file->getLastOffset(),
("loop detected resolving object " + QUtil::int_to_string(objid) + ("loop detected resolving object " + og.unparse(' ')));
" " + QUtil::int_to_string(generation)));
return QPDF_Null::create(); return QPDF_Null::create();
} }
ResolveRecorder rr(this, og); ResolveRecorder rr(this, og);
@ -2016,16 +1979,9 @@ QPDF::resolve(int objid, int generation)
{ {
qpdf_offset_t offset = entry.getOffset(); qpdf_offset_t offset = entry.getOffset();
// Object stored in cache by readObjectAtOffset // Object stored in cache by readObjectAtOffset
int aobjid; QPDFObjGen a_og;
int ageneration; QPDFObjectHandle oh =
QPDFObjectHandle oh = readObjectAtOffset( readObjectAtOffset(true, offset, "", og, a_og);
true,
offset,
"",
objid,
generation,
aobjid,
ageneration);
} }
break; break;
@ -2039,8 +1995,7 @@ QPDF::resolve(int objid, int generation)
this->m->file->getName(), this->m->file->getName(),
"", "",
0, 0,
("object " + QUtil::int_to_string(objid) + "/" + ("object " + og.unparse('/') +
QUtil::int_to_string(generation) +
" has unexpected xref entry type")); " has unexpected xref entry type"));
} }
} catch (QPDFExc& e) { } catch (QPDFExc& e) {
@ -2050,8 +2005,7 @@ QPDF::resolve(int objid, int generation)
qpdf_e_damaged_pdf, qpdf_e_damaged_pdf,
"", "",
0, 0,
("object " + QUtil::int_to_string(objid) + "/" + ("object " + og.unparse('/') +
QUtil::int_to_string(generation) +
": error reading object: " + e.what())); ": error reading object: " + e.what()));
} }
} }
@ -2065,10 +2019,7 @@ QPDF::resolve(int objid, int generation)
std::shared_ptr<QPDFObject> result(this->m->obj_cache[og].object); std::shared_ptr<QPDFObject> result(this->m->obj_cache[og].object);
if (!result->hasDescription()) { if (!result->hasDescription()) {
result->setDescription( result->setDescription(this, ("object " + og.unparse(' ')));
this,
("object " + QUtil::int_to_string(objid) + " " +
QUtil::int_to_string(generation)));
} }
return result; return result;
} }
@ -2165,7 +2116,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
(entry.getObjStreamNumber() == obj_stream_number)) { (entry.getObjStreamNumber() == obj_stream_number)) {
int offset = iter.second; int offset = iter.second;
input->seek(offset, SEEK_SET); input->seek(offset, SEEK_SET);
QPDFObjectHandle oh = readObject(input, "", obj, 0, true); QPDFObjectHandle oh = readObject(input, "", og, true);
this->m->obj_cache[og] = ObjCache( this->m->obj_cache[og] = ObjCache(
QPDFObjectHandle::ObjAccessor::getObject(oh), QPDFObjectHandle::ObjAccessor::getObject(oh),
end_before_space, end_before_space,
@ -2187,48 +2138,46 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh)
QPDFObjGen next(max_objid + 1, 0); QPDFObjGen next(max_objid + 1, 0);
this->m->obj_cache[next] = this->m->obj_cache[next] =
ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
return QPDFObjectHandle::Factory::newIndirect( return QPDFObjectHandle::Factory::newIndirect(this, next);
this, next.getObj(), next.getGen());
} }
QPDFObjectHandle QPDFObjectHandle
QPDF::reserveObjectIfNotExists(int objid, int gen) QPDF::reserveObjectIfNotExists(QPDFObjGen const& og)
{ {
QPDFObjGen og(objid, gen);
if ((!this->m->obj_cache.count(og)) && (!this->m->xref_table.count(og))) { if ((!this->m->obj_cache.count(og)) && (!this->m->xref_table.count(og))) {
resolve(objid, gen); resolve(og);
replaceObject(objid, gen, QPDFObjectHandle::Factory::makeReserved()); replaceObject(og, QPDFObjectHandle::Factory::makeReserved());
} }
return getObjectByID(objid, gen); return getObjectByObjGen(og);
} }
QPDFObjectHandle QPDFObjectHandle
QPDF::reserveStream(int objid, int gen) QPDF::reserveStream(QPDFObjGen const& og)
{ {
return QPDFObjectHandle::Factory::newStream( return QPDFObjectHandle::Factory::newStream(
this, objid, gen, QPDFObjectHandle::newDictionary(), 0, 0); this, og, QPDFObjectHandle::newDictionary(), 0, 0);
} }
QPDFObjectHandle QPDFObjectHandle
QPDF::getObjectByObjGen(QPDFObjGen const& og) QPDF::getObjectByObjGen(QPDFObjGen const& og)
{ {
return getObjectByID(og.getObj(), og.getGen()); return QPDFObjectHandle::Factory::newIndirect(this, og);
} }
QPDFObjectHandle QPDFObjectHandle
QPDF::getObjectByID(int objid, int generation) QPDF::getObjectByID(int objid, int generation)
{ {
return QPDFObjectHandle::Factory::newIndirect(this, objid, generation); return getObjectByObjGen(QPDFObjGen(objid, generation));
}
void
QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
{
replaceObject(og.getObj(), og.getGen(), oh);
} }
void void
QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh) QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
{
replaceObject(QPDFObjGen(objid, generation), oh);
}
void
QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
{ {
if (oh.isIndirect()) { if (oh.isIndirect()) {
QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
@ -2237,10 +2186,9 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
} }
// Force new object to appear in the cache // Force new object to appear in the cache
resolve(objid, generation); resolve(og);
// Replace the object in the object cache // Replace the object in the object cache
QPDFObjGen og(objid, generation);
this->m->ever_replaced_objects = true; this->m->ever_replaced_objects = true;
this->m->obj_cache[og] = this->m->obj_cache[og] =
ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
@ -2540,8 +2488,7 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
auto foreign_stream_data = std::make_shared<ForeignStreamData>( auto foreign_stream_data = std::make_shared<ForeignStreamData>(
foreign_stream_qpdf->m->encp, foreign_stream_qpdf->m->encp,
foreign_stream_qpdf->m->file, foreign_stream_qpdf->m->file,
foreign.getObjectID(), foreign.getObjGen(),
foreign.getGeneration(),
stream->getOffset(), stream->getOffset(),
stream->getLength(), stream->getLength(),
dict); dict);
@ -2555,20 +2502,19 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
} }
void void
QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2) QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2)
{ {
swapObjects(og1.getObj(), og1.getGen(), og2.getObj(), og2.getGen()); swapObjects(
QPDFObjGen(objid1, generation1), QPDFObjGen(objid2, generation2));
} }
void void
QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2) QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2)
{ {
// Force objects to be loaded into cache; then swap them in the // Force objects to be loaded into cache; then swap them in the
// cache. // cache.
resolve(objid1, generation1); resolve(og1);
resolve(objid2, generation2); resolve(og2);
QPDFObjGen og1(objid1, generation1);
QPDFObjGen og2(objid2, generation2);
ObjCache t = this->m->obj_cache[og1]; ObjCache t = this->m->obj_cache[og1];
this->m->ever_replaced_objects = true; this->m->ever_replaced_objects = true;
this->m->obj_cache[og1] = this->m->obj_cache[og2]; this->m->obj_cache[og1] = this->m->obj_cache[og2];
@ -2752,8 +2698,7 @@ QPDF::pipeStreamData(
std::shared_ptr<EncryptionParameters> encp, std::shared_ptr<EncryptionParameters> encp,
std::shared_ptr<InputSource> file, std::shared_ptr<InputSource> file,
QPDF& qpdf_for_warning, QPDF& qpdf_for_warning,
int objid, QPDFObjGen const& og,
int generation,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length, size_t length,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
@ -2764,14 +2709,7 @@ QPDF::pipeStreamData(
std::vector<std::shared_ptr<Pipeline>> to_delete; std::vector<std::shared_ptr<Pipeline>> to_delete;
if (encp->encrypted) { if (encp->encrypted) {
decryptStream( decryptStream(
encp, encp, file, qpdf_for_warning, pipeline, og, stream_dict, to_delete);
file,
qpdf_for_warning,
pipeline,
objid,
generation,
stream_dict,
to_delete);
} }
bool success = false; bool success = false;
@ -2809,8 +2747,7 @@ QPDF::pipeStreamData(
"", "",
file->getLastOffset(), file->getLastOffset(),
("error decoding stream data for object " + ("error decoding stream data for object " +
QUtil::int_to_string(objid) + " " + og.unparse(' ') + ": " + e.what())));
QUtil::int_to_string(generation) + ": " + e.what())));
if (will_retry) { if (will_retry) {
qpdf_for_warning.warn( qpdf_for_warning.warn(
// line-break // line-break
@ -2836,8 +2773,7 @@ QPDF::pipeStreamData(
bool bool
QPDF::pipeStreamData( QPDF::pipeStreamData(
int objid, QPDFObjGen const& og,
int generation,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length, size_t length,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
@ -2849,8 +2785,7 @@ QPDF::pipeStreamData(
this->m->encp, this->m->encp,
this->m->file, this->m->file,
*this, *this,
objid, og,
generation,
offset, offset,
length, length,
stream_dict, stream_dict,
@ -2873,8 +2808,7 @@ QPDF::pipeForeignStreamData(
foreign->encp, foreign->encp,
foreign->file, foreign->file,
*this, *this,
foreign->foreign_objid, foreign->foreign_og,
foreign->foreign_generation,
foreign->offset, foreign->offset,
foreign->length, foreign->length,
foreign->local_dict, foreign->local_dict,

View File

@ -991,8 +991,8 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
} else { } else {
parent.warnIfPossible( parent.warnIfPossible(
"while traversing field " + "while traversing field " +
obj.getObjGen().unparse() + ", found parent (" + obj.getObjGen().unparse(',') + ", found parent (" +
parent_og.unparse() + parent_og.unparse(',') +
") that had not been seen, indicating likely" ") that had not been seen, indicating likely"
" invalid field structure"); " invalid field structure");
} }

View File

@ -49,8 +49,7 @@ namespace
size_t oi_min_area, size_t oi_min_area,
QPDFObjectHandle& image); QPDFObjectHandle& image);
virtual ~ImageOptimizer() = default; virtual ~ImageOptimizer() = default;
virtual void virtual void provideStreamData(QPDFObjGen const&, Pipeline* pipeline);
provideStreamData(int objid, int generation, Pipeline* pipeline);
std::shared_ptr<Pipeline> std::shared_ptr<Pipeline>
makePipeline(std::string const& description, Pipeline* next); makePipeline(std::string const& description, Pipeline* next);
bool evaluate(std::string const& description); bool evaluate(std::string const& description);
@ -250,7 +249,7 @@ ImageOptimizer::evaluate(std::string const& description)
} }
void void
ImageOptimizer::provideStreamData(int, int, Pipeline* pipeline) ImageOptimizer::provideStreamData(QPDFObjGen const&, Pipeline* pipeline)
{ {
std::shared_ptr<Pipeline> p = makePipeline("", pipeline); std::shared_ptr<Pipeline> p = makePipeline("", pipeline);
if (p.get() == nullptr) { if (p.get() == nullptr) {
@ -947,7 +946,7 @@ QPDFJob::doShowObj(QPDF& pdf)
} }
if (error) { if (error) {
throw std::runtime_error( throw std::runtime_error(
"unable to get object " + obj.getObjGen().unparse()); "unable to get object " + obj.getObjGen().unparse(','));
} }
} }
@ -995,7 +994,8 @@ QPDFJob::doListAttachments(QPDF& pdf)
auto efoh = i.second; auto efoh = i.second;
*this->m->log->getInfo() *this->m->log->getInfo()
<< key << " -> " << key << " -> "
<< efoh->getEmbeddedFileStream().getObjGen().unparse() << "\n"; << efoh->getEmbeddedFileStream().getObjGen().unparse(',')
<< "\n";
doIfVerbose([&](Pipeline& v, std::string const& prefix) { doIfVerbose([&](Pipeline& v, std::string const& prefix) {
auto desc = efoh->getDescription(); auto desc = efoh->getDescription();
if (!desc.empty()) { if (!desc.empty()) {
@ -1010,7 +1010,7 @@ QPDFJob::doListAttachments(QPDF& pdf)
for (auto i2: efoh->getEmbeddedFileStreams().ditems()) { for (auto i2: efoh->getEmbeddedFileStreams().ditems()) {
auto efs = QPDFEFStreamObjectHelper(i2.second); auto efs = QPDFEFStreamObjectHelper(i2.second);
v << " " << i2.first << " -> " v << " " << i2.first << " -> "
<< efs.getObjectHandle().getObjGen().unparse() << "\n"; << efs.getObjectHandle().getObjGen().unparse(',') << "\n";
v << " creation date: " << efs.getCreationDate() v << " creation date: " << efs.getCreationDate()
<< "\n" << "\n"
<< " modification date: " << efs.getModDate() << "\n" << " modification date: " << efs.getModDate() << "\n"
@ -2463,7 +2463,7 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf)
QTC::TC("qpdf", "QPDFJob found resources in non-leaf"); QTC::TC("qpdf", "QPDFJob found resources in non-leaf");
doIfVerbose([&](Pipeline& v, std::string const& prefix) { doIfVerbose([&](Pipeline& v, std::string const& prefix) {
v << " found resources in non-leaf page node " v << " found resources in non-leaf page node "
<< og.getObj() << " " << og.getGen() << "\n"; << og.unparse(' ') << "\n";
}); });
return true; return true;
} }
@ -2480,9 +2480,8 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf)
QTC::TC("qpdf", "QPDFJob found shared resources in leaf"); QTC::TC("qpdf", "QPDFJob found shared resources in leaf");
doIfVerbose([&](Pipeline& v, std::string const& prefix) { doIfVerbose([&](Pipeline& v, std::string const& prefix) {
v << " found shared resources in leaf node " v << " found shared resources in leaf node "
<< og.getObj() << " " << og.getGen() << ": " << og.unparse(' ') << ": "
<< resources_og.getObj() << " " << resources_og.unparse(' ') << "\n";
<< resources_og.getGen() << "\n";
}); });
return true; return true;
} }
@ -2497,8 +2496,7 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf)
QTC::TC("qpdf", "QPDFJob found shared xobject in leaf"); QTC::TC("qpdf", "QPDFJob found shared xobject in leaf");
doIfVerbose([&](Pipeline& v, std::string const& prefix) { doIfVerbose([&](Pipeline& v, std::string const& prefix) {
v << " found shared xobject in leaf node " v << " found shared xobject in leaf node "
<< og.getObj() << " " << og.getGen() << ": " << og.unparse(' ') << ": " << xobject_og.unparse(' ')
<< xobject_og.getObj() << " " << xobject_og.getGen()
<< "\n"; << "\n";
}); });
return true; return true;
@ -3375,7 +3373,7 @@ QPDFJob::writeJSON(QPDF& pdf)
auto wanted = getWantedJSONObjects(); auto wanted = getWantedJSONObjects();
for (auto const& og: wanted) { for (auto const& og: wanted) {
std::ostringstream s; std::ostringstream s;
s << "obj:" << og.getObj() << " " << og.getGen() << " R"; s << "obj:" << og.unparse(' ') << " R";
json_objects.insert(s.str()); json_objects.insert(s.str());
} }
pdf.writeJSON( pdf.writeJSON(

17
libqpdf/QPDFObjGen.cc Normal file
View File

@ -0,0 +1,17 @@
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QUtil.hh>
std::ostream&
operator<<(std::ostream& os, const QPDFObjGen& og)
{
os << og.obj << "," << og.gen;
return os;
}
std::string
QPDFObjGen::unparse(char separator) const
{
return QUtil::int_to_string(this->obj) + separator +
QUtil::int_to_string(this->gen);
}

View File

@ -51,6 +51,24 @@ QPDFObjectHandle::StreamDataProvider::~StreamDataProvider()
// README-maintainer // README-maintainer
} }
void
QPDFObjectHandle::StreamDataProvider::provideStreamData(
QPDFObjGen const& og, Pipeline* pipeline)
{
return provideStreamData(og.getObj(), og.getGen(), pipeline);
}
bool
QPDFObjectHandle::StreamDataProvider::provideStreamData(
QPDFObjGen const& og,
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry)
{
return provideStreamData(
og.getObj(), og.getGen(), pipeline, suppress_warnings, will_retry);
}
void void
QPDFObjectHandle::StreamDataProvider::provideStreamData( QPDFObjectHandle::StreamDataProvider::provideStreamData(
int objid, int generation, Pipeline* pipeline) int objid, int generation, Pipeline* pipeline)
@ -90,8 +108,7 @@ namespace
{ {
} }
virtual ~CoalesceProvider() = default; virtual ~CoalesceProvider() = default;
virtual void virtual void provideStreamData(QPDFObjGen const&, Pipeline* pipeline);
provideStreamData(int objid, int generation, Pipeline* pipeline);
private: private:
QPDFObjectHandle containing_page; QPDFObjectHandle containing_page;
@ -100,12 +117,11 @@ namespace
} // namespace } // namespace
void void
CoalesceProvider::provideStreamData(int, int, Pipeline* p) CoalesceProvider::provideStreamData(QPDFObjGen const&, Pipeline* p)
{ {
QTC::TC("qpdf", "QPDFObjectHandle coalesce provide stream data"); QTC::TC("qpdf", "QPDFObjectHandle coalesce provide stream data");
std::string description = "page object " + std::string description =
QUtil::int_to_string(containing_page.getObjectID()) + " " + "page object " + containing_page.getObjGen().unparse(' ');
QUtil::int_to_string(containing_page.getGeneration());
std::string all_description; std::string all_description;
old_contents.pipeContentStreams(p, description, all_description); old_contents.pipeContentStreams(p, description, all_description);
} }
@ -219,27 +235,22 @@ LastChar::getLastChar()
QPDFObjectHandle::QPDFObjectHandle() : QPDFObjectHandle::QPDFObjectHandle() :
initialized(false), initialized(false),
qpdf(0), qpdf(nullptr),
objid(0),
generation(0),
reserved(false) reserved(false)
{ {
} }
QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, int objid, int generation) : QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, QPDFObjGen const& og) :
initialized(true), initialized(true),
qpdf(qpdf), qpdf(qpdf),
objid(objid), og(og),
generation(generation),
reserved(false) reserved(false)
{ {
} }
QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr<QPDFObject> const& data) : QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr<QPDFObject> const& data) :
initialized(true), initialized(true),
qpdf(0), qpdf(nullptr),
objid(0),
generation(0),
obj(data), obj(data),
reserved(false) reserved(false)
{ {
@ -1431,15 +1442,14 @@ namespace
} }
virtual void virtual void
provideStreamData(int, int, Pipeline* pipeline) override provideStreamData(QPDFObjGen const&, Pipeline* pipeline) override
{ {
p1(pipeline); p1(pipeline);
} }
virtual bool virtual bool
provideStreamData( provideStreamData(
int, QPDFObjGen const&,
int,
Pipeline* pipeline, Pipeline* pipeline,
bool suppress_warnings, bool suppress_warnings,
bool will_retry) override bool will_retry) override
@ -1482,26 +1492,19 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjGen QPDFObjGen
QPDFObjectHandle::getObjGen() const QPDFObjectHandle::getObjGen() const
{ {
return QPDFObjGen(this->objid, this->generation); return og;
}
std::string
QPDFObjectHandle::getObjGenAsStr() const
{
return QUtil::int_to_string(this->objid) + " " +
QUtil::int_to_string(this->generation);
} }
int int
QPDFObjectHandle::getObjectID() const QPDFObjectHandle::getObjectID() const
{ {
return this->objid; return og.getObj();
} }
int int
QPDFObjectHandle::getGeneration() const QPDFObjectHandle::getGeneration() const
{ {
return this->generation; return og.getGen();
} }
std::map<std::string, QPDFObjectHandle> std::map<std::string, QPDFObjectHandle>
@ -1556,7 +1559,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
} else { } else {
all_description += ","; all_description += ",";
} }
all_description += " stream " + item.getObjGenAsStr(); all_description += " stream " + item.getObjGen().unparse(' ');
} }
return result; return result;
@ -1565,7 +1568,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
std::vector<QPDFObjectHandle> std::vector<QPDFObjectHandle>
QPDFObjectHandle::getPageContents() QPDFObjectHandle::getPageContents()
{ {
std::string description = "page object " + getObjGenAsStr(); std::string description = "page object " + getObjGen().unparse(' ');
std::string all_description; std::string all_description;
return this->getKey("/Contents") return this->getKey("/Contents")
.arrayOrStreamToStreamArray(description, all_description); .arrayOrStreamToStreamArray(description, all_description);
@ -1674,7 +1677,7 @@ QPDFObjectHandle::unparse()
{ {
std::string result; std::string result;
if (this->isIndirect()) { if (this->isIndirect()) {
result = getObjGenAsStr() + " R"; result = getObjGen().unparse(' ') + " R";
} else { } else {
result = unparseResolved(); result = unparseResolved();
} }
@ -1789,7 +1792,7 @@ QPDFObjectHandle::parse(
void void
QPDFObjectHandle::pipePageContents(Pipeline* p) QPDFObjectHandle::pipePageContents(Pipeline* p)
{ {
std::string description = "page object " + getObjGenAsStr(); std::string description = "page object " + getObjGen().unparse(' ');
std::string all_description; std::string all_description;
this->getKey("/Contents") this->getKey("/Contents")
.pipeContentStreams(p, description, all_description); .pipeContentStreams(p, description, all_description);
@ -1813,7 +1816,7 @@ QPDFObjectHandle::pipeContentStreams(
throw QPDFExc( throw QPDFExc(
qpdf_e_damaged_pdf, qpdf_e_damaged_pdf,
"content stream", "content stream",
"content stream object " + stream.getObjGenAsStr(), "content stream object " + stream.getObjGen().unparse(' '),
0, 0,
"errors while decoding content stream"); "errors while decoding content stream");
} }
@ -1829,7 +1832,7 @@ QPDFObjectHandle::pipeContentStreams(
void void
QPDFObjectHandle::parsePageContents(ParserCallbacks* callbacks) QPDFObjectHandle::parsePageContents(ParserCallbacks* callbacks)
{ {
std::string description = "page object " + getObjGenAsStr(); std::string description = "page object " + getObjGen().unparse(' ');
this->getKey("/Contents") this->getKey("/Contents")
.parseContentStream_internal(description, callbacks); .parseContentStream_internal(description, callbacks);
} }
@ -1837,14 +1840,15 @@ QPDFObjectHandle::parsePageContents(ParserCallbacks* callbacks)
void void
QPDFObjectHandle::parseAsContents(ParserCallbacks* callbacks) QPDFObjectHandle::parseAsContents(ParserCallbacks* callbacks)
{ {
std::string description = "object " + getObjGenAsStr(); std::string description = "object " + getObjGen().unparse(' ');
this->parseContentStream_internal(description, callbacks); this->parseContentStream_internal(description, callbacks);
} }
void void
QPDFObjectHandle::filterPageContents(TokenFilter* filter, Pipeline* next) QPDFObjectHandle::filterPageContents(TokenFilter* filter, Pipeline* next)
{ {
auto description = "token filter for page object " + getObjGenAsStr(); auto description =
"token filter for page object " + getObjGen().unparse(' ');
Pl_QPDFTokenizer token_pipeline(description.c_str(), filter, next); Pl_QPDFTokenizer token_pipeline(description.c_str(), filter, next);
this->pipePageContents(&token_pipeline); this->pipePageContents(&token_pipeline);
} }
@ -1852,7 +1856,7 @@ QPDFObjectHandle::filterPageContents(TokenFilter* filter, Pipeline* next)
void void
QPDFObjectHandle::filterAsContents(TokenFilter* filter, Pipeline* next) QPDFObjectHandle::filterAsContents(TokenFilter* filter, Pipeline* next)
{ {
auto description = "token filter for object " + getObjGenAsStr(); auto description = "token filter for object " + getObjGen().unparse(' ');
Pl_QPDFTokenizer token_pipeline(description.c_str(), filter, next); Pl_QPDFTokenizer token_pipeline(description.c_str(), filter, next);
this->pipeStreamData(&token_pipeline, 0, qpdf_dl_specialized); this->pipeStreamData(&token_pipeline, 0, qpdf_dl_specialized);
} }
@ -2192,8 +2196,9 @@ QPDFObjectHandle::parseInternal(
// Try to resolve indirect objects // Try to resolve indirect objects
object = newIndirect( object = newIndirect(
context, context,
olist.at(olist.size() - 2).getIntValueAsInt(), QPDFObjGen(
olist.at(olist.size() - 1).getIntValueAsInt()); olist.at(olist.size() - 2).getIntValueAsInt(),
olist.at(olist.size() - 1).getIntValueAsInt()));
olist.remove_last(); olist.remove_last();
olist.remove_last(); olist.remove_last();
} else if ((value == "endobj") && (state == st_top)) { } else if ((value == "endobj") && (state == st_top)) {
@ -2481,9 +2486,9 @@ QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset)
} }
QPDFObjectHandle QPDFObjectHandle
QPDFObjectHandle::newIndirect(QPDF* qpdf, int objid, int generation) QPDFObjectHandle::newIndirect(QPDF* qpdf, QPDFObjGen const& og)
{ {
if (objid == 0) { if (!og.isIndirect()) {
// Special case: QPDF uses objid 0 as a sentinel for direct // Special case: QPDF uses objid 0 as a sentinel for direct
// objects, and the PDF specification doesn't allow for object // objects, and the PDF specification doesn't allow for object
// 0. Treat indirect references to object 0 as null so that we // 0. Treat indirect references to object 0 as null so that we
@ -2492,7 +2497,7 @@ QPDFObjectHandle::newIndirect(QPDF* qpdf, int objid, int generation)
return newNull(); return newNull();
} }
return QPDFObjectHandle(qpdf, objid, generation); return QPDFObjectHandle(qpdf, og);
} }
QPDFObjectHandle QPDFObjectHandle
@ -2640,14 +2645,13 @@ QPDFObjectHandle::newDictionary(
QPDFObjectHandle QPDFObjectHandle
QPDFObjectHandle::newStream( QPDFObjectHandle::newStream(
QPDF* qpdf, QPDF* qpdf,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length) size_t length)
{ {
QPDFObjectHandle result = QPDFObjectHandle(QPDF_Stream::create( QPDFObjectHandle result = QPDFObjectHandle(
qpdf, objid, generation, stream_dict, offset, length)); QPDF_Stream::create(qpdf, og, stream_dict, offset, length));
if (offset) { if (offset) {
result.setParsedOffset(offset); result.setParsedOffset(offset);
} }
@ -2663,11 +2667,11 @@ QPDFObjectHandle::newStream(QPDF* qpdf)
} }
QTC::TC("qpdf", "QPDFObjectHandle newStream"); QTC::TC("qpdf", "QPDFObjectHandle newStream");
QPDFObjectHandle stream_dict = newDictionary(); QPDFObjectHandle stream_dict = newDictionary();
QPDFObjectHandle result = qpdf->makeIndirectObject( QPDFObjectHandle result = qpdf->makeIndirectObject(QPDFObjectHandle(
QPDFObjectHandle(QPDF_Stream::create(qpdf, 0, 0, stream_dict, 0, 0))); QPDF_Stream::create(qpdf, QPDFObjGen(), stream_dict, 0, 0)));
result.dereference(); result.dereference();
QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>(result.obj.get()); QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>(result.obj.get());
stream->setObjGen(result.getObjectID(), result.getGeneration()); stream->setObjGen(result.getObjGen());
return result; return result;
} }
@ -2695,8 +2699,7 @@ QPDFObjectHandle::newReserved(QPDF* qpdf)
// Reserve a spot for this object by assigning it an object // Reserve a spot for this object by assigning it an object
// number, but then return an unresolved handle to the object. // number, but then return an unresolved handle to the object.
QPDFObjectHandle reserved = qpdf->makeIndirectObject(makeReserved()); QPDFObjectHandle reserved = qpdf->makeIndirectObject(makeReserved());
QPDFObjectHandle result = QPDFObjectHandle result = newIndirect(qpdf, reserved.getObjGen());
newIndirect(qpdf, reserved.objid, reserved.generation);
result.reserved = true; result.reserved = true;
return result; return result;
} }
@ -2796,9 +2799,8 @@ QPDFObjectHandle::copyObject(
" reserved object handle direct"); " reserved object handle direct");
} }
this->qpdf = 0; qpdf = nullptr;
this->objid = 0; og = QPDFObjGen();
this->generation = 0;
std::shared_ptr<QPDFObject> new_obj; std::shared_ptr<QPDFObject> new_obj;
@ -3112,7 +3114,7 @@ QPDFObjectHandle::dereference()
} }
if (this->obj.get() == 0) { if (this->obj.get() == 0) {
std::shared_ptr<QPDFObject> obj = std::shared_ptr<QPDFObject> obj =
QPDF::Resolver::resolve(this->qpdf, getObjectID(), getGeneration()); QPDF::Resolver::resolve(this->qpdf, getObjGen());
if (obj.get() == 0) { if (obj.get() == 0) {
// QPDF::resolve never returns an uninitialized object, but // QPDF::resolve never returns an uninitialized object, but
// check just in case. // check just in case.

View File

@ -21,8 +21,7 @@ namespace
{ {
} }
virtual ~ContentProvider() = default; virtual ~ContentProvider() = default;
virtual void virtual void provideStreamData(QPDFObjGen const&, Pipeline* pipeline);
provideStreamData(int objid, int generation, Pipeline* pipeline);
private: private:
QPDFObjectHandle from_page; QPDFObjectHandle from_page;
@ -30,12 +29,11 @@ namespace
} // namespace } // namespace
void void
ContentProvider::provideStreamData(int, int, Pipeline* p) ContentProvider::provideStreamData(QPDFObjGen const&, Pipeline* p)
{ {
Pl_Concatenate concat("concatenate", p); Pl_Concatenate concat("concatenate", p);
std::string description = "contents from page object " + std::string description =
QUtil::int_to_string(from_page.getObjectID()) + " " + "contents from page object " + from_page.getObjGen().unparse(' ');
QUtil::int_to_string(from_page.getGeneration());
std::string all_description; std::string all_description;
from_page.getKey("/Contents") from_page.getKey("/Contents")
.pipeContentStreams(&concat, description, all_description); .pipeContentStreams(&concat, description, all_description);

View File

@ -1990,9 +1990,8 @@ QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index)
if (object_stream_index == -1) { if (object_stream_index == -1) {
if (this->m->qdf_mode && (!this->m->suppress_original_object_ids)) { if (this->m->qdf_mode && (!this->m->suppress_original_object_ids)) {
writeString( writeString(
"%% Original object ID: " + "%% Original object ID: " + object.getObjGen().unparse(' ') +
QUtil::int_to_string(object.getObjectID()) + " " + "\n");
QUtil::int_to_string(object.getGeneration()) + "\n");
} }
openObject(new_id); openObject(new_id);
setDataKey(new_id); setDataKey(new_id);

View File

@ -110,14 +110,12 @@ StreamBlobProvider::operator()(Pipeline* p)
QPDF_Stream::QPDF_Stream( QPDF_Stream::QPDF_Stream(
QPDF* qpdf, QPDF* qpdf,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length) : size_t length) :
qpdf(qpdf), qpdf(qpdf),
objid(objid), og(og),
generation(generation),
filter_on_write(true), filter_on_write(true),
stream_dict(stream_dict), stream_dict(stream_dict),
offset(offset), offset(offset),
@ -128,23 +126,18 @@ QPDF_Stream::QPDF_Stream(
"object for dictionary"); "object for dictionary");
} }
setDescription( setDescription(
this->qpdf, qpdf, qpdf->getFilename() + ", stream object " + og.unparse(' '));
this->qpdf->getFilename() + ", stream object " +
QUtil::int_to_string(this->objid) + " " +
QUtil::int_to_string(this->generation));
} }
std::shared_ptr<QPDFObject> std::shared_ptr<QPDFObject>
QPDF_Stream::create( QPDF_Stream::create(
QPDF* qpdf, QPDF* qpdf,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length) size_t length)
{ {
return do_create( return do_create(new QPDF_Stream(qpdf, og, stream_dict, offset, length));
new QPDF_Stream(qpdf, objid, generation, stream_dict, offset, length));
} }
std::shared_ptr<QPDFObject> std::shared_ptr<QPDFObject>
@ -181,23 +174,21 @@ QPDF_Stream::releaseResolved()
} }
void void
QPDF_Stream::setObjGen(int objid, int generation) QPDF_Stream::setObjGen(QPDFObjGen const& og)
{ {
if (!((this->objid == 0) && (this->generation == 0))) { if (this->og.isIndirect()) {
throw std::logic_error( throw std::logic_error(
"attempt to set object ID and generation of a stream" "attempt to set object ID and generation of a stream"
" that already has them"); " that already has them");
} }
this->objid = objid; this->og = og;
this->generation = generation;
} }
std::string std::string
QPDF_Stream::unparse() QPDF_Stream::unparse()
{ {
// Unparse stream objects as indirect references // Unparse stream objects as indirect references
return QUtil::int_to_string(this->objid) + " " + return og.unparse(' ') + " R";
QUtil::int_to_string(this->generation) + " R";
} }
JSON JSON
@ -619,17 +610,12 @@ QPDF_Stream::pipeStreamData(
Pl_Count count("stream provider count", pipeline); Pl_Count count("stream provider count", pipeline);
if (this->stream_provider->supportsRetry()) { if (this->stream_provider->supportsRetry()) {
if (!this->stream_provider->provideStreamData( if (!this->stream_provider->provideStreamData(
this->objid, og, &count, suppress_warnings, will_retry)) {
this->generation,
&count,
suppress_warnings,
will_retry)) {
filter = false; filter = false;
success = false; success = false;
} }
} else { } else {
this->stream_provider->provideStreamData( this->stream_provider->provideStreamData(og, &count);
this->objid, this->generation, &count);
} }
qpdf_offset_t actual_length = count.getCount(); qpdf_offset_t actual_length = count.getCount();
qpdf_offset_t desired_length = 0; qpdf_offset_t desired_length = 0;
@ -642,10 +628,8 @@ QPDF_Stream::pipeStreamData(
// This would be caused by programmer error on the // This would be caused by programmer error on the
// part of a library user, not by invalid input data. // part of a library user, not by invalid input data.
throw std::runtime_error( throw std::runtime_error(
"stream data provider for " + "stream data provider for " + og.unparse(' ') +
QUtil::int_to_string(this->objid) + " " + " provided " + QUtil::int_to_string(actual_length) +
QUtil::int_to_string(this->generation) + " provided " +
QUtil::int_to_string(actual_length) +
" bytes instead of expected " + " bytes instead of expected " +
QUtil::int_to_string(desired_length) + " bytes"); QUtil::int_to_string(desired_length) + " bytes");
} }
@ -661,8 +645,7 @@ QPDF_Stream::pipeStreamData(
QTC::TC("qpdf", "QPDF_Stream pipe original stream data"); QTC::TC("qpdf", "QPDF_Stream pipe original stream data");
if (!QPDF::Pipe::pipeStreamData( if (!QPDF::Pipe::pipeStreamData(
this->qpdf, this->qpdf,
this->objid, og,
this->generation,
this->offset, this->offset,
this->length, this->length,
this->stream_dict, this->stream_dict,

View File

@ -1075,8 +1075,7 @@ QPDF::initializeEncryption()
std::string std::string
QPDF::getKeyForObject( QPDF::getKeyForObject(
std::shared_ptr<EncryptionParameters> encp, std::shared_ptr<EncryptionParameters> encp,
int objid, QPDFObjGen const& og,
int generation,
bool use_aes) bool use_aes)
{ {
if (!encp->encrypted) { if (!encp->encrypted) {
@ -1084,26 +1083,24 @@ QPDF::getKeyForObject(
"request for encryption key in non-encrypted PDF"); "request for encryption key in non-encrypted PDF");
} }
if (!((objid == encp->cached_key_objid) && if (og != encp->cached_key_og) {
(generation == encp->cached_key_generation))) {
encp->cached_object_encryption_key = compute_data_key( encp->cached_object_encryption_key = compute_data_key(
encp->encryption_key, encp->encryption_key,
objid, og.getObj(),
generation, og.getGen(),
use_aes, use_aes,
encp->encryption_V, encp->encryption_V,
encp->encryption_R); encp->encryption_R);
encp->cached_key_objid = objid; encp->cached_key_og = og;
encp->cached_key_generation = generation;
} }
return encp->cached_object_encryption_key; return encp->cached_object_encryption_key;
} }
void void
QPDF::decryptString(std::string& str, int objid, int generation) QPDF::decryptString(std::string& str, QPDFObjGen const& og)
{ {
if (objid == 0) { if (!og.isIndirect()) {
return; return;
} }
bool use_aes = false; bool use_aes = false;
@ -1139,8 +1136,7 @@ QPDF::decryptString(std::string& str, int objid, int generation)
} }
} }
std::string key = std::string key = getKeyForObject(this->m->encp, og, use_aes);
getKeyForObject(this->m->encp, objid, generation, use_aes);
try { try {
if (use_aes) { if (use_aes) {
QTC::TC("qpdf", "QPDF_encryption aes decode string"); QTC::TC("qpdf", "QPDF_encryption aes decode string");
@ -1175,9 +1171,8 @@ QPDF::decryptString(std::string& str, int objid, int generation)
this->m->file->getName(), this->m->file->getName(),
this->m->last_object_description, this->m->last_object_description,
this->m->file->getLastOffset(), this->m->file->getLastOffset(),
"error decrypting string for object " + "error decrypting string for object " + og.unparse() + ": " +
QUtil::int_to_string(objid) + " " + e.what());
QUtil::int_to_string(generation) + ": " + e.what());
} }
} }
@ -1187,8 +1182,7 @@ QPDF::decryptStream(
std::shared_ptr<InputSource> file, std::shared_ptr<InputSource> file,
QPDF& qpdf_for_warning, QPDF& qpdf_for_warning,
Pipeline*& pipeline, Pipeline*& pipeline,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle& stream_dict, QPDFObjectHandle& stream_dict,
std::vector<std::shared_ptr<Pipeline>>& heap) std::vector<std::shared_ptr<Pipeline>>& heap)
{ {
@ -1283,7 +1277,7 @@ QPDF::decryptStream(
break; break;
} }
} }
std::string key = getKeyForObject(encp, objid, generation, use_aes); std::string key = getKeyForObject(encp, og, use_aes);
std::shared_ptr<Pipeline> new_pipeline; std::shared_ptr<Pipeline> new_pipeline;
if (use_aes) { if (use_aes) {
QTC::TC("qpdf", "QPDF_encryption aes decode stream"); QTC::TC("qpdf", "QPDF_encryption aes decode stream");

View File

@ -371,9 +371,10 @@ QPDF::JSONReactor::containerEnd(JSON const& value)
QPDFObjectHandle QPDFObjectHandle
QPDF::JSONReactor::reserveObject(int obj, int gen) QPDF::JSONReactor::reserveObject(int obj, int gen)
{ {
auto oh = pdf.reserveObjectIfNotExists(obj, gen); QPDFObjGen og(obj, gen);
auto oh = pdf.reserveObjectIfNotExists(og);
if (oh.isReserved()) { if (oh.isReserved()) {
this->reserved.insert(QPDFObjGen(obj, gen)); this->reserved.insert(og);
} }
return oh; return oh;
} }
@ -495,8 +496,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
QTC::TC("qpdf", "QPDF_json updating existing stream"); QTC::TC("qpdf", "QPDF_json updating existing stream");
} else { } else {
this->this_stream_needs_data = true; this->this_stream_needs_data = true;
replacement = replacement = pdf.reserveStream(tos.getObjGen());
pdf.reserveStream(tos.getObjectID(), tos.getGeneration());
replaceObject(tos, replacement, value); replaceObject(tos, replacement, value);
} }
} else { } else {

View File

@ -137,8 +137,8 @@ QPDF::isLinearized()
return false; return false;
} }
QPDFObjectHandle candidate = QPDFObjectHandle candidate = QPDFObjectHandle::Factory::newIndirect(
QPDFObjectHandle::Factory::newIndirect(this, lindict_obj, 0); this, QPDFObjGen(lindict_obj, 0));
if (!candidate.isDictionary()) { if (!candidate.isDictionary()) {
return false; return false;
} }
@ -325,11 +325,10 @@ QPDF::readLinearizationData()
QPDFObjectHandle QPDFObjectHandle
QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length)
{ {
int obj; QPDFObjGen og;
int gen;
QPDFObjectHandle H = readObjectAtOffset( QPDFObjectHandle H = readObjectAtOffset(
false, offset, "linearization hint stream", 0, 0, obj, gen); false, offset, "linearization hint stream", QPDFObjGen(0, 0), og);
ObjCache& oc = this->m->obj_cache[QPDFObjGen(obj, gen)]; ObjCache& oc = this->m->obj_cache[og];
qpdf_offset_t min_end_offset = oc.end_before_space; qpdf_offset_t min_end_offset = oc.end_before_space;
qpdf_offset_t max_end_offset = oc.end_after_space; qpdf_offset_t max_end_offset = oc.end_after_space;
if (!H.isStream()) { if (!H.isStream()) {
@ -707,7 +706,7 @@ QPDF::getUncompressedObject(
return obj; return obj;
} else { } else {
int repl = (*(object_stream_data.find(obj.getObjectID()))).second; int repl = (*(object_stream_data.find(obj.getObjectID()))).second;
return objGenToIndirect(QPDFObjGen(repl, 0)); return getObjectByObjGen(QPDFObjGen(repl, 0));
} }
} }
@ -1144,12 +1143,6 @@ QPDF::dumpHGeneric(HGeneric& t)
<< "group_length: " << t.group_length << "\n"; << "group_length: " << t.group_length << "\n";
} }
QPDFObjectHandle
QPDF::objGenToIndirect(QPDFObjGen const& og)
{
return getObjectByID(og.getObj(), og.getGen());
}
void void
QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data) QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
{ {
@ -1388,9 +1381,9 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
stopOnError("found other than one root while" stopOnError("found other than one root while"
" calculating linearization data"); " calculating linearization data");
} }
this->m->part4.push_back(objGenToIndirect(*(lc_root.begin()))); this->m->part4.push_back(getObjectByObjGen(*(lc_root.begin())));
for (auto const& og: lc_open_document) { for (auto const& og: lc_open_document) {
this->m->part4.push_back(objGenToIndirect(og)); this->m->part4.push_back(getObjectByObjGen(og));
} }
// Part 6: first page objects. Note: implementation note 124 // Part 6: first page objects. Note: implementation note 124
@ -1419,11 +1412,11 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
// hint tables. // hint tables.
for (auto const& og: lc_first_page_private) { for (auto const& og: lc_first_page_private) {
this->m->part6.push_back(objGenToIndirect(og)); this->m->part6.push_back(getObjectByObjGen(og));
} }
for (auto const& og: lc_first_page_shared) { for (auto const& og: lc_first_page_shared) {
this->m->part6.push_back(objGenToIndirect(og)); this->m->part6.push_back(getObjectByObjGen(og));
} }
// Place the outline dictionary if it goes in the first page section. // Place the outline dictionary if it goes in the first page section.
@ -1469,7 +1462,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
for (auto const& og: this->m->obj_user_to_objects[ou]) { for (auto const& og: this->m->obj_user_to_objects[ou]) {
if (lc_other_page_private.count(og)) { if (lc_other_page_private.count(og)) {
lc_other_page_private.erase(og); lc_other_page_private.erase(og);
this->m->part7.push_back(objGenToIndirect(og)); this->m->part7.push_back(getObjectByObjGen(og));
++this->m->c_page_offset_data.entries.at(i).nobjects; ++this->m->c_page_offset_data.entries.at(i).nobjects;
} }
} }
@ -1486,7 +1479,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
// Order is unimportant. // Order is unimportant.
for (auto const& og: lc_other_page_shared) { for (auto const& og: lc_other_page_shared) {
this->m->part8.push_back(objGenToIndirect(og)); this->m->part8.push_back(getObjectByObjGen(og));
} }
// Part 9: other objects // Part 9: other objects
@ -1508,7 +1501,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
for (auto const& og: pages_ogs) { for (auto const& og: pages_ogs) {
if (lc_other.count(og)) { if (lc_other.count(og)) {
lc_other.erase(og); lc_other.erase(og);
this->m->part9.push_back(objGenToIndirect(og)); this->m->part9.push_back(getObjectByObjGen(og));
} }
} }
@ -1538,7 +1531,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
for (auto const& og: ogs) { for (auto const& og: ogs) {
if (lc_thumbnail_private.count(og)) { if (lc_thumbnail_private.count(og)) {
lc_thumbnail_private.erase(og); lc_thumbnail_private.erase(og);
this->m->part9.push_back(objGenToIndirect(og)); this->m->part9.push_back(getObjectByObjGen(og));
} }
} }
} }
@ -1551,7 +1544,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
// Place shared thumbnail objects // Place shared thumbnail objects
for (auto const& og: lc_thumbnail_shared) { for (auto const& og: lc_thumbnail_shared) {
this->m->part9.push_back(objGenToIndirect(og)); this->m->part9.push_back(getObjectByObjGen(og));
} }
// Place outlines unless in first page // Place outlines unless in first page
@ -1561,7 +1554,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
// Place all remaining objects // Place all remaining objects
for (auto const& og: lc_other) { for (auto const& og: lc_other) {
this->m->part9.push_back(objGenToIndirect(og)); this->m->part9.push_back(getObjectByObjGen(og));
} }
// Make sure we got everything exactly once. // Make sure we got everything exactly once.
@ -1663,7 +1656,7 @@ QPDF::pushOutlinesToPart(
lc_outlines.erase(outlines_og); lc_outlines.erase(outlines_og);
part.push_back(outlines); part.push_back(outlines);
for (auto const& og: lc_outlines) { for (auto const& og: lc_outlines) {
part.push_back(objGenToIndirect(og)); part.push_back(getObjectByObjGen(og));
++this->m->c_outline_data.nobjects; ++this->m->c_outline_data.nobjects;
} }
} }

View File

@ -252,9 +252,7 @@ QPDF::pushInheritedAttributesToPageInternal(
if ((warn_skipped_keys) && (cur_pages.hasKey("/Parent"))) { if ((warn_skipped_keys) && (cur_pages.hasKey("/Parent"))) {
QTC::TC("qpdf", "QPDF unknown key not inherited"); QTC::TC("qpdf", "QPDF unknown key not inherited");
setLastObjectDescription( setLastObjectDescription(
"Pages object", "Pages object", cur_pages.getObjGen());
cur_pages.getObjectID(),
cur_pages.getGeneration());
warn( warn(
qpdf_e_pages, qpdf_e_pages,
this->m->last_object_description, this->m->last_object_description,

View File

@ -207,8 +207,7 @@ QPDF::insertPageobjToPage(
// that causes this to happen. // that causes this to happen.
setLastObjectDescription( setLastObjectDescription(
"page " + QUtil::int_to_string(pos) + " (numbered from zero)", "page " + QUtil::int_to_string(pos) + " (numbered from zero)",
og.getObj(), og);
og.getGen());
throw QPDFExc( throw QPDFExc(
qpdf_e_pages, qpdf_e_pages,
this->m->file->getName(), this->m->file->getName(),
@ -334,7 +333,7 @@ QPDF::findPage(QPDFObjGen const& og)
auto it = this->m->pageobj_to_pages_pos.find(og); auto it = this->m->pageobj_to_pages_pos.find(og);
if (it == this->m->pageobj_to_pages_pos.end()) { if (it == this->m->pageobj_to_pages_pos.end()) {
QTC::TC("qpdf", "QPDF_pages findPage not found"); QTC::TC("qpdf", "QPDF_pages findPage not found");
setLastObjectDescription("page object", og.getObj(), og.getGen()); setLastObjectDescription("page object", og);
throw QPDFExc( throw QPDFExc(
qpdf_e_pages, qpdf_e_pages,
this->m->file->getName(), this->m->file->getName(),

View File

@ -19,8 +19,7 @@ class QPDF_Stream: public QPDFObject
virtual ~QPDF_Stream() = default; virtual ~QPDF_Stream() = default;
static std::shared_ptr<QPDFObject> create( static std::shared_ptr<QPDFObject> create(
QPDF*, QPDF*,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length); size_t length);
@ -78,7 +77,7 @@ class QPDF_Stream: public QPDFObject
// Replace object ID and generation. This may only be called if // Replace object ID and generation. This may only be called if
// object ID and generation are 0. It is used by QPDFObjectHandle // object ID and generation are 0. It is used by QPDFObjectHandle
// when adding streams to files. // when adding streams to files.
void setObjGen(int objid, int generation); void setObjGen(QPDFObjGen const& og);
protected: protected:
virtual void releaseResolved(); virtual void releaseResolved();
@ -86,8 +85,7 @@ class QPDF_Stream: public QPDFObject
private: private:
QPDF_Stream( QPDF_Stream(
QPDF*, QPDF*,
int objid, QPDFObjGen const& og,
int generation,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length); size_t length);
@ -111,8 +109,7 @@ class QPDF_Stream: public QPDFObject
void setDictDescription(); void setDictDescription();
QPDF* qpdf; QPDF* qpdf;
int objid; QPDFObjGen og;
int generation;
bool filter_on_write; bool filter_on_write;
QPDFObjectHandle stream_dict; QPDFObjectHandle stream_dict;
qpdf_offset_t offset; qpdf_offset_t offset;

View File

@ -56,6 +56,8 @@ class Provider: public QPDFObjectHandle::StreamDataProvider
virtual void virtual void
provideStreamData(int objid, int generation, Pipeline* p) provideStreamData(int objid, int generation, Pipeline* p)
{ {
// Don't change signature to use QPDFObjGen const& to detect
// problems forwarding to legacy implementations.
p->write(b->getBuffer(), b->getSize()); p->write(b->getBuffer(), b->getSize());
if (this->bad_length) { if (this->bad_length) {
unsigned char ch = ' '; unsigned char ch = ' ';