Commit c3cee5f1549df6ba3a7829fcbf6a59739636bb88

Authored by Jay Berkenbilt
1 parent fddbcab0

Exercise out of scope original pdf for copyForeignObject

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
... ... @@ -408,3 +408,5 @@ qpdf image optimize too small 0
408 408 QPDFFormFieldObjectHelper WinAnsi 0
409 409 QPDF_encryption attachment stream 0
410 410 QPDF pipe foreign encrypted stream 0
  411 +QPDF copy foreign stream with provider 0
  412 +QPDF copy foreign stream with buffer 0
... ...
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();
... ...