diff options
Diffstat (limited to 'libqpdf/QPDFObjectHandle.cc')
-rw-r--r-- | libqpdf/QPDFObjectHandle.cc | 248 |
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>()); |