Commit a15d0afa3e362ef7744f43c9a238c46ddd902cf6

Authored by m-holger
1 parent 44fa03c6

Refactor `QPDFWriter`: move `generateID` and `getOriginalID1` to `QPDFWriter::Me…

…mbers` and update encryption parameter handling logic.
include/qpdf/QPDFWriter.hh
@@ -494,8 +494,6 @@ class QPDFWriter @@ -494,8 +494,6 @@ class QPDFWriter
494 void initializeSpecialStreams(); 494 void initializeSpecialStreams();
495 void preserveObjectStreams(); 495 void preserveObjectStreams();
496 void generateObjectStreams(); 496 void generateObjectStreams();
497 - std::string getOriginalID1();  
498 - void generateID(bool encrypted);  
499 void interpretR3EncryptionParameters( 497 void interpretR3EncryptionParameters(
500 bool allow_accessibility, 498 bool allow_accessibility,
501 bool allow_extract, 499 bool allow_extract,
libqpdf/QPDFWriter.cc
@@ -285,10 +285,13 @@ class QPDFWriter::Members @@ -285,10 +285,13 @@ class QPDFWriter::Members
285 } 285 }
286 286
287 void setMinimumPDFVersion(std::string const& version, int extension_level); 287 void setMinimumPDFVersion(std::string const& version, int extension_level);
  288 + void copyEncryptionParameters(QPDF&);
288 289
289 void disableIncompatibleEncryption(int major, int minor, int extension_level); 290 void disableIncompatibleEncryption(int major, int minor, int extension_level);
290 void parseVersion(std::string const& version, int& major, int& minor) const; 291 void parseVersion(std::string const& version, int& major, int& minor) const;
291 int compareVersions(int major1, int minor1, int major2, int minor2) const; 292 int compareVersions(int major1, int minor1, int major2, int minor2) const;
  293 + void generateID(bool encrypted);
  294 + std::string getOriginalID1();
292 295
293 private: 296 private:
294 QPDFWriter& w; 297 QPDFWriter& w;
@@ -867,7 +870,7 @@ QPDFWriter::interpretR3EncryptionParameters( @@ -867,7 +870,7 @@ QPDFWriter::interpretR3EncryptionParameters(
867 void 870 void
868 QPDFWriter::setEncryptionParameters(char const* user_password, char const* owner_password) 871 QPDFWriter::setEncryptionParameters(char const* user_password, char const* owner_password)
869 { 872 {
870 - generateID(true); 873 + m->generateID(true);
871 m->encryption->setId1(m->id1); 874 m->encryption->setId1(m->id1);
872 m->encryption_key = m->encryption->compute_parameters(user_password, owner_password); 875 m->encryption_key = m->encryption->compute_parameters(user_password, owner_password);
873 setEncryptionMinimumVersion(); 876 setEncryptionMinimumVersion();
@@ -876,11 +879,17 @@ QPDFWriter::setEncryptionParameters(char const* user_password, char const* owner @@ -876,11 +879,17 @@ QPDFWriter::setEncryptionParameters(char const* user_password, char const* owner
876 void 879 void
877 QPDFWriter::copyEncryptionParameters(QPDF& qpdf) 880 QPDFWriter::copyEncryptionParameters(QPDF& qpdf)
878 { 881 {
879 - m->preserve_encryption = false; 882 + m->copyEncryptionParameters(qpdf);
  883 +}
  884 +
  885 +void
  886 +QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf)
  887 +{
  888 + preserve_encryption = false;
880 QPDFObjectHandle trailer = qpdf.getTrailer(); 889 QPDFObjectHandle trailer = qpdf.getTrailer();
881 if (trailer.hasKey("/Encrypt")) { 890 if (trailer.hasKey("/Encrypt")) {
882 generateID(true); 891 generateID(true);
883 - m->id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue(); 892 + id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue();
884 QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); 893 QPDFObjectHandle encrypt = trailer.getKey("/Encrypt");
885 int V = encrypt.getKey("/V").getIntValueAsInt(); 894 int V = encrypt.getKey("/V").getIntValueAsInt();
886 int key_len = 5; 895 int key_len = 5;
@@ -896,12 +905,12 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) @@ -896,12 +905,12 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf)
896 // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of 905 // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of
897 // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF 906 // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF
898 // all potentially having different values. 907 // all potentially having different values.
899 - m->encrypt_use_aes = true; 908 + encrypt_use_aes = true;
900 } 909 }
901 QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1); 910 QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1);
902 - QTC::TC("qpdf", "QPDFWriter copy use_aes", m->encrypt_use_aes ? 0 : 1); 911 + QTC::TC("qpdf", "QPDFWriter copy use_aes", encrypt_use_aes ? 0 : 1);
903 912
904 - m->encryption = std::make_unique<QPDF::EncryptionData>( 913 + encryption = std::make_unique<QPDF::EncryptionData>(
905 V, 914 V,
906 encrypt.getKey("/R").getIntValueAsInt(), 915 encrypt.getKey("/R").getIntValueAsInt(),
907 key_len, 916 key_len,
@@ -911,12 +920,11 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf) @@ -911,12 +920,11 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf)
911 V < 5 ? "" : encrypt.getKey("/OE").getStringValue(), 920 V < 5 ? "" : encrypt.getKey("/OE").getStringValue(),
912 V < 5 ? "" : encrypt.getKey("/UE").getStringValue(), 921 V < 5 ? "" : encrypt.getKey("/UE").getStringValue(),
913 V < 5 ? "" : encrypt.getKey("/Perms").getStringValue(), 922 V < 5 ? "" : encrypt.getKey("/Perms").getStringValue(),
914 - m->id1, // m->id1 == the other file's id1 923 + id1, // id1 == the other file's id1
915 encrypt_metadata); 924 encrypt_metadata);
916 - m->encryption_key = V >= 5  
917 - ? qpdf.getEncryptionKey()  
918 - : m->encryption->compute_encryption_key(qpdf.getPaddedUserPassword());  
919 - setEncryptionMinimumVersion(); 925 + encryption_key = V >= 5 ? qpdf.getEncryptionKey()
  926 + : encryption->compute_encryption_key(qpdf.getPaddedUserPassword());
  927 + w.setEncryptionMinimumVersion();
