summaryrefslogtreecommitdiffstats
path: root/libqpdf/QPDF.cc
diff options
context:
space:
mode:
authorTobias Hoffmann <thobi@worker>2012-06-19 01:53:10 +0200
committerJay Berkenbilt <ejb@ql.org>2012-06-21 21:01:02 +0200
commit5d3f93be29800dd0eb876c3062451d32e7798948 (patch)
tree76b6d3767d20edb4e516254131549d28c6d658c5 /libqpdf/QPDF.cc
parent405a549f8c86769d14d6a350621f4642dd30920f (diff)
downloadqpdf-5d3f93be29800dd0eb876c3062451d32e7798948.tar.zst
Added first version of pages API.
Diffstat (limited to 'libqpdf/QPDF.cc')
-rw-r--r--libqpdf/QPDF.cc145
1 files changed, 145 insertions, 0 deletions
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index 64c454a2..d36aebe2 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -4,6 +4,7 @@
#include <map>
#include <string.h>
#include <memory.h>
+#include <assert.h>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
@@ -2203,8 +2204,152 @@ QPDF::getAllPagesInternal(QPDFObjectHandle cur_pages,
}
}
+// FIXXX here down
+
void
QPDF::clearPagesCache()
{
this->all_pages.clear();
+ this->pageobj_to_pages_pos.clear();
+}
+
+void
+QPDF::flattenPagesTree()
+{
+ clearPagesCache();
+
+ // FIXME: more specific method, we don't want to generate the extra stuff.
+ // We also need cheap fixup after addPage/removePage.
+
+ // no compressed objects to be produced here...
+ std::map<int, int> object_stream_data;
+ optimize(object_stream_data); // push down inheritance
+
+ std::vector<QPDFObjectHandle> kids = this->getAllPages();
+ QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages");
+
+ const int len = kids.size();
+ for (int pos = 0; pos < len; ++pos)
+ {
+ // populate pageobj_to_pages_pos
+ ObjGen og(kids[pos].getObjectID(), kids[pos].getGeneration());
+ if (! this->pageobj_to_pages_pos.insert(std::make_pair(og, pos)).second)
+ {
+ // insert failed: duplicate entry found
+ *out_stream << "WARNING: duplicate page reference found, "
+ << "but currently not fully supported." << std::endl;
+ }
+
+ // fix parent links
+ kids[pos].replaceKey("/Parent", pages);
+ }
+
+ pages.replaceKey("/Kids", QPDFObjectHandle::newArray(kids));
+ // /Count has not changed
+ assert(pages.getKey("/Count").getIntValue() == len);
+}
+
+int
+QPDF::findPage(int objid, int generation)
+{
+ if (this->pageobj_to_pages_pos.empty())
+ {
+ flattenPagesTree();
+ }
+ std::map<ObjGen, int>::iterator it =
+ this->pageobj_to_pages_pos.find(ObjGen(objid, generation));
+ if (it != this->pageobj_to_pages_pos.end())
+ {
+ return (*it).second;
+ }
+ return -1; // throw?
+}
+
+int
+QPDF::findPage(QPDFObjectHandle const& pageoh)
+{
+ if (!pageoh.isInitialized())
+ {
+ return -1;
+ // TODO? throw
+ }
+ return findPage(pageoh.getObjectID(), pageoh.getGeneration());
+}
+
+void
+QPDF::addPage(QPDFObjectHandle newpage, bool first)
+{
+ if (this->pageobj_to_pages_pos.empty())
+ {
+ flattenPagesTree();
+ }
+
+ newpage.assertPageObject(); // FIXME: currently private
+
+ QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages");
+ QPDFObjectHandle kids = pages.getKey("/Kids");
+
+ newpage.replaceKey("/Parent", pages);
+ if (first)
+ {
+ kids.insertItem(0, newpage);
+ }
+ else
+ {
+ kids.appendItem(newpage);
+ }
+ pages.replaceKey("/Count",
+ QPDFObjectHandle::newInteger(kids.getArrayNItems()));
+
+ // FIXME: this is overkill, but cache is now stale
+ clearPagesCache();
+}
+
+void
+QPDF::addPageAt(QPDFObjectHandle newpage, bool before,
+ QPDFObjectHandle const &refpage)
+{
+ int refpos = findPage(refpage); // also ensures flat /Pages
+ if (refpos == -1)
+ {
+ throw "Could not find refpage";
+ }
+
+ newpage.assertPageObject();
+
+ QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages");
+ QPDFObjectHandle kids = pages.getKey("/Kids");
+
+ if (! before)
+ {
+ ++refpos;
+ }
+
+ newpage.replaceKey("/Parent", pages);
+ kids.insertItem(refpos, newpage);
+ pages.replaceKey("/Count",
+ QPDFObjectHandle::newInteger(kids.getArrayNItems()));
+
+ // FIXME: this is overkill, but cache is now stale
+ clearPagesCache();
+}
+
+void
+QPDF::removePage(QPDFObjectHandle const& pageoh)
+{
+ int pos = findPage(pageoh); // also ensures flat /Pages
+ if (pos == -1)
+ {
+ throw "Can't remove non-existing page";
+ }
+
+ QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages");
+ QPDFObjectHandle kids = pages.getKey("/Kids");
+
+ kids.eraseItem(pos);
+ pages.replaceKey("/Count",
+ QPDFObjectHandle::newInteger(kids.getArrayNItems()));
+
+ // FIXME: this is overkill, but cache is now stale
+ clearPagesCache();
}