#include #include #include #include #include #include using namespace std::literals; 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 += QPDF_Name::normalizeName(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(QPDF_Name::normalizeName(iter.first)) << "\": "; } else if (auto res = QPDF_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(QPDF_Name::normalizeName(iter.first)) << "\": "; } iter.second.writeJSON(json_version, p); } } p.writeEnd('}'); } bool QPDF_Dictionary::hasKey(std::string const& key) { return ((this->items.count(key) > 0) && (!this->items[key].isNull())); } QPDFObjectHandle QPDF_Dictionary::getKey(std::string const& key) { // PDF spec says fetching a non-existent key from a dictionary returns the null object. auto item = this->items.find(key); if (item != this->items.end()) { // May be a null object return item->second; } else { static auto constexpr msg = " -> dictionary key $VD"sv; return QPDF_Null::create(shared_from_this(), msg, key); } } std::set QPDF_Dictionary::getKeys() { std::set result; for (auto& iter: this->items) { if (!iter.second.isNull()) { result.insert(iter.first); } } return result; } std::map const& QPDF_Dictionary::getAsMap() const { return this->items; } void QPDF_Dictionary::replaceKey(std::string const& key, QPDFObjectHandle value) { if (value.isNull() && !value.isIndirect()) { // The PDF spec doesn't distinguish between keys with null values and missing keys. Allow // indirect nulls which are equivalent to a dangling reference, which is permitted by the // spec. removeKey(key); } else { // add or replace value this->items[key] = value; } } void QPDF_Dictionary::removeKey(std::string const& key) { // no-op if key does not exist this->items.erase(key); }