diff --git a/include/qpdf/QPDFFileSpecObjectHelper.hh b/include/qpdf/QPDFFileSpecObjectHelper.hh index 1999ed2..6b6bde4 100644 --- a/include/qpdf/QPDFFileSpecObjectHelper.hh +++ b/include/qpdf/QPDFFileSpecObjectHelper.hh @@ -87,18 +87,7 @@ class QPDFFileSpecObjectHelper: public QPDFObjectHelper setFilename(std::string const& unicode_name, std::string const& compat_name = ""); private: - class Members - { - friend class QPDFFileSpecObjectHelper; - - public: - ~Members() = default; - - private: - Members() = default; - Members(Members const&) = delete; - }; - + class Members; std::shared_ptr m; }; diff --git a/libqpdf/QPDFFileSpecObjectHelper.cc b/libqpdf/QPDFFileSpecObjectHelper.cc index 3932466..d92aac4 100644 --- a/libqpdf/QPDFFileSpecObjectHelper.cc +++ b/libqpdf/QPDFFileSpecObjectHelper.cc @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -8,6 +9,11 @@ #include using namespace std::literals; +using namespace qpdf; + +class QPDFFileSpecObjectHelper::Members +{ +}; QPDFFileSpecObjectHelper::QPDFFileSpecObjectHelper(QPDFObjectHandle oh) : QPDFObjectHelper(oh) @@ -26,9 +32,8 @@ static const std::array name_keys = {"/UF"s, "/F"s, "/Unix"s, "/ std::string QPDFFileSpecObjectHelper::getDescription() { - auto desc = oh().getKey("/Desc"); - if (desc.isString()) { - return desc.getUTF8Value(); + if (String Desc = oh().getKey("/Desc")) { + return Desc.utf8_value(); } return {}; } @@ -37,12 +42,11 @@ std::string QPDFFileSpecObjectHelper::getFilename() { for (auto const& i: name_keys) { - auto k = oh().getKey(i); - if (k.isString()) { - return k.getUTF8Value(); + if (String k = oh()[i]) { + return k.utf8_value(); } } - return ""; + return {}; } std::map @@ -50,9 +54,8 @@ QPDFFileSpecObjectHelper::getFilenames() { std::map result; for (auto const& i: name_keys) { - auto k = oh().getKey(i); - if (k.isString()) { - result[i] = k.getUTF8Value(); + if (String k = oh()[i]) { + result[i] = k.utf8_value(); } } return result; @@ -61,17 +64,16 @@ QPDFFileSpecObjectHelper::getFilenames() QPDFObjectHandle QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key) { - auto ef = oh().getKey("/EF"); - if (!ef.isDictionary()) { - return QPDFObjectHandle::newNull(); - } - if (!key.empty()) { - return ef.getKey(key); - } - for (auto const& i: name_keys) { - auto k = ef.getKey(i); - if (k.isStream()) { - return k; + if (Dictionary EF = oh()["/EF"]) { + if (!key.empty() && EF.contains(key)) { + if (auto result = EF[key]) { + return result; + } + } + for (auto const& i: name_keys) { + if (Stream k = EF[i]) { + return k; + } } } return QPDFObjectHandle::newNull(); @@ -97,21 +99,18 @@ QPDFFileSpecObjectHelper QPDFFileSpecObjectHelper::createFileSpec( QPDF& qpdf, std::string const& filename, QPDFEFStreamObjectHelper efsoh) { - auto oh = qpdf.makeIndirectObject(QPDFObjectHandle::newDictionary()); - oh.replaceKey("/Type", QPDFObjectHandle::newName("/Filespec")); - QPDFFileSpecObjectHelper result(oh); - result.setFilename(filename); - auto ef = QPDFObjectHandle::newDictionary(); - ef.replaceKey("/F", efsoh.getObjectHandle()); - ef.replaceKey("/UF", efsoh.getObjectHandle()); - oh.replaceKey("/EF", ef); - return result; + auto UF = String::utf16(filename); + return {qpdf.makeIndirectObject(Dictionary( + {{"/Type", Name("/Filespec")}, + {"/F", UF}, + {"/UF", UF}, + {"/EF", Dictionary({{"/F", efsoh}, {"/UF", efsoh}})}}))}; } QPDFFileSpecObjectHelper& QPDFFileSpecObjectHelper::setDescription(std::string const& desc) { - oh().replaceKey("/Desc", QPDFObjectHandle::newUnicodeString(desc)); + oh().replaceKey("/Desc", String::utf16(desc)); return *this; } @@ -119,14 +118,12 @@ QPDFFileSpecObjectHelper& QPDFFileSpecObjectHelper::setFilename( std::string const& unicode_name, std::string const& compat_name) { - auto uf = QPDFObjectHandle::newUnicodeString(unicode_name); + auto uf = String::utf16(unicode_name); oh().replaceKey("/UF", uf); if (compat_name.empty()) { - QTC::TC("qpdf", "QPDFFileSpecObjectHelper empty compat_name"); oh().replaceKey("/F", uf); } else { - QTC::TC("qpdf", "QPDFFileSpecObjectHelper non-empty compat_name"); - oh().replaceKey("/F", QPDFObjectHandle::newString(compat_name)); + oh().replaceKey("/F", String(compat_name)); } return *this; } diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 9749f07..2c10208 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -325,8 +325,6 @@ QPDFPageObjectHelper::forEachXObject 3 NNTree erased last kid/item in tree 1 QPDFPageObjectHelper unresolved names 0 QPDFPageObjectHelper resolving unresolved 0 -QPDFFileSpecObjectHelper empty compat_name 0 -QPDFFileSpecObjectHelper non-empty compat_name 0 QPDFAcroFormDocumentHelper copy annotation 3 QPDFAcroFormDocumentHelper field with parent 3 QPDFObjectHandle merge reuse 0 diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 759f27e..b9a4e2f 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -2644,6 +2644,8 @@ test_76(QPDF& pdf, char const* arg2) "att2", QPDFFileSpecObjectHelper::createFileSpec(pdf, "att2.txt", efs2)); auto fs3 = QPDFFileSpecObjectHelper::createFileSpec(pdf, "att3.txt", efs3); efdh.replaceEmbeddedFile("att3", fs3); + fs3.setFilename("\xcf\x80.txt"); + assert(fs3.getFilename() == "\xcf\x80.txt"); fs3.setFilename("\xcf\x80.txt", "att3.txt"); assert(efs1.getCreationDate() == "D:20210207191121-05'00'");