Commit 893d38b87e4ad6c6c55f49464f6b721c516ec878

Authored by Jay Berkenbilt
1 parent a5367003

Allow propagation of errors and retry through StreamDataProvider

StreamDataProvider::provideStreamData now has a rich enough API for it
to effectively proxy to pipeStreamData.
ChangeLog
1 2020-04-04 Jay Berkenbilt <ejb@ql.org> 1 2020-04-04 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * Add a new provideStreamData method for StreamDataProvider that
  4 + allows a success code to be returned and that accepts the
  5 + suppress_warnings and will_retry methods. This makes it possible
  6 + to have a StreamDataProvider call pipeStreamData and propagate its
  7 + results back. This change allows better error handling and
  8 + recovery when objects are copied from other files and when
  9 + "immediate copy from" is enabled.
  10 +
  11 + * Add a new version of QPDFObjectHandle::pipeStreamData whose
  12 + return value indicates overall success or failure rather than
  13 + whether nor not filtering was attempted. It should have always
  14 + been this way. This change was done in a backward-compatible
  15 + fashion. Previously existing pipeStreamData methods' return values
  16 + mean the same as always.
  17 +
3 * Add "objectinfo" section to json output. In this release, 18 * Add "objectinfo" section to json output. In this release,
4 information about whether each object is a stream or not is 19 information about whether each object is a stream or not is
5 provided. There's otherwise no way to tell conclusively from the 20 provided. There's otherwise no way to tell conclusively from the
@@ -20,18 +20,6 @@ ABI Changes @@ -20,18 +20,6 @@ ABI Changes
20 This is a list of changes to make next time there is an ABI change. 20 This is a list of changes to make next time there is an ABI change.
21 Comments appear in the code prefixed by "ABI" 21 Comments appear in the code prefixed by "ABI"
22 22
23 -* (Source compatibility) As somewhat discussed in issue 219, the  
24 - original pipeStreamData in QPDF_Stream has various logic for  
25 - reporting warnings and letting the caller retry. This logic is not  
26 - implemented for stream data providers. When copying foreign streams,  
27 - qpdf uses a stream data provider (QPDF::CopiedStreamDataProvider) to  
28 - read the stream data from the original file. While a warning is  
29 - issued for that case, there is no way to actually propagate failure  
30 - information back through because  
31 - StreamDataProvider::provideStreamData doesn't take the  
32 - suppress_warnings or will_retry options, and adding them would break  
33 - source compatibility.  
34 -  
35 C++-11 23 C++-11
36 ====== 24 ======
37 25
include/qpdf/QPDF.hh
@@ -813,8 +813,9 @@ class QPDF @@ -813,8 +813,9 @@ class QPDF
813 virtual ~CopiedStreamDataProvider() 813 virtual ~CopiedStreamDataProvider()
814 { 814 {
815 } 815 }
816 - virtual void provideStreamData(int objid, int generation,  
817 - Pipeline* pipeline); 816 + virtual bool provideStreamData(
  817 + int objid, int generation, Pipeline* pipeline,
  818 + bool suppress_warnings, bool will_retry) override;
