From 9a0b88bf7777c153dc46ace22db74ef24d51583a Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Tue, 29 Apr 2008 12:55:25 +0000 Subject: update release date to actual date git-svn-id: svn+q:///qpdf/trunk@599 71b93d88-0707-0410-a8cf-f5a4172ac649 --- libqpdf/QPDFObjectHandle.cc | 637 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 637 insertions(+) create mode 100644 libqpdf/QPDFObjectHandle.cc (limited to 'libqpdf/QPDFObjectHandle.cc') diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc new file mode 100644 index 00000000..9fba7b43 --- /dev/null +++ b/libqpdf/QPDFObjectHandle.cc @@ -0,0 +1,637 @@ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QPDFObjectHandle::QPDFObjectHandle() : + initialized(false), + objid(0), + generation(0) +{ +} + +QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, int objid, int generation) : + initialized(true), + qpdf(qpdf), + objid(objid), + generation(generation) +{ +} + +QPDFObjectHandle::QPDFObjectHandle(QPDFObject* data) : + initialized(true), + qpdf(0), + objid(0), + generation(0), + obj(data) +{ +} + +bool +QPDFObjectHandle::isInitialized() const +{ + return this->initialized; +} + +template +class QPDFObjectTypeAccessor +{ + public: + static bool check(QPDFObject* o) + { + return (o && dynamic_cast(o)); + } +}; + +bool +QPDFObjectHandle::isBool() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isNull() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isInteger() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isReal() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isNumber() +{ + return (isInteger() || isReal()); +} + +double +QPDFObjectHandle::getNumericValue() +{ + double result = 0.0; + if (isInteger()) + { + result = getIntValue(); + } + else if (isReal()) + { + result = atof(getRealValue().c_str()); + } + else + { + throw QEXC::Internal("getNumericValue called for non-numeric object"); + } + return result; +} + +bool +QPDFObjectHandle::isName() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isString() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isArray() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isDictionary() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isStream() +{ + dereference(); + return QPDFObjectTypeAccessor::check(obj.getPointer()); +} + +bool +QPDFObjectHandle::isIndirect() +{ + assertInitialized(); + return (this->objid != 0); +} + +bool +QPDFObjectHandle::isScalar() +{ + return (! (isArray() || isDictionary() || isStream())); +} + +// Bool accessors + +bool +QPDFObjectHandle::getBoolValue() +{ + assertType("Boolean", isBool()); + return dynamic_cast(obj.getPointer())->getVal(); +} + +// Integer accessors + +int +QPDFObjectHandle::getIntValue() +{ + assertType("Integer", isInteger()); + return dynamic_cast(obj.getPointer())->getVal(); +} + +// Real accessors + +std::string +QPDFObjectHandle::getRealValue() +{ + assertType("Real", isReal()); + return dynamic_cast(obj.getPointer())->getVal(); +} + +// Name acessors + +std::string +QPDFObjectHandle::getName() +{ + assertType("Name", isName()); + return dynamic_cast(obj.getPointer())->getName(); +} + +// String accessors + +std::string +QPDFObjectHandle::getStringValue() +{ + assertType("String", isString()); + return dynamic_cast(obj.getPointer())->getVal(); +} + +std::string +QPDFObjectHandle::getUTF8Value() +{ + assertType("String", isString()); + return dynamic_cast(obj.getPointer())->getUTF8Val(); +} + +// Array acessors + +int +QPDFObjectHandle::getArrayNItems() +{ + assertType("Array", isArray()); + return dynamic_cast(obj.getPointer())->getNItems(); +} + +QPDFObjectHandle +QPDFObjectHandle::getArrayItem(int n) +{ + assertType("Array", isArray()); + return dynamic_cast(obj.getPointer())->getItem(n); +} + +// Array mutators + +void +QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item) +{ + assertType("Array", isArray()); + return dynamic_cast(obj.getPointer())->setItem(n, item); +} + +// Dictionary accesors + +bool +QPDFObjectHandle::hasKey(std::string const& key) +{ + assertType("Dictionary", isDictionary()); + return dynamic_cast(obj.getPointer())->hasKey(key); +} + +QPDFObjectHandle +QPDFObjectHandle::getKey(std::string const& key) +{ + assertType("Dictionary", isDictionary()); + return dynamic_cast(obj.getPointer())->getKey(key); +} + +std::set +QPDFObjectHandle::getKeys() +{ + assertType("Dictionary", isDictionary()); + return dynamic_cast(obj.getPointer())->getKeys(); +} + +// Dictionary mutators + +void +QPDFObjectHandle::replaceKey(std::string const& key, + QPDFObjectHandle const& value) +{ + assertType("Dictionary", isDictionary()); + return dynamic_cast( + obj.getPointer())->replaceKey(key, value); +} + +void +QPDFObjectHandle::removeKey(std::string const& key) +{ + assertType("Dictionary", isDictionary()); + return dynamic_cast(obj.getPointer())->removeKey(key); +} + +// Stream accessors +QPDFObjectHandle +QPDFObjectHandle::getDict() +{ + assertType("Stream", isStream()); + return dynamic_cast(obj.getPointer())->getDict(); +} + +PointerHolder +QPDFObjectHandle::getStreamData() +{ + assertType("Stream", isStream()); + return dynamic_cast(obj.getPointer())->getStreamData(); +} + +bool +QPDFObjectHandle::pipeStreamData(Pipeline* p, bool filter, + bool normalize, bool compress) +{ + assertType("Stream", isStream()); + return dynamic_cast(obj.getPointer())->pipeStreamData( + p, filter, normalize, compress); +} + +int +QPDFObjectHandle::getObjectID() const +{ + return this->objid; +} + +int +QPDFObjectHandle::getGeneration() const +{ + return this->generation; +} + +std::map +QPDFObjectHandle::getPageImages() +{ + assertPageObject(); + + // 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 beacuse + // 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. + + std::map result; + if (this->hasKey("/Resources")) + { + QPDFObjectHandle resources = this->getKey("/Resources"); + if (resources.hasKey("/XObject")) + { + QPDFObjectHandle xobject = resources.getKey("/XObject"); + std::set keys = xobject.getKeys(); + for (std::set::iterator iter = keys.begin(); + iter != keys.end(); ++iter) + { + std::string key = (*iter); + QPDFObjectHandle value = xobject.getKey(key); + if (value.isStream()) + { + QPDFObjectHandle dict = value.getDict(); + if (dict.hasKey("/Subtype") && + (dict.getKey("/Subtype").getName() == "/Image") && + (! dict.hasKey("/ImageMask"))) + { + result[key] = value; + } + } + } + } + } + + return result; +} + +std::vector +QPDFObjectHandle::getPageContents() +{ + assertPageObject(); + + std::vector result; + QPDFObjectHandle contents = this->getKey("/Contents"); + if (contents.isArray()) + { + int n_items = contents.getArrayNItems(); + for (int i = 0; i < n_items; ++i) + { + QPDFObjectHandle item = contents.getArrayItem(i); + if (item.isStream()) + { + result.push_back(item); + } + else + { + throw QEXC::General("unknown item type while inspecting " + "element of /Contents array in page " + "dictionary"); + } + } + } + else if (contents.isStream()) + { + result.push_back(contents); + } + else + { + throw QEXC::General("unknown object type inspecting /Contents " + "key in page dictionary"); + } + + return result; +} + +std::string +QPDFObjectHandle::unparse() +{ + std::string result; + if (this->isIndirect()) + { + result = QUtil::int_to_string(this->objid) + " " + + QUtil::int_to_string(this->generation) + " R"; + } + else + { + result = unparseResolved(); + } + return result; +} + +std::string +QPDFObjectHandle::unparseResolved() +{ + dereference(); + return this->obj.getPointer()->unparse(); +} + +QPDFObjectHandle +QPDFObjectHandle::newIndirect(QPDF* qpdf, int objid, int generation) +{ + return QPDFObjectHandle(qpdf, objid, generation); +} + +QPDFObjectHandle +QPDFObjectHandle::newBool(bool value) +{ + return QPDFObjectHandle(new QPDF_Bool(value)); +} + +QPDFObjectHandle +QPDFObjectHandle::newNull() +{ + return QPDFObjectHandle(new QPDF_Null()); +} + +QPDFObjectHandle +QPDFObjectHandle::newInteger(int value) +{ + return QPDFObjectHandle(new QPDF_Integer(value)); +} + +QPDFObjectHandle +QPDFObjectHandle::newReal(std::string const& value) +{ + return QPDFObjectHandle(new QPDF_Real(value)); +} + +QPDFObjectHandle +QPDFObjectHandle::newName(std::string const& name) +{ + return QPDFObjectHandle(new QPDF_Name(name)); +} + +QPDFObjectHandle +QPDFObjectHandle::newString(std::string const& str) +{ + return QPDFObjectHandle(new QPDF_String(str)); +} + +QPDFObjectHandle +QPDFObjectHandle::newArray(std::vector const& items) +{ + return QPDFObjectHandle(new QPDF_Array(items)); +} + +QPDFObjectHandle +QPDFObjectHandle::newDictionary( + std::map const& items) +{ + return QPDFObjectHandle(new QPDF_Dictionary(items)); +} + + +QPDFObjectHandle +QPDFObjectHandle::newStream(QPDF* qpdf, int objid, int generation, + QPDFObjectHandle stream_dict, + off_t offset, int length) +{ + return QPDFObjectHandle(new QPDF_Stream( + qpdf, objid, generation, + stream_dict, offset, length)); +} + +void +QPDFObjectHandle::makeDirectInternal(std::set& visited) +{ + assertInitialized(); + + if (isStream()) + { + QTC::TC("qpdf", "QPDFObjectHandle ERR clone stream"); + throw QEXC::General("attempt to make a stream into a direct object"); + } + + int cur_objid = this->objid; + if (cur_objid != 0) + { + if (visited.count(cur_objid)) + { + QTC::TC("qpdf", "QPDFObjectHandle makeDirect loop"); + throw QEXC::General("loop detected while converting object from " + "indirect to direct"); + } + visited.insert(cur_objid); + } + + dereference(); + this->objid = 0; + this->generation = 0; + + QPDFObject* new_obj = 0; + + if (isBool()) + { + QTC::TC("qpdf", "QPDFObjectHandle clone bool"); + new_obj = new QPDF_Bool(getBoolValue()); + } + else if (isNull()) + { + QTC::TC("qpdf", "QPDFObjectHandle clone null"); + new_obj = new QPDF_Null(); + } + else if (isInteger()) + { + QTC::TC("qpdf", "QPDFObjectHandle clone integer"); + new_obj = new QPDF_Integer(getIntValue()); + } + else if (isReal()) + { + QTC::TC("qpdf", "QPDFObjectHandle clone real"); + new_obj = new QPDF_Real(getRealValue()); + } + else if (isName()) + { + QTC::TC("qpdf", "QPDFObjectHandle clone name"); + new_obj = new QPDF_Name(getName()); + } + else if (isString()) + { + QTC::TC("qpdf", "QPDFObjectHandle clone string"); + new_obj = new QPDF_String(getStringValue()); + } + else if (isArray()) + { + QTC::TC("qpdf", "QPDFObjectHandle clone array"); + std::vector items; + int n = getArrayNItems(); + for (int i = 0; i < n; ++i) + { + items.push_back(getArrayItem(i)); + items.back().makeDirectInternal(visited); + } + new_obj = new QPDF_Array(items); + } + else if (isDictionary()) + { + QTC::TC("qpdf", "QPDFObjectHandle clone dictionary"); + std::set keys = getKeys(); + std::map items; + for (std::set::iterator iter = keys.begin(); + iter != keys.end(); ++iter) + { + items[*iter] = getKey(*iter); + items[*iter].makeDirectInternal(visited); + } + new_obj = new QPDF_Dictionary(items); + } + else + { + throw QEXC::Internal("QPDFObjectHandle::makeIndirect: " + "unknown object type"); + } + + this->obj = new_obj; + + if (cur_objid) + { + visited.erase(cur_objid); + } +} + +void +QPDFObjectHandle::makeDirect() +{ + std::set visited; + makeDirectInternal(visited); +} + +void +QPDFObjectHandle::assertInitialized() const +{ + if (! this->initialized) + { + throw QEXC::Internal("operation attempted on uninitialized " + "QPDFObjectHandle"); + } +} + +void +QPDFObjectHandle::assertType(char const* type_name, bool istype) +{ + if (! istype) + { + throw QEXC::Internal(std::string("operation for ") + type_name + + " object attempted on object of wrong type"); + } +} + +void +QPDFObjectHandle::assertPageObject() +{ + if (! (this->isDictionary() && this->hasKey("/Type") && + (this->getKey("/Type").getName() == "/Page"))) + { + throw QEXC::Internal("page operation called on non-Page object"); + } +} + +void +QPDFObjectHandle::dereference() +{ + if (this->obj.getPointer() == 0) + { + this->obj = QPDF::Resolver::resolve( + this->qpdf, this->objid, this->generation); + if (this->obj.getPointer() == 0) + { + QTC::TC("qpdf", "QPDFObjectHandle indirect to unknown"); + this->obj = new QPDF_Null(); + } + } +} -- cgit v1.2.3-70-g09d2