aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/QPDFObjectHandle.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf/QPDFObjectHandle.cc')
-rw-r--r--libqpdf/QPDFObjectHandle.cc248
1 files changed, 221 insertions, 27 deletions
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index f4a8a0a4..a3a4d61d 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -18,6 +18,7 @@
#include <qpdf/Pl_QPDFTokenizer.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/QPDFExc.hh>
+#include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
@@ -575,6 +576,26 @@ QPDFObjectHandle::isRectangle()
return true;
}
+bool
+QPDFObjectHandle::isMatrix()
+{
+ if (! isArray())
+ {
+ return false;
+ }
+ if (getArrayNItems() != 6)
+ {
+ return false;
+ }
+ for (size_t i = 0; i < 6; ++i)
+ {
+ if (! getArrayItem(i).isNumber())
+ {
+ return false;
+ }
+ }
+ return true;
+}
QPDFObjectHandle::Rectangle
QPDFObjectHandle::getArrayAsRectangle()
@@ -590,6 +611,22 @@ QPDFObjectHandle::getArrayAsRectangle()
return result;
}
+QPDFObjectHandle::Matrix
+QPDFObjectHandle::getArrayAsMatrix()
+{
+ Matrix result;
+ if (isMatrix())
+ {
+ result = Matrix(getArrayItem(0).getNumericValue(),
+ getArrayItem(1).getNumericValue(),
+ getArrayItem(2).getNumericValue(),
+ getArrayItem(3).getNumericValue(),
+ getArrayItem(4).getNumericValue(),
+ getArrayItem(5).getNumericValue());
+ }
+ return result;
+}
+
std::vector<QPDFObjectHandle>
QPDFObjectHandle::getArrayAsVector()
{
@@ -789,6 +826,135 @@ QPDFObjectHandle::isOrHasName(std::string const& value)
return false;
}
+void
+QPDFObjectHandle::mergeResources(QPDFObjectHandle other)
+{
+ if (! (isDictionary() && other.isDictionary()))
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle merge top type mismatch");
+ return;
+ }
+ std::set<std::string> other_keys = other.getKeys();
+ for (std::set<std::string>::iterator iter = other_keys.begin();
+ iter != other_keys.end(); ++iter)
+ {
+ std::string const& key = *iter;
+ QPDFObjectHandle other_val = other.getKey(key);
+ if (hasKey(key))
+ {
+ QPDFObjectHandle this_val = getKey(key);
+ if (this_val.isDictionary() && other_val.isDictionary())
+ {
+ if (this_val.isIndirect())
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle replace with copy");
+ this_val = this_val.shallowCopy();
+ replaceKey(key, this_val);
+ }
+ std::set<std::string> other_val_keys = other_val.getKeys();
+ for (std::set<std::string>::iterator i2 =
+ other_val_keys.begin();
+ i2 != other_val_keys.end(); ++i2)
+ {
+ if (! this_val.hasKey(*i2))
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle merge shallow copy");
+ this_val.replaceKey(
+ *i2, other_val.getKey(*i2).shallowCopy());
+ }
+ }
+ }
+ else if (this_val.isArray() && other_val.isArray())
+ {
+ std::set<std::string> scalars;
+ int n = this_val.getArrayNItems();
+ for (int i = 0; i < n; ++i)
+ {
+ QPDFObjectHandle this_item = this_val.getArrayItem(i);
+ if (this_item.isScalar())
+ {
+ scalars.insert(this_item.unparse());
+ }
+ }
+ n = other_val.getArrayNItems();
+ for (int i = 0; i < n; ++i)
+ {
+ QPDFObjectHandle other_item = other_val.getArrayItem(i);
+ if (other_item.isScalar())
+ {
+ if (scalars.count(other_item.unparse()) == 0)
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle merge array");
+ this_val.appendItem(other_item);
+ }
+ else
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle merge array dup");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle merge copy from other");
+ replaceKey(key, other_val.shallowCopy());
+ }
+ }
+}
+
+std::set<std::string>
+QPDFObjectHandle::getResourceNames()
+{
+ // Return second-level dictionary keys
+ std::set<std::string> result;
+ if (! isDictionary())
+ {
+ return result;
+ }
+ std::set<std::string> keys = getKeys();
+ for (std::set<std::string>::iterator iter = keys.begin();
+ iter != keys.end(); ++iter)
+ {
+ std::string const& key = *iter;
+ QPDFObjectHandle val = getKey(key);
+ if (val.isDictionary())
+ {
+ std::set<std::string> val_keys = val.getKeys();
+ for (std::set<std::string>::iterator i2 = val_keys.begin();
+ i2 != val_keys.end(); ++i2)
+ {
+ result.insert(*i2);
+ }
+ }
+ }
+ return result;
+}
+
+std::string
+QPDFObjectHandle::getUniqueResourceName(std::string const& prefix,
+ int& min_suffix)
+{
+ std::set<std::string> names = getResourceNames();
+ int max_suffix = min_suffix + names.size();
+ while (min_suffix <= max_suffix)
+ {
+ std::string candidate = prefix + QUtil::int_to_string(min_suffix);
+ if (names.count(candidate) == 0)
+ {
+ return candidate;
+ }
+ // Increment after return; min_suffix should be the value
+ // used, not the next value.
+ ++min_suffix;
+ }
+ // This could only happen if there is a coding error.
+ // The number of candidates we test is more than the
+ // number of keys we're checking against.
+ throw std::logic_error("unable to find unconflicting name in"
+ " QPDFObjectHandle::getUniqueResourceName");
+}
+
// Indirect object accessors
QPDF*
QPDFObjectHandle::getOwningQPDF()
@@ -968,24 +1134,11 @@ QPDFObjectHandle::getGeneration() const
std::map<std::string, QPDFObjectHandle>
QPDFObjectHandle::getPageImages()
{
- // Note: this code doesn't handle inherited resources. If this
- // page dictionary doesn't have a /Resources key or has one whose
- // value is null or an empty dictionary, you are supposed to walk
- // up the page tree until you find a /Resources dictionary. As of
- // this writing, I don't have any test files that use inherited
- // resources, and hand-generating one won't be a good test because
- // any mistakes in my understanding would be present in both the
- // code and the test file.
-
- // NOTE: If support of inherited resources (see above comment) is
- // implemented, edit comment in QPDFObjectHandle.hh for this
- // function. Also remove call to pushInheritedAttributesToPage
- // from qpdf.cc when show_page_images is true.
-
std::map<std::string, QPDFObjectHandle> result;
- if (this->hasKey("/Resources"))
+ QPDFObjectHandle resources =
+ QPDFPageObjectHelper(*this).getAttribute("/Resources", false);
+ if (resources.isDictionary())
{
- QPDFObjectHandle resources = this->getKey("/Resources");
if (resources.hasKey("/XObject"))
{
QPDFObjectHandle xobject = resources.getKey("/XObject");
@@ -1235,6 +1388,37 @@ QPDFObjectHandle::unparseBinary()
}
}
+JSON
+QPDFObjectHandle::getJSON(bool dereference_indirect)
+{
+ if ((! dereference_indirect) && this->isIndirect())
+ {
+ return JSON::makeString(unparse());
+ }
+ else
+ {
+ if (this->m->reserved)
+ {
+ throw std::logic_error(
+ "QPDFObjectHandle: attempting to unparse a reserved object");
+ }
+ dereference();
+ return this->m->obj->getJSON();
+ }
+}
+
+QPDFObjectHandle
+QPDFObjectHandle::wrapInArray()
+{
+ if (isArray())
+ {
+ return *this;
+ }
+ QPDFObjectHandle result = QPDFObjectHandle::newArray();
+ result.appendItem(*this);
+ return result;
+}
+
QPDFObjectHandle
QPDFObjectHandle::parse(std::string const& object_str,
std::string const& object_description)
@@ -1374,7 +1558,7 @@ QPDFObjectHandle::parseContentStream_data(
// terminated the token. Read until end of inline image.
char ch;
input->read(&ch, 1);
- tokenizer.expectInlineImage();
+ tokenizer.expectInlineImage(input);
QPDFTokenizer::Token t =
tokenizer.readToken(input, description, true);
if (t.getType() == QPDFTokenizer::tt_bad)
@@ -1386,16 +1570,7 @@ QPDFObjectHandle::parseContentStream_data(
}
else
{
- // Skip back over EI
- input->seek(-3, SEEK_CUR);
- std::string inline_image = t.getRawValue();
- for (int i = 0; i < 4; ++i)
- {
- if (inline_image.length() > 0)
- {
- inline_image.erase(inline_image.length() - 1);
- }
- }
+ std::string inline_image = t.getValue();
QTC::TC("qpdf", "QPDFObjectHandle inline image token");
callbacks->handleObject(
QPDFObjectHandle::newInlineImage(inline_image));
@@ -1900,12 +2075,31 @@ QPDFObjectHandle::newArray(Rectangle const& rect)
}
QPDFObjectHandle
+QPDFObjectHandle::newArray(Matrix const& matrix)
+{
+ std::vector<QPDFObjectHandle> items;
+ items.push_back(newReal(matrix.a));
+ items.push_back(newReal(matrix.b));
+ items.push_back(newReal(matrix.c));
+ items.push_back(newReal(matrix.d));
+ items.push_back(newReal(matrix.e));
+ items.push_back(newReal(matrix.f));
+ return newArray(items);
+}
+
+QPDFObjectHandle
QPDFObjectHandle::newFromRectangle(Rectangle const& rect)
{
return newArray(rect);
}
QPDFObjectHandle
+QPDFObjectHandle::newFromMatrix(Matrix const& rect)
+{
+ return newArray(rect);
+}
+
+QPDFObjectHandle
QPDFObjectHandle::newDictionary()
{
return newDictionary(std::map<std::string, QPDFObjectHandle>());