Commit a15d0afa3e362ef7744f43c9a238c46ddd902cf6
1 parent
44fa03c6
Refactor `QPDFWriter`: move `generateID` and `getOriginalID1` to `QPDFWriter::Me…
…mbers` and update encryption parameter handling logic.
Showing
2 changed files
with
38 additions
and
32 deletions
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& qpdf) | @@ -911,12 +920,11 @@ QPDFWriter::copyEncryptionParameters(QPDF& 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 |