Commit c3cee5f1549df6ba3a7829fcbf6a59739636bb88
1 parent
fddbcab0
Exercise out of scope original pdf for copyForeignObject
Showing
5 changed files
with
114 additions
and
64 deletions
libqpdf/QPDF.cc
| ... | ... | @@ -2380,7 +2380,7 @@ QPDF::replaceForeignIndirectObjects( |
| 2380 | 2380 | stream->getStreamDataProvider(); |
| 2381 | 2381 | if (stream_buffer.getPointer()) |
| 2382 | 2382 | { |
| 2383 | -// QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); | |
| 2383 | + QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); | |
| 2384 | 2384 | result.replaceStreamData(stream_buffer, |
| 2385 | 2385 | dict.getKey("/Filter"), |
| 2386 | 2386 | dict.getKey("/DecodeParms")); |
| ... | ... | @@ -2388,7 +2388,7 @@ QPDF::replaceForeignIndirectObjects( |
| 2388 | 2388 | else if (stream_provider.getPointer()) |
| 2389 | 2389 | { |
| 2390 | 2390 | // In this case, the remote stream's QPDF must stay in scope. |
| 2391 | -// QTC::TC("qpdf", "QPDF copy foreign stream with provider"); | |
| 2391 | + QTC::TC("qpdf", "QPDF copy foreign stream with provider"); | |
| 2392 | 2392 | this->m->copied_stream_data_provider->registerForeignStream( |
| 2393 | 2393 | local_og, foreign); |
| 2394 | 2394 | result.replaceStreamData(this->m->copied_streams, | ... | ... |
qpdf/qpdf.testcov
qpdf/qtest/qpdf.test
| ... | ... | @@ -1921,7 +1921,7 @@ foreach my $d ([25, 1], [26, 2], [27, 3]) |
| 1921 | 1921 | my ($testn, $outn) = @$d; |
| 1922 | 1922 | $td->runtest("copy objects $outn", |
| 1923 | 1923 | {$td->COMMAND => "test_driver $testn" . |
| 1924 | - " copy-foreign-objects-in.pdf minimal.pdf"}, | |
| 1924 | + " minimal.pdf copy-foreign-objects-in.pdf"}, | |
| 1925 | 1925 | {$td->STRING => "test $testn done\n", $td->EXIT_STATUS => 0}, |
| 1926 | 1926 | $td->NORMALIZE_NEWLINES); |
| 1927 | 1927 | $td->runtest("check output", | ... | ... |
qpdf/qtest/qpdf/copy-foreign-objects-out3.pdf
| 1 | 1 | %PDF-1.3 |
| 2 | 2 | %¿÷¢þ |
| 3 | 3 | 1 0 obj |
| 4 | -<< /Pages 3 0 R /Type /Catalog >> | |
| 4 | +<< /Pages 5 0 R /Type /Catalog >> | |
| 5 | 5 | endobj |
| 6 | 6 | 2 0 obj |
| 7 | -<< /O1 4 0 R /O2 5 0 R /O3 6 0 R /This-is-QTest true >> | |
| 7 | +<< /O1 6 0 R /O2 7 0 R /O3 8 0 R /This-is-QTest true >> | |
| 8 | 8 | endobj |
| 9 | 9 | 3 0 obj |
| 10 | -<< /Count 3 /Kids [ 7 0 R 8 0 R 6 0 R ] /Type /Pages >> | |
| 10 | +<< /Length 20 >> | |
| 11 | +stream | |
| 12 | +new data for stream | |
| 13 | +endstream | |
| 11 | 14 | endobj |
| 12 | 15 | 4 0 obj |
| 13 | -[ /This-is-O1 /potato << /O2 [ 3.14159 << /O2 5 0 R >> 2.17828 ] >> /salad /O2 5 0 R /Stream1 9 0 R ] | |
| 16 | +<< /Length 7 >> | |
| 17 | +stream | |
| 18 | +potato | |
| 19 | +endstream | |
| 14 | 20 | endobj |
| 15 | 21 | 5 0 obj |
| 16 | -<< /K1 [ 2.236 /O1 4 0 R 1.732 ] /O1 4 0 R /This-is-O2 true >> | |
| 22 | +<< /Count 3 /Kids [ 9 0 R 10 0 R 8 0 R ] /Type /Pages >> | |
| 17 | 23 | endobj |
| 18 | 24 | 6 0 obj |
| 19 | -<< /Contents 10 0 R /MediaBox [ 0 0 612 792 ] /OtherPage 8 0 R /Parent 3 0 R /Resources << /Font << /F1 11 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3 true /Type /Page >> | |
| 25 | +[ /This-is-O1 /potato << /O2 [ 3.14159 << /O2 7 0 R >> 2.17828 ] >> /salad /O2 7 0 R /Stream1 11 0 R ] | |
| 20 | 26 | endobj |
| 21 | 27 | 7 0 obj |
| 22 | -<< /Contents 12 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 13 0 R >> /ProcSet 14 0 R >> /Type /Page >> | |
| 28 | +<< /K1 [ 2.236 /O1 6 0 R 1.732 ] /O1 6 0 R /This-is-O2 true >> | |
| 23 | 29 | endobj |
| 24 | 30 | 8 0 obj |
| 25 | -<< /Contents 15 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 11 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3-other-page true /Type /Page >> | |
| 31 | +<< /Contents 12 0 R /MediaBox [ 0 0 612 792 ] /OtherPage 10 0 R /Parent 5 0 R /Resources << /Font << /F1 13 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3 true /Type /Page >> | |
| 26 | 32 | endobj |
| 27 | 33 | 9 0 obj |
| 28 | -<< /Stream2 16 0 R /This-is-Stream1 true /Length 18 >> | |
| 34 | +<< /Contents 14 0 R /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources << /Font << /F1 15 0 R >> /ProcSet 16 0 R >> /Type /Page >> | |
| 35 | +endobj | |
| 36 | +10 0 obj | |
| 37 | +<< /Contents 17 0 R /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources << /Font << /F1 13 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3-other-page true /Type /Page >> | |
| 38 | +endobj | |
| 39 | +11 0 obj | |
| 40 | +<< /Stream2 18 0 R /This-is-Stream1 true /Length 18 >> | |
| 29 | 41 | stream |
| 30 | 42 | This is stream 1. |
| 31 | 43 | endstream |
| 32 | 44 | endobj |
| 33 | -10 0 obj | |
| 45 | +12 0 obj | |
| 34 | 46 | << /Length 47 >> |
| 35 | 47 | stream |
| 36 | 48 | BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET |
| 37 | 49 | endstream |
| 38 | 50 | endobj |
| 39 | -11 0 obj | |
| 51 | +13 0 obj | |
| 40 | 52 | << /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >> |
| 41 | 53 | endobj |
| 42 | -12 0 obj | |
| 54 | +14 0 obj | |
| 43 | 55 | << /Length 44 >> |
| 44 | 56 | stream |
| 45 | 57 | BT |
| ... | ... | @@ -49,44 +61,46 @@ BT |
| 49 | 61 | ET |
| 50 | 62 | endstream |
| 51 | 63 | endobj |
| 52 | -13 0 obj | |
| 64 | +15 0 obj | |
| 53 | 65 | << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> |
| 54 | 66 | endobj |
| 55 | -14 0 obj | |
| 67 | +16 0 obj | |
| 56 | 68 | [ /PDF /Text ] |
| 57 | 69 | endobj |
| 58 | -15 0 obj | |
| 70 | +17 0 obj | |
| 59 | 71 | << /Length 47 >> |
| 60 | 72 | stream |
| 61 | 73 | BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET |
| 62 | 74 | endstream |
| 63 | 75 | endobj |
| 64 | -16 0 obj | |
| 65 | -<< /Stream1 9 0 R /This-is-Stream2 true /Length 18 >> | |
| 76 | +18 0 obj | |
| 77 | +<< /Stream1 11 0 R /This-is-Stream2 true /Length 18 >> | |
| 66 | 78 | stream |
| 67 | 79 | This is stream 2. |
| 68 | 80 | endstream |
| 69 | 81 | endobj |
| 70 | 82 | xref |
| 71 | -0 17 | |
| 83 | +0 19 | |
| 72 | 84 | 0000000000 65535 f |
| 73 | 85 | 0000000015 00000 n |
| 74 | 86 | 0000000064 00000 n |
| 75 | 87 | 0000000135 00000 n |
| 76 | -0000000206 00000 n | |
| 77 | -0000000323 00000 n | |
| 78 | -0000000401 00000 n | |
| 79 | -0000000601 00000 n | |
| 80 | -0000000747 00000 n | |
| 81 | -0000000941 00000 n | |
| 82 | -0000001046 00000 n | |
| 83 | -0000001143 00000 n | |
| 84 | -0000001243 00000 n | |
| 85 | -0000001337 00000 n | |
| 86 | -0000001445 00000 n | |
| 87 | -0000001476 00000 n | |
| 88 | -0000001573 00000 n | |
| 89 | -trailer << /QTest 2 0 R /Root 1 0 R /Size 17 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> | |
| 88 | +0000000204 00000 n | |
| 89 | +0000000259 00000 n | |
| 90 | +0000000331 00000 n | |
| 91 | +0000000449 00000 n | |
| 92 | +0000000527 00000 n | |
| 93 | +0000000728 00000 n | |
| 94 | +0000000874 00000 n | |
| 95 | +0000001069 00000 n | |
| 96 | +0000001175 00000 n | |
| 97 | +0000001272 00000 n | |
| 98 | +0000001372 00000 n | |
| 99 | +0000001466 00000 n | |
| 100 | +0000001574 00000 n | |
| 101 | +0000001605 00000 n | |
| 102 | +0000001702 00000 n | |
| 103 | +trailer << /QTest 2 0 R /QTest2 [ 3 0 R 4 0 R ] /Root 1 0 R /Size 19 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> | |
| 90 | 104 | startxref |
| 91 | -1678 | |
| 105 | +1808 | |
| 92 | 106 | %%EOF | ... | ... |
qpdf/test_driver.cc
| ... | ... | @@ -1085,13 +1085,16 @@ void runtest(int n, char const* filename1, char const* arg2) |
| 1085 | 1085 | // and O2 and their streams but not O3 or any other pages. |
| 1086 | 1086 | |
| 1087 | 1087 | assert(arg2 != 0); |
| 1088 | - QPDF newpdf; | |
| 1089 | - newpdf.processFile(arg2); | |
| 1090 | - QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest"); | |
| 1091 | - newpdf.getTrailer().replaceKey( | |
| 1092 | - "/QTest", newpdf.copyForeignObject(qtest)); | |
| 1088 | + { | |
| 1089 | + // Make sure original PDF is out of scope when we write. | |
| 1090 | + QPDF oldpdf; | |
| 1091 | + oldpdf.processFile(arg2); | |
| 1092 | + QPDFObjectHandle qtest = oldpdf.getTrailer().getKey("/QTest"); | |
| 1093 | + pdf.getTrailer().replaceKey( | |
| 1094 | + "/QTest", pdf.copyForeignObject(qtest)); | |
| 1095 | + } | |
| 1093 | 1096 | |
| 1094 | - QPDFWriter w(newpdf, "a.pdf"); | |
| 1097 | + QPDFWriter w(pdf, "a.pdf"); | |
| 1095 | 1098 | w.setStaticID(true); |
| 1096 | 1099 | w.setStreamDataMode(qpdf_s_preserve); |
| 1097 | 1100 | w.write(); |
| ... | ... | @@ -1104,16 +1107,19 @@ void runtest(int n, char const* filename1, char const* arg2) |
| 1104 | 1107 | // that O3 points to. Also, inherited object will have been |
| 1105 | 1108 | // pushed down and will be preserved. |
| 1106 | 1109 | |
| 1107 | - assert(arg2 != 0); | |
| 1108 | - QPDF newpdf; | |
| 1109 | - newpdf.processFile(arg2); | |
| 1110 | - QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest"); | |
| 1111 | - QPDFObjectHandle O3 = qtest.getKey("/O3"); | |
| 1112 | - QPDFPageDocumentHelper(newpdf).addPage(O3, false); | |
| 1113 | - newpdf.getTrailer().replaceKey( | |
| 1114 | - "/QTest", newpdf.copyForeignObject(qtest)); | |
| 1110 | + { | |
| 1111 | + // Make sure original PDF is out of scope when we write. | |
| 1112 | + assert(arg2 != 0); | |
| 1113 | + QPDF oldpdf; | |
| 1114 | + oldpdf.processFile(arg2); | |
| 1115 | + QPDFObjectHandle qtest = oldpdf.getTrailer().getKey("/QTest"); | |
| 1116 | + QPDFObjectHandle O3 = qtest.getKey("/O3"); | |
| 1117 | + QPDFPageDocumentHelper(pdf).addPage(O3, false); | |
| 1118 | + pdf.getTrailer().replaceKey( | |
| 1119 | + "/QTest", pdf.copyForeignObject(qtest)); | |
| 1120 | + } | |
| 1115 | 1121 | |
| 1116 | - QPDFWriter w(newpdf, "a.pdf"); | |
| 1122 | + QPDFWriter w(pdf, "a.pdf"); | |
| 1117 | 1123 | w.setStaticID(true); |
| 1118 | 1124 | w.setStreamDataMode(qpdf_s_preserve); |
| 1119 | 1125 | w.write(); |
| ... | ... | @@ -1122,20 +1128,48 @@ void runtest(int n, char const* filename1, char const* arg2) |
| 1122 | 1128 | { |
| 1123 | 1129 | // Copy O3 and the page O3 refers to before copying qtest. |
| 1124 | 1130 | // Should get qtest plus only the O3 page and the page that O3 |
| 1125 | - // points to. Inherited objects should be preserved. | |
| 1131 | + // points to. Inherited objects should be preserved. This test | |
| 1132 | + // also exercises copying from a stream that has a buffer and | |
| 1133 | + // a provider, including copying a provider multiple times. | |
| 1126 | 1134 | |
| 1127 | - assert(arg2 != 0); | |
| 1128 | - QPDF newpdf; | |
| 1129 | - newpdf.processFile(arg2); | |
| 1130 | - QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest"); | |
| 1131 | - QPDFObjectHandle O3 = qtest.getKey("/O3"); | |
| 1132 | - QPDFPageDocumentHelper dh(newpdf); | |
| 1133 | - dh.addPage(O3.getKey("/OtherPage"), false); | |
| 1134 | - dh.addPage(O3, false); | |
| 1135 | - newpdf.getTrailer().replaceKey( | |
| 1136 | - "/QTest", newpdf.copyForeignObject(qtest)); | |
| 1137 | - | |
| 1138 | - QPDFWriter w(newpdf, "a.pdf"); | |
| 1135 | + Pl_Buffer p1("buffer"); | |
| 1136 | + p1.write(QUtil::unsigned_char_pointer("new data for stream\n"), | |
| 1137 | + 20); // no null! | |
| 1138 | + p1.finish(); | |
| 1139 | + PointerHolder<Buffer> b = p1.getBuffer(); | |
| 1140 | + Provider* provider = new Provider(b); | |
| 1141 | + PointerHolder<QPDFObjectHandle::StreamDataProvider> p = provider; | |
| 1142 | + QPDF empty1; | |
| 1143 | + empty1.emptyPDF(); | |
| 1144 | + QPDFObjectHandle s1 = QPDFObjectHandle::newStream(&empty1); | |
| 1145 | + s1.replaceStreamData( | |
| 1146 | + p, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull()); | |
| 1147 | + QPDF empty2; | |
| 1148 | + empty2.emptyPDF(); | |
| 1149 | + s1 = empty2.copyForeignObject(s1); | |
| 1150 | + { | |
| 1151 | + // Make sure original PDF is out of scope when we write. | |
| 1152 | + assert(arg2 != 0); | |
| 1153 | + QPDF oldpdf; | |
| 1154 | + oldpdf.processFile(arg2); | |
| 1155 | + QPDFObjectHandle qtest = oldpdf.getTrailer().getKey("/QTest"); | |
| 1156 | + QPDFObjectHandle O3 = qtest.getKey("/O3"); | |
| 1157 | + QPDFPageDocumentHelper dh(pdf); | |
| 1158 | + dh.addPage(O3.getKey("/OtherPage"), false); | |
| 1159 | + dh.addPage(O3, false); | |
| 1160 | + QPDFObjectHandle s2 = QPDFObjectHandle::newStream( | |
| 1161 | + &oldpdf, "potato\n"); | |
| 1162 | + pdf.getTrailer().replaceKey( | |
| 1163 | + "/QTest", pdf.copyForeignObject(qtest)); | |
| 1164 | + pdf.getTrailer().replaceKey( | |
| 1165 | + "/QTest2", QPDFObjectHandle::newArray()); | |
| 1166 | + pdf.getTrailer().getKey("/QTest2").appendItem( | |
| 1167 | + pdf.copyForeignObject(s1)); | |
| 1168 | + pdf.getTrailer().getKey("/QTest2").appendItem( | |
| 1169 | + pdf.copyForeignObject(s2)); | |
| 1170 | + } | |
| 1171 | + | |
| 1172 | + QPDFWriter w(pdf, "a.pdf"); | |
| 1139 | 1173 | w.setStaticID(true); |
| 1140 | 1174 | w.setStreamDataMode(qpdf_s_preserve); |
| 1141 | 1175 | w.write(); | ... | ... |