Commit 2336590ff19ed1fab25901fe0f14694c46818b6a

Authored by m-holger
Committed by GitHub
2 parents 628cf873 9cbc87e1

Merge pull request #1578 from m-holger/members

Refactor QPDFFormFieldObjectHelper and QPDFEFStreamObjectHelper
include/qpdf/QPDFEFStreamObjectHelper.hh
@@ -92,17 +92,7 @@ class QPDFEFStreamObjectHelper: public QPDFObjectHelper @@ -92,17 +92,7 @@ class QPDFEFStreamObjectHelper: public QPDFObjectHelper
92 void setParam(std::string const& pkey, QPDFObjectHandle const&); 92 void setParam(std::string const& pkey, QPDFObjectHandle const&);
93 static QPDFEFStreamObjectHelper newFromStream(QPDFObjectHandle stream); 93 static QPDFEFStreamObjectHelper newFromStream(QPDFObjectHandle stream);
94 94
95 - class Members  
96 - {  
97 - friend class QPDFEFStreamObjectHelper;  
98 -  
99 - public:  
100 - ~Members() = default;  
101 -  
102 - private:  
103 - Members() = default;  
104 - Members(Members const&) = delete;  
105 - }; 95 + class Members;
106 96
107 std::shared_ptr<Members> m; 97 std::shared_ptr<Members> m;
108 }; 98 };
include/qpdf/QPDFFileSpecObjectHelper.hh
@@ -87,18 +87,7 @@ class QPDFFileSpecObjectHelper: public QPDFObjectHelper @@ -87,18 +87,7 @@ class QPDFFileSpecObjectHelper: public QPDFObjectHelper
87 setFilename(std::string const& unicode_name, std::string const& compat_name = ""); 87 setFilename(std::string const& unicode_name, std::string const& compat_name = "");
88 88
89 private: 89 private:
90 - class Members  
91 - {  
92 - friend class QPDFFileSpecObjectHelper;  
93 -  
94 - public:  
95 - ~Members() = default;  
96 -  
97 - private:  
98 - Members() = default;  
99 - Members(Members const&) = delete;  
100 - };  
101 - 90 + class Members;
102 std::shared_ptr<Members> m; 91 std::shared_ptr<Members> m;
103 }; 92 };
104 93
libqpdf/CMakeLists.txt
@@ -44,7 +44,6 @@ set(libqpdf_SOURCES @@ -44,7 +44,6 @@ set(libqpdf_SOURCES
44 Pl_Flate.cc 44 Pl_Flate.cc
45 Pl_Function.cc 45 Pl_Function.cc
46 Pl_LZWDecoder.cc 46 Pl_LZWDecoder.cc
47 - Pl_MD5.cc  
48 Pl_OStream.cc 47 Pl_OStream.cc
49 Pl_PNGFilter.cc 48 Pl_PNGFilter.cc
50 Pl_QPDFTokenizer.cc 49 Pl_QPDFTokenizer.cc
libqpdf/MD5.cc
1 #include <qpdf/MD5.hh> 1 #include <qpdf/MD5.hh>
2 2
  3 +#include <qpdf/Pl_MD5.hh>
  4 +
3 #include <qpdf/QIntC.hh> 5 #include <qpdf/QIntC.hh>
4 #include <qpdf/QPDFCryptoProvider.hh> 6 #include <qpdf/QPDFCryptoProvider.hh>
5 #include <qpdf/QUtil.hh> 7 #include <qpdf/QUtil.hh>
@@ -163,3 +165,29 @@ MD5::checkFileChecksum(char const* const checksum, char const* filename, qpdf_of @@ -163,3 +165,29 @@ MD5::checkFileChecksum(char const* const checksum, char const* filename, qpdf_of
163 } 165 }
164 return result; 166 return result;
165 } 167 }
  168 +
  169 +void
  170 +Pl_MD5::write(unsigned char const* buf, size_t len)
  171 +{
  172 + if (enabled) {
  173 + if (!in_progress) {
  174 + md5.reset();
  175 + in_progress = true;
  176 + }
  177 +
  178 + // Write in chunks in case len is too big to fit in an int. Assume int is at least 32 bits.
  179 + static size_t const max_bytes = 1 << 30;
  180 + size_t bytes_left = len;
  181 + unsigned char const* data = buf;
  182 + while (bytes_left > 0) {
  183 + size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
  184 + md5.encodeDataIncrementally(reinterpret_cast<char const*>(data), bytes);
  185 + bytes_left -= bytes;
  186 + data += bytes;
  187 + }
  188 + }
  189 +
  190 + if (next()) {
  191 + next()->write(buf, len);
  192 + }
  193 +}
