Commit 551a953452e54d337bab6a6fa9d5b689f18446a3

Authored by m-holger
Committed by GitHub
2 parents 46425856 6346e664

Merge pull request #1540 from m-holger/oh_name

Create new private-API class Name
libqpdf/QPDFAnnotationObjectHelper.cc
1 1 #include <qpdf/QPDFAnnotationObjectHelper.hh>
2 2  
3   -#include <qpdf/QPDF.hh>
4 3 #include <qpdf/QPDFMatrix.hh>
  4 +#include <qpdf/QPDFObjectHandle_private.hh>
5 5 #include <qpdf/QTC.hh>
6 6 #include <qpdf/QUtil.hh>
7 7  
  8 +using namespace qpdf;
  9 +
8 10 QPDFAnnotationObjectHelper::QPDFAnnotationObjectHelper(QPDFObjectHandle oh) :
9 11 QPDFObjectHelper(oh)
10 12 {
... ... @@ -31,19 +33,15 @@ QPDFAnnotationObjectHelper::getAppearanceDictionary()
31 33 std::string
32 34 QPDFAnnotationObjectHelper::getAppearanceState()
33 35 {
34   - if (oh().getKey("/AS").isName()) {
35   - QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS present");
36   - return oh().getKey("/AS").getName();
37   - }
38   - QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS absent");
39   - return "";
  36 + Name AS = (*this)["/AS"];
  37 + return AS ? AS.value() : "";
40 38 }
41 39  
42 40 int
43 41 QPDFAnnotationObjectHelper::getFlags()
44 42 {
45   - QPDFObjectHandle flags_obj = oh().getKey("/F");
46   - return flags_obj.isInteger() ? flags_obj.getIntValueAsInt() : 0;
  43 + Integer flags_obj = (*this)["/F"];
  44 + return flags_obj ? flags_obj : 0;
47 45 }
48 46  
49 47 QPDFObjectHandle
... ...
libqpdf/QPDFFormFieldObjectHelper.cc
... ... @@ -10,6 +10,8 @@
10 10 #include <qpdf/QUtil.hh>
11 11 #include <cstdlib>
12 12  
  13 +using namespace qpdf;
  14 +
13 15 QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper(QPDFObjectHandle oh) :
14 16 QPDFObjectHelper(oh),
15 17 m(new Members())
... ... @@ -98,9 +100,8 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const&amp; n
98 100 std::string
99 101 QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const& name)
100 102 {
101   - auto fv = getInheritableFieldValue(name);
102   - if (fv.isName()) {
103   - return fv.getName();
  103 + if (Name fv = getInheritableFieldValue(name)) {
  104 + return fv;
104 105 }
105 106 return {};
106 107 }
... ... @@ -245,7 +246,7 @@ QPDFFormFieldObjectHelper::isCheckbox()
245 246 bool
246 247 QPDFFormFieldObjectHelper::isChecked()
247 248 {
248   - return isCheckbox() && getValue().isName() && getValue().getName() != "/Off";
  249 + return isCheckbox() && Name(getValue()) != "/Off";
249 250 }
250 251  
251 252 bool
... ... @@ -301,25 +302,25 @@ QPDFFormFieldObjectHelper::setFieldAttribute(std::string const&amp; key, std::string
301 302 void
302 303 QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances)
303 304 {
  305 + Name name = value;
304 306 if (getFieldType() == "/Btn") {
305 307 if (isCheckbox()) {
306   - if (!value.isName()) {
  308 + if (!name) {
307 309 warn("ignoring attempt to set a checkbox field to a value whose type is not name");
308 310 return;
309 311 }
310   - std::string name = value.getName();
311 312 // Accept any value other than /Off to mean checked. Files have been seen that use
312 313 // /1 or other values.
313 314 setCheckBoxValue(name != "/Off");
314 315 return;
315 316 }
316 317 if (isRadioButton()) {
317   - if (!value.isName()) {
  318 + if (!name) {
318 319 warn(
319 320 "ignoring attempt to set a radio button field to an object that is not a name");
320 321 return;
321 322 }
322   - setRadioButtonValue(value);
  323 + setRadioButtonValue(name);
323 324 return;
324 325 }
325 326 if (isPushbutton()) {
... ... @@ -743,17 +744,18 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper&amp; ao
743 744 {
744 745 QPDFObjectHandle AS = aoh.getAppearanceStream("/N");
745 746 if (AS.null()) {
746   - QTC::TC("qpdf", "QPDFFormFieldObjectHelper create AS from scratch");
747 747 QPDFObjectHandle::Rectangle rect = aoh.getRect();
748 748 QPDFObjectHandle::Rectangle bbox(0, 0, rect.urx - rect.llx, rect.ury - rect.lly);
749   - QPDFObjectHandle dict = QPDFObjectHandle::parse(
750   - "<< /Resources << /ProcSet [ /PDF /Text ] >> /Type /XObject /Subtype /Form >>");
751   - dict.replaceKey("/BBox", QPDFObjectHandle::newFromRectangle(bbox));
  749 + auto dict = Dictionary(
  750 + {{"/BBox", QPDFObjectHandle::newFromRectangle(bbox)},
  751 + {"/Resources", Dictionary({{"/ProcSet", Array({Name("/PDF"), Name("/Text")})}})},
  752 + {"/Type", Name("/XObject")},
  753 + {"/Subtype", Name("/Form")}});
752 754 AS = QPDFObjectHandle::newStream(oh().getOwningQPDF(), "/Tx BMC\nEMC\n");
753 755 AS.replaceDict(dict);
754   - QPDFObjectHandle AP = aoh.getAppearanceDictionary();
755   - if (AP.null()) {
756   - aoh.getObjectHandle().replaceKey("/AP", QPDFObjectHandle::newDictionary());
  756 + Dictionary AP = aoh.getAppearanceDictionary();
  757 + if (!AP) {
  758 + aoh.getObjectHandle().replaceKey("/AP", Dictionary::empty());
757 759 AP = aoh.getAppearanceDictionary();
758 760 }
759 761 AP.replaceKey("/N", AS);
... ... @@ -776,7 +778,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper&amp; ao
776 778 std::string DA = getDefaultAppearance();
777 779 std::string V = getValueAsString();
778 780 std::vector<std::string> opt;
779   - if (isChoice() && ((getFlags() & ff_ch_combo) == 0)) {
  781 + if (isChoice() && (getFlags() & ff_ch_combo) == 0) {
780 782 opt = getChoices();
781 783 }
782 784  
... ... @@ -791,29 +793,26 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper&amp; ao
791 793 std::string font_name = tff.getFontName();
792 794 if (!font_name.empty()) {
793 795 // See if the font is encoded with something we know about.
794   - QPDFObjectHandle resources = AS.getDict().getKey("/Resources");
795   - QPDFObjectHandle font = getFontFromResource(resources, font_name);
796   - bool found_font_in_dr = false;
  796 + Dictionary resources = AS.getDict()["/Resources"];
  797 + Dictionary font = getFontFromResource(resources, font_name);
797 798 if (!font) {
798   - QPDFObjectHandle dr = getDefaultResources();
799   - font = getFontFromResource(dr, font_name);
800   - found_font_in_dr = font.isDictionary();
801   - }
802   - if (found_font_in_dr && resources.isDictionary()) {
803   - if (resources.isIndirect()) {
804   - resources = resources.getQPDF().makeIndirectObject(resources.shallowCopy());
805   - AS.getDict().replaceKey("/Resources", resources);
  799 + font = getFontFromResource(getDefaultResources(), font_name);
  800 + if (resources) {
  801 + if (resources.indirect()) {
  802 + resources = resources.qpdf()->makeIndirectObject(resources.copy());
  803 + AS.getDict().replaceKey("/Resources", resources);
  804 + }
  805 + // Use mergeResources to force /Font to be local
  806 + QPDFObjectHandle res = resources;
  807 + res.mergeResources(Dictionary({{"/Font", Dictionary::empty()}}));
  808 + res.getKey("/Font").replaceKey(font_name, font);
806 809 }
807   - // Use mergeResources to force /Font to be local
808   - resources.mergeResources("<< /Font << >> >>"_qpdf);
809   - resources.getKey("/Font").replaceKey(font_name, font);
810 810 }
811 811  
812   - if (font.isDictionary() && font.getKey("/Encoding").isName()) {
813   - std::string encoding = font.getKey("/Encoding").getName();
814   - if (encoding == "/WinAnsiEncoding") {
  812 + if (Name Encoding = font["/Encoding"]) {
  813 + if (Encoding == "/WinAnsiEncoding") {
815 814 encoder = &QUtil::utf8_to_win_ansi;
816   - } else if (encoding == "/MacRomanEncoding") {
  815 + } else if (Encoding == "/MacRomanEncoding") {
817 816 encoder = &QUtil::utf8_to_mac_roman;
818 817 }
819 818 }
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -766,14 +766,14 @@ QPDFObjectHandle::isScalar() const
766 766 bool
767 767 QPDFObjectHandle::isNameAndEquals(std::string const& name) const
768 768 {
769   - return isName() && (getName() == name);
  769 + return Name(*this) == name;
770 770 }
771 771  
772 772 bool
773 773 QPDFObjectHandle::isDictionaryOfType(std::string const& type, std::string const& subtype) const
774 774 {
775   - return isDictionary() && (type.empty() || getKey("/Type").isNameAndEquals(type)) &&
776   - (subtype.empty() || getKey("/Subtype").isNameAndEquals(subtype));
  775 + return isDictionary() && (type.empty() || Name((*this)["/Type"]) == type) &&
  776 + (subtype.empty() || Name((*this)["/Subtype"]) == subtype);
777 777 }
778 778  
779 779 bool
... ... @@ -952,7 +952,33 @@ QPDFObjectHandle::getValueAsReal(std::string&amp; value) const
952 952 return true;
953 953 }
954 954  
955   -// Name accessors
  955 +// Name methods
  956 +
  957 +QPDFObjectHandle
  958 +QPDFObjectHandle::newName(std::string const& name)
  959 +{
  960 + return {QPDFObject::create<QPDF_Name>(name)};
  961 +}
  962 +
  963 +Name::Name(std::string const& name) :
  964 + BaseHandle(QPDFObject::create<QPDF_Name>(name))
  965 +{
  966 +}
  967 +
  968 +Name::Name(std::string&& name) :
  969 + BaseHandle(QPDFObject::create<QPDF_Name>(std::move(name)))
  970 +{
  971 +}
  972 +
  973 +std::string const&
  974 +Name::value() const
  975 +{
  976 + auto* n = as<QPDF_Name>();
  977 + if (!n) {
  978 + throw invalid_error("Name");
  979 + }
  980 + return n->name;
  981 +}
956 982  
957 983 std::string
958 984 QPDFObjectHandle::getName() const
... ... @@ -961,7 +987,6 @@ QPDFObjectHandle::getName() const
961 987 return obj->getStringValue();
962 988 } else {
963 989 typeWarning("name", "returning dummy name");
964   - QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name");
965 990 return "/QPDFFakeName";
966 991 }
967 992 }
... ... @@ -1695,12 +1720,6 @@ QPDFObjectHandle::newReal(double value, int decimal_places, bool trim_trailing_z
1695 1720 }
1696 1721  
1697 1722 QPDFObjectHandle
1698   -QPDFObjectHandle::newName(std::string const& name)
1699   -{
1700   - return {QPDFObject::create<QPDF_Name>(name)};
1701   -}
1702   -
1703   -QPDFObjectHandle
1704 1723 QPDFObjectHandle::newString(std::string const& str)
1705 1724 {
1706 1725 return {QPDFObject::create<QPDF_String>(str)};
... ...
libqpdf/QPDFOutlineObjectHelper.cc
... ... @@ -48,26 +48,19 @@ QPDFOutlineObjectHelper::getKids()
48 48 QPDFObjectHandle
49 49 QPDFOutlineObjectHelper::getDest()
50 50 {
51   - QPDFObjectHandle dest;
52   - QPDFObjectHandle A;
53   - if (oh().hasKey("/Dest")) {
54   - QTC::TC("qpdf", "QPDFOutlineObjectHelper direct dest");
55   - dest = oh().getKey("/Dest");
56   - } else if (
57   - (A = oh().getKey("/A")).isDictionary() && A.getKey("/S").isName() &&
58   - (A.getKey("/S").getName() == "/GoTo") && A.hasKey("/D")) {
59   - QTC::TC("qpdf", "QPDFOutlineObjectHelper action dest");
60   - dest = A.getKey("/D");
  51 + auto dest = (*this)["/Dest"];
  52 + if (dest.null()) {
  53 + auto const& A = (*this)["/A"];
  54 + if (Name(A["/S"]) == "/GoTo") {
  55 + dest = A["/D"];
  56 + }
61 57 }
62   - if (!dest) {
  58 + if (dest.null()) {
63 59 return QPDFObjectHandle::newNull();
64 60 }
65   -
66 61 if (dest.isName() || dest.isString()) {
67   - QTC::TC("qpdf", "QPDFOutlineObjectHelper named dest");
68   - dest = m->dh.resolveNamedDest(dest);
  62 + return m->dh.resolveNamedDest(dest);
69 63 }
70   -
71 64 return dest;
72 65 }
73 66  
... ...
libqpdf/QPDF_Stream.cc
... ... @@ -38,11 +38,10 @@ namespace
38 38 setDecodeParms(QPDFObjectHandle decode_parms) final
39 39 {
40 40 // we only validate here - processing happens in decryptStream
41   - if (auto dict = decode_parms.as_dictionary(optional)) {
  41 + if (Dictionary dict = decode_parms) {
42 42 for (auto const& [key, value]: dict) {
43 43 if (key == "/Type" &&
44   - (value.null() ||
45   - (value.isName() && value.getName() == "/CryptFilterDecodeParms"))) {
  44 + (value.null() || Name(value) == "/CryptFilterDecodeParms")) {
46 45 continue;
47 46 }
48 47 if (key == "/Name") {
... ... @@ -54,7 +53,7 @@ namespace
54 53 }
55 54 return true;
56 55 }
57   - return false;
  56 + return decode_parms.null();
58 57 }
59 58  
60 59 Pipeline*
... ... @@ -374,7 +373,7 @@ Stream::filterable(
374 373 auto s = stream();
375 374 // Check filters
376 375  
377   - auto filter_obj = s->stream_dict.getKey("/Filter");
  376 + auto const& filter_obj = s->stream_dict["/Filter"];
378 377  
379 378 if (filter_obj.null()) {
380 379 // No filters
... ... @@ -387,14 +386,14 @@ Stream::filterable(
387 386 return false;
388 387 }
389 388 filters.emplace_back(ff());
390   - } else if (auto array = filter_obj.as_array(strict)) {
  389 + } else if (Array array = filter_obj) {
391 390 // Potentially multiple filters
392   - for (auto const& item: array) {
393   - if (!item.isName()) {
  391 + for (Name item: array) {
  392 + if (!item) {
394 393 warn("stream filter type is not name or array");
395 394 return false;
396 395 }
397   - auto ff = s->filter_factory(item.getName());
  396 + auto ff = s->filter_factory(item);
398 397 if (!ff) {
399 398 filters.clear();
400 399 return false;
... ...
libqpdf/QPDF_encryption.cc
... ... @@ -600,18 +600,17 @@ QPDF::EncryptionData::recover_encryption_key_with_password(
600 600 }
601 601  
602 602 QPDF::encryption_method_e
603   -QPDF::EncryptionParameters::interpretCF(QPDFObjectHandle const& cf) const
  603 +QPDF::EncryptionParameters::interpretCF(Name const& cf) const
604 604 {
605   - if (!cf.isName()) {
  605 + if (!cf) {
606 606 // Default: /Identity
607 607 return e_none;
608 608 }
609   - std::string filter = cf.getName();
610   - auto it = crypt_filters.find(filter);
  609 + auto it = crypt_filters.find(cf);
611 610 if (it != crypt_filters.end()) {
612 611 return it->second;
613 612 }
614   - if (filter == "/Identity") {
  613 + if (cf == "/Identity") {
615 614 return e_none;
616 615 }
617 616 return e_unknown;
... ... @@ -677,8 +676,7 @@ QPDF::EncryptionParameters::initialize(QPDF&amp; qpdf)
677 676 throw qpdf.damagedPDF("/Encrypt in trailer dictionary is not a dictionary");
678 677 }
679 678  
680   - if (!(encryption_dict.getKey("/Filter").isName() &&
681   - (encryption_dict.getKey("/Filter").getName() == "/Standard"))) {
  679 + if (Name(encryption_dict["/Filter"]) != "/Standard") {
682 680 throw unsupported("unsupported encryption filter");
683 681 }
684 682 if (!encryption_dict.getKey("/SubFilter").null()) {
... ... @@ -766,16 +764,12 @@ QPDF::EncryptionParameters::initialize(QPDF&amp; qpdf)
766 764 for (auto const& [filter, cdict]: CF.as_dictionary()) {
767 765 if (cdict.isDictionary()) {
768 766 encryption_method_e method = e_none;
769   - if (cdict.getKey("/CFM").isName()) {
770   - std::string method_name = cdict.getKey("/CFM").getName();
771   - if (method_name == "/V2") {
772   - QTC::TC("qpdf", "QPDF_encryption CFM V2");
  767 + if (Name const& CFM = cdict["/CFM"]) {
  768 + if (CFM == "/V2") {
773 769 method = e_rc4;
774   - } else if (method_name == "/AESV2") {
775   - QTC::TC("qpdf", "QPDF_encryption CFM AESV2");
  770 + } else if (CFM == "/AESV2") {
776 771 method = e_aes;
777   - } else if (method_name == "/AESV3") {
778   - QTC::TC("qpdf", "QPDF_encryption CFM AESV3");
  772 + } else if (CFM == "/AESV3") {
779 773 method = e_aesv3;
780 774 } else {
781 775 // Don't complain now -- maybe we won't need to reference this type.
... ... @@ -786,9 +780,9 @@ QPDF::EncryptionParameters::initialize(QPDF&amp; qpdf)
786 780 }
787 781 }
788 782  
789   - cf_stream = interpretCF(encryption_dict.getKey("/StmF"));
790   - cf_string = interpretCF(encryption_dict.getKey("/StrF"));
791   - if (auto EFF = encryption_dict.getKey("/EFF"); EFF.isName()) {
  783 + cf_stream = interpretCF(encryption_dict["/StmF"]);
  784 + cf_string = interpretCF(encryption_dict["/StrF"]);
  785 + if (Name const& EFF = encryption_dict["/EFF"]) {
792 786 // qpdf does not use this for anything other than informational purposes. This is
793 787 // intended to instruct conforming writers on which crypt filter should be used when new
794 788 // file attachments are added to a PDF file, but qpdf never generates encrypted files
... ... @@ -937,12 +931,7 @@ QPDF::decryptStream(
937 931 bool is_root_metadata,
938 932 std::unique_ptr<Pipeline>& decrypt_pipeline)
939 933 {
940   - std::string type;
941   - if (stream_dict.getKey("/Type").isName()) {
942   - type = stream_dict.getKey("/Type").getName();
943   - }
944   - if (type == "/XRef") {
945   - QTC::TC("qpdf", "QPDF_encryption xref stream from encrypted file");
  934 + if (Name(stream_dict["/Type"]) == "/XRef") {
946 935 return;
947 936 }
948 937 bool use_aes = false;
... ... @@ -951,26 +940,20 @@ QPDF::decryptStream(
951 940 std::string method_source = "/StmF from /Encrypt dictionary";
952 941  
953 942 if (stream_dict.getKey("/Filter").isOrHasName("/Crypt")) {
954   - if (stream_dict.getKey("/DecodeParms").isDictionary()) {
955   - QPDFObjectHandle decode_parms = stream_dict.getKey("/DecodeParms");
956   - if (decode_parms.isDictionaryOfType("/CryptFilterDecodeParms")) {
957   - QTC::TC("qpdf", "QPDF_encryption stream crypt filter");
958   - method = encp->interpretCF(decode_parms.getKey("/Name"));
  943 + if (Dictionary decode_parms = stream_dict["/DecodeParms"]) {
  944 + if (Name(decode_parms["/Type"]) == "/CryptFilterDecodeParms") {
  945 + method = encp->interpretCF(decode_parms["/Name"]);
959 946 method_source = "stream's Crypt decode parameters";
960 947 }
961   - } else if (
962   - stream_dict.getKey("/DecodeParms").isArray() &&
963   - stream_dict.getKey("/Filter").isArray()) {
964   - auto filter = stream_dict.getKey("/Filter");
965   - auto decode = stream_dict.getKey("/DecodeParms");
  948 + } else {
  949 + Array filter = stream_dict["/Filter"];
  950 + Array decode = stream_dict.getKey("/DecodeParms");
966 951 if (filter.size() == decode.size()) {
967   - int i = 0;
968   - for (auto const& item: filter.as_array()) {
969   - if (item.isNameAndEquals("/Crypt")) {
970   - auto crypt_params = decode.getArrayItem(i);
971   - if (crypt_params.isDictionary() &&
972   - crypt_params.getKey("/Name").isName()) {
973   - method = encp->interpretCF(crypt_params.getKey("/Name"));
  952 + size_t i = 0;
  953 + for (Name item: filter) {
  954 + if (item == "/Crypt") {
  955 + if (Name name = decode[i]["/Name"]) {
  956 + method = encp->interpretCF(name);
974 957 method_source = "stream's Crypt decode parameters (array)";
975 958 }
976 959 break;
... ... @@ -982,8 +965,7 @@ QPDF::decryptStream(
982 965 }
983 966  
984 967 if (method == e_unknown) {
985   - if ((!encp->encrypt_metadata) && is_root_metadata) {
986   - QTC::TC("qpdf", "QPDF_encryption cleartext metadata");
  968 + if (!encp->encrypt_metadata && is_root_metadata) {
987 969 method = e_none;
988 970 } else {
989 971 method = encp->cf_stream;
... ... @@ -1008,13 +990,13 @@ QPDF::decryptStream(
1008 990  
1009 991 default:
1010 992 // filter local to this stream.
1011   - qpdf_for_warning.warn(QPDFExc(
1012   - qpdf_e_damaged_pdf,
1013   - file->getName(),
1014   - "",
1015   - file->getLastOffset(),
1016   - "unknown encryption filter for streams (check " + method_source +
1017   - "); streams may be decrypted improperly"));
  993 + qpdf_for_warning.warn(
  994 + {qpdf_e_damaged_pdf,
  995 + file->getName(),
  996 + "",
  997 + file->getLastOffset(),
  998 + "unknown encryption filter for streams (check " + method_source +
  999 + "); streams may be decrypted improperly"});
1018 1000 // To avoid repeated warnings, reset cf_stream. Assume we'd want to use AES if V == 4.
1019 1001 encp->cf_stream = e_aes;
1020 1002 use_aes = true;
... ... @@ -1023,11 +1005,9 @@ QPDF::decryptStream(
1023 1005 }
1024 1006 std::string key = getKeyForObject(encp, og, use_aes);
1025 1007 if (use_aes) {
1026   - QTC::TC("qpdf", "QPDF_encryption aes decode stream");
1027 1008 decrypt_pipeline =
1028 1009 std::make_unique<Pl_AES_PDF>("AES stream decryption", pipeline, false, key);
1029 1010 } else {
1030   - QTC::TC("qpdf", "QPDF_encryption rc4 decode stream");
1031 1011 decrypt_pipeline = std::make_unique<Pl_RC4>("RC4 stream decryption", pipeline, key);
1032 1012 }
1033 1013 pipeline = decrypt_pipeline.get();
... ...
libqpdf/qpdf/QPDFObjectHandle_private.hh
... ... @@ -324,7 +324,7 @@ namespace qpdf
324 324 {
325 325 }
326 326  
327   - // Return the integer value. If the object is not a valid integer, throw a
  327 + // Return the integer value. If the object is not a valid Integer, throw a
328 328 // std::invalid_argument exception. If the object is out of range for the target type,
329 329 // throw a std::overflow_error or std::underflow_error exception.
330 330 template <std::integral T>
... ... @@ -391,6 +391,45 @@ namespace qpdf
391 391 // escaping. Return {false, false} if the name is not valid utf-8, otherwise return {true,
392 392 // true} if no characters require or {true, false} if escaping is required.
393 393 static std::pair<bool, bool> analyzeJSONEncoding(std::string const& name);
  394 +
  395 + Name() = default;
  396 + Name(Name const&) = default;
  397 + Name(Name&&) = default;
  398 + Name& operator=(Name const&) = default;
  399 + Name& operator=(Name&&) = default;
  400 + ~Name() = default;
  401 +
  402 + explicit Name(std::string const&);
  403 + explicit Name(std::string&&);
  404 +
  405 + Name(QPDFObjectHandle const& oh) :
  406 + BaseHandle(oh.type_code() == ::ot_name ? oh : QPDFObjectHandle())
  407 + {
  408 + }
  409 +
  410 + Name(QPDFObjectHandle&& oh) :
  411 + BaseHandle(oh.type_code() == ::ot_name ? std::move(oh) : QPDFObjectHandle())
  412 + {
  413 + }
  414 +
  415 + // Return the name value. If the object is not a valid Name, throw a
  416 + // std::invalid_argument exception.
  417 + operator std::string() const&
  418 + {
  419 + return value();
  420 + }
  421 +
  422 + // Return the integer value. If the object is not a valid integer, throw a
  423 + // std::invalid_argument exception.
  424 + std::string const& value() const;
  425 +
  426 + // Return true if object value is equal to the 'rhs' value. Return false if the object is
  427 + // not a valid Name.
  428 + friend bool
  429 + operator==(Name const& lhs, std::string_view rhs)
  430 + {
  431 + return lhs && lhs.value() == rhs;
  432 + }
394 433 };
395 434  
396 435 class Stream final: public BaseHandle
... ...
libqpdf/qpdf/QPDFObject_private.hh
... ... @@ -28,6 +28,7 @@ namespace qpdf
28 28 class BaseDictionary;
29 29 class Dictionary;
30 30 class Integer;
  31 + class Name;
31 32 class Stream;
32 33 } // namespace qpdf
33 34  
... ... @@ -138,6 +139,7 @@ class QPDF_Name final
138 139 {
139 140 friend class QPDFObject;
140 141 friend class qpdf::BaseHandle;
  142 + friend class qpdf::Name;
141 143  
142 144 explicit QPDF_Name(std::string name) :
143 145 name(std::move(name))
... ...
libqpdf/qpdf/QPDF_private.hh
... ... @@ -7,6 +7,8 @@
7 7 #include <qpdf/QPDFObject_private.hh>
8 8 #include <qpdf/QPDFTokenizer_private.hh>
9 9  
  10 +using namespace qpdf;
  11 +
10 12 // Writer class is restricted to QPDFWriter so that only it can call certain methods.
11 13 class QPDF::Writer
12 14 {
... ... @@ -204,7 +206,7 @@ class QPDF::EncryptionParameters
204 206 }
205 207  
206 208 void initialize(QPDF& qpdf);
207   - encryption_method_e interpretCF(QPDFObjectHandle const& cf) const;
  209 + encryption_method_e interpretCF(Name const& cf) const;
208 210  
209 211 private:
210 212 bool encrypted{false};
... ...
qpdf/qpdf.testcov
... ... @@ -96,7 +96,6 @@ QPDF recovered stream length 0
96 96 QPDF found wrong endstream in recovery 0
97 97 QPDF_Stream pipeStreamData with null pipeline 0
98 98 QPDFWriter not recompressing /FlateDecode 0
99   -QPDF_encryption xref stream from encrypted file 0
100 99 QPDFJob unable to filter 0
101 100 QUtil non-trivial UTF-16 0
102 101 QPDF xref overwrite invalid objgen 0
... ... @@ -141,18 +140,12 @@ qpdf-c called qpdf_set_minimum_pdf_version 0
141 140 qpdf-c called qpdf_force_pdf_version 0
142 141 qpdf-c called qpdf_init_write multiple times 0
143 142 QPDF_encryption rc4 decode string 0
144   -QPDF_encryption rc4 decode stream 0
145 143 QPDFWriter not compressing metadata 0
146   -QPDF_encryption CFM V2 0
147   -QPDF_encryption CFM AESV2 0
148 144 QPDF_encryption aes decode string 0
149   -QPDF_encryption cleartext metadata 0
150   -QPDF_encryption aes decode stream 0
151 145 QPDFWriter forcing object stream disable 0
152 146 QPDFWriter forced version disabled encryption 0
153 147 qpdf-c called qpdf_set_r4_encryption_parameters_insecure 0
154 148 qpdf-c called qpdf_set_static_aes_IV 0
155   -QPDF_encryption stream crypt filter 0
156 149 QPDF ERR object stream with wrong type 0
157 150 QPDF object gone after xref reconstruction 0
158 151 qpdf-c called qpdf_has_error 0
... ... @@ -222,7 +215,6 @@ QPDFWriter remove ADBE 0
222 215 QPDFWriter remove existing Extensions 0
223 216 QPDFWriter preserve ADBE 0
224 217 QPDF_encryption skip 0x28 0
225   -QPDF_encryption CFM AESV3 0
226 218 qpdf-c called qpdf_get_pdf_extension_level 0
227 219 qpdf-c called qpdf_set_r5_encryption_parameters 0
228 220 qpdf-c called qpdf_set_r6_encryption_parameters 0
... ... @@ -275,7 +267,6 @@ QPDFParser eof in parse 0
275 267 QPDFParser eof in parseRemainder 0
276 268 QPDFObjectHandle boolean returning false 0
277 269 QPDFObjectHandle real returning 0.0 0
278   -QPDFObjectHandle name returning dummy name 0
279 270 QPDFObjectHandle string returning empty string 0
280 271 QPDFObjectHandle string returning empty utf8 0
281 272 QPDFObjectHandle operator returning fake value 0
... ... @@ -301,8 +292,6 @@ QPDFFormFieldObjectHelper TU absent 0
301 292 QPDFFormFieldObjectHelper TM absent 0
302 293 QPDFFormFieldObjectHelper Q present 1
303 294 QPDFFormFieldObjectHelper DA present 1
304   -QPDFAnnotationObjectHelper AS present 0
305   -QPDFAnnotationObjectHelper AS absent 0
306 295 QPDFAnnotationObjectHelper AP stream 0
307 296 QPDFAnnotationObjectHelper AP dictionary 0
308 297 QPDFAnnotationObjectHelper AP sub stream 0
... ... @@ -317,9 +306,6 @@ QPDFAcroFormDocumentHelper annotation found 1
317 306 QPDFJob keep files open n 0
318 307 QPDFJob keep files open y 0
319 308 QPDFJob automatically set keep files open 1
320   -QPDFOutlineObjectHelper direct dest 0
321   -QPDFOutlineObjectHelper action dest 0
322   -QPDFOutlineObjectHelper named dest 0
323 309 QPDFOutlineDocumentHelper string named dest 0
324 310 QPDFObjectHandle merge top type mismatch 0
325 311 QPDFObjectHandle merge shallow copy 0
... ... @@ -366,7 +352,6 @@ QPDFJob bytes fallback warning 0
366 352 QPDFJob invalid utf-8 in auto 0
367 353 QPDFJob input password hex-bytes 0
368 354 QPDFPageDocumentHelper ignore annotation with no appearance 0
369   -QPDFFormFieldObjectHelper create AS from scratch 0
370 355 QPDFFormFieldObjectHelper replaced BMC at EOF 0
371 356 QPDFFormFieldObjectHelper fallback Tf 0
372 357 QPDFPageObjectHelper copy shared attribute 1
... ...