818 void registerForeignStream(QPDFObjGen const& local_og, 819 void registerForeignStream(QPDFObjGen const& local_og,
819 QPDFObjectHandle foreign_stream); 820 QPDFObjectHandle foreign_stream);
820 void registerForeignStream(QPDFObjGen const& local_og, 821 void registerForeignStream(QPDFObjGen const& local_og,
@@ -909,9 +910,7 @@ class QPDF @@ -909,9 +910,7 @@ class QPDF
909 bool will_retry); 910 bool will_retry);
910 bool pipeForeignStreamData( 911 bool pipeForeignStreamData(
911 PointerHolder<ForeignStreamData>, 912 PointerHolder<ForeignStreamData>,
912 - Pipeline*,  
913 - int encode_flags,  
914 - qpdf_stream_decode_level_e decode_level); 913 + Pipeline*, bool suppress_warnings, bool will_retry);
915 static bool pipeStreamData(PointerHolder<QPDF::EncryptionParameters> encp, 914 static bool pipeStreamData(PointerHolder<QPDF::EncryptionParameters> encp,
916 PointerHolder<InputSource> file, 915 PointerHolder<InputSource> file,
917 QPDF& qpdf_for_warning, 916 QPDF& qpdf_for_warning,
include/qpdf/QPDFObjectHandle.hh
@@ -57,6 +57,9 @@ class QPDFObjectHandle @@ -57,6 +57,9 @@ class QPDFObjectHandle
57 class QPDF_DLL_CLASS StreamDataProvider 57 class QPDF_DLL_CLASS StreamDataProvider
58 { 58 {
59 public: 59 public:
  60 + QPDF_DLL
  61 + StreamDataProvider(bool supports_retry = false);
  62 +
60 QPDF_DLL 63 QPDF_DLL
61 virtual ~StreamDataProvider() 64 virtual ~StreamDataProvider()
62 { 65 {
@@ -74,8 +77,30 @@ class QPDFObjectHandle @@ -74,8 +77,30 @@ class QPDFObjectHandle
74 // information is made available just to make it more 77 // information is made available just to make it more
75 // convenient to use a single StreamDataProvider object to 78 // convenient to use a single StreamDataProvider object to
76 // provide data for multiple streams. 79 // provide data for multiple streams.
  80 +
  81 + // Prior to qpdf 10.0.0, it was not possible to handle errors
  82 + // the way pipeStreamData does or to pass back success.
  83 + // Starting in qpdf 10.0.0, those capabilities have been added
  84 + // by allowing an alternative provideStreamData to be
  85 + // implemented. You must implement at least one of the
  86 + // versions of provideStreamData below. If you implement the
  87 + // version that supports retry and returns a value, you should
  88 + // pass true as the value of supports_retry in the base class
  89 + // constructor. This will cause the library to call that
  90 + // version of the method, which should also return a boolean
  91 + // indicating whether it ran without errors.
  92 + QPDF_DLL
77 virtual void provideStreamData(int objid, int generation, 93 virtual void provideStreamData(int objid, int generation,
78 - Pipeline* pipeline) = 0; 94 + Pipeline* pipeline);
  95 + QPDF_DLL
  96 + virtual bool provideStreamData(
  97 + int objid, int generation, Pipeline* pipeline,
  98 + bool suppress_warnings, bool will_retry);
  99 + QPDF_DLL
  100 + bool supportsRetry();
  101 +
  102 + private:
  103 + bool supports_retry;
79 }; 104 };
80 105
81 // The TokenFilter class provides a way to filter content streams 106 // The TokenFilter class provides a way to filter content streams
@@ -779,18 +804,39 @@ class QPDFObjectHandle @@ -779,18 +804,39 @@ class QPDFObjectHandle
779 // we determine that we know how to apply all requested filters, 804 // we determine that we know how to apply all requested filters,
780 // do so and return true if we are successful. 805 // do so and return true if we are successful.
781 // 806 //
782 - // In all cases, a return value of true means that filtered data  
783 - // has been written successfully. If filtering is requested but  
784 - // this method returns false, it means there was some error in the  
785 - // filtering, in which case the resulting data is likely partially  
786 - // filtered and/or incomplete and may not be consistent with the  
787 - // configured filters. QPDFWriter handles this by attempting to  
788 - // get the stream data without filtering, but callers should  
789 - // consider a false return value when decode_level is not  
790 - // qpdf_dl_none to be a potential loss of data. If you intend to  
791 - // retry in that case, pass true as the value of will_retry. This  
792 - // changes the warning issued by the library to indicate that the  
793 - // operation will be retried without filtering to avoid data loss. 807 + // The exact meaning of the return value differs the different
  808 + // versions of this function, but for any version, the meaning has
  809 + // been the same. For the main version, added in qpdf 10, the
  810 + // return value indicates whether the overall operation succeeded.
  811 + // The filter parameter, if specified, will be set to whether or
  812 + // not filtering was attempted. If filtering was not requested,
  813 + // this value will be false even if the overall operation
  814 + // succeeded.
  815 + //
  816 + // If filtering is requested but this method returns false, it
  817 + // means there was some error in the filtering, in which case the
  818 + // resulting data is likely partially filtered and/or incomplete
  819 + // and may not be consistent with the configured filters.
  820 + // QPDFWriter handles this by attempting to get the stream data
  821 + // without filtering, but callers should consider a false return
  822 + // value when decode_level is not qpdf_dl_none to be a potential
  823 + // loss of data. If you intend to retry in that case, pass true as
  824 + // the value of will_retry. This changes the warning issued by the
  825 + // library to indicate that the operation will be retried without
  826 + // filtering to avoid data loss.
  827 +
  828 + // Return value is overall success, even if filtering is not
  829 + // requested.
  830 + QPDF_DLL
  831 + bool pipeStreamData(Pipeline*, bool* filtering_attempted,
  832 + int encode_flags,
  833 + qpdf_stream_decode_level_e decode_level,
  834 + bool suppress_warnings = false,
  835 + bool will_retry = false);
  836 +
  837 + // Legacy version. Return value is whether filtering was
  838 + // attempted. There is no way to determine success if filtering
  839 + // was not attempted.
794 QPDF_DLL 840 QPDF_DLL
795 bool pipeStreamData(Pipeline*, 841 bool pipeStreamData(Pipeline*,
796 int encode_flags, 842 int encode_flags,
@@ -804,6 +850,7 @@ class QPDFObjectHandle @@ -804,6 +850,7 @@ class QPDFObjectHandle
804 // filter = true -> decode_level = qpdf_dl_generalized 850 // filter = true -> decode_level = qpdf_dl_generalized
805 // normalize = true -> encode_flags |= qpdf_sf_normalize 851 // normalize = true -> encode_flags |= qpdf_sf_normalize
806 // compress = true -> encode_flags |= qpdf_sf_compress 852 // compress = true -> encode_flags |= qpdf_sf_compress
  853 + // Return value is whether filtering was attempted.
807 QPDF_DLL 854 QPDF_DLL
808 bool pipeStreamData(Pipeline*, bool filter, 855 bool pipeStreamData(Pipeline*, bool filter,
809 bool normalize, bool compress); 856 bool normalize, bool compress);
libqpdf/QPDF.cc
@@ -68,27 +68,37 @@ QPDF::ForeignStreamData::ForeignStreamData( @@ -68,27 +68,37 @@ QPDF::ForeignStreamData::ForeignStreamData(
68 68
69 QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider( 69 QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider(
70 QPDF& destination_qpdf) : 70 QPDF& destination_qpdf) :
  71 + QPDFObjectHandle::StreamDataProvider(true),
71 destination_qpdf(destination_qpdf) 72 destination_qpdf(destination_qpdf)
72 { 73 {
73 } 74 }
74 75
75 -void 76 +bool
76 QPDF::CopiedStreamDataProvider::provideStreamData( 77 QPDF::CopiedStreamDataProvider::provideStreamData(
77 - int objid, int generation, Pipeline* pipeline) 78 + int objid, int generation, Pipeline* pipeline,
  79 + bool suppress_warnings, bool will_retry)
78 { 80 {
79 PointerHolder<ForeignStreamData> foreign_data = 81 PointerHolder<ForeignStreamData> foreign_data =
80 this->foreign_stream_data[QPDFObjGen(objid, generation)]; 82 this->foreign_stream_data[QPDFObjGen(objid, generation)];
  83 + bool result = false;
81 if (foreign_data.getPointer()) 84 if (foreign_data.getPointer())
82 { 85 {
83 - destination_qpdf.pipeForeignStreamData(  
84 - foreign_data, pipeline, 0, qpdf_dl_none); 86 + result = destination_qpdf.pipeForeignStreamData(
  87 + foreign_data, pipeline, suppress_warnings, will_retry);
  88 + QTC::TC("qpdf", "QPDF copy foreign with data",
  89 + result ? 0 : 1);
85 } 90 }
86 else 91 else
87 { 92 {
88 QPDFObjectHandle foreign_stream = 93 QPDFObjectHandle foreign_stream =
89 this->foreign_streams[QPDFObjGen(objid, generation)]; 94 this->foreign_streams[QPDFObjGen(objid, generation)];
90 - foreign_stream.pipeStreamData(pipeline, 0, qpdf_dl_none); 95 + result = foreign_stream.pipeStreamData(
  96 + pipeline, nullptr, 0, qpdf_dl_none,
  97 + suppress_warnings, will_retry);
  98 + QTC::TC("qpdf", "QPDF copy foreign with foreign_stream",
  99 + result ? 0 : 1);
91 } 100 }
  101 + return result;
92 } 102 }
93 103
94 void 104 void
@@ -2851,8 +2861,7 @@ bool @@ -2851,8 +2861,7 @@ bool
2851 QPDF::pipeForeignStreamData( 2861 QPDF::pipeForeignStreamData(
2852 PointerHolder<ForeignStreamData> foreign, 2862 PointerHolder<ForeignStreamData> foreign,
2853 Pipeline* pipeline, 2863 Pipeline* pipeline,
2854 - int encode_flags,  
2855 - qpdf_stream_decode_level_e decode_level) 2864 + bool suppress_warnings, bool will_retry)
2856 { 2865 {
2857 if (foreign->encp->encrypted) 2866 if (foreign->encp->encrypted)
2858 { 2867 {
@@ -2863,7 +2872,7 @@ QPDF::pipeForeignStreamData( @@ -2863,7 +2872,7 @@ QPDF::pipeForeignStreamData(
2863 foreign->foreign_objid, foreign->foreign_generation, 2872 foreign->foreign_objid, foreign->foreign_generation,
2864 foreign->offset, foreign->length, 2873 foreign->offset, foreign->length,
2865 foreign->local_dict, foreign->is_attachment_stream, 2874 foreign->local_dict, foreign->is_attachment_stream,
2866 - pipeline, false, false); 2875 + pipeline, suppress_warnings, will_retry);
2867 } 2876 }
2868 2877
2869 void 2878 void
libqpdf/QPDFObjectHandle.cc
@@ -36,6 +36,36 @@ class TerminateParsing @@ -36,6 +36,36 @@ class TerminateParsing
36 { 36 {
37 }; 37 };
38 38
  39 +QPDFObjectHandle::StreamDataProvider::StreamDataProvider(
  40 + bool supports_retry) :
  41 + supports_retry(supports_retry)
  42 +{
  43 +}
  44 +
  45 +void
  46 +QPDFObjectHandle::StreamDataProvider::provideStreamData(
  47 + int objid, int generation, Pipeline* pipeline)
  48 +{
  49 + throw std::logic_error(
  50 + "you must override provideStreamData -- see QPDFObjectHandle.hh");
  51 +}
  52 +
  53 +bool
  54 +QPDFObjectHandle::StreamDataProvider::provideStreamData(
  55 + int objid, int generation, Pipeline* pipeline,
  56 + bool suppress_warnings, bool will_retry)
  57 +{
  58 + throw std::logic_error(
  59 + "you must override provideStreamData -- see QPDFObjectHandle.hh");
  60 + return false;
  61 +}
  62 +
  63 +bool
  64 +QPDFObjectHandle::StreamDataProvider::supportsRetry()
  65 +{
  66 + return this->supports_retry;
  67 +}
  68 +
39 class CoalesceProvider: public QPDFObjectHandle::StreamDataProvider 69 class CoalesceProvider: public QPDFObjectHandle::StreamDataProvider
40 { 70 {
41 public: 71 public:
@@ -1135,14 +1165,29 @@ QPDFObjectHandle::getRawStreamData() @@ -1135,14 +1165,29 @@ QPDFObjectHandle::getRawStreamData()
1135 } 1165 }
1136 1166
1137 bool 1167 bool
1138 -QPDFObjectHandle::pipeStreamData(Pipeline* p, 1168 +QPDFObjectHandle::pipeStreamData(Pipeline* p, bool* filtering_attempted,
1139 int encode_flags, 1169 int encode_flags,
1140 qpdf_stream_decode_level_e decode_level, 1170 qpdf_stream_decode_level_e decode_level,
1141 bool suppress_warnings, bool will_retry) 1171 bool suppress_warnings, bool will_retry)
1142 { 1172 {
1143 assertStream(); 1173 assertStream();
1144 return dynamic_cast<QPDF_Stream*>(obj.getPointer())->pipeStreamData( 1174 return dynamic_cast<QPDF_Stream*>(obj.getPointer())->pipeStreamData(
1145 - p, encode_flags, decode_level, suppress_warnings, will_retry); 1175 + p, filtering_attempted, encode_flags, decode_level,
  1176 + suppress_warnings, will_retry);
  1177 +}
  1178 +
  1179 +bool
  1180 +QPDFObjectHandle::pipeStreamData(Pipeline* p,
  1181 + int encode_flags,
  1182 + qpdf_stream_decode_level_e decode_level,
  1183 + bool suppress_warnings, bool will_retry)
  1184 +{
  1185 + assertStream();
  1186 + bool filtering_attempted;
  1187 + dynamic_cast<QPDF_Stream*>(obj.getPointer())->pipeStreamData(
  1188 + p, &filtering_attempted, encode_flags, decode_level,
  1189 + suppress_warnings, will_retry);
  1190 + return filtering_attempted;
1146 } 1191 }
1147 1192
1148 bool 1193 bool
libqpdf/QPDF_Stream.cc
@@ -163,7 +163,7 @@ PointerHolder&lt;Buffer&gt; @@ -163,7 +163,7 @@ PointerHolder&lt;Buffer&gt;
163 QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) 163 QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
164 { 164 {
165 Pl_Buffer buf("stream data buffer"); 165 Pl_Buffer buf("stream data buffer");
166 - if (! pipeStreamData(&buf, 0, decode_level, false, false)) 166 + if (! pipeStreamData(&buf, nullptr, 0, decode_level, false, false))
167 { 167 {
168 throw QPDFExc(qpdf_e_unsupported, qpdf->getFilename(), 168 throw QPDFExc(qpdf_e_unsupported, qpdf->getFilename(),
169 "", this->offset, 169 "", this->offset,
@@ -177,7 +177,12 @@ PointerHolder&lt;Buffer&gt; @@ -177,7 +177,12 @@ PointerHolder&lt;Buffer&gt;
177 QPDF_Stream::getRawStreamData() 177 QPDF_Stream::getRawStreamData()
178 { 178 {
179 Pl_Buffer buf("stream data buffer"); 179 Pl_Buffer buf("stream data buffer");
180 - pipeStreamData(&buf, 0, qpdf_dl_none, false, false); 180 + if (! pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false))
  181 + {
  182 + throw QPDFExc(qpdf_e_unsupported, qpdf->getFilename(),
  183 + "", this->offset,
  184 + "error getting raw stream data");
  185 + }
181 QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); 186 QTC::TC("qpdf", "QPDF_Stream getRawStreamData");
182 return buf.getBuffer(); 187 return buf.getBuffer();
183 } 188 }
@@ -467,7 +472,7 @@ QPDF_Stream::filterable(std::vector&lt;std::string&gt;&amp; filters, @@ -467,7 +472,7 @@ QPDF_Stream::filterable(std::vector&lt;std::string&gt;&amp; filters,
467 } 472 }
468 473
469 bool 474 bool
470 -QPDF_Stream::pipeStreamData(Pipeline* pipeline, 475 +QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool* filterp,
471 int encode_flags, 476 int encode_flags,
472 qpdf_stream_decode_level_e decode_level, 477 qpdf_stream_decode_level_e decode_level,
473 bool suppress_warnings, bool will_retry) 478 bool suppress_warnings, bool will_retry)
@@ -480,7 +485,14 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, @@ -480,7 +485,14 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
480 bool early_code_change = true; 485 bool early_code_change = true;
481 bool specialized_compression = false; 486 bool specialized_compression = false;
482 bool lossy_compression = false; 487 bool lossy_compression = false;
483 - bool filter = (! ((encode_flags == 0) && (decode_level == qpdf_dl_none))); 488 + bool ignored;
  489 + if (filterp == nullptr)
  490 + {
  491 + filterp = &ignored;
  492 + }
  493 + bool& filter = *filterp;
  494 + filter = (! ((encode_flags == 0) && (decode_level == qpdf_dl_none)));
  495 + bool success = true;
484 if (filter) 496 if (filter)
485 { 497 {
486 filter = filterable(filters, specialized_compression, lossy_compression, 498 filter = filterable(filters, specialized_compression, lossy_compression,
@@ -505,6 +517,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, @@ -505,6 +517,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
505 if (pipeline == 0) 517 if (pipeline == 0)
506 { 518 {
507 QTC::TC("qpdf", "QPDF_Stream pipeStreamData with null pipeline"); 519 QTC::TC("qpdf", "QPDF_Stream pipeStreamData with null pipeline");
  520 + // Return value is whether we can filter in this case.
508 return filter; 521 return filter;
509 } 522 }
510 523
@@ -625,8 +638,21 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, @@ -625,8 +638,21 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
625 else if (this->stream_provider.getPointer()) 638 else if (this->stream_provider.getPointer())
626 { 639 {
627 Pl_Count count("stream provider count", pipeline); 640 Pl_Count count("stream provider count", pipeline);
628 - this->stream_provider->provideStreamData(  
629 - this->objid, this->generation, &count); 641 + if (this->stream_provider->supportsRetry())
  642 + {
  643 + if (! this->stream_provider->provideStreamData(
  644 + this->objid, this->generation, &count,
  645 + suppress_warnings, will_retry))
  646 + {
  647 + filter = false;
  648 + success = false;
  649 + }
  650 + }
  651 + else
  652 + {
  653 + this->stream_provider->provideStreamData(
  654 + this->objid, this->generation, &count);
  655 + }
630 qpdf_offset_t actual_length = count.getCount(); 656 qpdf_offset_t actual_length = count.getCount();
631 qpdf_offset_t desired_length = 0; 657 qpdf_offset_t desired_length = 0;
632 if (this->stream_dict.hasKey("/Length")) 658 if (this->stream_dict.hasKey("/Length"))
@@ -674,6 +700,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, @@ -674,6 +700,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
674 will_retry)) 700 will_retry))
675 { 701 {
676 filter = false; 702 filter = false;
  703 + success = false;
677 } 704 }
678 } 705 }
679 706
@@ -704,7 +731,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, @@ -704,7 +731,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
704 " for content normalization in the manual.")); 731 " for content normalization in the manual."));
705 } 732 }
706 733
707 - return filter; 734 + return success;
708 } 735 }
709 736
710 void 737 void
libqpdf/qpdf/QPDF_Stream.hh
@@ -31,7 +31,7 @@ class QPDF_Stream: public QPDFObject @@ -31,7 +31,7 @@ class QPDF_Stream: public QPDFObject
31 PointerHolder<QPDFObjectHandle::StreamDataProvider> getStreamDataProvider() const; 31 PointerHolder<QPDFObjectHandle::StreamDataProvider> getStreamDataProvider() const;
32 32
33 // See comments in QPDFObjectHandle.hh for these methods. 33 // See comments in QPDFObjectHandle.hh for these methods.
34 - bool pipeStreamData(Pipeline*, 34 + bool pipeStreamData(Pipeline*, bool* tried_filtering,
35 int encode_flags, 35 int encode_flags,
36 qpdf_stream_decode_level_e decode_level, 36 qpdf_stream_decode_level_e decode_level,
37 bool suppress_warnings, bool will_retry); 37 bool suppress_warnings, bool will_retry);
qpdf/qpdf.testcov
@@ -453,3 +453,5 @@ QPDFPageObjectHelper filter form xobject 0 @@ -453,3 +453,5 @@ QPDFPageObjectHelper filter form xobject 0
453 qpdf found resources in non-leaf 0 453 qpdf found resources in non-leaf 0
454 qpdf found shared resources in leaf 0 454 qpdf found shared resources in leaf 0
455 qpdf found shared xobject in leaf 0 455 qpdf found shared xobject in leaf 0
  456 +QPDF copy foreign with data 1
  457 +QPDF copy foreign with foreign_stream 1
qpdf/qtest/qpdf.test
@@ -1698,6 +1698,8 @@ my @sp_cases = ( @@ -1698,6 +1698,8 @@ my @sp_cases = (
1698 [11, '%d in middle', '--encrypt u o 128 --', 'a-%d-split-out.zdf'], 1698 [11, '%d in middle', '--encrypt u o 128 --', 'a-%d-split-out.zdf'],
1699 [11, 'pdf extension', '', 'split-out.Pdf'], 1699 [11, 'pdf extension', '', 'split-out.Pdf'],
1700 [4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'], 1700 [4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'],
  1701 + [1, 'broken data', '--pages broken-lzw.pdf --', 'split-out.pdf',
  1702 + {$td->FILE => "broken-lzw.out", $td->EXIT_STATUS => 3}],
1701 ); 1703 );
1702 $n_tests += 35; 1704 $n_tests += 35;
1703 $n_compare_pdfs += 1; 1705 $n_compare_pdfs += 1;
@@ -1713,7 +1715,7 @@ $td-&gt;runtest(&quot;split page group &gt; 1&quot;, @@ -1713,7 +1715,7 @@ $td-&gt;runtest(&quot;split page group &gt; 1&quot;,
1713 $td->NORMALIZE_NEWLINES); 1715 $td->NORMALIZE_NEWLINES);
1714 foreach my $f ('01-05', '06-10', '11-11') 1716 foreach my $f ('01-05', '06-10', '11-11')
1715 { 1717 {
1716 - $td->runtest("checkout group $f", 1718 + $td->runtest("check out group $f",
1717 {$td->FILE => "split-out-group-$f.pdf"}, 1719 {$td->FILE => "split-out-group-$f.pdf"},
1718 {$td->FILE => "split-exp-group-$f.pdf"}); 1720 {$td->FILE => "split-exp-group-$f.pdf"});
1719 } 1721 }
@@ -1761,12 +1763,17 @@ foreach my $i (qw(01-10 11-20 21-30)) @@ -1761,12 +1763,17 @@ foreach my $i (qw(01-10 11-20 21-30))
1761 1763
1762 foreach my $d (@sp_cases) 1764 foreach my $d (@sp_cases)
1763 { 1765 {
1764 - my ($n, $description, $xargs, $out) = @$d; 1766 + my ($n, $description, $xargs, $out, $exp) = @$d;
  1767 + if (! defined $exp)
  1768 + {
  1769 + $exp = {$td->STRING => "", $td->EXIT_STATUS => 0};
  1770 + }
1765 $td->runtest("split pages " . $description, 1771 $td->runtest("split pages " . $description,
1766 {$td->COMMAND => 1772 {$td->COMMAND =>
1767 "qpdf --static-id --split-pages 11-pages.pdf" . 1773 "qpdf --static-id --split-pages 11-pages.pdf" .
1768 " $xargs $out"}, 1774 " $xargs $out"},
1769 - {$td->STRING => "", $td->EXIT_STATUS => 0}); 1775 + $exp,
  1776 + $td->NORMALIZE_NEWLINES);
1770 my $pattern = $out; 1777 my $pattern = $out;
1771 my $nlen = length($n); 1778 my $nlen = length($n);
1772 if ($pattern =~ m/\%d/) 1779 if ($pattern =~ m/\%d/)
@@ -1786,7 +1793,7 @@ foreach my $d (@sp_cases) @@ -1786,7 +1793,7 @@ foreach my $d (@sp_cases)
1786 my $actual = sprintf($pattern, $i); 1793 my $actual = sprintf($pattern, $i);
1787 my $expected = $actual; 1794 my $expected = $actual;
1788 $expected =~ s/split-out/split-exp/; 1795 $expected =~ s/split-out/split-exp/;
1789 - $td->runtest("checkout output page $i", 1796 + $td->runtest("check output page $i ($description)",
1790 {$td->FILE => $actual}, 1797 {$td->FILE => $actual},
1791 {$td->FILE => $expected}); 1798 {$td->FILE => $expected});
1792 } 1799 }
@@ -2390,7 +2397,8 @@ foreach my $d ([25, 1], [26, 2], [27, 3]) @@ -2390,7 +2397,8 @@ foreach my $d ([25, 1], [26, 2], [27, 3])
2390 $td->runtest("copy objects $outn", 2397 $td->runtest("copy objects $outn",
2391 {$td->COMMAND => "test_driver $testn" . 2398 {$td->COMMAND => "test_driver $testn" .
2392 " minimal.pdf copy-foreign-objects-in.pdf"}, 2399 " minimal.pdf copy-foreign-objects-in.pdf"},
2393 - {$td->STRING => "test $testn done\n", $td->EXIT_STATUS => 0}, 2400 + {$td->FILE => "copy-foreign-objects-$testn.out",
  2401 + $td->EXIT_STATUS => 0},
2394 $td->NORMALIZE_NEWLINES); 2402 $td->NORMALIZE_NEWLINES);
2395 $td->runtest("check output", 2403 $td->runtest("check output",
2396 {$td->FILE => "a.pdf"}, 2404 {$td->FILE => "a.pdf"},
qpdf/qtest/qpdf/broken-lzw.out 0 → 100644
  1 +WARNING: broken-lzw.pdf (offset 444): error decoding stream data for object 4 0: LZWDecoder: bad code received
  2 +WARNING: broken-lzw.pdf (offset 444): stream will be re-processed without filtering to avoid data loss
  3 +qpdf: operation succeeded with warnings; resulting file may have some problems
qpdf/qtest/qpdf/broken-lzw.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +1 0 obj
  6 +<<
  7 + /Pages 2 0 R
  8 + /Type /Catalog
  9 +>>
  10 +endobj
  11 +
  12 +2 0 obj
  13 +<<
  14 + /Count 1
  15 + /Kids [
  16 + 3 0 R
  17 + ]
  18 + /Type /Pages
  19 +>>
  20 +endobj
  21 +
  22 +%% Page 1
  23 +3 0 obj
  24 +<<
  25 + /Contents [ 4 0 R 6 0 R ]
  26 + /MediaBox [
  27 + 0
  28 + 0
  29 + 612
  30 + 792
  31 + ]
  32 + /Parent 2 0 R
  33 + /Resources <<
  34 + /Font <<
  35 + /F1 8 0 R
  36 + >>
  37 + /ProcSet 9 0 R
  38 + >>
  39 + /Type /Page
  40 +>>
  41 +endobj
  42 +
  43 +%% Contents for page 1
  44 +4 0 obj
  45 +<<
  46 + /Filter /LZWDecode
  47 + /Length 5 0 R
  48 +>>
  49 +stream
  50 +Not really compressed.
  51 +endstream
  52 +endobj
  53 +
  54 +5 0 obj
  55 +23
  56 +endobj
  57 +
  58 +%% Contents for page 1
  59 +6 0 obj
  60 +<<
  61 + /Length 7 0 R
  62 +>>
  63 +stream
  64 +Really compressed.
  65 +endstream
  66 +endobj
  67 +
  68 +7 0 obj
  69 +19
  70 +endobj
  71 +
  72 +8 0 obj
  73 +<<
  74 + /BaseFont /Helvetica
  75 + /Encoding /WinAnsiEncoding
  76 + /Name /F1
  77 + /Subtype /Type1
  78 + /Type /Font
  79 +>>
  80 +endobj
  81 +
  82 +9 0 obj
  83 +[
  84 + /PDF
  85 + /Text
  86 +]
  87 +endobj
  88 +
  89 +xref
  90 +0 10
  91 +0000000000 65535 f
  92 +0000000025 00000 n
  93 +0000000079 00000 n
  94 +0000000161 00000 n
  95 +0000000386 00000 n
  96 +0000000485 00000 n
  97 +0000000527 00000 n
  98 +0000000601 00000 n
  99 +0000000620 00000 n
  100 +0000000738 00000 n
  101 +trailer <<
  102 + /Root 1 0 R
  103 + /Size 10
  104 + /ID [<8b40e25fc6409c63043ed789f3ae4a4b><8b40e25fc6409c63043ed789f3ae4a4b>]
  105 +>>
  106 +startxref
  107 +773
  108 +%%EOF
qpdf/qtest/qpdf/copy-foreign-objects-25.out 0 → 100644
  1 +test 25 done
qpdf/qtest/qpdf/copy-foreign-objects-26.out 0 → 100644
  1 +test 26 done
qpdf/qtest/qpdf/copy-foreign-objects-27.out 0 → 100644
  1 +WARNING: copy-foreign-objects-in.pdf (offset 3627): error decoding stream data for object 26 0: LZWDecoder: bad code received
  2 +WARNING: copy-foreign-objects-in.pdf (offset 3627): stream will be re-processed without filtering to avoid data loss
  3 +test 27 done
qpdf/qtest/qpdf/copy-foreign-objects-in.pdf
@@ -7,12 +7,13 @@ @@ -7,12 +7,13 @@
7 % file. 7 % file.
8 8
9 % The /QTest key in trailer has pointers to several indirect objects: 9 % The /QTest key in trailer has pointers to several indirect objects:
10 -% O1, O2, O3 where O1 is an array that contains a dictionary that has  
11 -% a key that points to O2, O2 is a dictionary that contains an array  
12 -% that points to O1, and O3 is a page object that inherits some  
13 -% resource from its parent /Pages and also points to some other page.  
14 -% O1 also points to a stream whose dictionary has a key that points to  
15 -% another stream whose dictionary points back to the first stream. 10 +% O1, O2, O3, O4 where O1 is an array that contains a dictionary that
  11 +% has a key that points to O2, O2 is a dictionary that contains an
  12 +% array that points to O1, O3 is a page object that inherits some
  13 +% resource from its parent /Pages and also points to some other page,
  14 +% and O4 is a stream with invalid compressed data. O1 also points to a
  15 +% stream whose dictionary has a key that points to another stream
  16 +% whose dictionary points back to the first stream.
16 17
17 1 0 obj 18 1 0 obj
18 << 19 <<
@@ -293,43 +294,59 @@ endobj @@ -293,43 +294,59 @@ endobj
293 294
294 % QTest 295 % QTest
295 25 0 obj 296 25 0 obj
296 -<< /This-is-QTest true /O1 19 0 R /O2 20 0 R /O3 5 0 R >> 297 +<< /This-is-QTest true /O1 19 0 R /O2 20 0 R /O3 5 0 R /O4 26 0 R >>
  298 +endobj
  299 +
  300 +26 0 obj
  301 +<<
  302 + /Length 27 0 R
  303 + /Filter /LZWDecode
  304 +>>
  305 +stream
  306 +Not really compresed.
  307 +endstream
  308 +endobj
  309 +
  310 +27 0 obj
  311 +22
297 endobj 312 endobj
298 313
299 xref 314 xref
300 -0 26 315 +0 28
301 0000000000 65535 f 316 0000000000 65535 f
302 -0000000655 00000 n  
303 -0000000709 00000 n  
304 -0000000845 00000 n  
305 -0000001073 00000 n  
306 -0000001313 00000 n  
307 -0000001580 00000 n  
308 -0000001839 00000 n  
309 -0000002081 00000 n  
310 -0000002183 00000 n  
311 -0000002202 00000 n  
312 -0000002334 00000 n  
313 -0000002438 00000 n  
314 -0000002481 00000 n  
315 -0000002585 00000 n  
316 -0000002628 00000 n  
317 -0000002732 00000 n  
318 -0000002775 00000 n  
319 -0000002879 00000 n  
320 -0000002904 00000 n  
321 -0000003042 00000 n  
322 -0000003138 00000 n  
323 -0000003255 00000 n  
324 -0000003285 00000 n  
325 -0000003402 00000 n  
326 -0000003430 00000 n 317 +0000000706 00000 n
  318 +0000000760 00000 n
  319 +0000000896 00000 n
  320 +0000001124 00000 n
  321 +0000001364 00000 n
  322 +0000001631 00000 n
  323 +0000001890 00000 n
  324 +0000002132 00000 n
  325 +0000002234 00000 n
  326 +0000002253 00000 n
  327 +0000002385 00000 n
  328 +0000002489 00000 n
  329 +0000002532 00000 n
  330 +0000002636 00000 n
  331 +0000002679 00000 n
  332 +0000002783 00000 n
  333 +0000002826 00000 n
  334 +0000002930 00000 n
  335 +0000002955 00000 n
  336 +0000003093 00000 n
  337 +0000003189 00000 n
  338 +0000003306 00000 n
  339 +0000003336 00000 n
  340 +0000003453 00000 n
  341 +0000003481 00000 n
  342 +0000003567 00000 n
  343 +0000003667 00000 n
327 trailer << 344 trailer <<
328 /Root 1 0 R 345 /Root 1 0 R
329 - /Size 26 346 + /Size 28
330 /QTest 25 0 R 347 /QTest 25 0 R
331 /ID [<d15f7aca3be584a96c1c94adb0931e71><9adb6b2fdb22e857340f7103917b16e4>] 348 /ID [<d15f7aca3be584a96c1c94adb0931e71><9adb6b2fdb22e857340f7103917b16e4>]
332 >> 349 >>
333 startxref 350 startxref
334 -3505 351 +3687
335 %%EOF 352 %%EOF
qpdf/qtest/qpdf/copy-foreign-objects-out1.pdf
@@ -4,27 +4,33 @@ @@ -4,27 +4,33 @@
4 << /Pages 3 0 R /Type /Catalog >> 4 << /Pages 3 0 R /Type /Catalog >>
5 endobj 5 endobj
6 2 0 obj 6 2 0 obj
7 -<< /O1 4 0 R /O2 5 0 R /This-is-QTest true >> 7 +<< /O1 4 0 R /O2 5 0 R /O4 6 0 R /This-is-QTest true >>
8 endobj 8 endobj
9 3 0 obj 9 3 0 obj
10 -<< /Count 1 /Kids [ 6 0 R ] /Type /Pages >> 10 +<< /Count 1 /Kids [ 7 0 R ] /Type /Pages >>
11 endobj 11 endobj
12 4 0 obj 12 4 0 obj
13 -[ /This-is-O1 /potato << /O2 [ 3.14159 << /O2 5 0 R >> 2.17828 ] >> /salad /O2 5 0 R /Stream1 7 0 R ] 13 +[ /This-is-O1 /potato << /O2 [ 3.14159 << /O2 5 0 R >> 2.17828 ] >> /salad /O2 5 0 R /Stream1 8 0 R ]
14 endobj 14 endobj
15 5 0 obj 15 5 0 obj
16 << /K1 [ 2.236 /O1 4 0 R 1.732 ] /O1 4 0 R /This-is-O2 true >> 16 << /K1 [ 2.236 /O1 4 0 R 1.732 ] /O1 4 0 R /This-is-O2 true >>
17 endobj 17 endobj
18 6 0 obj 18 6 0 obj
19 -<< /Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 9 0 R >> /ProcSet 10 0 R >> /Type /Page >> 19 +<< /Filter /LZWDecode /Length 22 >>
  20 +stream
  21 +Not really compresed.
  22 +endstream
20 endobj 23 endobj
21 7 0 obj 24 7 0 obj
22 -<< /Stream2 11 0 R /This-is-Stream1 true /Length 18 >> 25 +<< /Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 10 0 R >> /ProcSet 11 0 R >> /Type /Page >>
  26 +endobj
  27 +8 0 obj
  28 +<< /Stream2 12 0 R /This-is-Stream1 true /Length 18 >>
23 stream 29 stream
24 This is stream 1. 30 This is stream 1.
25 endstream 31 endstream
26 endobj 32 endobj
27 -8 0 obj 33 +9 0 obj
28 << /Length 44 >> 34 << /Length 44 >>
29 stream 35 stream
30 BT 36 BT
@@ -34,33 +40,34 @@ BT @@ -34,33 +40,34 @@ BT
34 ET 40 ET
35 endstream 41 endstream
36 endobj 42 endobj
37 -9 0 obj 43 +10 0 obj
38 << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> 44 << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
39 endobj 45 endobj
40 -10 0 obj 46 +11 0 obj
41 [ /PDF /Text ] 47 [ /PDF /Text ]
42 endobj 48 endobj
43 -11 0 obj  
44 -<< /Stream1 7 0 R /This-is-Stream2 true /Length 18 >> 49 +12 0 obj
  50 +<< /Stream1 8 0 R /This-is-Stream2 true /Length 18 >>
45 stream 51 stream
46 This is stream 2. 52 This is stream 2.
47 endstream 53 endstream
48 endobj 54 endobj
49 xref 55 xref
50 -0 12 56 +0 13
51 0000000000 65535 f 57 0000000000 65535 f
52 0000000015 00000 n 58 0000000015 00000 n
53 0000000064 00000 n 59 0000000064 00000 n
54 -0000000125 00000 n  
55 -0000000184 00000 n  
56 -0000000301 00000 n  
57 -0000000379 00000 n  
58 -0000000523 00000 n  
59 -0000000628 00000 n  
60 -0000000721 00000 n  
61 -0000000828 00000 n  
62 -0000000859 00000 n  
63 -trailer << /QTest 2 0 R /Root 1 0 R /Size 12 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> 60 +0000000135 00000 n
  61 +0000000194 00000 n
  62 +0000000311 00000 n
  63 +0000000389 00000 n
  64 +0000000479 00000 n
  65 +0000000624 00000 n
  66 +0000000729 00000 n
  67 +0000000822 00000 n
  68 +0000000930 00000 n
  69 +0000000961 00000 n
  70 +trailer << /QTest 2 0 R /Root 1 0 R /Size 13 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >>
64 startxref 71 startxref
65 -964 72 +1066
66 %%EOF 73 %%EOF
qpdf/qtest/qpdf/copy-foreign-objects-out2.pdf
@@ -4,39 +4,45 @@ @@ -4,39 +4,45 @@
4 << /Pages 3 0 R /Type /Catalog >> 4 << /Pages 3 0 R /Type /Catalog >>
5 endobj 5 endobj
6 2 0 obj 6 2 0 obj
7 -<< /O1 4 0 R /O2 5 0 R /O3 6 0 R /This-is-QTest true >> 7 +<< /O1 4 0 R /O2 5 0 R /O3 6 0 R /O4 7 0 R /This-is-QTest true >>
8 endobj 8 endobj
9 3 0 obj 9 3 0 obj
10 -<< /Count 2 /Kids [ 7 0 R 6 0 R ] /Type /Pages >> 10 +<< /Count 2 /Kids [ 8 0 R 6 0 R ] /Type /Pages >>
11 endobj 11 endobj
12 4 0 obj 12 4 0 obj
13 -[ /This-is-O1 /potato << /O2 [ 3.14159 << /O2 5 0 R >> 2.17828 ] >> /salad /O2 5 0 R /Stream1 8 0 R ] 13 +[ /This-is-O1 /potato << /O2 [ 3.14159 << /O2 5 0 R >> 2.17828 ] >> /salad /O2 5 0 R /Stream1 9 0 R ]
14 endobj 14 endobj
15 5 0 obj 15 5 0 obj
16 << /K1 [ 2.236 /O1 4 0 R 1.732 ] /O1 4 0 R /This-is-O2 true >> 16 << /K1 [ 2.236 /O1 4 0 R 1.732 ] /O1 4 0 R /This-is-O2 true >>
17 endobj 17 endobj
18 6 0 obj 18 6 0 obj
19 -<< /Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 10 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3 true /Type /Page >> 19 +<< /Contents 10 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 true /Type /Page >>
20 endobj 20 endobj
21 7 0 obj 21 7 0 obj
22 -<< /Contents 11 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 12 0 R >> /ProcSet 13 0 R >> /Type /Page >> 22 +<< /Filter /LZWDecode /Length 22 >>
  23 +stream
  24 +Not really compresed.
  25 +endstream
23 endobj 26 endobj
24 8 0 obj 27 8 0 obj
25 -<< /Stream2 14 0 R /This-is-Stream1 true /Length 18 >> 28 +<< /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 >>
  29 +endobj
  30 +9 0 obj
  31 +<< /Stream2 15 0 R /This-is-Stream1 true /Length 18 >>
26 stream 32 stream
27 This is stream 1. 33 This is stream 1.
28 endstream 34 endstream
29 endobj 35 endobj
30 -9 0 obj 36 +10 0 obj
31 << /Length 47 >> 37 << /Length 47 >>
32 stream 38 stream
33 BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET 39 BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET
34 endstream 40 endstream
35 endobj 41 endobj
36 -10 0 obj 42 +11 0 obj
37 << /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >> 43 << /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
38 endobj 44 endobj
39 -11 0 obj 45 +12 0 obj
40 << /Length 44 >> 46 << /Length 44 >>
41 stream 47 stream
42 BT 48 BT
@@ -46,36 +52,37 @@ BT @@ -46,36 +52,37 @@ BT
46 ET 52 ET
47 endstream 53 endstream
48 endobj 54 endobj
49 -12 0 obj 55 +13 0 obj
50 << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> 56 << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
51 endobj 57 endobj
52 -13 0 obj 58 +14 0 obj
53 [ /PDF /Text ] 59 [ /PDF /Text ]
54 endobj 60 endobj
55 -14 0 obj  
56 -<< /Stream1 8 0 R /This-is-Stream2 true /Length 18 >> 61 +15 0 obj
  62 +<< /Stream1 9 0 R /This-is-Stream2 true /Length 18 >>
57 stream 63 stream
58 This is stream 2. 64 This is stream 2.
59 endstream 65 endstream
60 endobj 66 endobj
61 xref 67 xref
62 -0 15 68 +0 16
63 0000000000 65535 f 69 0000000000 65535 f
64 0000000015 00000 n 70 0000000015 00000 n
65 0000000064 00000 n 71 0000000064 00000 n
66 -0000000135 00000 n  
67 -0000000200 00000 n  
68 -0000000317 00000 n  
69 -0000000395 00000 n  
70 -0000000577 00000 n  
71 -0000000723 00000 n  
72 -0000000828 00000 n  
73 -0000000924 00000 n  
74 -0000001024 00000 n  
75 -0000001118 00000 n  
76 -0000001226 00000 n  
77 -0000001257 00000 n  
78 -trailer << /QTest 2 0 R /Root 1 0 R /Size 15 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> 72 +0000000145 00000 n
  73 +0000000210 00000 n
  74 +0000000327 00000 n
  75 +0000000405 00000 n
  76 +0000000588 00000 n
  77 +0000000678 00000 n
  78 +0000000824 00000 n
  79 +0000000929 00000 n
  80 +0000001026 00000 n
  81 +0000001126 00000 n
  82 +0000001220 00000 n
  83 +0000001328 00000 n
  84 +0000001359 00000 n
  85 +trailer << /QTest 2 0 R /Root 1 0 R /Size 16 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >>
79 startxref 86 startxref
80 -1362 87 +1464
81 %%EOF 88 %%EOF
qpdf/qtest/qpdf/copy-foreign-objects-out3.pdf
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 << /Pages 6 0 R /Type /Catalog >> 4 << /Pages 6 0 R /Type /Catalog >>
5 endobj 5 endobj
6 2 0 obj 6 2 0 obj
7 -<< /O1 7 0 R /O2 8 0 R /O3 9 0 R /This-is-QTest true >> 7 +<< /O1 7 0 R /O2 8 0 R /O3 9 0 R /O4 10 0 R /This-is-QTest true >>
8 endobj 8 endobj
9 3 0 obj 9 3 0 obj
10 << /Length 20 >> 10 << /Length 20 >>
@@ -25,39 +25,45 @@ more data for stream @@ -25,39 +25,45 @@ more data for stream
25 endstream 25 endstream
26 endobj 26 endobj
27 6 0 obj 27 6 0 obj
28 -<< /Count 3 /Kids [ 10 0 R 11 0 R 9 0 R ] /Type /Pages >> 28 +<< /Count 3 /Kids [ 11 0 R 12 0 R 9 0 R ] /Type /Pages >>
29 endobj 29 endobj
30 7 0 obj 30 7 0 obj
31 -[ /This-is-O1 /potato << /O2 [ 3.14159 << /O2 8 0 R >> 2.17828 ] >> /salad /O2 8 0 R /Stream1 12 0 R ] 31 +[ /This-is-O1 /potato << /O2 [ 3.14159 << /O2 8 0 R >> 2.17828 ] >> /salad /O2 8 0 R /Stream1 13 0 R ]
32 endobj 32 endobj
33 8 0 obj 33 8 0 obj
34 << /K1 [ 2.236 /O1 7 0 R 1.732 ] /O1 7 0 R /This-is-O2 true >> 34 << /K1 [ 2.236 /O1 7 0 R 1.732 ] /O1 7 0 R /This-is-O2 true >>
35 endobj 35 endobj
36 9 0 obj 36 9 0 obj
37 -<< /Contents 13 0 R /MediaBox [ 0 0 612 792 ] /OtherPage 11 0 R /Parent 6 0 R /Resources << /Font << /F1 14 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3 true /Type /Page >> 37 +<< /Contents 14 0 R /MediaBox [ 0 0 612 792 ] /OtherPage 12 0 R /Parent 6 0 R /Resources << /Font << /F1 15 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3 true /Type /Page >>
38 endobj 38 endobj
39 10 0 obj 39 10 0 obj
40 -<< /Contents 15 0 R /MediaBox [ 0 0 612 792 ] /Parent 6 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet 17 0 R >> /Type /Page >> 40 +<< /Filter /LZWDecode /Length 22 >>
  41 +stream
  42 +Not really compresed.
  43 +endstream
41 endobj 44 endobj
42 11 0 obj 45 11 0 obj
43 -<< /Contents 18 0 R /MediaBox [ 0 0 612 792 ] /Parent 6 0 R /Resources << /Font << /F1 14 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3-other-page true /Type /Page >> 46 +<< /Contents 16 0 R /MediaBox [ 0 0 612 792 ] /Parent 6 0 R /Resources << /Font << /F1 17 0 R >> /ProcSet 18 0 R >> /Type /Page >>
44 endobj 47 endobj
45 12 0 obj 48 12 0 obj
46 -<< /Stream2 19 0 R /This-is-Stream1 true /Length 18 >> 49 +<< /Contents 19 0 R /MediaBox [ 0 0 612 792 ] /Parent 6 0 R /Resources << /Font << /F1 15 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 180 /This-is-O3-other-page true /Type /Page >>
  50 +endobj
  51 +13 0 obj
  52 +<< /Stream2 20 0 R /This-is-Stream1 true /Length 18 >>
47 stream 53 stream
48 This is stream 1. 54 This is stream 1.
49 endstream 55 endstream
50 endobj 56 endobj
51 -13 0 obj 57 +14 0 obj
52 << /Length 47 >> 58 << /Length 47 >>
53 stream 59 stream
54 BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET 60 BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET
55 endstream 61 endstream
56 endobj 62 endobj
57 -14 0 obj 63 +15 0 obj
58 << /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >> 64 << /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
59 endobj 65 endobj
60 -15 0 obj 66 +16 0 obj
61 << /Length 44 >> 67 << /Length 44 >>
62 stream 68 stream
63 BT 69 BT
@@ -67,47 +73,48 @@ BT @@ -67,47 +73,48 @@ BT
67 ET 73 ET
68 endstream 74 endstream
69 endobj 75 endobj
70 -16 0 obj 76 +17 0 obj
71 << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> 77 << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
72 endobj 78 endobj
73 -17 0 obj 79 +18 0 obj
74 [ /PDF /Text ] 80 [ /PDF /Text ]
75 endobj 81 endobj
76 -18 0 obj 82 +19 0 obj
77 << /Length 47 >> 83 << /Length 47 >>
78 stream 84 stream
79 BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET 85 BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET
80 endstream 86 endstream
81 endobj 87 endobj
82 -19 0 obj  
83 -<< /Stream1 12 0 R /This-is-Stream2 true /Length 18 >> 88 +20 0 obj
  89 +<< /Stream1 13 0 R /This-is-Stream2 true /Length 18 >>
84 stream 90 stream
85 This is stream 2. 91 This is stream 2.
86 endstream 92 endstream
87 endobj 93 endobj
88 xref 94 xref
89 -0 20 95 +0 21
90 0000000000 65535 f 96 0000000000 65535 f
91 0000000015 00000 n 97 0000000015 00000 n
92 0000000064 00000 n 98 0000000064 00000 n
93 -0000000135 00000 n  
94 -0000000204 00000 n  
95 -0000000259 00000 n  
96 -0000000329 00000 n  
97 -0000000402 00000 n  
98 -0000000520 00000 n  
99 -0000000598 00000 n  
100 -0000000799 00000 n  
101 -0000000946 00000 n  
102 -0000001141 00000 n  
103 -0000001247 00000 n  
104 -0000001344 00000 n  
105 -0000001444 00000 n  
106 -0000001538 00000 n  
107 -0000001646 00000 n  
108 -0000001677 00000 n  
109 -0000001774 00000 n  
110 -trailer << /QTest 2 0 R /QTest2 [ 3 0 R 4 0 R 5 0 R ] /Root 1 0 R /Size 20 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> 99 +0000000146 00000 n
  100 +0000000215 00000 n
  101 +0000000270 00000 n
  102 +0000000340 00000 n
  103 +0000000413 00000 n
  104 +0000000531 00000 n
  105 +0000000609 00000 n
  106 +0000000810 00000 n
  107 +0000000901 00000 n
  108 +0000001048 00000 n
  109 +0000001243 00000 n
  110 +0000001349 00000 n
  111 +0000001446 00000 n
  112 +0000001546 00000 n
  113 +0000001640 00000 n
  114 +0000001748 00000 n
  115 +0000001779 00000 n
  116 +0000001876 00000 n
  117 +trailer << /QTest 2 0 R /QTest2 [ 3 0 R 4 0 R 5 0 R ] /Root 1 0 R /Size 21 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >>
111 startxref 118 startxref
112 -1880 119 +1982
113 %%EOF 120 %%EOF
qpdf/qtest/qpdf/split-exp-1.pdf 0 → 100644
No preview for this file type
qpdf/test_driver.cc
@@ -1210,7 +1210,8 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1210,7 +1210,8 @@ void runtest(int n, char const* filename1, char const* arg2)
1210 1210
1211 QPDFWriter w(pdf, "a.pdf"); 1211 QPDFWriter w(pdf, "a.pdf");
1212 w.setStaticID(true); 1212 w.setStaticID(true);
1213 - w.setStreamDataMode(qpdf_s_preserve); 1213 + w.setCompressStreams(false);
  1214 + w.setDecodeLevel(qpdf_dl_generalized);
1214 w.write(); 1215 w.write();
1215 } 1216 }
1216 else if (n == 28) 1217 else if (n == 28)