libqpdf/Pl_MD5.cc deleted
1 -#include <qpdf/Pl_MD5.hh>  
2 -  
3 -#include <stdexcept>  
4 -  
5 -Pl_MD5::Pl_MD5(char const* identifier, Pipeline* next) :  
6 - Pipeline(identifier, next)  
7 -{  
8 - if (!next) {  
9 - throw std::logic_error("Attempt to create Pl_MD5 with nullptr as next");  
10 - }  
11 -}  
12 -  
13 -void  
14 -Pl_MD5::write(unsigned char const* buf, size_t len)  
15 -{  
16 - if (enabled) {  
17 - if (!in_progress) {  
18 - md5.reset();  
19 - in_progress = true;  
20 - }  
21 -  
22 - // Write in chunks in case len is too big to fit in an int. Assume int is at least 32 bits.  
23 - static size_t const max_bytes = 1 << 30;  
24 - size_t bytes_left = len;  
25 - unsigned char const* data = buf;  
26 - while (bytes_left > 0) {  
27 - size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);  
28 - md5.encodeDataIncrementally(reinterpret_cast<char const*>(data), bytes);  
29 - bytes_left -= bytes;  
30 - data += bytes;  
31 - }  
32 - }  
33 -  
34 - next()->write(buf, len);  
35 -}  
36 -  
37 -void  
38 -Pl_MD5::finish()  
39 -{  
40 - next()->finish();  
41 - if (!persist_across_finish) {  
42 - in_progress = false;  
43 - }  
44 -}  
45 -  
46 -void  
47 -Pl_MD5::enable(bool is_enabled)  
48 -{  
49 - enabled = is_enabled;  
50 -}  
51 -  
52 -void  
53 -Pl_MD5::persistAcrossFinish(bool persist)  
54 -{  
55 - persist_across_finish = persist;  
56 -}  
57 -  
58 -std::string  
59 -Pl_MD5::getHexDigest()  
60 -{  
61 - if (!enabled) {  
62 - throw std::logic_error("digest requested for a disabled MD5 Pipeline");  
63 - }  
64 - in_progress = false;  
65 - return md5.unparse();  
66 -}  
libqpdf/QPDFEFStreamObjectHelper.cc
1 #include <qpdf/QPDFEFStreamObjectHelper.hh> 1 #include <qpdf/QPDFEFStreamObjectHelper.hh>
2 2
3 -#include <qpdf/Pl_Count.hh>  
4 -#include <qpdf/Pl_Discard.hh> 3 +#include <qpdf/Pipeline_private.hh>
5 #include <qpdf/Pl_MD5.hh> 4 #include <qpdf/Pl_MD5.hh>
6 #include <qpdf/QIntC.hh> 5 #include <qpdf/QIntC.hh>
7 #include <qpdf/QPDF.hh> 6 #include <qpdf/QPDF.hh>
  7 +#include <qpdf/QPDFObjectHandle_private.hh>
8 #include <qpdf/QUtil.hh> 8 #include <qpdf/QUtil.hh>
9 9
  10 +using namespace qpdf;
  11 +
  12 +class QPDFEFStreamObjectHelper::Members
  13 +{
  14 +};
  15 +
