diff --git a/include/qpdf/Constants.h b/include/qpdf/Constants.h index d009e3e..fe19448 100644 --- a/include/qpdf/Constants.h +++ b/include/qpdf/Constants.h @@ -126,6 +126,7 @@ enum qpdf_object_type_e { /* Object types internal to qpdf */ ot_unresolved, ot_destroyed, + ot_reference, }; /* Write Parameters. See QPDFWriter.hh for details. */ diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 9721d63..089cc59 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1087,7 +1087,8 @@ class QPDF QPDFObjGen og, std::shared_ptr const& object, qpdf_offset_t end_before_space, - qpdf_offset_t end_after_space); + qpdf_offset_t end_after_space, + bool destroy = true); static QPDFExc damagedPDF( InputSource& input, std::string const& object, diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 068083f..c525e77 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1254,8 +1254,7 @@ class QPDFObjectHandle final: public qpdf::BaseHandle // Provide access to specific classes for recursive disconnected(). class DisconnectAccess { - friend class QPDF_Dictionary; - friend class QPDF_Stream; + friend class QPDFObject; private: static void diff --git a/include/qpdf/QPDFObjectHandle_future.hh b/include/qpdf/QPDFObjectHandle_future.hh deleted file mode 100644 index e69de29..0000000 --- a/include/qpdf/QPDFObjectHandle_future.hh +++ /dev/null diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt index 5480f12..ce60238 100644 --- a/libqpdf/CMakeLists.txt +++ b/libqpdf/CMakeLists.txt @@ -86,23 +86,12 @@ set(libqpdf_SOURCES QPDFSystemError.cc QPDFTokenizer.cc QPDFUsage.cc - QPDFValue.cc QPDFWriter.cc QPDFXRefEntry.cc QPDF_Array.cc - QPDF_Bool.cc - QPDF_Destroyed.cc QPDF_Dictionary.cc - QPDF_InlineImage.cc - QPDF_Integer.cc - QPDF_Name.cc - QPDF_Null.cc - QPDF_Operator.cc - QPDF_Real.cc - QPDF_Reserved.cc QPDF_Stream.cc QPDF_String.cc - QPDF_Unresolved.cc QPDF_encryption.cc QPDF_json.cc QPDF_linearization.cc diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 6602fa1..3c6324c 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -20,11 +20,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include @@ -1565,7 +1560,7 @@ QPDF::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) throw; } } - object = {QPDF_Stream::create(this, og, object, stream_offset, length)}; + object = QPDFObjectHandle(qpdf::Stream(*this, og, object, stream_offset, length)); } void @@ -1884,7 +1879,7 @@ QPDF::resolve(QPDFObjGen og) // has to be resolved during object parsing, such as stream length. QTC::TC("qpdf", "QPDF recursion loop in resolve"); warn(damagedPDF("", "loop detected resolving object " + og.unparse(' '))); - updateCache(og, QPDF_Null::create(), -1, -1); + updateCache(og, QPDFObject::create(), -1, -1); return m->obj_cache[og].object.get(); } ResolveRecorder rr(this, og); @@ -1921,7 +1916,7 @@ QPDF::resolve(QPDFObjGen og) if (isUnresolved(og)) { // PDF spec says unknown objects resolve to the null object. QTC::TC("qpdf", "QPDF resolve failure to null"); - updateCache(og, QPDF_Null::create(), -1, -1); + updateCache(og, QPDFObject::create(), -1, -1); } auto result(m->obj_cache[og].object); @@ -2034,12 +2029,13 @@ QPDF::updateCache( QPDFObjGen og, std::shared_ptr const& object, qpdf_offset_t end_before_space, - qpdf_offset_t end_after_space) + qpdf_offset_t end_after_space, + bool destroy) { object->setObjGen(this, og); if (isCached(og)) { auto& cache = m->obj_cache[og]; - cache.object->assign(object); + object->move_to(cache.object, destroy); cache.end_before_space = end_before_space; cache.end_after_space = end_after_space; } else { @@ -2089,20 +2085,20 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) QPDFObjectHandle QPDF::newReserved() { - return makeIndirectFromQPDFObject(QPDF_Reserved::create()); + return makeIndirectFromQPDFObject(QPDFObject::create()); } QPDFObjectHandle QPDF::newIndirectNull() { - return makeIndirectFromQPDFObject(QPDF_Null::create()); + return makeIndirectFromQPDFObject(QPDFObject::create()); } QPDFObjectHandle QPDF::newStream() { - return makeIndirectFromQPDFObject( - QPDF_Stream::create(this, nextObjGen(), QPDFObjectHandle::newDictionary(), 0, 0)); + return makeIndirectObject( + qpdf::Stream(*this, nextObjGen(), QPDFObjectHandle::newDictionary(), 0, 0)); } QPDFObjectHandle @@ -2130,12 +2126,13 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf) return iter->second.object; } if (m->xref_table.count(og) || !m->parsed) { - return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object; + return m->obj_cache.insert({og, QPDFObject::create(this, og)}) + .first->second.object; } if (parse_pdf) { - return QPDF_Null::create(); + return QPDFObject::create(); } - return m->obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object; + return m->obj_cache.insert({og, QPDFObject::create(this, og)}).first->second.object; } std::shared_ptr @@ -2145,8 +2142,9 @@ QPDF::getObjectForJSON(int id, int gen) auto [it, inserted] = m->obj_cache.try_emplace(og); auto& obj = it->second.object; if (inserted) { - obj = (m->parsed && !m->xref_table.count(og)) ? QPDF_Null::create(this, og) - : QPDF_Unresolved::create(this, og); + obj = (m->parsed && !m->xref_table.count(og)) + ? QPDFObject::create(this, og) + : QPDFObject::create(this, og); } return obj; } @@ -2157,9 +2155,10 @@ QPDF::getObject(QPDFObjGen og) if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) { return {it->second.object}; } else if (m->parsed && !m->xref_table.count(og)) { - return QPDF_Null::create(); + return QPDFObject::create(); } else { - auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1); + auto result = + m->obj_cache.try_emplace(og, QPDFObject::create(this, og), -1, -1); return {result.first->second.object}; } } @@ -2195,7 +2194,7 @@ QPDF::replaceObject(QPDFObjGen og, QPDFObjectHandle oh) QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); throw std::logic_error("QPDF::replaceObject called with indirect object handle"); } - updateCache(og, oh.getObj(), -1, -1); + updateCache(og, oh.getObj(), -1, -1, false); } void @@ -2204,7 +2203,7 @@ QPDF::removeObject(QPDFObjGen og) m->xref_table.erase(og); if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) { // Take care of any object handles that may be floating around. - cached->second.object->assign(QPDF_Null::create()); + cached->second.object->assign_null(); cached->second.object->setObjGen(nullptr, QPDFObjGen()); m->obj_cache.erase(cached); } diff --git a/libqpdf/QPDFObject.cc b/libqpdf/QPDFObject.cc index 7e3cc21..a5cb986 100644 --- a/libqpdf/QPDFObject.cc +++ b/libqpdf/QPDFObject.cc @@ -1,10 +1,52 @@ #include -#include -#include - -void -QPDFObject::destroy() +std::string +QPDFObject::getDescription() { - value = QPDF_Destroyed::getInstance(); + if (object_description) { + switch (object_description->index()) { + case 0: + { + // Simple template string + auto description = std::get<0>(*object_description); + + if (auto pos = description.find("$OG"); pos != std::string::npos) { + description.replace(pos, 3, og.unparse(' ')); + } + if (auto pos = description.find("$PO"); pos != std::string::npos) { + qpdf_offset_t shift = (getTypeCode() == ::ot_dictionary) ? 2 + : (getTypeCode() == ::ot_array) ? 1 + : 0; + + description.replace(pos, 3, std::to_string(parsed_offset + shift)); + } + return description; + } + case 1: + { + // QPDF::JSONReactor generated description + auto j_descr = std::get<1>(*object_description); + return ( + *j_descr.input + (j_descr.object.empty() ? "" : ", " + j_descr.object) + + " at offset " + std::to_string(parsed_offset)); + } + case 2: + { + // Child object description + auto j_descr = std::get<2>(*object_description); + std::string result; + if (auto p = j_descr.parent.lock()) { + result = p->getDescription(); + } + result += j_descr.static_descr; + if (auto pos = result.find("$VD"); pos != std::string::npos) { + result.replace(pos, 3, j_descr.var_descr); + } + return result; + } + } + } else if (og.isIndirect()) { + return "object " + og.unparse(' '); + } + return {}; } diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 71ad050..db6f35f 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -11,19 +11,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -228,6 +215,443 @@ LastChar::getLastChar() return this->last_char; } +std::pair +Name::analyzeJSONEncoding(const std::string& name) +{ + int tail = 0; // Number of continuation characters expected. + bool tail2 = false; // Potential overlong 3 octet utf-8. + bool tail3 = false; // potential overlong 4 octet + bool needs_escaping = false; + for (auto const& it: name) { + auto c = static_cast(it); + if (tail) { + if ((c & 0xc0) != 0x80) { + return {false, false}; + } + if (tail2) { + if ((c & 0xe0) == 0x80) { + return {false, false}; + } + tail2 = false; + } else if (tail3) { + if ((c & 0xf0) == 0x80) { + return {false, false}; + } + tail3 = false; + } + tail--; + } else if (c < 0x80) { + if (!needs_escaping) { + needs_escaping = !((c > 34 && c != '\\') || c == ' ' || c == 33); + } + } else if ((c & 0xe0) == 0xc0) { + if ((c & 0xfe) == 0xc0) { + return {false, false}; + } + tail = 1; + } else if ((c & 0xf0) == 0xe0) { + tail2 = (c == 0xe0); + tail = 2; + } else if ((c & 0xf8) == 0xf0) { + tail3 = (c == 0xf0); + tail = 3; + } else { + return {false, false}; + } + } + return {tail == 0, !needs_escaping}; +} + +std::string +Name::normalize(std::string const& name) +{ + if (name.empty()) { + return name; + } + std::string result; + result += name.at(0); + for (size_t i = 1; i < name.length(); ++i) { + char ch = name.at(i); + // Don't use locale/ctype here; follow PDF spec guidelines. + if (ch == '\0') { + // QPDFTokenizer embeds a null character to encode an invalid #. + result += "#"; + } else if ( + ch < 33 || ch == '#' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' || + ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch > 126) { + result += QUtil::hex_encode_char(ch); + } else { + result += ch; + } + } + return result; +} + +std::shared_ptr +QPDFObject::copy(bool shallow) +{ + switch (getResolvedTypeCode()) { + case ::ot_uninitialized: + throw std::logic_error("QPDFObjectHandle: attempting to copy an uninitialized object"); + return {}; // does not return + case ::ot_reserved: + return create(); + case ::ot_null: + return create(); + case ::ot_boolean: + return create(std::get(value).val); + case ::ot_integer: + return create(std::get(value).val); + case ::ot_real: + return create(std::get(value).val); + case ::ot_string: + return create(std::get(value).val); + case ::ot_name: + return create(std::get(value).name); + case ::ot_array: + { + auto const& a = std::get(value); + if (shallow) { + return QPDFObject::create(a); + } else { + QTC::TC("qpdf", "QPDF_Array copy", a.sp ? 0 : 1); + if (a.sp) { + QPDF_Array result; + result.sp = std::make_unique(); + result.sp->size = a.sp->size; + for (auto const& element: a.sp->elements) { + auto const& obj = element.second; + result.sp->elements[element.first] = + obj->getObjGen().isIndirect() ? obj : obj->copy(); + } + return QPDFObject::create(std::move(result)); + } else { + std::vector> result; + result.reserve(a.elements.size()); + for (auto const& element: a.elements) { + result.push_back( + element + ? (element->getObjGen().isIndirect() ? element : element->copy()) + : element); + } + return QPDFObject::create(std::move(result), false); + } + } + } + case ::ot_dictionary: + { + auto const& d = std::get(value); + if (shallow) { + return QPDFObject::create(d.items); + } else { + std::map new_items; + for (auto const& [key, val]: d.items) { + new_items[key] = val.isIndirect() ? val : val.getObj()->copy(); + } + return QPDFObject::create(new_items); + } + } + case ::ot_stream: + QTC::TC("qpdf", "QPDF_Stream ERR shallow copy stream"); + throw std::runtime_error("stream objects cannot be cloned"); + return {}; // does not return + case ::ot_operator: + return create(std::get(value).val); + case ::ot_inlineimage: + return create(std::get(value).val); + case ::ot_unresolved: + throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object"); + return {}; // does not return + case ::ot_destroyed: + throw std::logic_error("attempted to shallow copy QPDFObjectHandle from destroyed QPDF"); + return {}; // does not return + case ::ot_reference: + return qpdf->getObject(og).getObj(); + } + return {}; // does not return +} + +std::string +QPDFObject::unparse() +{ + switch (getResolvedTypeCode()) { + case ::ot_uninitialized: + throw std::logic_error("QPDFObjectHandle: attempting to unparse an uninitialized object"); + return ""; // does not return + case ::ot_reserved: + throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object"); + return ""; // does not return + case ::ot_null: + return "null"; + case ::ot_boolean: + return std::get(value).val ? "true" : "false"; + case ::ot_integer: + return std::to_string(std::get(value).val); + case ::ot_real: + return std::get(value).val; + case ::ot_string: + return std::get(value).unparse(false); + case ::ot_name: + return Name::normalize(std::get(value).name); + case ::ot_array: + { + auto const& a = std::get(value); + std::string result = "[ "; + if (a.sp) { + int next = 0; + for (auto& item: a.sp->elements) { + int key = item.first; + for (int j = next; j < key; ++j) { + result += "null "; + } + auto item_og = item.second->resolved_object()->getObjGen(); + result += item_og.isIndirect() ? item_og.unparse(' ') + " R " + : item.second->unparse() + " "; + next = ++key; + } + for (int j = next; j < a.sp->size; ++j) { + result += "null "; + } + } else { + for (auto const& item: a.elements) { + auto item_og = item->resolved_object()->getObjGen(); + result += + item_og.isIndirect() ? item_og.unparse(' ') + " R " : item->unparse() + " "; + } + } + result += "]"; + return result; + } + case ::ot_dictionary: + { + auto const& items = std::get(value).items; + std::string result = "<< "; + for (auto& iter: items) { + if (!iter.second.isNull()) { + result += Name::normalize(iter.first) + " " + iter.second.unparse() + " "; + } + } + result += ">>"; + return result; + } + case ::ot_stream: + return og.unparse(' ') + " R"; + case ::ot_operator: + return std::get(value).val; + case ::ot_inlineimage: + return std::get(value).val; + case ::ot_unresolved: + throw std::logic_error("QPDFObjectHandle: attempting to unparse a unresolved object"); + return ""; // does not return + case ::ot_destroyed: + throw std::logic_error("attempted to unparse a QPDFObjectHandle from a destroyed QPDF"); + return ""; // does not return + case ::ot_reference: + return og.unparse(' ') + " R"; + } + return {}; // does not return +} + +void +QPDFObject::write_json(int json_version, JSON::Writer& p) +{ + switch (getResolvedTypeCode()) { + case ::ot_uninitialized: + throw std::logic_error( + "QPDFObjectHandle: attempting to get JSON from a uninitialized object"); + break; // unreachable + case ::ot_null: + case ::ot_operator: + case ::ot_inlineimage: + p << "null"; + break; + case ::ot_boolean: + p << std::get(value).val; + break; + case ::ot_integer: + p << std::to_string(std::get(value).val); + break; + case ::ot_real: + { + auto const& val = std::get(value).val; + if (val.length() == 0) { + // Can't really happen... + p << "0"; + } else if (val.at(0) == '.') { + p << "0" << val; + } else if (val.length() >= 2 && val.at(0) == '-' && val.at(1) == '.') { + p << "-0." << val.substr(2); + } else { + p << val; + } + if (val.back() == '.') { + p << "0"; + } + } + break; + case ::ot_string: + std::get(value).writeJSON(json_version, p); + break; + case ::ot_name: + { + auto const& n = std::get(value); + // For performance reasons this code is duplicated in QPDF_Dictionary::writeJSON. When + // updating this method make sure QPDF_Dictionary is also update. + if (json_version == 1) { + p << "\"" << JSON::Writer::encode_string(Name::normalize(n.name)) << "\""; + } else { + if (auto res = Name::analyzeJSONEncoding(n.name); res.first) { + if (res.second) { + p << "\"" << n.name << "\""; + } else { + p << "\"" << JSON::Writer::encode_string(n.name) << "\""; + } + } else { + p << "\"n:" << JSON::Writer::encode_string(Name::normalize(n.name)) << "\""; + } + } + } + break; + case ::ot_array: + { + auto const& a = std::get(value); + p.writeStart('['); + if (a.sp) { + int next = 0; + for (auto& item: a.sp->elements) { + int key = item.first; + for (int j = next; j < key; ++j) { + p.writeNext() << "null"; + } + p.writeNext(); + auto item_og = item.second->getObjGen(); + if (item_og.isIndirect()) { + p << "\"" << item_og.unparse(' ') << " R\""; + } else { + item.second->write_json(json_version, p); + } + next = ++key; + } + for (int j = next; j < a.sp->size; ++j) { + p.writeNext() << "null"; + } + } else { + for (auto const& item: a.elements) { + p.writeNext(); + auto item_og = item->getObjGen(); + if (item_og.isIndirect()) { + p << "\"" << item_og.unparse(' ') << " R\""; + } else { + item->write_json(json_version, p); + } + } + } + p.writeEnd(']'); + } + break; + case ::ot_dictionary: + { + auto const& d = std::get(value); + p.writeStart('{'); + for (auto& iter: d.items) { + if (!iter.second.isNull()) { + p.writeNext(); + if (json_version == 1) { + p << "\"" << JSON::Writer::encode_string(Name::normalize(iter.first)) + << "\": "; + } else if (auto res = Name::analyzeJSONEncoding(iter.first); res.first) { + if (res.second) { + p << "\"" << iter.first << "\": "; + } else { + p << "\"" << JSON::Writer::encode_string(iter.first) << "\": "; + } + } else { + p << "\"n:" << JSON::Writer::encode_string(Name::normalize(iter.first)) + << "\": "; + } + iter.second.writeJSON(json_version, p); + } + } + p.writeEnd('}'); + } + break; + case ::ot_stream: + std::get(value).m->stream_dict.writeJSON(json_version, p); + break; + case ::ot_reference: + p << "\"" << getObjGen().unparse(' ') << " R\""; + break; + default: + throw std::logic_error("attempted to write an unsuitable object as JSON"); + } +} + +void +QPDFObject::disconnect() +{ + // Disconnect an object from its owning QPDF. This is called by QPDF's destructor. + + switch (getTypeCode()) { + case ::ot_array: + { + auto& a = std::get(value); + if (a.sp) { + for (auto& item: a.sp->elements) { + auto& obj = item.second; + if (!obj->getObjGen().isIndirect()) { + obj->disconnect(); + } + } + } else { + for (auto& obj: a.elements) { + if (!obj->getObjGen().isIndirect()) { + obj->disconnect(); + } + } + } + } + break; + case ::ot_dictionary: + for (auto& iter: std::get(value).items) { + QPDFObjectHandle::DisconnectAccess::disconnect(iter.second); + } + break; + case ::ot_stream: + { + auto& s = std::get(value); + s.m->stream_provider = nullptr; + QPDFObjectHandle::DisconnectAccess::disconnect(s.m->stream_dict); + } + break; + default: + break; + } + qpdf = nullptr; + og = QPDFObjGen(); +} +std::string +QPDFObject::getStringValue() const +{ + switch (getResolvedTypeCode()) { + case ::ot_real: + return std::get(value).val; + case ::ot_string: + return std::get(value).val; + case ::ot_name: + return std::get(value).name; + case ::ot_operator: + return std::get(value).val; + case ::ot_inlineimage: + return std::get(value).val; + case ::ot_reference: + return std::get(value).obj->getStringValue(); + default: + throw std::logic_error("Internal error in QPDFObject::getStringValue"); + return ""; // does not return + } + return {}; // does not return +} + bool QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const { @@ -253,7 +677,7 @@ QPDFObjectHandle::getTypeCode() const char const* QPDFObjectHandle::getTypeName() const { - static constexpr std::array tn{ + static constexpr std::array tn{ "uninitialized", "reserved", "null", @@ -268,84 +692,23 @@ QPDFObjectHandle::getTypeName() const "operator", "inline-image", "unresolved", - "destroyed"}; + "destroyed", + "reference"}; return obj ? tn[getTypeCode()] : "uninitialized"; } -QPDF_Array* -QPDFObjectHandle::asArray() const -{ - return obj ? obj->as() : nullptr; -} - QPDF_Bool* QPDFObjectHandle::asBool() const { return obj ? obj->as() : nullptr; } -QPDF_Dictionary* -QPDFObjectHandle::asDictionary() const -{ - return obj ? obj->as() : nullptr; -} - -QPDF_InlineImage* -QPDFObjectHandle::asInlineImage() const -{ - return obj ? obj->as() : nullptr; -} - QPDF_Integer* QPDFObjectHandle::asInteger() const { return obj ? obj->as() : nullptr; } -QPDF_Name* -QPDFObjectHandle::asName() const -{ - return obj ? obj->as() : nullptr; -} - -QPDF_Null* -QPDFObjectHandle::asNull() const -{ - return obj ? obj->as() : nullptr; -} - -QPDF_Operator* -QPDFObjectHandle::asOperator() const -{ - return obj ? obj->as() : nullptr; -} - -QPDF_Real* -QPDFObjectHandle::asReal() const -{ - return obj ? obj->as() : nullptr; -} - -QPDF_Reserved* -QPDFObjectHandle::asReserved() const -{ - return obj ? obj->as() : nullptr; -} - -QPDF_Stream* -QPDFObjectHandle::asStream() const -{ - return obj ? obj->as() : nullptr; -} - -QPDF_Stream* -QPDFObjectHandle::asStreamWithAssert() const -{ - auto stream = asStream(); - assertType("stream", stream); - return stream; -} - QPDF_String* QPDFObjectHandle::asString() const { @@ -500,7 +863,7 @@ QPDFObjectHandle::getBoolValue() const { auto boolean = asBool(); if (boolean) { - return boolean->getVal(); + return boolean->val; } else { typeWarning("boolean", "returning false"); QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); @@ -515,7 +878,7 @@ QPDFObjectHandle::getValueAsBool(bool& value) const if (boolean == nullptr) { return false; } - value = boolean->getVal(); + value = boolean->val; return true; } @@ -526,7 +889,7 @@ QPDFObjectHandle::getIntValue() const { auto integer = asInteger(); if (integer) { - return integer->getVal(); + return integer->val; } else { typeWarning("integer", "returning 0"); QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); @@ -541,7 +904,7 @@ QPDFObjectHandle::getValueAsInt(long long& value) const if (integer == nullptr) { return false; } - value = integer->getVal(); + value = integer->val; return true; } @@ -1155,7 +1518,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_ } else if (!obj) { throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); } else { - obj->writeJSON(json_version, p); + obj->write_json(json_version, p); } } @@ -1392,43 +1755,43 @@ QPDFObjectHandle::getParsedOffset() const QPDFObjectHandle QPDFObjectHandle::newBool(bool value) { - return {QPDF_Bool::create(value)}; + return {QPDFObject::create(value)}; } QPDFObjectHandle QPDFObjectHandle::newNull() { - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } QPDFObjectHandle QPDFObjectHandle::newInteger(long long value) { - return {QPDF_Integer::create(value)}; + return {QPDFObject::create(value)}; } QPDFObjectHandle QPDFObjectHandle::newReal(std::string const& value) { - return {QPDF_Real::create(value)}; + return {QPDFObject::create(value)}; } QPDFObjectHandle QPDFObjectHandle::newReal(double value, int decimal_places, bool trim_trailing_zeroes) { - return {QPDF_Real::create(value, decimal_places, trim_trailing_zeroes)}; + return {QPDFObject::create(value, decimal_places, trim_trailing_zeroes)}; } QPDFObjectHandle QPDFObjectHandle::newName(std::string const& name) { - return {QPDF_Name::create(name)}; + return {QPDFObject::create(name)}; } QPDFObjectHandle QPDFObjectHandle::newString(std::string const& str) { - return {QPDF_String::create(str)}; + return {QPDFObject::create(str)}; } QPDFObjectHandle @@ -1440,13 +1803,13 @@ QPDFObjectHandle::newUnicodeString(std::string const& utf8_str) QPDFObjectHandle QPDFObjectHandle::newOperator(std::string const& value) { - return {QPDF_Operator::create(value)}; + return {QPDFObject::create(value)}; } QPDFObjectHandle QPDFObjectHandle::newInlineImage(std::string const& value) { - return {QPDF_InlineImage::create(value)}; + return {QPDFObject::create(value)}; } QPDFObjectHandle @@ -1458,7 +1821,7 @@ QPDFObjectHandle::newArray() QPDFObjectHandle QPDFObjectHandle::newArray(std::vector const& items) { - return {QPDF_Array::create(items)}; + return {QPDFObject::create(items)}; } QPDFObjectHandle @@ -1518,7 +1881,7 @@ QPDFObjectHandle::newDictionary() QPDFObjectHandle QPDFObjectHandle::newDictionary(std::map const& items) { - return {QPDF_Dictionary::create(items)}; + return {QPDFObject::create(items)}; } QPDFObjectHandle @@ -1564,7 +1927,7 @@ void QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) { if (obj) { - auto descr = std::make_shared(object_description); + auto descr = std::make_shared(object_description); obj->setDescription(owning_qpdf, descr); } } @@ -1614,7 +1977,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set& visited, bool stop_at_streams) items.emplace_back(array.at(i).second); items.back().makeDirect(visited, stop_at_streams); } - this->obj = QPDF_Array::create(items); + this->obj = QPDFObject::create(items); } else if (isDictionary()) { std::map items; auto dict = as_dictionary(strict); @@ -1622,7 +1985,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set& visited, bool stop_at_streams) items[key] = dict.getKey(key); items[key].makeDirect(visited, stop_at_streams); } - this->obj = QPDF_Dictionary::create(items); + this->obj = QPDFObject::create(items); } else if (isStream()) { QTC::TC("qpdf", "QPDFObjectHandle copy stream", stop_at_streams ? 0 : 1); if (!stop_at_streams) { diff --git a/libqpdf/QPDFParser.cc b/libqpdf/QPDFParser.cc index 4e9de63..eafe6de 100644 --- a/libqpdf/QPDFParser.cc +++ b/libqpdf/QPDFParser.cc @@ -4,18 +4,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -47,27 +35,27 @@ QPDFParser::parse(bool& empty, bool content_stream) } QTC::TC("qpdf", "QPDFParser eof in parse"); warn("unexpected EOF"); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; case QPDFTokenizer::tt_bad: QTC::TC("qpdf", "QPDFParser bad token in parse"); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; case QPDFTokenizer::tt_brace_open: case QPDFTokenizer::tt_brace_close: QTC::TC("qpdf", "QPDFParser bad brace"); warn("treating unexpected brace token as null"); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; case QPDFTokenizer::tt_array_close: QTC::TC("qpdf", "QPDFParser bad array close"); warn("treating unexpected array close token as null"); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; case QPDFTokenizer::tt_dict_close: QTC::TC("qpdf", "QPDFParser bad dictionary close"); warn("unexpected dictionary close token"); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; case QPDFTokenizer::tt_array_open: case QPDFTokenizer::tt_dict_open: @@ -82,7 +70,7 @@ QPDFParser::parse(bool& empty, bool content_stream) return withDescription(tokenizer.getValue() == "true"); case QPDFTokenizer::tt_null: - return {QPDF_Null::create()}; + return {QPDFObject::create()}; case QPDFTokenizer::tt_integer: return withDescription(QUtil::string_to_ll(tokenizer.getValue().c_str())); @@ -103,7 +91,7 @@ QPDFParser::parse(bool& empty, bool content_stream) // not move the input source's offset. input.seek(input.getLastOffset(), SEEK_SET); empty = true; - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } else { QTC::TC("qpdf", "QPDFParser treat word as string"); warn("unknown token while reading object; treating as string"); @@ -122,7 +110,7 @@ QPDFParser::parse(bool& empty, bool content_stream) default: warn("treating unknown token type as null while reading object"); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } } @@ -194,12 +182,12 @@ QPDFParser::parseRemainder(bool content_stream) } QTC::TC("qpdf", "QPDFParser eof in parseRemainder"); warn("unexpected EOF"); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; case QPDFTokenizer::tt_bad: QTC::TC("qpdf", "QPDFParser bad token in parseRemainder"); if (tooManyBadTokens()) { - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } addNull(); continue; @@ -209,7 +197,7 @@ QPDFParser::parseRemainder(bool content_stream) QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder"); warn("treating unexpected brace token as null"); if (tooManyBadTokens()) { - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } addNull(); continue; @@ -218,10 +206,11 @@ QPDFParser::parseRemainder(bool content_stream) if (bad_count && !max_bad_count) { // Trigger warning. (void)tooManyBadTokens(); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } if (frame->state == st_array) { - auto object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100); + auto object = QPDFObject::create( + std::move(frame->olist), frame->null_count > 100); setDescription(object, frame->offset - 1); // The `offset` points to the next of "[". Set the rewind offset to point to the // beginning of "[". This has been explicitly tested with whitespace surrounding the @@ -237,7 +226,7 @@ QPDFParser::parseRemainder(bool content_stream) QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); warn("treating unexpected array close token as null"); if (tooManyBadTokens()) { - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } addNull(); } @@ -247,7 +236,7 @@ QPDFParser::parseRemainder(bool content_stream) if (bad_count && !max_bad_count) { // Trigger warning. (void)tooManyBadTokens(); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } if (frame->state <= st_dictionary_value) { // Attempt to recover more or less gracefully from invalid dictionaries. @@ -258,7 +247,7 @@ QPDFParser::parseRemainder(bool content_stream) warn( frame->offset, "dictionary ended prematurely; using null as value for last key"); - dict[frame->key] = QPDF_Null::create(); + dict[frame->key] = QPDFObject::create(); } if (!frame->olist.empty()) { @@ -271,7 +260,7 @@ QPDFParser::parseRemainder(bool content_stream) dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string); dict["/Contents"].setParsedOffset(frame->contents_offset); } - auto object = QPDF_Dictionary::create(std::move(dict)); + auto object = QPDFObject::create(std::move(dict)); setDescription(object, frame->offset - 2); // The `offset` points to the next of "<<". Set the rewind offset to point to the // beginning of "<<". This has been explicitly tested with whitespace surrounding @@ -287,7 +276,7 @@ QPDFParser::parseRemainder(bool content_stream) QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder"); warn("unexpected dictionary close token"); if (tooManyBadTokens()) { - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } addNull(); } @@ -298,7 +287,7 @@ QPDFParser::parseRemainder(bool content_stream) if (stack.size() > 499) { QTC::TC("qpdf", "QPDFParser too deep"); warn("ignoring excessively deeply nested data structure"); - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } else { b_contents = false; stack.emplace_back( @@ -350,7 +339,7 @@ QPDFParser::parseRemainder(bool content_stream) QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); warn("unknown token while reading object; treating as string"); if (tooManyBadTokens()) { - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } addScalar(tokenizer.getValue()); } @@ -377,7 +366,7 @@ QPDFParser::parseRemainder(bool content_stream) default: warn("treating unknown token type as null while reading object"); if (tooManyBadTokens()) { - return {QPDF_Null::create()}; + return {QPDFObject::create()}; } addNull(); } @@ -402,7 +391,7 @@ QPDFParser::add(std::shared_ptr&& obj) void QPDFParser::addNull() { - const static ObjectPtr null_obj = QPDF_Null::create(); + const static ObjectPtr null_obj = QPDFObject::create(); if (frame->state != st_dictionary_value) { // If state is st_dictionary_key then there is a missing key. Push onto olist for @@ -420,7 +409,7 @@ QPDFParser::addNull() void QPDFParser::addInt(int count) { - auto obj = QPDF_Integer::create(int_buffer[count % 2]); + auto obj = QPDFObject::create(int_buffer[count % 2]); obj->setDescription(context, description, last_offset_buffer[count % 2]); add(std::move(obj)); } @@ -435,7 +424,7 @@ QPDFParser::addScalar(Args&&... args) max_bad_count = 0; return; } - auto obj = T::create(args...); + auto obj = QPDFObject::create(std::forward(args)...); obj->setDescription(context, description, input.getLastOffset()); add(std::move(obj)); } @@ -444,7 +433,7 @@ template QPDFObjectHandle QPDFParser::withDescription(Args&&... args) { - auto obj = T::create(args...); + auto obj = QPDFObject::create(std::forward(args)...); obj->setDescription(context, description, start); return {obj}; } diff --git a/libqpdf/QPDFValue.cc b/libqpdf/QPDFValue.cc deleted file mode 100644 index 3441223..0000000 --- a/libqpdf/QPDFValue.cc +++ /dev/null @@ -1,62 +0,0 @@ -#include - -#include - -std::shared_ptr -QPDFValue::do_create(QPDFValue* object) -{ - std::shared_ptr obj(new QPDFObject()); - obj->value = std::shared_ptr(object); - return obj; -} - -std::string -QPDFValue::getDescription() -{ - if (object_description) { - switch (object_description->index()) { - case 0: - { - // Simple template string - auto description = std::get<0>(*object_description); - - if (auto pos = description.find("$OG"); pos != std::string::npos) { - description.replace(pos, 3, og.unparse(' ')); - } - if (auto pos = description.find("$PO"); pos != std::string::npos) { - qpdf_offset_t shift = (type_code == ::ot_dictionary) ? 2 - : (type_code == ::ot_array) ? 1 - : 0; - - description.replace(pos, 3, std::to_string(parsed_offset + shift)); - } - return description; - } - case 1: - { - // QPDF::JSONReactor generated description - auto j_descr = std::get<1>(*object_description); - return ( - *j_descr.input + (j_descr.object.empty() ? "" : ", " + j_descr.object) + - " at offset " + std::to_string(parsed_offset)); - } - case 2: - { - // Child object description - auto j_descr = std::get<2>(*object_description); - std::string result; - if (auto p = j_descr.parent.lock()) { - result = p->getDescription(); - } - result += j_descr.static_descr; - if (auto pos = result.find("$VD"); pos != std::string::npos) { - result.replace(pos, 3, j_descr.var_descr); - } - return result; - } - } - } else if (og.isIndirect()) { - return "object " + og.unparse(' '); - } - return {}; -} diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index beb0279..f1cf511 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -16,8 +16,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/libqpdf/QPDF_Array.cc b/libqpdf/QPDF_Array.cc index c29fd28..8ca7ed9 100644 --- a/libqpdf/QPDF_Array.cc +++ b/libqpdf/QPDF_Array.cc @@ -1,9 +1,5 @@ -#include - -#include #include -#include -#include + #include using namespace std::literals; @@ -40,25 +36,12 @@ Array::checkOwnership(QPDFObjectHandle const& item) const } } -QPDF_Array::QPDF_Array() : - QPDFValue(::ot_array) -{ -} - -QPDF_Array::QPDF_Array(QPDF_Array const& other) : - QPDFValue(::ot_array), - sp(other.sp ? std::make_unique(*other.sp) : nullptr) -{ -} - -QPDF_Array::QPDF_Array(std::vector const& v) : - QPDFValue(::ot_array) +QPDF_Array::QPDF_Array(std::vector const& v) { setFromVector(v); } -QPDF_Array::QPDF_Array(std::vector>&& v, bool sparse) : - QPDFValue(::ot_array) +QPDF_Array::QPDF_Array(std::vector>&& v, bool sparse) { if (sparse) { sp = std::make_unique(); @@ -73,132 +56,6 @@ QPDF_Array::QPDF_Array(std::vector>&& v, bool sparse } } -std::shared_ptr -QPDF_Array::create(std::vector const& items) -{ - return do_create(new QPDF_Array(items)); -} - -std::shared_ptr -QPDF_Array::create(std::vector>&& items, bool sparse) -{ - return do_create(new QPDF_Array(std::move(items), sparse)); -} - -std::shared_ptr -QPDF_Array::copy(bool shallow) -{ - if (shallow) { - return do_create(new QPDF_Array(*this)); - } else { - QTC::TC("qpdf", "QPDF_Array copy", sp ? 0 : 1); - if (sp) { - auto* result = new QPDF_Array(); - result->sp = std::make_unique(); - result->sp->size = sp->size; - for (auto const& element: sp->elements) { - auto const& obj = element.second; - result->sp->elements[element.first] = - obj->getObjGen().isIndirect() ? obj : obj->copy(); - } - return do_create(result); - } else { - std::vector> result; - result.reserve(elements.size()); - for (auto const& element: elements) { - result.push_back( - element ? (element->getObjGen().isIndirect() ? element : element->copy()) - : element); - } - return create(std::move(result), false); - } - } -} - -void -QPDF_Array::disconnect() -{ - if (sp) { - for (auto& item: sp->elements) { - auto& obj = item.second; - if (!obj->getObjGen().isIndirect()) { - obj->disconnect(); - } - } - } else { - for (auto& obj: elements) { - if (!obj->getObjGen().isIndirect()) { - obj->disconnect(); - } - } - } -} - -std::string -QPDF_Array::unparse() -{ - std::string result = "[ "; - if (sp) { - int next = 0; - for (auto& item: sp->elements) { - int key = item.first; - for (int j = next; j < key; ++j) { - result += "null "; - } - auto og = item.second->resolved_object()->getObjGen(); - result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " "; - next = ++key; - } - for (int j = next; j < sp->size; ++j) { - result += "null "; - } - } else { - for (auto const& item: elements) { - auto og = item->resolved_object()->getObjGen(); - result += og.isIndirect() ? og.unparse(' ') + " R " : item->unparse() + " "; - } - } - result += "]"; - return result; -} - -void -QPDF_Array::writeJSON(int json_version, JSON::Writer& p) -{ - p.writeStart('['); - if (sp) { - int next = 0; - for (auto& item: sp->elements) { - int key = item.first; - for (int j = next; j < key; ++j) { - p.writeNext() << "null"; - } - p.writeNext(); - auto og = item.second->getObjGen(); - if (og.isIndirect()) { - p << "\"" << og.unparse(' ') << " R\""; - } else { - item.second->writeJSON(json_version, p); - } - next = ++key; - } - for (int j = next; j < sp->size; ++j) { - p.writeNext() << "null"; - } - } else { - for (auto const& item: elements) { - p.writeNext(); - auto og = item->getObjGen(); - if (og.isIndirect()) { - p << "\"" << og.unparse(' ') << " R\""; - } else { - item->writeJSON(json_version, p); - } - } - } - p.writeEnd(']'); -} - QPDF_Array* Array::array() const { diff --git a/libqpdf/QPDF_Bool.cc b/libqpdf/QPDF_Bool.cc deleted file mode 100644 index edb47a7..0000000 --- a/libqpdf/QPDF_Bool.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include - -QPDF_Bool::QPDF_Bool(bool val) : - QPDFValue(::ot_boolean), - val(val) -{ -} - -std::shared_ptr -QPDF_Bool::create(bool value) -{ - return do_create(new QPDF_Bool(value)); -} - -std::shared_ptr -QPDF_Bool::copy(bool shallow) -{ - return create(val); -} - -std::string -QPDF_Bool::unparse() -{ - return (val ? "true" : "false"); -} - -void -QPDF_Bool::writeJSON(int json_version, JSON::Writer& p) -{ - p << val; -} - -bool -QPDF_Bool::getVal() const -{ - return this->val; -} diff --git a/libqpdf/QPDF_Destroyed.cc b/libqpdf/QPDF_Destroyed.cc deleted file mode 100644 index 34b2a9c..0000000 --- a/libqpdf/QPDF_Destroyed.cc +++ /dev/null @@ -1,35 +0,0 @@ -#include - -#include - -QPDF_Destroyed::QPDF_Destroyed() : - QPDFValue(::ot_destroyed) -{ -} - -std::shared_ptr -QPDF_Destroyed::getInstance() -{ - static std::shared_ptr instance(new QPDF_Destroyed()); - return instance; -} - -std::shared_ptr -QPDF_Destroyed::copy(bool shallow) -{ - throw std::logic_error("attempted to shallow copy QPDFObjectHandle from destroyed QPDF"); - return nullptr; -} - -std::string -QPDF_Destroyed::unparse() -{ - throw std::logic_error("attempted to unparse a QPDFObjectHandle from a destroyed QPDF"); - return ""; -} - -void -QPDF_Destroyed::writeJSON(int json_version, JSON::Writer& p) -{ - throw std::logic_error("attempted to get JSON from a QPDFObjectHandle from a destroyed QPDF"); -} \ No newline at end of file diff --git a/libqpdf/QPDF_Dictionary.cc b/libqpdf/QPDF_Dictionary.cc index ae6bce0..256e01e 100644 --- a/libqpdf/QPDF_Dictionary.cc +++ b/libqpdf/QPDF_Dictionary.cc @@ -1,99 +1,11 @@ -#include - -#include #include + #include -#include #include -#include using namespace std::literals; using namespace qpdf; -QPDF_Dictionary::QPDF_Dictionary(std::map const& items) : - QPDFValue(::ot_dictionary), - items(items) -{ -} - -QPDF_Dictionary::QPDF_Dictionary(std::map&& items) : - QPDFValue(::ot_dictionary), - items(items) -{ -} - -std::shared_ptr -QPDF_Dictionary::create(std::map const& items) -{ - return do_create(new QPDF_Dictionary(items)); -} - -std::shared_ptr -QPDF_Dictionary::create(std::map&& items) -{ - return do_create(new QPDF_Dictionary(items)); -} - -std::shared_ptr -QPDF_Dictionary::copy(bool shallow) -{ - if (shallow) { - return create(items); - } else { - std::map new_items; - for (auto const& item: this->items) { - auto value = item.second; - new_items[item.first] = value.isIndirect() ? value : value.shallowCopy(); - } - return create(new_items); - } -} - -void -QPDF_Dictionary::disconnect() -{ - for (auto& iter: this->items) { - QPDFObjectHandle::DisconnectAccess::disconnect(iter.second); - } -} - -std::string -QPDF_Dictionary::unparse() -{ - std::string result = "<< "; - for (auto& iter: this->items) { - if (!iter.second.isNull()) { - result += Name::normalize(iter.first) + " " + iter.second.unparse() + " "; - } - } - result += ">>"; - return result; -} - -void -QPDF_Dictionary::writeJSON(int json_version, JSON::Writer& p) -{ - p.writeStart('{'); - for (auto& iter: this->items) { - if (!iter.second.isNull()) { - p.writeNext(); - if (json_version == 1) { - p << "\"" << JSON::Writer::encode_string(Name::normalize(iter.first)) << "\": "; - } else if (auto res = Name::analyzeJSONEncoding(iter.first); res.first) { - if (res.second) { - p << "\"" << iter.first << "\": "; - } else { - p << "\"" << JSON::Writer::encode_string(iter.first) << "\": "; - } - } else { - p << "\"n:" << JSON::Writer::encode_string(Name::normalize(iter.first)) << "\": "; - } - iter.second.writeJSON(json_version, p); - } - } - p.writeEnd('}'); -} - QPDF_Dictionary* BaseDictionary::dict() const { diff --git a/libqpdf/QPDF_InlineImage.cc b/libqpdf/QPDF_InlineImage.cc deleted file mode 100644 index 3b8c12d..0000000 --- a/libqpdf/QPDF_InlineImage.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include - -#include - -QPDF_InlineImage::QPDF_InlineImage(std::string const& val) : - QPDFValue(::ot_inlineimage), - val(val) -{ -} - -std::shared_ptr -QPDF_InlineImage::create(std::string const& val) -{ - return do_create(new QPDF_InlineImage(val)); -} - -std::shared_ptr -QPDF_InlineImage::copy(bool shallow) -{ - return create(val); -} - -std::string -QPDF_InlineImage::unparse() -{ - return this->val; -} - -void -QPDF_InlineImage::writeJSON(int json_version, JSON::Writer& p) -{ - p << "null"; -} diff --git a/libqpdf/QPDF_Integer.cc b/libqpdf/QPDF_Integer.cc deleted file mode 100644 index 5327edb..0000000 --- a/libqpdf/QPDF_Integer.cc +++ /dev/null @@ -1,40 +0,0 @@ -#include - -#include -#include - -QPDF_Integer::QPDF_Integer(long long val) : - QPDFValue(::ot_integer), - val(val) -{ -} - -std::shared_ptr -QPDF_Integer::create(long long value) -{ - return do_create(new QPDF_Integer(value)); -} - -std::shared_ptr -QPDF_Integer::copy(bool shallow) -{ - return create(val); -} - -std::string -QPDF_Integer::unparse() -{ - return std::to_string(this->val); -} - -void -QPDF_Integer::writeJSON(int json_version, JSON::Writer& p) -{ - p << std::to_string(this->val); -} - -long long -QPDF_Integer::getVal() const -{ - return this->val; -} diff --git a/libqpdf/QPDF_Name.cc b/libqpdf/QPDF_Name.cc index c3b36a8..e69de29 100644 --- a/libqpdf/QPDF_Name.cc +++ b/libqpdf/QPDF_Name.cc @@ -1,123 +0,0 @@ -#include - -#include -#include -#include - -using namespace qpdf; - -QPDF_Name::QPDF_Name(std::string const& name) : - QPDFValue(::ot_name), - name(name) -{ -} - -std::shared_ptr -QPDF_Name::create(std::string const& name) -{ - return do_create(new QPDF_Name(name)); -} - -std::shared_ptr -QPDF_Name::copy(bool shallow) -{ - return create(name); -} - -std::string -Name::normalize(std::string const& name) -{ - if (name.empty()) { - return name; - } - std::string result; - result += name.at(0); - for (size_t i = 1; i < name.length(); ++i) { - char ch = name.at(i); - // Don't use locale/ctype here; follow PDF spec guidelines. - if (ch == '\0') { - // QPDFTokenizer embeds a null character to encode an invalid #. - result += "#"; - } else if ( - ch < 33 || ch == '#' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' || - ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch > 126) { - result += QUtil::hex_encode_char(ch); - } else { - result += ch; - } - } - return result; -} - -std::string -QPDF_Name::unparse() -{ - return Name::normalize(name); -} - -std::pair -Name::analyzeJSONEncoding(const std::string& name) -{ - int tail = 0; // Number of continuation characters expected. - bool tail2 = false; // Potential overlong 3 octet utf-8. - bool tail3 = false; // potential overlong 4 octet - bool needs_escaping = false; - for (auto const& it: name) { - auto c = static_cast(it); - if (tail) { - if ((c & 0xc0) != 0x80) { - return {false, false}; - } - if (tail2) { - if ((c & 0xe0) == 0x80) { - return {false, false}; - } - tail2 = false; - } else if (tail3) { - if ((c & 0xf0) == 0x80) { - return {false, false}; - } - tail3 = false; - } - tail--; - } else if (c < 0x80) { - if (!needs_escaping) { - needs_escaping = !((c > 34 && c != '\\') || c == ' ' || c == 33); - } - } else if ((c & 0xe0) == 0xc0) { - if ((c & 0xfe) == 0xc0) { - return {false, false}; - } - tail = 1; - } else if ((c & 0xf0) == 0xe0) { - tail2 = (c == 0xe0); - tail = 2; - } else if ((c & 0xf8) == 0xf0) { - tail3 = (c == 0xf0); - tail = 3; - } else { - return {false, false}; - } - } - return {tail == 0, !needs_escaping}; -} - -void -QPDF_Name::writeJSON(int json_version, JSON::Writer& p) -{ - // For performance reasons this code is duplicated in QPDF_Dictionary::writeJSON. When updating - // this method make sure QPDF_Dictionary is also update. - if (json_version == 1) { - p << "\"" << JSON::Writer::encode_string(Name::normalize(name)) << "\""; - } else { - if (auto res = Name::analyzeJSONEncoding(name); res.first) { - if (res.second) { - p << "\"" << name << "\""; - } else { - p << "\"" << JSON::Writer::encode_string(name) << "\""; - } - } else { - p << "\"n:" << JSON::Writer::encode_string(Name::normalize(name)) << "\""; - } - } -} diff --git a/libqpdf/QPDF_Null.cc b/libqpdf/QPDF_Null.cc deleted file mode 100644 index 4fd36ab..0000000 --- a/libqpdf/QPDF_Null.cc +++ /dev/null @@ -1,51 +0,0 @@ -#include - -#include -#include - -QPDF_Null::QPDF_Null(QPDF* qpdf, QPDFObjGen og) : - QPDFValue(::ot_null, qpdf, og) -{ -} - -std::shared_ptr -QPDF_Null::create(QPDF* qpdf, QPDFObjGen og) -{ - return do_create(new QPDF_Null(qpdf, og)); -} - -std::shared_ptr -QPDF_Null::create( - std::shared_ptr parent, std::string_view const& static_descr, std::string var_descr) -{ - auto n = do_create(new QPDF_Null()); - n->setChildDescription(parent, static_descr, var_descr); - return n; -} - -std::shared_ptr -QPDF_Null::create( - std::shared_ptr parent, std::string_view const& static_descr, std::string var_descr) -{ - auto n = do_create(new QPDF_Null()); - n->setChildDescription(parent, static_descr, var_descr); - return n; -} - -std::shared_ptr -QPDF_Null::copy(bool shallow) -{ - return create(); -} - -std::string -QPDF_Null::unparse() -{ - return "null"; -} - -void -QPDF_Null::writeJSON(int json_version, JSON::Writer& p) -{ - p << "null"; -} diff --git a/libqpdf/QPDF_Operator.cc b/libqpdf/QPDF_Operator.cc deleted file mode 100644 index f0de6d3..0000000 --- a/libqpdf/QPDF_Operator.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include - -#include - -QPDF_Operator::QPDF_Operator(std::string const& val) : - QPDFValue(::ot_operator), - val(val) -{ -} - -std::shared_ptr -QPDF_Operator::create(std::string const& val) -{ - return do_create(new QPDF_Operator(val)); -} - -std::shared_ptr -QPDF_Operator::copy(bool shallow) -{ - return create(val); -} - -std::string -QPDF_Operator::unparse() -{ - return val; -} - -void -QPDF_Operator::writeJSON(int json_version, JSON::Writer& p) -{ - p << "null"; -} diff --git a/libqpdf/QPDF_Real.cc b/libqpdf/QPDF_Real.cc deleted file mode 100644 index df1da62..0000000 --- a/libqpdf/QPDF_Real.cc +++ /dev/null @@ -1,58 +0,0 @@ -#include - -#include -#include - -QPDF_Real::QPDF_Real(std::string const& val) : - QPDFValue(::ot_real), - val(val) -{ -} - -QPDF_Real::QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes) : - QPDFValue(::ot_real), - val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes)) -{ -} - -std::shared_ptr -QPDF_Real::create(std::string const& val) -{ - return do_create(new QPDF_Real(val)); -} - -std::shared_ptr -QPDF_Real::create(double value, int decimal_places, bool trim_trailing_zeroes) -{ - return do_create(new QPDF_Real(value, decimal_places, trim_trailing_zeroes)); -} - -std::shared_ptr -QPDF_Real::copy(bool shallow) -{ - return create(val); -} - -std::string -QPDF_Real::unparse() -{ - return this->val; -} - -void -QPDF_Real::writeJSON(int json_version, JSON::Writer& p) -{ - if (this->val.length() == 0) { - // Can't really happen... - p << "0"; - } else if (this->val.at(0) == '.') { - p << "0" << this->val; - } else if (this->val.length() >= 2 && this->val.at(0) == '-' && this->val.at(1) == '.') { - p << "-0." << this->val.substr(2); - } else { - p << this->val; - } - if (val.back() == '.') { - p << "0"; - } -} diff --git a/libqpdf/QPDF_Reserved.cc b/libqpdf/QPDF_Reserved.cc deleted file mode 100644 index 242567f..0000000 --- a/libqpdf/QPDF_Reserved.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include - -#include - -QPDF_Reserved::QPDF_Reserved() : - QPDFValue(::ot_reserved) -{ -} - -std::shared_ptr -QPDF_Reserved::create() -{ - return do_create(new QPDF_Reserved()); -} - -std::shared_ptr -QPDF_Reserved::copy(bool shallow) -{ - return create(); -} - -std::string -QPDF_Reserved::unparse() -{ - throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object"); - return ""; -} - -void -QPDF_Reserved::writeJSON(int json_version, JSON::Writer& p) -{ - throw std::logic_error("QPDFObjectHandle: attempting to get JSON from a reserved object"); -} diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 552d220..c846b5a 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -105,34 +104,14 @@ std::map()>> Stream {"/ASCIIHexDecode", SF_ASCIIHexDecode::factory}, }; -QPDF_Stream::QPDF_Stream( - QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) : - QPDFValue(::ot_stream, qpdf, og), - filter_on_write(true), - stream_dict(stream_dict), - length(length) -{ - if (!stream_dict.isDictionary()) { - throw std::logic_error( - "stream object instantiated with non-dictionary object for dictionary"); - } - auto descr = std::make_shared( - qpdf->getFilename() + ", stream object " + og.unparse(' ')); - setDescription(qpdf, descr, offset); -} - -std::shared_ptr -QPDF_Stream::create( - QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) +Stream::Stream( + QPDF& qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) : + BaseHandle(QPDFObject::create(&qpdf, og, std::move(stream_dict), length)) { - return do_create(new QPDF_Stream(qpdf, og, stream_dict, offset, length)); -} - -std::shared_ptr -QPDF_Stream::copy(bool shallow) -{ - QTC::TC("qpdf", "QPDF_Stream ERR shallow copy stream"); - throw std::runtime_error("stream objects cannot be cloned"); + auto descr = std::make_shared( + qpdf.getFilename() + ", stream object " + og.unparse(' ')); + obj->setDescription(&qpdf, descr, offset); + setDictDescription(); } void @@ -142,26 +121,6 @@ Stream::registerStreamFilter( filter_factories[filter_name] = factory; } -void -QPDF_Stream::disconnect() -{ - this->stream_provider = nullptr; - QPDFObjectHandle::DisconnectAccess::disconnect(this->stream_dict); -} - -std::string -QPDF_Stream::unparse() -{ - // Unparse stream objects as indirect references - return og.unparse(' ') + " R"; -} - -void -QPDF_Stream::writeJSON(int json_version, JSON::Writer& jw) -{ - stream_dict.writeJSON(json_version, jw); -} - JSON Stream::getStreamJSON( int json_version, @@ -278,34 +237,27 @@ Stream::writeStreamJSON( } void -QPDF_Stream::setDescription( - QPDF* qpdf, std::shared_ptr& description, qpdf_offset_t offset) +qpdf::Stream::setDictDescription() { - this->QPDFValue::setDescription(qpdf, description, offset); - setDictDescription(); -} - -void -QPDF_Stream::setDictDescription() -{ - if (!this->stream_dict.hasObjectDescription()) { - this->stream_dict.setObjectDescription(qpdf, getDescription() + " -> stream dictionary"); + auto s = stream(); + if (!s->stream_dict.hasObjectDescription()) { + s->stream_dict.setObjectDescription( + obj->getQPDF(), obj->getDescription() + " -> stream dictionary"); } } std::shared_ptr Stream::getStreamData(qpdf_stream_decode_level_e decode_level) { - auto s = stream(); Pl_Buffer buf("stream data buffer"); bool filtered; pipeStreamData(&buf, &filtered, 0, decode_level, false, false); if (!filtered) { throw QPDFExc( qpdf_e_unsupported, - s->qpdf->getFilename(), + obj->getQPDF()->getFilename(), "", - s->parsed_offset, + obj->getParsedOffset(), "getStreamData called on unfilterable stream"); } QTC::TC("qpdf", "QPDF_Stream getStreamData"); @@ -315,14 +267,13 @@ Stream::getStreamData(qpdf_stream_decode_level_e decode_level) std::shared_ptr Stream::getRawStreamData() { - auto s = stream(); Pl_Buffer buf("stream data buffer"); if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) { throw QPDFExc( qpdf_e_unsupported, - s->qpdf->getFilename(), + obj->getQPDF()->getFilename(), "", - s->parsed_offset, + obj->getParsedOffset(), "error getting raw stream data"); } QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); @@ -532,12 +483,12 @@ Stream::pipeStreamData( Pl_Count count("stream provider count", pipeline); if (s->stream_provider->supportsRetry()) { if (!s->stream_provider->provideStreamData( - s->og, &count, suppress_warnings, will_retry)) { + obj->getObjGen(), &count, suppress_warnings, will_retry)) { filter = false; success = false; } } else { - s->stream_provider->provideStreamData(s->og, &count); + s->stream_provider->provideStreamData(obj->getObjGen(), &count); } qpdf_offset_t actual_length = count.getCount(); qpdf_offset_t desired_length = 0; @@ -550,7 +501,7 @@ Stream::pipeStreamData( // This would be caused by programmer error on the part of a library user, not by // invalid input data. throw std::runtime_error( - "stream data provider for " + s->og.unparse(' ') + " provided " + + "stream data provider for " + obj->getObjGen().unparse(' ') + " provided " + std::to_string(actual_length) + " bytes instead of expected " + std::to_string(desired_length) + " bytes"); } @@ -558,15 +509,15 @@ Stream::pipeStreamData( QTC::TC("qpdf", "QPDF_Stream provider length not provided"); s->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length)); } - } else if (s->parsed_offset == 0) { + } else if (obj->getParsedOffset() == 0) { QTC::TC("qpdf", "QPDF_Stream pipe no stream data"); throw std::logic_error("pipeStreamData called for stream with no data"); } else { QTC::TC("qpdf", "QPDF_Stream pipe original stream data"); if (!QPDF::Pipe::pipeStreamData( - s->qpdf, - s->og, - s->parsed_offset, + obj->getQPDF(), + obj->getObjGen(), + obj->getParsedOffset(), s->length, s->stream_dict, pipeline, @@ -642,8 +593,7 @@ Stream::replaceFilterData( void Stream::warn(std::string const& message) { - auto s = stream(); - s->qpdf->warn(qpdf_e_damaged_pdf, "", s->parsed_offset, message); + obj->getQPDF()->warn(qpdf_e_damaged_pdf, "", obj->getParsedOffset(), message); } QPDFObjectHandle diff --git a/libqpdf/QPDF_String.cc b/libqpdf/QPDF_String.cc index 9f12a3d..187106f 100644 --- a/libqpdf/QPDF_String.cc +++ b/libqpdf/QPDF_String.cc @@ -1,6 +1,6 @@ -#include +#include -#include +#include #include // DO NOT USE ctype -- it is locale dependent for some things, and it's not worth the risk of @@ -12,18 +12,6 @@ is_iso_latin1_printable(char ch) return (((ch >= 32) && (ch <= 126)) || (static_cast(ch) >= 160)); } -QPDF_String::QPDF_String(std::string const& val) : - QPDFValue(::ot_string), - val(val) -{ -} - -std::shared_ptr -QPDF_String::create(std::string const& val) -{ - return do_create(new QPDF_String(val)); -} - std::shared_ptr QPDF_String::create_utf16(std::string const& utf8_val) { @@ -31,19 +19,7 @@ QPDF_String::create_utf16(std::string const& utf8_val) if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) { result = QUtil::utf8_to_utf16(utf8_val); } - return do_create(new QPDF_String(result)); -} - -std::shared_ptr -QPDF_String::copy(bool shallow) -{ - return create(val); -} - -std::string -QPDF_String::unparse() -{ - return unparse(false); + return QPDFObject::create(result); } void diff --git a/libqpdf/QPDF_Unresolved.cc b/libqpdf/QPDF_Unresolved.cc deleted file mode 100644 index ae0c6a6..0000000 --- a/libqpdf/QPDF_Unresolved.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include -#include - -QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen og) : - QPDFValue(::ot_unresolved, qpdf, og) -{ -} - -std::shared_ptr -QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen og) -{ - return do_create(new QPDF_Unresolved(qpdf, og)); -} - -std::shared_ptr -QPDF_Unresolved::copy(bool shallow) -{ - return QPDF::Resolver::resolved(qpdf, og)->copy(shallow); -} - -std::string -QPDF_Unresolved::unparse() -{ - return QPDF::Resolver::resolved(qpdf, og)->unparse(); -} - -void -QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p) -{ - QPDF::Resolver::resolved(qpdf, og)->writeJSON(json_version, p); -} - -std::string -QPDF_Unresolved::getStringValue() const -{ - return QPDF::Resolver::resolved(qpdf, og)->getStringValue(); -} diff --git a/libqpdf/QPDF_json.cc b/libqpdf/QPDF_json.cc index 1b9318d..288f265 100644 --- a/libqpdf/QPDF_json.cc +++ b/libqpdf/QPDF_json.cc @@ -7,9 +7,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -239,8 +236,8 @@ class QPDF::JSONReactor: public JSON::Reactor is(is), must_be_complete(must_be_complete), descr( - std::make_shared( - QPDFValue::JSON_Descr(std::make_shared(is->getName()), ""))) + std::make_shared( + QPDFObject::JSON_Descr(std::make_shared(is->getName()), ""))) { } ~JSONReactor() override = default; @@ -287,7 +284,7 @@ class QPDF::JSONReactor: public JSON::Reactor QPDF& pdf; std::shared_ptr is; bool must_be_complete{true}; - std::shared_ptr descr; + std::shared_ptr descr; bool errors{false}; bool saw_qpdf{false}; bool saw_qpdf_meta{false}; @@ -577,8 +574,8 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) } else { this_stream_needs_data = true; replaceObject( - QPDF_Stream::create( - &pdf, tos.object.getObjGen(), QPDFObjectHandle::newDictionary(), 0, 0), + qpdf::Stream( + pdf, tos.object.getObjGen(), QPDFObjectHandle::newDictionary(), 0, 0), value); } next_obj = tos.object; @@ -707,10 +704,10 @@ QPDF::JSONReactor::arrayItem(JSON const& value) void QPDF::JSONReactor::setObjectDescription(QPDFObjectHandle& oh, JSON const& value) { - auto j_descr = std::get(*descr); + auto j_descr = std::get(*descr); if (j_descr.object != cur_object) { - descr = std::make_shared( - QPDFValue::JSON_Descr(j_descr.input, cur_object)); + descr = std::make_shared( + QPDFObject::JSON_Descr(j_descr.input, cur_object)); } oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart()); diff --git a/libqpdf/QPDF_optimization.cc b/libqpdf/QPDF_optimization.cc index d8c5129..1fd66b6 100644 --- a/libqpdf/QPDF_optimization.cc +++ b/libqpdf/QPDF_optimization.cc @@ -5,9 +5,8 @@ #include #include +#include #include -#include -#include #include QPDF::ObjUser::ObjUser() : diff --git a/libqpdf/qpdf/QPDFObjectHandle_private.hh b/libqpdf/qpdf/QPDFObjectHandle_private.hh index f7820f9..cd4e8ff 100644 --- a/libqpdf/qpdf/QPDFObjectHandle_private.hh +++ b/libqpdf/qpdf/QPDFObjectHandle_private.hh @@ -4,9 +4,7 @@ #include #include -#include -#include -#include +#include namespace qpdf { @@ -106,6 +104,13 @@ namespace qpdf { } + Stream( + QPDF& qpdf, + QPDFObjGen og, + QPDFObjectHandle stream_dict, + qpdf_offset_t offset, + size_t length); + QPDFObjectHandle getDict() const { @@ -186,20 +191,22 @@ namespace qpdf { auto s = stream(); s->stream_dict = new_dict; - s->setDictDescription(); + setDictDescription(); } + void setDictDescription(); + static void registerStreamFilter( std::string const& filter_name, std::function()> factory); private: - QPDF_Stream* + QPDF_Stream::Members* stream() const { if (obj) { if (auto s = obj->as()) { - return s; + return s->m.get(); } } throw std::runtime_error("operation for stream attempted on object of type dictionary"); @@ -227,6 +234,32 @@ namespace qpdf } // namespace qpdf +inline QPDF_Dictionary::QPDF_Dictionary(std::map&& items) : + items(std::move(items)) +{ +} + +inline std::shared_ptr +QPDF_Null::create( + std::shared_ptr parent, std::string_view const& static_descr, std::string var_descr) +{ + auto n = QPDFObject::create(); + n->setChildDescription(parent->getQPDF(), parent, static_descr, var_descr); + return n; +} + +inline QPDF_Real::QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes) : + val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes)) +{ +} + +template +inline std::shared_ptr +QPDFObject::create(Args&&... args) +{ + return std::make_shared(std::forward(T(std::forward(args)...))); +} + inline qpdf::Array QPDFObjectHandle::as_array(qpdf::typed options) const { diff --git a/libqpdf/qpdf/QPDFObject_private.hh b/libqpdf/qpdf/QPDFObject_private.hh index d3f3821..501485b 100644 --- a/libqpdf/qpdf/QPDFObject_private.hh +++ b/libqpdf/qpdf/QPDFObject_private.hh @@ -6,182 +6,508 @@ #include #include +#include #include -#include +#include #include +#include +#include #include #include +#include +#include -class QPDF; +class QPDFObject; class QPDFObjectHandle; -class QPDFObject +namespace qpdf +{ + class Array; + class BaseDictionary; + class Dictionary; + class Stream; +} // namespace qpdf + +class QPDF_Array final { - friend class QPDFValue; + private: + struct Sparse + { + int size{0}; + std::map> elements; + }; public: - QPDFObject() = default; + QPDF_Array() = default; + QPDF_Array(QPDF_Array const& other) : + sp(other.sp ? std::make_unique(*other.sp) : nullptr) + { + } + + QPDF_Array(QPDF_Array&&) = default; + QPDF_Array& operator=(QPDF_Array&&) = default; + + private: + friend class QPDFObject; + friend class qpdf::Array; + QPDF_Array(std::vector const& items); + QPDF_Array(std::vector>&& items, bool sparse); - std::shared_ptr - copy(bool shallow = false) + int + size() const { - return value->copy(shallow); + return sp ? sp->size : int(elements.size()); } - std::string - unparse() + void setFromVector(std::vector const& items); + void checkOwnership(QPDFObjectHandle const& item) const; + + std::unique_ptr sp; + std::vector> elements; +}; + +class QPDF_Bool final +{ + friend class QPDFObject; + friend class QPDFObjectHandle; + + explicit QPDF_Bool(bool val) : + val(val) { - return value->unparse(); } - void - writeJSON(int json_version, JSON::Writer& p) + bool val; +}; + +class QPDF_Destroyed final +{ +}; + +class QPDF_Dictionary final +{ + friend class QPDFObject; + friend class qpdf::BaseDictionary; + + QPDF_Dictionary(std::map const& items) : + items(items) { - return value->writeJSON(json_version, p); } - std::string - getStringValue() const + inline QPDF_Dictionary(std::map&& items); + + std::map items; +}; + +class QPDF_InlineImage final +{ + friend class QPDFObject; + + explicit QPDF_InlineImage(std::string val) : + val(std::move(val)) + { + } + std::string val; +}; + +class QPDF_Integer final +{ + friend class QPDFObject; + friend class QPDFObjectHandle; + + QPDF_Integer(long long val) : + val(val) + { + } + long long val; +}; + +class QPDF_Name final +{ + friend class QPDFObject; + + explicit QPDF_Name(std::string name) : + name(std::move(name)) + { + } + std::string name; +}; + +class QPDF_Null final +{ + friend class QPDFObject; + + public: + static inline std::shared_ptr create( + std::shared_ptr parent, + std::string_view const& static_descr, + std::string var_descr); +}; + +class QPDF_Operator final +{ + friend class QPDFObject; + + QPDF_Operator(std::string val) : + val(std::move(val)) + { + } + + std::string val; +}; + +class QPDF_Real final +{ + friend class QPDFObject; + + QPDF_Real(std::string val) : + val(std::move(val)) + { + } + inline QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes); + // Store reals as strings to avoid roundoff errors. + std::string val; +}; + +class QPDF_Reference +{ + // This is a minimal implementation to support QPDF::replaceObject. Once we support parsing of + // objects that are an indirect reference we will need to support multiple levels of + // indirection, including the possibility of circular references. + friend class QPDFObject; + + QPDF_Reference(std::shared_ptr obj) : + obj(std::move(obj)) + { + } + + std::shared_ptr obj; +}; + +class QPDF_Reserved final +{ +}; + +class QPDF_Stream final +{ + class Members + { + friend class QPDF_Stream; + friend class QPDFObject; + friend class qpdf::Stream; + + public: + Members(QPDFObjectHandle stream_dict, size_t length) : + stream_dict(std::move(stream_dict)), + length(length) + { + } + + private: + void replaceFilterData( + QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length); + + bool filter_on_write{true}; + QPDFObjectHandle stream_dict; + size_t length{0}; + std::shared_ptr stream_data; + std::shared_ptr stream_provider; + std::vector> token_filters; + }; + + friend class QPDFObject; + friend class qpdf::Stream; + + QPDF_Stream(QPDFObjectHandle stream_dict, size_t length) : + m(std::make_unique(stream_dict, length)) + { + if (!stream_dict.isDictionary()) { + throw std::logic_error( + "stream object instantiated with non-dictionary object for dictionary"); + } + } + + std::unique_ptr m; +}; + +// QPDF_Strings may included embedded null characters. +class QPDF_String final +{ + friend class QPDFObject; + friend class QPDFWriter; + + public: + static std::shared_ptr create_utf16(std::string const& utf8_val); + std::string unparse(bool force_binary = false); + void writeJSON(int json_version, JSON::Writer& p); + std::string getUTF8Val() const; + + private: + QPDF_String(std::string val) : + val(std::move(val)) { - return value->getStringValue(); } + bool useHexString() const; + std::string val; +}; + +class QPDF_Unresolved final +{ +}; + +class QPDFObject +{ + public: + template + QPDFObject(T&& value) : + value(std::forward(value)) + { + } + + template + QPDFObject(QPDF* qpdf, QPDFObjGen og, T&& value) : + value(std::forward(value)), + qpdf(qpdf), + og(og) + { + } + + template + inline static std::shared_ptr create(Args&&... args); + + template + inline static std::shared_ptr + create(QPDF* qpdf, QPDFObjGen og, Args&&... args) + { + return std::make_shared( + qpdf, og, std::forward(T(std::forward(args)...))); + } + + std::shared_ptr copy(bool shallow = false); + std::string unparse(); + void write_json(int json_version, JSON::Writer& p); + void disconnect(); + std::string getStringValue() const; + // Return a unique type code for the resolved object qpdf_object_type_e getResolvedTypeCode() const { - auto tc = value->type_code; - return tc == ::ot_unresolved - ? QPDF::Resolver::resolved(value->qpdf, value->og)->value->type_code - : tc; + if (getTypeCode() == ::ot_unresolved) { + return QPDF::Resolver::resolved(qpdf, og)->getTypeCode(); + } + if (getTypeCode() == ::ot_reference) { + return std::get(value).obj->getResolvedTypeCode(); + } + return getTypeCode(); } // Return a unique type code for the object qpdf_object_type_e - getTypeCode() const noexcept + getTypeCode() const { - return value->type_code; + return static_cast(value.index()); } QPDF* getQPDF() const { - return value->qpdf; + return qpdf; } QPDFObjGen getObjGen() const { - return value->og; + return og; } void - setDescription( - QPDF* qpdf, std::shared_ptr& description, qpdf_offset_t offset = -1) + assign_null() { - return value->setDescription(qpdf, description, offset); + value = QPDF_Null(); + qpdf = nullptr; + og = QPDFObjGen(); + object_description = nullptr; + parsed_offset = -1; } void - setChildDescription( - std::shared_ptr parent, - std::string_view const& static_descr, - std::string var_descr) + move_to(std::shared_ptr& o, bool destroy) { - auto qpdf = parent ? parent->value->qpdf : nullptr; - value->setChildDescription(qpdf, parent->value, static_descr, var_descr); + o->value = std::move(value); + o->qpdf = qpdf; + o->og = og; + o->object_description = object_description; + o->parsed_offset = parsed_offset; + if (!destroy) { + value = QPDF_Reference(o); + } } void - setChildDescription( - std::shared_ptr parent, - std::string_view const& static_descr, - std::string var_descr) + swapWith(std::shared_ptr o) { - auto qpdf = parent ? parent->qpdf : nullptr; - value->setChildDescription(qpdf, parent, static_descr, var_descr); + std::swap(value, o->value); + std::swap(qpdf, o->qpdf); + std::swap(object_description, o->object_description); + std::swap(parsed_offset, o->parsed_offset); } - bool - getDescription(QPDF*& qpdf, std::string& description) + + void + setObjGen(QPDF* a_qpdf, QPDFObjGen a_og) { - qpdf = value->qpdf; - description = value->getDescription(); - return qpdf != nullptr; + qpdf = a_qpdf; + og = a_og; } - bool - hasDescription() + // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects. + void + destroy() { - return value->hasDescription(); + value = QPDF_Destroyed(); } - void - setParsedOffset(qpdf_offset_t offset) + + bool + isUnresolved() const { - value->setParsedOffset(offset); + return getTypeCode() == ::ot_unresolved; } - qpdf_offset_t - getParsedOffset() + const QPDFObject* + resolved_object() const { - return value->getParsedOffset(); + return isUnresolved() ? QPDF::Resolver::resolved(qpdf, og) : this; } + + struct JSON_Descr + { + JSON_Descr(std::shared_ptr input, std::string const& object) : + input(input), + object(object) + { + } + + std::shared_ptr input; + std::string object; + }; + + struct ChildDescr + { + ChildDescr( + std::shared_ptr parent, + std::string_view const& static_descr, + std::string var_descr) : + parent(parent), + static_descr(static_descr), + var_descr(var_descr) + { + } + + std::weak_ptr parent; + std::string_view const& static_descr; + std::string var_descr; + }; + + using Description = std::variant; + void - assign(std::shared_ptr o) + setDescription( + QPDF* qpdf_p, std::shared_ptr& description, qpdf_offset_t offset = -1) { - value = o->value; + qpdf = qpdf_p; + object_description = description; + setParsedOffset(offset); } void - swapWith(std::shared_ptr o) + setDefaultDescription(QPDF* a_qpdf, QPDFObjGen const& a_og) { - auto v = value; - value = o->value; - o->value = v; - auto og = value->og; - value->og = o->value->og; - o->value->og = og; + qpdf = a_qpdf; + og = a_og; } - void - setDefaultDescription(QPDF* qpdf, QPDFObjGen og) + setChildDescription( + QPDF* a_qpdf, + std::shared_ptr parent, + std::string_view const& static_descr, + std::string var_descr) { - // Intended for use by the QPDF class - value->setDefaultDescription(qpdf, og); + object_description = + std::make_shared(ChildDescr(parent, static_descr, var_descr)); + qpdf = a_qpdf; } - void - setObjGen(QPDF* qpdf, QPDFObjGen og) + std::string getDescription(); + bool + hasDescription() { - value->qpdf = qpdf; - value->og = og; + return object_description || og.isIndirect(); } void - disconnect() + setParsedOffset(qpdf_offset_t offset) { - // Disconnect an object from its owning QPDF. This is called by QPDF's destructor. - value->disconnect(); - value->qpdf = nullptr; - value->og = QPDFObjGen(); + if (parsed_offset < 0) { + parsed_offset = offset; + } } - // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects. - void destroy(); - bool - isUnresolved() const + getDescription(QPDF*& a_qpdf, std::string& description) { - return value->type_code == ::ot_unresolved; + a_qpdf = qpdf; + description = getDescription(); + return qpdf != nullptr; } - const QPDFObject* - resolved_object() const + qpdf_offset_t + getParsedOffset() { - return isUnresolved() ? QPDF::Resolver::resolved(value->qpdf, value->og) : this; + return parsed_offset; + } + QPDF* + getQPDF() + { + return qpdf; + } + QPDFObjGen + getObjGen() + { + return og; } template T* - as() const - { - if (auto result = dynamic_cast(value.get())) { - return result; - } else { - return isUnresolved() - ? dynamic_cast(QPDF::Resolver::resolved(value->qpdf, value->og)->value.get()) - : nullptr; + as() + { + if (std::holds_alternative(value)) { + return &std::get(value); } + if (std::holds_alternative(value)) { + return QPDF::Resolver::resolved(qpdf, og)->as(); + } + if (std::holds_alternative(value)) { + // see comment in QPDF_Reference. + return std::get(value).obj->as(); + } + return nullptr; } private: + friend class QPDF_Stream; + typedef std::variant< + std::monostate, + QPDF_Reserved, + QPDF_Null, + QPDF_Bool, + QPDF_Integer, + QPDF_Real, + QPDF_String, + QPDF_Name, + QPDF_Array, + QPDF_Dictionary, + QPDF_Stream, + QPDF_Operator, + QPDF_InlineImage, + QPDF_Unresolved, + QPDF_Destroyed, + QPDF_Reference> + Value; + Value value; + QPDFObject(QPDFObject const&) = delete; QPDFObject& operator=(QPDFObject const&) = delete; - std::shared_ptr value; + + std::shared_ptr object_description; + + QPDF* qpdf{nullptr}; + QPDFObjGen og{}; + qpdf_offset_t parsed_offset{-1}; }; #endif // QPDFOBJECT_HH diff --git a/libqpdf/qpdf/QPDFParser.hh b/libqpdf/qpdf/QPDFParser.hh index 8a3dadd..b2b609f 100644 --- a/libqpdf/qpdf/QPDFParser.hh +++ b/libqpdf/qpdf/QPDFParser.hh @@ -1,8 +1,8 @@ #ifndef QPDFPARSER_HH #define QPDFPARSER_HH -#include -#include +#include +#include #include #include @@ -24,7 +24,7 @@ class QPDFParser decrypter(decrypter), context(context), description( - std::make_shared( + std::make_shared( std::string(input.getName() + ", " + object_description + " at offset $PO"))), parse_pdf(parse_pdf) { @@ -78,7 +78,7 @@ class QPDFParser QPDFTokenizer& tokenizer; QPDFObjectHandle::StringDecrypter* decrypter; QPDF* context; - std::shared_ptr description; + std::shared_ptr description; bool parse_pdf; std::vector stack; diff --git a/libqpdf/qpdf/QPDFValue.hh b/libqpdf/qpdf/QPDFValue.hh deleted file mode 100644 index b247093..0000000 --- a/libqpdf/qpdf/QPDFValue.hh +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef QPDFVALUE_HH -#define QPDFVALUE_HH - -#include -#include -#include -#include -#include - -#include -#include -#include - -class QPDF; -class QPDFObjectHandle; -class QPDFObject; - -class QPDFValue: public std::enable_shared_from_this -{ - friend class QPDFObject; - - public: - virtual ~QPDFValue() = default; - - virtual std::shared_ptr copy(bool shallow = false) = 0; - virtual std::string unparse() = 0; - virtual void writeJSON(int json_version, JSON::Writer& p) = 0; - - struct JSON_Descr - { - JSON_Descr(std::shared_ptr input, std::string const& object) : - input(input), - object(object) - { - } - - std::shared_ptr input; - std::string object; - }; - - struct ChildDescr - { - ChildDescr( - std::shared_ptr parent, - std::string_view const& static_descr, - std::string var_descr) : - parent(parent), - static_descr(static_descr), - var_descr(var_descr) - { - } - - std::weak_ptr parent; - std::string_view const& static_descr; - std::string var_descr; - }; - - using Description = std::variant; - - virtual void - setDescription(QPDF* qpdf_p, std::shared_ptr& description, qpdf_offset_t offset) - { - qpdf = qpdf_p; - object_description = description; - setParsedOffset(offset); - } - void - setDefaultDescription(QPDF* a_qpdf, QPDFObjGen a_og) - { - qpdf = a_qpdf; - og = a_og; - } - void - setChildDescription( - QPDF* a_qpdf, - std::shared_ptr parent, - std::string_view const& static_descr, - std::string var_descr) - { - object_description = - std::make_shared(ChildDescr(parent, static_descr, var_descr)); - qpdf = a_qpdf; - } - std::string getDescription(); - bool - hasDescription() - { - return object_description || og.isIndirect(); - } - void - setParsedOffset(qpdf_offset_t offset) - { - if (parsed_offset < 0) { - parsed_offset = offset; - } - } - qpdf_offset_t - getParsedOffset() - { - return parsed_offset; - } - QPDF* - getQPDF() - { - return qpdf; - } - QPDFObjGen - getObjGen() - { - return og; - } - virtual void - disconnect() - { - } - virtual std::string - getStringValue() const - { - return ""; - } - - protected: - QPDFValue() = default; - - QPDFValue(qpdf_object_type_e type_code) : - type_code(type_code) - { - } - QPDFValue(qpdf_object_type_e type_code, QPDF* qpdf, QPDFObjGen og) : - type_code(type_code), - qpdf(qpdf), - og(og) - { - } - - static std::shared_ptr do_create(QPDFValue*); - - private: - QPDFValue(QPDFValue const&) = delete; - QPDFValue& operator=(QPDFValue const&) = delete; - std::shared_ptr object_description; - - const qpdf_object_type_e type_code{::ot_uninitialized}; - - protected: - QPDF* qpdf{nullptr}; - QPDFObjGen og{}; - qpdf_offset_t parsed_offset{-1}; -}; - -#endif // QPDFVALUE_HH diff --git a/libqpdf/qpdf/QPDF_Array.hh b/libqpdf/qpdf/QPDF_Array.hh deleted file mode 100644 index 4ab65d5..0000000 --- a/libqpdf/qpdf/QPDF_Array.hh +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef QPDF_ARRAY_HH -#define QPDF_ARRAY_HH - -#include -#include -#include - -#include -#include - -class QPDF_Array: public QPDFValue -{ - private: - struct Sparse - { - int size{0}; - std::map> elements; - }; - - public: - ~QPDF_Array() override = default; - static std::shared_ptr create(std::vector const& items); - static std::shared_ptr - create(std::vector>&& items, bool sparse); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - void disconnect() override; - - private: - friend class qpdf::Array; - QPDF_Array(); - QPDF_Array(QPDF_Array const&); - QPDF_Array(std::vector const& items); - QPDF_Array(std::vector>&& items, bool sparse); - - int - size() const - { - return sp ? sp->size : int(elements.size()); - } - void setFromVector(std::vector const& items); - - void checkOwnership(QPDFObjectHandle const& item) const; - - std::unique_ptr sp; - std::vector> elements; -}; - -#endif // QPDF_ARRAY_HH diff --git a/libqpdf/qpdf/QPDF_Bool.hh b/libqpdf/qpdf/QPDF_Bool.hh deleted file mode 100644 index 1692bdc..0000000 --- a/libqpdf/qpdf/QPDF_Bool.hh +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef QPDF_BOOL_HH -#define QPDF_BOOL_HH - -#include - -class QPDF_Bool: public QPDFValue -{ - public: - ~QPDF_Bool() override = default; - static std::shared_ptr create(bool val); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - - bool getVal() const; - - private: - QPDF_Bool(bool val); - bool val; -}; - -#endif // QPDF_BOOL_HH diff --git a/libqpdf/qpdf/QPDF_Destroyed.hh b/libqpdf/qpdf/QPDF_Destroyed.hh deleted file mode 100644 index 9259a2d..0000000 --- a/libqpdf/qpdf/QPDF_Destroyed.hh +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef QPDF_DESTROYED_HH -#define QPDF_DESTROYED_HH - -#include - -class QPDF_Destroyed: public QPDFValue -{ - public: - ~QPDF_Destroyed() override = default; - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - static std::shared_ptr getInstance(); - - private: - QPDF_Destroyed(); -}; - -#endif // QPDF_DESTROYED_HH diff --git a/libqpdf/qpdf/QPDF_Dictionary.hh b/libqpdf/qpdf/QPDF_Dictionary.hh deleted file mode 100644 index ffa4d19..0000000 --- a/libqpdf/qpdf/QPDF_Dictionary.hh +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef QPDF_DICTIONARY_HH -#define QPDF_DICTIONARY_HH - -#include - -#include -#include - -#include -#include -#include -#include - -class QPDF_Dictionary: public QPDFValue -{ - public: - ~QPDF_Dictionary() override = default; - static std::shared_ptr create(std::map const& items); - static std::shared_ptr create(std::map&& items); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - void disconnect() override; - - private: - friend class qpdf::BaseDictionary; - - QPDF_Dictionary(std::map const& items); - QPDF_Dictionary(std::map&& items); - - std::map items; -}; - -#endif // QPDF_DICTIONARY_HH diff --git a/libqpdf/qpdf/QPDF_InlineImage.hh b/libqpdf/qpdf/QPDF_InlineImage.hh deleted file mode 100644 index c06662d..0000000 --- a/libqpdf/qpdf/QPDF_InlineImage.hh +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef QPDF_INLINEIMAGE_HH -#define QPDF_INLINEIMAGE_HH - -#include - -class QPDF_InlineImage: public QPDFValue -{ - public: - ~QPDF_InlineImage() override = default; - static std::shared_ptr create(std::string const& val); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - std::string - getStringValue() const override - { - return val; - } - - private: - QPDF_InlineImage(std::string const& val); - std::string val; -}; - -#endif // QPDF_INLINEIMAGE_HH diff --git a/libqpdf/qpdf/QPDF_Integer.hh b/libqpdf/qpdf/QPDF_Integer.hh deleted file mode 100644 index ae7f789..0000000 --- a/libqpdf/qpdf/QPDF_Integer.hh +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef QPDF_INTEGER_HH -#define QPDF_INTEGER_HH - -#include - -class QPDF_Integer: public QPDFValue -{ - public: - ~QPDF_Integer() override = default; - static std::shared_ptr create(long long value); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - long long getVal() const; - - private: - QPDF_Integer(long long val); - long long val; -}; - -#endif // QPDF_INTEGER_HH diff --git a/libqpdf/qpdf/QPDF_Name.hh b/libqpdf/qpdf/QPDF_Name.hh index fdc51fb..e69de29 100644 --- a/libqpdf/qpdf/QPDF_Name.hh +++ b/libqpdf/qpdf/QPDF_Name.hh @@ -1,25 +0,0 @@ -#ifndef QPDF_NAME_HH -#define QPDF_NAME_HH - -#include - -class QPDF_Name: public QPDFValue -{ - public: - ~QPDF_Name() override = default; - static std::shared_ptr create(std::string const& name); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - std::string - getStringValue() const override - { - return name; - } - - private: - QPDF_Name(std::string const& name); - std::string name; -}; - -#endif // QPDF_NAME_HH diff --git a/libqpdf/qpdf/QPDF_Null.hh b/libqpdf/qpdf/QPDF_Null.hh deleted file mode 100644 index 231ea66..0000000 --- a/libqpdf/qpdf/QPDF_Null.hh +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef QPDF_NULL_HH -#define QPDF_NULL_HH - -#include - -class QPDF_Null: public QPDFValue -{ - public: - ~QPDF_Null() override = default; - static std::shared_ptr create(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen()); - static std::shared_ptr create( - std::shared_ptr parent, - std::string_view const& static_descr, - std::string var_descr); - static std::shared_ptr create( - std::shared_ptr parent, - std::string_view const& static_descr, - std::string var_descr); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - - private: - QPDF_Null(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen()); -}; - -#endif // QPDF_NULL_HH diff --git a/libqpdf/qpdf/QPDF_Operator.hh b/libqpdf/qpdf/QPDF_Operator.hh deleted file mode 100644 index b9b040d..0000000 --- a/libqpdf/qpdf/QPDF_Operator.hh +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef QPDF_OPERATOR_HH -#define QPDF_OPERATOR_HH - -#include - -class QPDF_Operator: public QPDFValue -{ - public: - ~QPDF_Operator() override = default; - static std::shared_ptr create(std::string const& val); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - std::string - getStringValue() const override - { - return val; - } - - private: - QPDF_Operator(std::string const& val); - std::string val; -}; - -#endif // QPDF_OPERATOR_HH diff --git a/libqpdf/qpdf/QPDF_Real.hh b/libqpdf/qpdf/QPDF_Real.hh deleted file mode 100644 index aa9baa5..0000000 --- a/libqpdf/qpdf/QPDF_Real.hh +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef QPDF_REAL_HH -#define QPDF_REAL_HH - -#include - -class QPDF_Real: public QPDFValue -{ - public: - ~QPDF_Real() override = default; - static std::shared_ptr create(std::string const& val); - static std::shared_ptr - create(double value, int decimal_places, bool trim_trailing_zeroes); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - std::string - getStringValue() const override - { - return val; - } - - private: - QPDF_Real(std::string const& val); - QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes); - // Store reals as strings to avoid roundoff errors. - std::string val; -}; - -#endif // QPDF_REAL_HH diff --git a/libqpdf/qpdf/QPDF_Reserved.hh b/libqpdf/qpdf/QPDF_Reserved.hh deleted file mode 100644 index 801987e..0000000 --- a/libqpdf/qpdf/QPDF_Reserved.hh +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef QPDF_RESERVED_HH -#define QPDF_RESERVED_HH - -#include - -class QPDF_Reserved: public QPDFValue -{ - public: - ~QPDF_Reserved() override = default; - static std::shared_ptr create(); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - - private: - QPDF_Reserved(); -}; - -#endif // QPDF_RESERVED_HH diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh deleted file mode 100644 index 7d44262..0000000 --- a/libqpdf/qpdf/QPDF_Stream.hh +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef QPDF_STREAM_HH -#define QPDF_STREAM_HH - -#include - -#include -#include -#include -#include - -#include -#include - -class Pipeline; -class QPDF; - -class QPDF_Stream final: public QPDFValue -{ - public: - ~QPDF_Stream() final = default; - static std::shared_ptr - create(QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); - std::shared_ptr copy(bool shallow = false) final; - std::string unparse() final; - void writeJSON(int json_version, JSON::Writer& p) final; - void setDescription( - QPDF*, std::shared_ptr& description, qpdf_offset_t offset) final; - void disconnect() final; - - private: - friend class qpdf::Stream; - - QPDF_Stream( - QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); - - void replaceFilterData( - QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length); - void setDictDescription(); - - bool filter_on_write; - QPDFObjectHandle stream_dict; - size_t length; - std::shared_ptr stream_data; - std::shared_ptr stream_provider; - std::vector> token_filters; -}; - -#endif // QPDF_STREAM_HH diff --git a/libqpdf/qpdf/QPDF_String.hh b/libqpdf/qpdf/QPDF_String.hh deleted file mode 100644 index 967b2d3..0000000 --- a/libqpdf/qpdf/QPDF_String.hh +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef QPDF_STRING_HH -#define QPDF_STRING_HH - -#include - -// QPDF_Strings may included embedded null characters. - -class QPDF_String: public QPDFValue -{ - friend class QPDFWriter; - - public: - ~QPDF_String() override = default; - static std::shared_ptr create(std::string const& val); - static std::shared_ptr create_utf16(std::string const& utf8_val); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - std::string unparse(bool force_binary); - void writeJSON(int json_version, JSON::Writer& p) override; - std::string getUTF8Val() const; - std::string - getStringValue() const override - { - return val; - } - - private: - QPDF_String(std::string const& val); - bool useHexString() const; - std::string val; -}; - -#endif // QPDF_STRING_HH diff --git a/libqpdf/qpdf/QPDF_Unresolved.hh b/libqpdf/qpdf/QPDF_Unresolved.hh deleted file mode 100644 index bcd5a63..0000000 --- a/libqpdf/qpdf/QPDF_Unresolved.hh +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef QPDF_UNRESOLVED_HH -#define QPDF_UNRESOLVED_HH - -#include - -class QPDF_Unresolved: public QPDFValue -{ - public: - ~QPDF_Unresolved() override = default; - static std::shared_ptr create(QPDF* qpdf, QPDFObjGen og); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; - std::string getStringValue() const override; - - private: - QPDF_Unresolved(QPDF* qpdf, QPDFObjGen og); -}; - -#endif // QPDF_UNRESOLVED_HH diff --git a/libtests/sparse_array.cc b/libtests/sparse_array.cc index 0212512..84fca1f 100644 --- a/libtests/sparse_array.cc +++ b/libtests/sparse_array.cc @@ -3,14 +3,13 @@ #include #include #include -#include #include int main() { - auto obj = QPDF_Array::create({}, true); + auto obj = QPDFObject::create(std::vector>(), true); auto a = qpdf::Array(obj); assert(a.size() == 0); @@ -88,7 +87,8 @@ main() QPDF pdf; pdf.emptyPDF(); - obj = QPDF_Array::create({10, "null"_qpdf.getObj()}, true); + obj = QPDFObject::create( + std::vector>{10, "null"_qpdf.getObj()}, true); auto b = qpdf::Array(obj); b.setAt(5, pdf.newIndirectNull()); b.setAt(7, "[0 1 2 3]"_qpdf);