920 } 928 }
921 } 929 }
922 930
@@ -1292,7 +1300,7 @@ QPDFWriter::writeTrailer( @@ -1292,7 +1300,7 @@ QPDFWriter::writeTrailer(
1292 // Write ID 1300 // Write ID
1293 write_qdf(" ").write(" /ID ["); 1301 write_qdf(" ").write(" /ID [");
1294 if (linearization_pass == 1) { 1302 if (linearization_pass == 1) {
1295 - std::string original_id1 = getOriginalID1(); 1303 + std::string original_id1 = m->getOriginalID1();
1296 if (original_id1.empty()) { 1304 if (original_id1.empty()) {
1297 write("<00000000000000000000000000000000>"); 1305 write("<00000000000000000000000000000000>");
1298 } else { 1306 } else {
@@ -1308,7 +1316,7 @@ QPDFWriter::writeTrailer( @@ -1308,7 +1316,7 @@ QPDFWriter::writeTrailer(
1308 if (linearization_pass == 0 && m->deterministic_id) { 1316 if (linearization_pass == 0 && m->deterministic_id) {
1309 computeDeterministicIDData(); 1317 computeDeterministicIDData();
1310 } 1318 }
1311 - generateID(m->encryption.get()); 1319 + m->generateID(m->encryption.get());
1312 write_string(m->id1, true).write_string(m->id2, true); 1320 write_string(m->id1, true).write_string(m->id2, true);
1313 } 1321 }
1314 write("]"); 1322 write("]");
@@ -1855,9 +1863,9 @@ QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index) @@ -1855,9 +1863,9 @@ QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index)
1855 } 1863 }
1856 1864
1857 std::string 1865 std::string
1858 -QPDFWriter::getOriginalID1() 1866 +QPDFWriter::Members::getOriginalID1()
1859 { 1867 {
1860 - QPDFObjectHandle trailer = m->pdf.getTrailer(); 1868 + QPDFObjectHandle trailer = pdf.getTrailer();
1861 if (trailer.hasKey("/ID")) { 1869 if (trailer.hasKey("/ID")) {
1862 return trailer.getKey("/ID").getArrayItem(0).getStringValue(); 1870 return trailer.getKey("/ID").getArrayItem(0).getStringValue();
1863 } else { 1871 } else {
@@ -1866,20 +1874,20 @@ QPDFWriter::getOriginalID1() @@ -1866,20 +1874,20 @@ QPDFWriter::getOriginalID1()
1866 } 1874 }
1867 1875
1868 void 1876 void
1869 -QPDFWriter::generateID(bool encrypted) 1877 +QPDFWriter::Members::generateID(bool encrypted)
1870 { 1878 {
1871 // Generate the ID lazily so that we can handle the user's preference to use static or 1879 // Generate the ID lazily so that we can handle the user's preference to use static or
1872 // deterministic ID generation. 1880 // deterministic ID generation.
1873 1881
1874 - if (!m->id2.empty()) { 1882 + if (!id2.empty()) {
1875 return; 1883 return;
1876 } 1884 }
1877 1885
1878 - QPDFObjectHandle trailer = m->pdf.getTrailer(); 1886 + QPDFObjectHandle trailer = pdf.getTrailer();
1879 1887
1880 std::string result; 1888 std::string result;
1881 1889
1882 - if (m->static_id) { 1890 + if (static_id) {
1883 // For test suite use only... 1891 // For test suite use only...
1884 static unsigned char tmp[] = { 1892 static unsigned char tmp[] = {
1885 0x31, 1893 0x31,
@@ -1911,20 +1919,20 @@ QPDFWriter::generateID(bool encrypted) @@ -1911,20 +1919,20 @@ QPDFWriter::generateID(bool encrypted)
1911 // that case, would have the same ID regardless of the output file's name. 1919 // that case, would have the same ID regardless of the output file's name.
1912 1920
1913 std::string seed; 1921 std::string seed;
1914 - if (m->deterministic_id) { 1922 + if (deterministic_id) {
1915 if (encrypted) { 1923 if (encrypted) {
1916 throw std::runtime_error( 1924 throw std::runtime_error(
1917 "QPDFWriter: unable to generated a deterministic ID because the file to be " 1925 "QPDFWriter: unable to generated a deterministic ID because the file to be "
1918 "written is encrypted (even though the file may not require a password)"); 1926 "written is encrypted (even though the file may not require a password)");
1919 } 1927 }
1920 - if (m->deterministic_id_data.empty()) { 1928 + if (deterministic_id_data.empty()) {
1921 throw std::logic_error( 1929 throw std::logic_error(
1922 "INTERNAL ERROR: QPDFWriter::generateID has no data for deterministic ID"); 1930 "INTERNAL ERROR: QPDFWriter::generateID has no data for deterministic ID");
1923 } 1931 }
1924 - seed += m->deterministic_id_data; 1932 + seed += deterministic_id_data;
1925 } else { 1933 } else {
1926 seed += std::to_string(QUtil::get_current_time()); 1934 seed += std::to_string(QUtil::get_current_time());
1927 - seed += m->filename; 1935 + seed += filename;
1928 seed += " "; 1936 seed += " ";
1929 } 1937 }
1930 seed += " QPDF "; 1938 seed += " QPDF ";
@@ -1937,21 +1945,21 @@ QPDFWriter::generateID(bool encrypted) @@ -1937,21 +1945,21 @@ QPDFWriter::generateID(bool encrypted)
1937 } 1945 }
1938 } 1946 }
1939 1947
1940 - MD5 m;  
1941 - m.encodeString(seed.c_str()); 1948 + MD5 md5;
  1949 + md5.encodeString(seed.c_str());
1942 MD5::Digest digest; 1950 MD5::Digest digest;
1943 - m.digest(digest); 1951 + md5.digest(digest);
1944 result = std::string(reinterpret_cast<char*>(digest), sizeof(MD5::Digest)); 1952 result = std::string(reinterpret_cast<char*>(digest), sizeof(MD5::Digest));
1945 } 1953 }
1946 1954
1947 // If /ID already exists, follow the spec: use the original first word and generate a new second 1955 // If /ID already exists, follow the spec: use the original first word and generate a new second
1948 // word. Otherwise, we'll use the generated ID for both. 1956 // word. Otherwise, we'll use the generated ID for both.
1949 1957
1950 - m->id2 = result; 1958 + id2 = result;
1951 // Note: keep /ID from old file even if --static-id was given. 1959 // Note: keep /ID from old file even if --static-id was given.
1952 - m->id1 = getOriginalID1();  
1953 - if (m->id1.empty()) {  
1954 - m->id1 = m->id2; 1960 + id1 = getOriginalID1();
  1961 + if (id1.empty()) {
  1962 + id1 = id2;
1955 } 1963 }
1956 } 1964 }
1957 1965