10 QPDFEFStreamObjectHelper::QPDFEFStreamObjectHelper(QPDFObjectHandle oh) : 16 QPDFEFStreamObjectHelper::QPDFEFStreamObjectHelper(QPDFObjectHandle oh) :
11 - QPDFObjectHelper(oh),  
12 - m(new Members()) 17 + QPDFObjectHelper(oh)
13 { 18 {
14 } 19 }
15 20
16 QPDFObjectHandle 21 QPDFObjectHandle
17 QPDFEFStreamObjectHelper::getParam(std::string const& pkey) 22 QPDFEFStreamObjectHelper::getParam(std::string const& pkey)
18 { 23 {
19 - auto params = oh().getDict().getKey("/Params");  
20 - if (params.isDictionary()) {  
21 - return params.getKey(pkey); 24 + if (auto result = oh().getDict()["/Params"][pkey]) {
  25 + return result;
22 } 26 }
23 - return QPDFObjectHandle::newNull(); 27 + return {};
24 } 28 }
25 29
26 void 30 void
27 QPDFEFStreamObjectHelper::setParam(std::string const& pkey, QPDFObjectHandle const& pval) 31 QPDFEFStreamObjectHelper::setParam(std::string const& pkey, QPDFObjectHandle const& pval)
28 { 32 {
29 - auto params = oh().getDict().getKey("/Params");  
30 - if (!params.isDictionary()) {  
31 - params = oh().getDict().replaceKeyAndGetNew("/Params", QPDFObjectHandle::newDictionary()); 33 + if (Dictionary Params = oh().getDict()["/Params"]) {
  34 + Params.replaceKey(pkey, pval);
  35 + return;
32 } 36 }
33 - params.replaceKey(pkey, pval); 37 + oh().getDict().replaceKey("/Params", Dictionary({{pkey, pval}}));
34 } 38 }
35 39
36 std::string 40 std::string
37 QPDFEFStreamObjectHelper::getCreationDate() 41 QPDFEFStreamObjectHelper::getCreationDate()
38 { 42 {
39 - auto val = getParam("/CreationDate");  
40 - if (val.isString()) {  
41 - return val.getUTF8Value(); 43 + if (String CreationDate = getParam("/CreationDate")) {
  44 + return CreationDate.utf8_value();
42 } 45 }
43 - return ""; 46 + return {};
44 } 47 }
45 48
46 std::string 49 std::string
47 QPDFEFStreamObjectHelper::getModDate() 50 QPDFEFStreamObjectHelper::getModDate()
48 { 51 {
49 - auto val = getParam("/ModDate");  
50 - if (val.isString()) {  
51 - return val.getUTF8Value(); 52 + if (String ModDate = getParam("/ModDate")) {
  53 + return ModDate.utf8_value();
52 } 54 }
53 - return ""; 55 + return {};
54 } 56 }
55 57
56 size_t 58 size_t
57 QPDFEFStreamObjectHelper::getSize() 59 QPDFEFStreamObjectHelper::getSize()
58 { 60 {
59 - auto val = getParam("/Size");  
60 - if (val.isInteger()) {  
61 - return QIntC::to_size(val.getUIntValueAsUInt()); 61 + if (Integer Size = getParam("/Size")) {
  62 + size_t result = Size;
  63 + return result;
62 } 64 }
63 return 0; 65 return 0;
64 } 66 }
@@ -66,30 +68,27 @@ QPDFEFStreamObjectHelper::getSize() @@ -66,30 +68,27 @@ QPDFEFStreamObjectHelper::getSize()
66 std::string 68 std::string
67 QPDFEFStreamObjectHelper::getSubtype() 69 QPDFEFStreamObjectHelper::getSubtype()
68 { 70 {
69 - auto val = oh().getDict().getKey("/Subtype");  
70 - if (val.isName()) {  
71 - auto n = val.getName();  
72 - if (n.length() > 1) {  
73 - return n.substr(1); 71 + if (Name Subtype = oh().getDict()["/Subtype"]) {
  72 + if (Subtype.value().size() > 1) {
  73 + return Subtype.value().substr(1);
74 } 74 }
75 } 75 }
76 - return ""; 76 + return {};
77 } 77 }
78 78
79 std::string 79 std::string
80 QPDFEFStreamObjectHelper::getChecksum() 80 QPDFEFStreamObjectHelper::getChecksum()
81 { 81 {
82 - auto val = getParam("/CheckSum");  
83 - if (val.isString()) {  
84 - return val.getStringValue(); 82 + if (String CheckSum = getParam("/CheckSum")) {
  83 + return CheckSum.value();
85 } 84 }
86 - return ""; 85 + return {};
87 } 86 }
88 87
89 QPDFEFStreamObjectHelper 88 QPDFEFStreamObjectHelper
90 QPDFEFStreamObjectHelper::createEFStream(QPDF& qpdf, std::shared_ptr<Buffer> data) 89 QPDFEFStreamObjectHelper::createEFStream(QPDF& qpdf, std::shared_ptr<Buffer> data)
91 { 90 {
92 - return newFromStream(qpdf.newStream(data)); 91 + return newFromStream(qpdf.newStream(std::move(data)));
93 } 92 }
94 93
95 QPDFEFStreamObjectHelper 94 QPDFEFStreamObjectHelper
@@ -102,28 +101,28 @@ QPDFEFStreamObjectHelper @@ -102,28 +101,28 @@ QPDFEFStreamObjectHelper
102 QPDFEFStreamObjectHelper::createEFStream(QPDF& qpdf, std::function<void(Pipeline*)> provider) 101 QPDFEFStreamObjectHelper::createEFStream(QPDF& qpdf, std::function<void(Pipeline*)> provider)
103 { 102 {
104 auto stream = qpdf.newStream(); 103 auto stream = qpdf.newStream();
105 - stream.replaceStreamData(provider, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull()); 104 + stream.replaceStreamData(provider, {}, {});
106 return newFromStream(stream); 105 return newFromStream(stream);
107 } 106 }
108 107
109 QPDFEFStreamObjectHelper& 108 QPDFEFStreamObjectHelper&
110 QPDFEFStreamObjectHelper::setCreationDate(std::string const& date) 109 QPDFEFStreamObjectHelper::setCreationDate(std::string const& date)
111 { 110 {
112 - setParam("/CreationDate", QPDFObjectHandle::newString(date)); 111 + setParam("/CreationDate", String(date));
113 return *this; 112 return *this;
114 } 113 }
115 114
116 QPDFEFStreamObjectHelper& 115 QPDFEFStreamObjectHelper&
117 QPDFEFStreamObjectHelper::setModDate(std::string const& date) 116 QPDFEFStreamObjectHelper::setModDate(std::string const& date)
118 { 117 {
119 - setParam("/ModDate", QPDFObjectHandle::newString(date)); 118 + setParam("/ModDate", String(date));
120 return *this; 119 return *this;
121 } 120 }
122 121
123 QPDFEFStreamObjectHelper& 122 QPDFEFStreamObjectHelper&
124 QPDFEFStreamObjectHelper::setSubtype(std::string const& subtype) 123 QPDFEFStreamObjectHelper::setSubtype(std::string const& subtype)
125 { 124 {
126 - oh().getDict().replaceKey("/Subtype", QPDFObjectHandle::newName("/" + subtype)); 125 + oh().getDict().replaceKey("/Subtype", Name("/" + subtype));
127 return *this; 126 return *this;
128 } 127 }
129 128
@@ -131,18 +130,16 @@ QPDFEFStreamObjectHelper @@ -131,18 +130,16 @@ QPDFEFStreamObjectHelper
131 QPDFEFStreamObjectHelper::newFromStream(QPDFObjectHandle stream) 130 QPDFEFStreamObjectHelper::newFromStream(QPDFObjectHandle stream)
132 { 131 {
133 QPDFEFStreamObjectHelper result(stream); 132 QPDFEFStreamObjectHelper result(stream);
134 - stream.getDict().replaceKey("/Type", QPDFObjectHandle::newName("/EmbeddedFile"));  
135 - Pl_Discard discard; 133 + stream.getDict().replaceKey("/Type", Name("/EmbeddedFile"));
136 // The PDF spec specifies use of MD5 here and notes that it is not to be used for security. MD5 134 // The PDF spec specifies use of MD5 here and notes that it is not to be used for security. MD5
137 // is known to be insecure. 135 // is known to be insecure.
138 - Pl_MD5 md5("EF md5", &discard);  
139 - Pl_Count count("EF size", &md5); 136 + Pl_MD5 md5("EF md5");
  137 + pl::Count count(0, &md5);
140 if (!stream.pipeStreamData(&count, nullptr, 0, qpdf_dl_all)) { 138 if (!stream.pipeStreamData(&count, nullptr, 0, qpdf_dl_all)) {
141 stream.warn("unable to get stream data for new embedded file stream"); 139 stream.warn("unable to get stream data for new embedded file stream");
142 } else { 140 } else {
143 - result.setParam("/Size", QPDFObjectHandle::newInteger(count.getCount()));  
144 - result.setParam(  
145 - "/CheckSum", QPDFObjectHandle::newString(QUtil::hex_decode(md5.getHexDigest()))); 141 + result.setParam("/Size", Integer(count.getCount()));
  142 + result.setParam("/CheckSum", String(QUtil::hex_decode(md5.getHexDigest())));
146 } 143 }
147 return result; 144 return result;
148 } 145 }
libqpdf/QPDFFileSpecObjectHelper.cc
1 #include <qpdf/QPDFFileSpecObjectHelper.hh> 1 #include <qpdf/QPDFFileSpecObjectHelper.hh>
2 2
3 #include <qpdf/QPDF.hh> 3 #include <qpdf/QPDF.hh>
  4 +#include <qpdf/QPDFObjectHandle_private.hh>
