summaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2012-07-08 20:19:19 +0200
committerJay Berkenbilt <ejb@ql.org>2012-07-11 05:34:32 +0200
commit8a217eb3a26931453b4f003c6c18ad8569230cf1 (patch)
treedfca77568e0640be6555bfe550a1e334dfb0710e /libqpdf
parentaf64668ad190a3f28fbeb233238cb4a76db67d7c (diff)
downloadqpdf-8a217eb3a26931453b4f003c6c18ad8569230cf1.tar.zst
Add concept of reserved objects
QPDFObjectHandle::{new,is,assert}Reserved, QPDF::replaceReserved provide a mechanism to add objects to a PDF file when there are circular references. This is a prerequisite to copying objects from one PDF to another.
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/QPDF.cc12
-rw-r--r--libqpdf/QPDFObjectHandle.cc62
-rw-r--r--libqpdf/QPDF_Reserved.cc13
-rw-r--r--libqpdf/build.mk1
-rw-r--r--libqpdf/qpdf/QPDF_Reserved.hh13
5 files changed, 96 insertions, 5 deletions
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index a66b4f15..1c4e5d8d 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -2057,6 +2057,18 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
}
void
+QPDF::replaceReserved(QPDFObjectHandle reserved,
+ QPDFObjectHandle replacement)
+{
+ QTC::TC("qpdf", "QPDF replaceReserved");
+ reserved.assertReserved();
+ replaceObject(reserved.getObjectID(),
+ reserved.getGeneration(),
+ replacement);
+}
+
+
+void
QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2)
{
// Force objects to be loaded into cache; then swap them in the
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index 73d0019c..25298bee 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -10,6 +10,7 @@
#include <qpdf/QPDF_Array.hh>
#include <qpdf/QPDF_Dictionary.hh>
#include <qpdf/QPDF_Stream.hh>
+#include <qpdf/QPDF_Reserved.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
@@ -20,7 +21,8 @@
QPDFObjectHandle::QPDFObjectHandle() :
initialized(false),
objid(0),
- generation(0)
+ generation(0),
+ reserved(false)
{
}
@@ -28,7 +30,8 @@ QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, int objid, int generation) :
initialized(true),
qpdf(qpdf),
objid(objid),
- generation(generation)
+ generation(generation),
+ reserved(false)
{
}
@@ -37,7 +40,8 @@ QPDFObjectHandle::QPDFObjectHandle(QPDFObject* data) :
qpdf(0),
objid(0),
generation(0),
- obj(data)
+ obj(data),
+ reserved(false)
{
}
@@ -166,6 +170,14 @@ QPDFObjectHandle::isStream()
}
bool
+QPDFObjectHandle::isReserved()
+{
+ // dereference will clear reserved if this has been replaced
+ dereference();
+ return this->reserved;
+}
+
+bool
QPDFObjectHandle::isIndirect()
{
assertInitialized();
@@ -568,6 +580,11 @@ QPDFObjectHandle::unparse()
std::string
QPDFObjectHandle::unparseResolved()
{
+ if (this->reserved)
+ {
+ throw std::logic_error(
+ "QPDFObjectHandle: attempting to unparse a reserved object");
+ }
dereference();
return this->obj->unparse();
}
@@ -690,6 +707,19 @@ QPDFObjectHandle::newStream(QPDF* qpdf, std::string const& data)
}
QPDFObjectHandle
+QPDFObjectHandle::newReserved(QPDF* qpdf)
+{
+ // Reserve a spot for this object by assigning it an object
+ // number, but then return an unresolved handle to the object.
+ QPDFObjectHandle reserved = qpdf->makeIndirectObject(
+ QPDFObjectHandle(new QPDF_Reserved()));
+ QPDFObjectHandle result =
+ newIndirect(qpdf, reserved.objid, reserved.generation);
+ result.reserved = true;
+ return result;
+}
+
+QPDFObjectHandle
QPDFObjectHandle::shallowCopy()
{
assertInitialized();
@@ -746,6 +776,13 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited)
visited.insert(cur_objid);
}
+ if (isReserved())
+ {
+ throw std::logic_error(
+ "QPDFObjectHandle: attempting to make a"
+ " reserved object handle direct");
+ }
+
dereference();
this->objid = 0;
this->generation = 0;
@@ -903,6 +940,12 @@ QPDFObjectHandle::assertStream()
}
void
+QPDFObjectHandle::assertReserved()
+{
+ assertType("Reserved", isReserved());
+}
+
+void
QPDFObjectHandle::assertScalar()
{
assertType("Scalar", isScalar());
@@ -929,12 +972,21 @@ QPDFObjectHandle::dereference()
{
if (this->obj.getPointer() == 0)
{
- this->obj = QPDF::Resolver::resolve(
+ PointerHolder<QPDFObject> obj = QPDF::Resolver::resolve(
this->qpdf, this->objid, this->generation);
- if (this->obj.getPointer() == 0)
+ if (obj.getPointer() == 0)
{
QTC::TC("qpdf", "QPDFObjectHandle indirect to unknown");
this->obj = new QPDF_Null();
}
+ else if (dynamic_cast<QPDF_Reserved*>(obj.getPointer()))
+ {
+ // Do not resolve
+ }
+ else
+ {
+ this->reserved = false;
+ this->obj = obj;
+ }
}
}
diff --git a/libqpdf/QPDF_Reserved.cc b/libqpdf/QPDF_Reserved.cc
new file mode 100644
index 00000000..368db3b4
--- /dev/null
+++ b/libqpdf/QPDF_Reserved.cc
@@ -0,0 +1,13 @@
+#include <qpdf/QPDF_Reserved.hh>
+#include <stdexcept>
+
+QPDF_Reserved::~QPDF_Reserved()
+{
+}
+
+std::string
+QPDF_Reserved::unparse()
+{
+ throw std::logic_error("attempt to unparse QPDF_Reserved");
+ return "";
+}
diff --git a/libqpdf/build.mk b/libqpdf/build.mk
index 7efbbd85..422878f2 100644
--- a/libqpdf/build.mk
+++ b/libqpdf/build.mk
@@ -39,6 +39,7 @@ SRCS_libqpdf = \
libqpdf/QPDF_Name.cc \
libqpdf/QPDF_Null.cc \
libqpdf/QPDF_Real.cc \
+ libqpdf/QPDF_Reserved.cc \
libqpdf/QPDF_Stream.cc \
libqpdf/QPDF_String.cc \
libqpdf/QPDF_encryption.cc \
diff --git a/libqpdf/qpdf/QPDF_Reserved.hh b/libqpdf/qpdf/QPDF_Reserved.hh
new file mode 100644
index 00000000..b149f776
--- /dev/null
+++ b/libqpdf/qpdf/QPDF_Reserved.hh
@@ -0,0 +1,13 @@
+#ifndef __QPDF_RESERVED_HH__
+#define __QPDF_RESERVED_HH__
+
+#include <qpdf/QPDFObject.hh>
+
+class QPDF_Reserved: public QPDFObject
+{
+ public:
+ virtual ~QPDF_Reserved();
+ virtual std::string unparse();
+};
+
+#endif // __QPDF_RESERVED_HH__