Commit fe122b0b8c8256b5cf5f824701923ded8439ae36

Authored by m-holger
1 parent fad1399f

Refactor `QPDFWriter` to remove `encryption_dictionary` member, streamline encry…

…ption dictionary generation, and reduce redundancy in encryption handling logic.
Showing 1 changed file with 43 additions and 38 deletions
libqpdf/QPDFWriter.cc
@@ -89,7 +89,6 @@ class QPDFWriter::Members @@ -89,7 +89,6 @@ class QPDFWriter::Members
89 std::unique_ptr<QPDF::EncryptionData> encryption; 89 std::unique_ptr<QPDF::EncryptionData> encryption;
90 std::string encryption_key; 90 std::string encryption_key;
91 bool encrypt_use_aes{false}; 91 bool encrypt_use_aes{false};
92 - std::map<std::string, std::string> encryption_dictionary;  
93 92
94 std::string id1; // for /ID key of 93 std::string id1; // for /ID key of
95 std::string id2; // trailer dictionary 94 std::string id2; // trailer dictionary
@@ -783,21 +782,7 @@ void @@ -783,21 +782,7 @@ void
783 QPDFWriter::setEncryptionParametersInternal( 782 QPDFWriter::setEncryptionParametersInternal(
784 std::string const& user_password, std::string const& encryption_key) 783 std::string const& user_password, std::string const& encryption_key)
785 { 784 {
786 - auto& enc = *m->encryption;  
787 - auto const V = enc.getV();  
788 - auto const R = enc.getR();  
789 - m->encryption_dictionary["/Filter"] = "/Standard";  
790 - m->encryption_dictionary["/V"] = std::to_string(enc.getV());  
791 - m->encryption_dictionary["/Length"] = std::to_string(enc.getLengthBytes() * 8);  
792 - m->encryption_dictionary["/R"] = std::to_string(enc.getR());  
793 - m->encryption_dictionary["/P"] = std::to_string(enc.getP());  
794 - m->encryption_dictionary["/O"] = QPDF_String(enc.getO()).unparse(true);  
795 - m->encryption_dictionary["/U"] = QPDF_String(enc.getU()).unparse(true);  
796 - if (V >= 5) {  
797 - m->encryption_dictionary["/OE"] = QPDF_String(enc.getOE()).unparse(true);  
798 - m->encryption_dictionary["/UE"] = QPDF_String(enc.getUE()).unparse(true);  
799 - m->encryption_dictionary["/Perms"] = QPDF_String(enc.getPerms()).unparse(true);  
800 - } 785 + auto const R = m->encryption->getR();
801 if (R >= 6) { 786 if (R >= 6) {
802 setMinimumPDFVersion("1.7", 8); 787 setMinimumPDFVersion("1.7", 8);
803 } else if (R == 5) { 788 } else if (R == 5) {
@@ -810,23 +795,8 @@ QPDFWriter::setEncryptionParametersInternal( @@ -810,23 +795,8 @@ QPDFWriter::setEncryptionParametersInternal(
810 setMinimumPDFVersion("1.3"); 795 setMinimumPDFVersion("1.3");
811 } 796 }
812 797
813 - if (R >= 4 && !m->encryption->getEncryptMetadata()) {  
814 - m->encryption_dictionary["/EncryptMetadata"] = "false";  
815 - }  
816 - if ((V == 4) || (V == 5)) {  
817 - // The spec says the value for the crypt filter key can be anything, and xpdf seems to  
818 - // agree. However, Adobe Reader won't open our files unless we use /StdCF.  
819 - m->encryption_dictionary["/StmF"] = "/StdCF";  
820 - m->encryption_dictionary["/StrF"] = "/StdCF";  
821 - std::string method = (m->encrypt_use_aes ? ((V < 5) ? "/AESV2" : "/AESV3") : "/V2");  
822 - // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of  
823 - // MacOS won't open encrypted files without it.  
824 - m->encryption_dictionary["/CF"] = "<< /StdCF << /AuthEvent /DocOpen /CFM " + method +  
825 - " /Length " + std::string((V < 5) ? "16" : "32") + " >> >>";  
826 - }  
827 -  
828 - if (V < 5) {  
829 - m->encryption_key = enc.compute_encryption_key(user_password); 798 + if (m->encryption->getV() < 5) {
  799 + m->encryption_key = m->encryption->compute_encryption_key(user_password);
830 } else { 800 } else {
831 m->encryption_key = encryption_key; 801 m->encryption_key = encryption_key;
832 } 802 }
@@ -2310,13 +2280,48 @@ void @@ -2310,13 +2280,48 @@ void
2310 QPDFWriter::writeEncryptionDictionary() 2280 QPDFWriter::writeEncryptionDictionary()
2311 { 2281 {
2312 m->encryption_dict_objid = openObject(m->encryption_dict_objid); 2282 m->encryption_dict_objid = openObject(m->encryption_dict_objid);
  2283 + auto& enc = *m->encryption;
  2284 + auto const V = enc.getV();
  2285 +
2313 writeString("<<"); 2286 writeString("<<");
2314 - for (auto const& iter: m->encryption_dictionary) {  
2315 - writeString(" ");  
2316 - writeString(iter.first);  
2317 - writeString(" ");  
2318 - writeString(iter.second); 2287 + if (V >= 4) {
  2288 + writeString(" /CF << /StdCF << /AuthEvent /DocOpen /CFM ");
  2289 + writeString(m->encrypt_use_aes ? ((V < 5) ? "/AESV2" : "/AESV3") : "/V2");
  2290 + // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of
  2291 + // MacOS won't open encrypted files without it.
  2292 + writeString((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>");
  2293 + if (!m->encryption->getEncryptMetadata()) {
  2294 + writeString(" /EncryptMetadata false");
  2295 + }
  2296 + }
  2297 + writeString(" /Filter /Standard /Length ");
  2298 + writeString(std::to_string(enc.getLengthBytes() * 8));
  2299 + writeString(" /O ");
  2300 + writeString(QPDF_String(enc.getO()).unparse(true));
  2301 + if (V >= 4) {
  2302 + writeString(" /OE ");
  2303 + writeString(QPDF_String(enc.getOE()).unparse(true));
  2304 + }
  2305 + writeString(" /P ");
  2306 + writeString(std::to_string(enc.getP()));
  2307 + if (V >= 5) {
  2308 + writeString(" /Perms ");
  2309 + writeString(QPDF_String(enc.getPerms()).unparse(true));
  2310 + }
  2311 + writeString(" /R ");
  2312 + writeString(std::to_string(enc.getR()));
  2313 +
  2314 + if (V >= 4) {
  2315 + writeString(" /StmF /StdCF /StrF /StdCF");
  2316 + }
  2317 + writeString(" /U ");
  2318 + writeString(QPDF_String(enc.getU()).unparse(true));
  2319 + if (V >= 4) {
  2320 + writeString(" /UE ");
  2321 + writeString(QPDF_String(enc.getUE()).unparse(true));
2319 } 2322 }
  2323 + writeString(" /V ");
  2324 + writeString(std::to_string(enc.getV()));
2320 writeString(" >>"); 2325 writeString(" >>");
2321 closeObject(m->encryption_dict_objid); 2326 closeObject(m->encryption_dict_objid);
2322 } 2327 }