4 #include <qpdf/QTC.hh> 5 #include <qpdf/QTC.hh>
5 #include <qpdf/QUtil.hh> 6 #include <qpdf/QUtil.hh>
6 7
@@ -8,6 +9,11 @@ @@ -8,6 +9,11 @@
8 #include <string> 9 #include <string>
9 10
10 using namespace std::literals; 11 using namespace std::literals;
  12 +using namespace qpdf;
  13 +
  14 +class QPDFFileSpecObjectHelper::Members
  15 +{
  16 +};
11 17
12 QPDFFileSpecObjectHelper::QPDFFileSpecObjectHelper(QPDFObjectHandle oh) : 18 QPDFFileSpecObjectHelper::QPDFFileSpecObjectHelper(QPDFObjectHandle oh) :
13 QPDFObjectHelper(oh) 19 QPDFObjectHelper(oh)
@@ -26,9 +32,8 @@ static const std::array&lt;std::string, 5&gt; name_keys = {&quot;/UF&quot;s, &quot;/F&quot;s, &quot;/Unix&quot;s, &quot;/ @@ -26,9 +32,8 @@ static const std::array&lt;std::string, 5&gt; name_keys = {&quot;/UF&quot;s, &quot;/F&quot;s, &quot;/Unix&quot;s, &quot;/
26 std::string 32 std::string
27 QPDFFileSpecObjectHelper::getDescription() 33 QPDFFileSpecObjectHelper::getDescription()
28 { 34 {
29 - auto desc = oh().getKey("/Desc");  
30 - if (desc.isString()) {  
31 - return desc.getUTF8Value(); 35 + if (String Desc = oh().getKey("/Desc")) {
  36 + return Desc.utf8_value();
32 } 37 }
33 return {}; 38 return {};
34 } 39 }
@@ -37,12 +42,11 @@ std::string @@ -37,12 +42,11 @@ std::string
37 QPDFFileSpecObjectHelper::getFilename() 42 QPDFFileSpecObjectHelper::getFilename()
38 { 43 {
39 for (auto const& i: name_keys) { 44 for (auto const& i: name_keys) {
40 - auto k = oh().getKey(i);  
41 - if (k.isString()) {  
42 - return k.getUTF8Value(); 45 + if (String k = oh()[i]) {
  46 + return k.utf8_value();
43 } 47 }
44 } 48 }
45 - return ""; 49 + return {};
46 } 50 }
47 51
48 std::map<std::string, std::string> 52 std::map<std::string, std::string>
@@ -50,9 +54,8 @@ QPDFFileSpecObjectHelper::getFilenames() @@ -50,9 +54,8 @@ QPDFFileSpecObjectHelper::getFilenames()
50 { 54 {
51 std::map<std::string, std::string> result; 55 std::map<std::string, std::string> result;
52 for (auto const& i: name_keys) { 56 for (auto const& i: name_keys) {
53 - auto k = oh().getKey(i);  
54 - if (k.isString()) {  
55 - result[i] = k.getUTF8Value(); 57 + if (String k = oh()[i]) {
  58 + result[i] = k.utf8_value();
56 } 59 }
57 } 60 }
58 return result; 61 return result;
@@ -61,17 +64,16 @@ QPDFFileSpecObjectHelper::getFilenames() @@ -61,17 +64,16 @@ QPDFFileSpecObjectHelper::getFilenames()
61 QPDFObjectHandle 64 QPDFObjectHandle
62 QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key) 65 QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key)
63 { 66 {
64 - auto ef = oh().getKey("/EF");  
65 - if (!ef.isDictionary()) {  
66 - return QPDFObjectHandle::newNull();  
67 - }  
68 - if (!key.empty()) {  
69 - return ef.getKey(key);  
70 - }  
71 - for (auto const& i: name_keys) {  
72 - auto k = ef.getKey(i);  
73 - if (k.isStream()) {  
74 - return k; 67 + if (Dictionary EF = oh()["/EF"]) {
  68 + if (!key.empty() && EF.contains(key)) {
  69 + if (auto result = EF[key]) {
  70 + return result;
  71 + }
  72 + }
  73 + for (auto const& i: name_keys) {
  74 + if (Stream k = EF[i]) {
  75 + return k;
  76 + }
75 } 77 }
76 } 78 }
77 return QPDFObjectHandle::newNull(); 79 return QPDFObjectHandle::newNull();
@@ -97,21 +99,18 @@ QPDFFileSpecObjectHelper @@ -97,21 +99,18 @@ QPDFFileSpecObjectHelper
97 QPDFFileSpecObjectHelper::createFileSpec( 99 QPDFFileSpecObjectHelper::createFileSpec(
98 QPDF& qpdf, std::string const& filename, QPDFEFStreamObjectHelper efsoh) 100 QPDF& qpdf, std::string const& filename, QPDFEFStreamObjectHelper efsoh)
99 { 101 {
100 - auto oh = qpdf.makeIndirectObject(QPDFObjectHandle::newDictionary());  
101 - oh.replaceKey("/Type", QPDFObjectHandle::newName("/Filespec"));  
102 - QPDFFileSpecObjectHelper result(oh);  
103 - result.setFilename(filename);  
104 - auto ef = QPDFObjectHandle::newDictionary();  
105 - ef.replaceKey("/F", efsoh.getObjectHandle());  
106 - ef.replaceKey("/UF", efsoh.getObjectHandle());  
107 - oh.replaceKey("/EF", ef);  
108 - return result; 102 + auto UF = String::utf16(filename);
  103 + return {qpdf.makeIndirectObject(Dictionary(
  104 + {{"/Type", Name("/Filespec")},
  105 + {"/F", UF},
  106 + {"/UF", UF},
  107 + {"/EF", Dictionary({{"/F", efsoh}, {"/UF", efsoh}})}}))};
109 } 108 }
110 109
111 QPDFFileSpecObjectHelper& 110 QPDFFileSpecObjectHelper&
112 QPDFFileSpecObjectHelper::setDescription(std::string const& desc) 111 QPDFFileSpecObjectHelper::setDescription(std::string const& desc)
113 { 112 {
114 - oh().replaceKey("/Desc", QPDFObjectHandle::newUnicodeString(desc)); 113 + oh().replaceKey("/Desc", String::utf16(desc));
115 return *this; 114 return *this;
116 } 115 }
117 116
@@ -119,14 +118,12 @@ QPDFFileSpecObjectHelper&amp; @@ -119,14 +118,12 @@ QPDFFileSpecObjectHelper&amp;
119 QPDFFileSpecObjectHelper::setFilename( 118 QPDFFileSpecObjectHelper::setFilename(
120 std::string const& unicode_name, std::string const& compat_name) 119 std::string const& unicode_name, std::string const& compat_name)
121 { 120 {
122 - auto uf = QPDFObjectHandle::newUnicodeString(unicode_name); 121 + auto uf = String::utf16(unicode_name);
123 oh().replaceKey("/UF", uf); 122 oh().replaceKey("/UF", uf);
124 if (compat_name.empty()) { 123 if (compat_name.empty()) {
125 - QTC::TC("qpdf", "QPDFFileSpecObjectHelper empty compat_name");  
126 oh().replaceKey("/F", uf); 124 oh().replaceKey("/F", uf);
127 } else { 125 } else {
128 - QTC::TC("qpdf", "QPDFFileSpecObjectHelper non-empty compat_name");  
129 - oh().replaceKey("/F", QPDFObjectHandle::newString(compat_name)); 126 + oh().replaceKey("/F", String(compat_name));
130 } 127 }
131 return *this; 128 return *this;
132 } 129 }
libqpdf/qpdf/Pl_MD5.hh
@@ -4,6 +4,8 @@ @@ -4,6 +4,8 @@
4 #include <qpdf/MD5.hh> 4 #include <qpdf/MD5.hh>
5 #include <qpdf/Pipeline.hh> 5 #include <qpdf/Pipeline.hh>
6 6
  7 +#include <stdexcept>
  8 +
7 // This pipeline sends its output to its successor unmodified. After calling finish, the MD5 9 // This pipeline sends its output to its successor unmodified. After calling finish, the MD5
8 // checksum of the data that passed through the pipeline is available. 10 // checksum of the data that passed through the pipeline is available.
9 11
@@ -12,18 +14,47 @@ @@ -12,18 +14,47 @@
12 class Pl_MD5 final: public Pipeline 14 class Pl_MD5 final: public Pipeline
13 { 15 {
14 public: 16 public:
15 - Pl_MD5(char const* identifier, Pipeline* next); 17 + Pl_MD5(char const* identifier, Pipeline* next = nullptr) :
  18 + Pipeline(identifier, next)
  19 + {
  20 + }
  21 +
16 ~Pl_MD5() final = default; 22 ~Pl_MD5() final = default;
17 void write(unsigned char const*, size_t) final; 23 void write(unsigned char const*, size_t) final;
18 - void finish() final;  
19 - std::string getHexDigest(); 24 + void
  25 + finish() final
  26 + {
  27 + if (next()) {
  28 + next()->finish();
  29 + }
  30 + if (!persist_across_finish) {
  31 + in_progress = false;
  32 + }
  33 + }
  34 + std::string
  35 + getHexDigest()
  36 + {
  37 + if (!enabled) {
  38 + throw std::logic_error("digest requested for a disabled MD5 Pipeline");
  39 + }
  40 + in_progress = false;
  41 + return md5.unparse();
  42 + }
20 // Enable/disable. Disabling the pipeline causes it to become a pass-through. This makes it 43 // Enable/disable. Disabling the pipeline causes it to become a pass-through. This makes it
21 // possible to stick an MD5 pipeline in a pipeline when it may or may not be required. Disabling 44 // possible to stick an MD5 pipeline in a pipeline when it may or may not be required. Disabling
22 // it avoids incurring the runtime overhead of doing needless digest computation. 45 // it avoids incurring the runtime overhead of doing needless digest computation.
23 - void enable(bool enabled); 46 + void
  47 + enable(bool val)
  48 + {
  49 + enabled = val;
  50 + }
24 // If persistAcrossFinish is called, calls to finish do not finalize the underlying md5 object. 51 // If persistAcrossFinish is called, calls to finish do not finalize the underlying md5 object.
25 // In this case, the object is not finalized until getHexDigest() is called. 52 // In this case, the object is not finalized until getHexDigest() is called.
26 - void persistAcrossFinish(bool); 53 + void
  54 + persistAcrossFinish(bool val)
  55 + {
  56 + persist_across_finish = val;
  57 + }
27 58
28 private: 59 private:
29 bool in_progress{false}; 60 bool in_progress{false};
qpdf/qpdf.testcov
@@ -325,8 +325,6 @@ QPDFPageObjectHelper::forEachXObject 3 @@ -325,8 +325,6 @@ QPDFPageObjectHelper::forEachXObject 3
325 NNTree erased last kid/item in tree 1 325 NNTree erased last kid/item in tree 1
326 QPDFPageObjectHelper unresolved names 0 326 QPDFPageObjectHelper unresolved names 0
327 QPDFPageObjectHelper resolving unresolved 0 327 QPDFPageObjectHelper resolving unresolved 0
328 -QPDFFileSpecObjectHelper empty compat_name 0  
329 -QPDFFileSpecObjectHelper non-empty compat_name 0  
330 QPDFAcroFormDocumentHelper copy annotation 3 328 QPDFAcroFormDocumentHelper copy annotation 3
331 QPDFAcroFormDocumentHelper field with parent 3 329 QPDFAcroFormDocumentHelper field with parent 3
332 QPDFObjectHandle merge reuse 0 330 QPDFObjectHandle merge reuse 0
qpdf/test_driver.cc
@@ -2644,6 +2644,8 @@ test_76(QPDF&amp; pdf, char const* arg2) @@ -2644,6 +2644,8 @@ test_76(QPDF&amp; pdf, char const* arg2)
2644 "att2", QPDFFileSpecObjectHelper::createFileSpec(pdf, "att2.txt", efs2)); 2644 "att2", QPDFFileSpecObjectHelper::createFileSpec(pdf, "att2.txt", efs2));
2645 auto fs3 = QPDFFileSpecObjectHelper::createFileSpec(pdf, "att3.txt", efs3); 2645 auto fs3 = QPDFFileSpecObjectHelper::createFileSpec(pdf, "att3.txt", efs3);
2646 efdh.replaceEmbeddedFile("att3", fs3); 2646 efdh.replaceEmbeddedFile("att3", fs3);
  2647 + fs3.setFilename("\xcf\x80.txt");
  2648 + assert(fs3.getFilename() == "\xcf\x80.txt");
2647 fs3.setFilename("\xcf\x80.txt", "att3.txt"); 2649 fs3.setFilename("\xcf\x80.txt", "att3.txt");
2648 2650
2649 assert(efs1.getCreationDate() == "D:20210207191121-05'00'"); 2651 assert(efs1.getCreationDate() == "D:20210207191121-05'00'");