Commit a72ce95c922228e624e47bb43a68c55a9dd8eab2

Authored by Jay Berkenbilt
1 parent 9f444ffe

setOutputStreams

git-svn-id: svn+q:///qpdf/trunk@1035 71b93d88-0707-0410-a8cf-f5a4172ac649
ChangeLog
1 2010-10-01 Jay Berkenbilt <ejb@ql.org> 1 2010-10-01 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * include/qpdf/QPDF.hh: Add setOutputStreams method to allow
  4 + redirection of library-generated output/error to alternative
  5 + streams.
  6 +
3 * include/qpdf/QPDF.hh: Add processMemoryFile method for 7 * include/qpdf/QPDF.hh: Add processMemoryFile method for
4 processing a PDF file from a memory buffer instead of a file. 8 processing a PDF file from a memory buffer instead of a file.
5 9
1 -General  
2 -======= 1 +2.2.1
  2 +=====
  3 +
  4 + * Remove cerr and cout from QPDF*.cc
3 5
4 * QPDF::checkLinearization writes things to std::cout, which makes it 6 * QPDF::checkLinearization writes things to std::cout, which makes it
5 hard for GUIs that want to display the result. Go through all 7 hard for GUIs that want to display the result. Go through all
@@ -12,6 +14,10 @@ General @@ -12,6 +14,10 @@ General
12 rethrow if needed. The old version should call the ostream version 14 rethrow if needed. The old version should call the ostream version
13 with std::cout. 15 with std::cout.
14 16
  17 +
  18 +General
  19 +=======
  20 +
15 * In general, take a fresh look at private methods to see which, if 21 * In general, take a fresh look at private methods to see which, if
16 any, should be protected. 22 any, should be protected.
17 23
include/qpdf/QPDF.hh
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 #include <string> 12 #include <string>
13 #include <map> 13 #include <map>
14 #include <list> 14 #include <list>
  15 +#include <iostream>
15 16
16 #include <qpdf/DLL.h> 17 #include <qpdf/DLL.h>
17 18
@@ -61,6 +62,21 @@ class QPDF @@ -61,6 +62,21 @@ class QPDF
61 62
62 // Parameter settings 63 // Parameter settings
63 64
  65 + // By default, warning messages are issued to std::cerr and output
  66 + // messages printed by certain check calls are issued to
  67 + // std::cout. This method allows you to specify alternative
  68 + // streams for this purpose. Note that no normal QPDF operations
  69 + // generate output to std::cout, so for applications that just
  70 + // wish to avoid creating output and don't call any check
  71 + // functions, calling setSuppressWarnings(true) is sufficient.
  72 + // Applications that wish to present check or warning information
  73 + // to users may replace the output and error streams to capture
  74 + // the output and errors for other use. A null value for either
  75 + // stream will cause QPDF to use std::cout or std::cerr as
  76 + // appropriate.
  77 + QPDF_DLL
  78 + void setOutputStreams(std::ostream* out_stream, std::ostream* err_stream);
  79 +
64 // If true, ignore any cross-reference streams in a hybrid file 80 // If true, ignore any cross-reference streams in a hybrid file
65 // (one that contains both cross-reference streams and 81 // (one that contains both cross-reference streams and
66 // cross-reference tables). This can be useful for testing to 82 // cross-reference tables). This can be useful for testing to
@@ -68,7 +84,8 @@ class QPDF @@ -68,7 +84,8 @@ class QPDF
68 QPDF_DLL 84 QPDF_DLL
69 void setIgnoreXRefStreams(bool); 85 void setIgnoreXRefStreams(bool);
70 86
71 - // By default, any warnings are issued to stderr as they are 87 + // By default, any warnings are issued to std::cerr or the error
  88 + // stream specified in a call to setOutputStreams as they are
72 // encountered. If this is called with a true value, reporting of 89 // encountered. If this is called with a true value, reporting of
73 // warnings is suppressed. You may still retrieve warnings by 90 // warnings is suppressed. You may still retrieve warnings by
74 // calling getWarnings. 91 // calling getWarnings.
@@ -88,7 +105,7 @@ class QPDF @@ -88,7 +105,7 @@ class QPDF
88 // clear the list. This method may be called even if processFile 105 // clear the list. This method may be called even if processFile
89 // throws an exception. Note that if setSuppressWarnings was not 106 // throws an exception. Note that if setSuppressWarnings was not
90 // called or was called with a false value, any warnings retrieved 107 // called or was called with a false value, any warnings retrieved
91 - // here will have already been issued to stderr. 108 + // here will have already been output.
92 QPDF_DLL 109 QPDF_DLL
93 std::vector<QPDFExc> getWarnings(); 110 std::vector<QPDFExc> getWarnings();
94 111
@@ -204,12 +221,14 @@ class QPDF @@ -204,12 +221,14 @@ class QPDF
204 221
205 // Performs various sanity checks on a linearized file. Return 222 // Performs various sanity checks on a linearized file. Return
206 // true if no errors or warnings. Otherwise, return false and 223 // true if no errors or warnings. Otherwise, return false and
207 - // output errors and warnings to stdout. 224 + // output errors and warnings to std::cout or the output stream
  225 + // specified in a call to setOutputStreams.
208 QPDF_DLL 226 QPDF_DLL
209 bool checkLinearization(); 227 bool checkLinearization();
210 228
211 // Calls checkLinearization() and, if possible, prints normalized 229 // Calls checkLinearization() and, if possible, prints normalized
212 - // contents of some of the hints tables to stdout. Normalization 230 + // contents of some of the hints tables to std::cout or the output
  231 + // stream specified in a call to setOutputStreams. Normalization
213 // includes adding min values to delta values and adjusting 232 // includes adding min values to delta values and adjusting
214 // offsets based on the location and size of the primary hint 233 // offsets based on the location and size of the primary hint
215 // stream. 234 // stream.
@@ -803,6 +822,8 @@ class QPDF @@ -803,6 +822,8 @@ class QPDF
803 bool encryption_initialized; 822 bool encryption_initialized;
804 bool ignore_xref_streams; 823 bool ignore_xref_streams;
805 bool suppress_warnings; 824 bool suppress_warnings;
  825 + std::ostream* out_stream;
  826 + std::ostream* err_stream;
806 bool attempt_recovery; 827 bool attempt_recovery;
807 int encryption_V; 828 int encryption_V;
808 bool encrypt_metadata; 829 bool encrypt_metadata;
libqpdf/QPDF.cc
@@ -267,6 +267,8 @@ QPDF::QPDF() : @@ -267,6 +267,8 @@ QPDF::QPDF() :
267 encryption_initialized(false), 267 encryption_initialized(false),
268 ignore_xref_streams(false), 268 ignore_xref_streams(false),
269 suppress_warnings(false), 269 suppress_warnings(false),
  270 + out_stream(&std::cout),
  271 + err_stream(&std::cerr),
270 attempt_recovery(true), 272 attempt_recovery(true),
271 encryption_V(0), 273 encryption_V(0),
272 encrypt_metadata(true), 274 encrypt_metadata(true),
@@ -333,6 +335,13 @@ QPDF::setIgnoreXRefStreams(bool val) @@ -333,6 +335,13 @@ QPDF::setIgnoreXRefStreams(bool val)
333 } 335 }
334 336
335 void 337 void
  338 +QPDF::setOutputStreams(std::ostream* out, std::ostream* err)
  339 +{
  340 + this->out_stream = out ? out : &std::cout;
  341 + this->err_stream = err ? err : &std::cerr;
  342 +}
  343 +
  344 +void
336 QPDF::setSuppressWarnings(bool val) 345 QPDF::setSuppressWarnings(bool val)
337 { 346 {
338 this->suppress_warnings = val; 347 this->suppress_warnings = val;
@@ -449,7 +458,8 @@ QPDF::warn(QPDFExc const&amp; e) @@ -449,7 +458,8 @@ QPDF::warn(QPDFExc const&amp; e)
449 this->warnings.push_back(e); 458 this->warnings.push_back(e);
450 if (! this->suppress_warnings) 459 if (! this->suppress_warnings)
451 { 460 {
452 - std::cerr << "WARNING: " << this->warnings.back().what() << std::endl; 461 + *err_stream << "WARNING: "
  462 + << this->warnings.back().what() << std::endl;
453 } 463 }
454 } 464 }
455 465
@@ -1045,16 +1055,16 @@ QPDF::showXRefTable() @@ -1045,16 +1055,16 @@ QPDF::showXRefTable()
1045 { 1055 {
1046 ObjGen const& og = (*iter).first; 1056 ObjGen const& og = (*iter).first;
1047 QPDFXRefEntry const& entry = (*iter).second; 1057 QPDFXRefEntry const& entry = (*iter).second;
1048 - std::cout << og.obj << "/" << og.gen << ": "; 1058 + *out_stream << og.obj << "/" << og.gen << ": ";
1049 switch (entry.getType()) 1059 switch (entry.getType())
1050 { 1060 {
1051 case 1: 1061 case 1:
1052 - std::cout << "uncompressed; offset = " << entry.getOffset(); 1062 + *out_stream << "uncompressed; offset = " << entry.getOffset();
1053 break; 1063 break;
1054 1064
1055 case 2: 1065 case 2:
1056 - std::cout << "compressed; stream = " << entry.getObjStreamNumber()  
1057 - << ", index = " << entry.getObjStreamIndex(); 1066 + *out_stream << "compressed; stream = " << entry.getObjStreamNumber()
  1067 + << ", index = " << entry.getObjStreamIndex();
1058 break; 1068 break;
1059 1069
1060 default: 1070 default:
@@ -1062,7 +1072,7 @@ QPDF::showXRefTable() @@ -1062,7 +1072,7 @@ QPDF::showXRefTable()
1062 " showing xref_table"); 1072 " showing xref_table");
1063 break; 1073 break;
1064 } 1074 }
1065 - std::cout << std::endl; 1075 + *out_stream << std::endl;
1066 } 1076 }
1067 } 1077 }
1068 1078
libqpdf/QPDF_linearization.cc
@@ -64,7 +64,7 @@ QPDF::checkLinearization() @@ -64,7 +64,7 @@ QPDF::checkLinearization()
64 } 64 }
65 catch (QPDFExc& e) 65 catch (QPDFExc& e)
66 { 66 {
67 - std::cout << e.what() << std::endl; 67 + *out_stream << e.what() << std::endl;
68 } 68 }
69 return result; 69 return result;
70 } 70 }
@@ -351,9 +351,9 @@ QPDF::readHintStream(Pipeline&amp; pl, off_t offset, size_t length) @@ -351,9 +351,9 @@ QPDF::readHintStream(Pipeline&amp; pl, off_t offset, size_t length)
351 if ((computed_end < min_end_offset) || 351 if ((computed_end < min_end_offset) ||
352 (computed_end > max_end_offset)) 352 (computed_end > max_end_offset))
353 { 353 {
354 - std::cout << "expected = " << computed_end  
355 - << "; actual = " << min_end_offset << ".."  
356 - << max_end_offset << std::endl; 354 + *out_stream << "expected = " << computed_end
  355 + << "; actual = " << min_end_offset << ".."
  356 + << max_end_offset << std::endl;
357 throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), 357 throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
358 "linearization dictionary", 358 "linearization dictionary",
359 this->file->getLastOffset(), 359 this->file->getLastOffset(),
@@ -617,7 +617,7 @@ QPDF::checkLinearizationInternal() @@ -617,7 +617,7 @@ QPDF::checkLinearizationInternal()
617 for (std::list<std::string>::iterator iter = errors.begin(); 617 for (std::list<std::string>::iterator iter = errors.begin();
618 iter != errors.end(); ++iter) 618 iter != errors.end(); ++iter)
619 { 619 {
620 - std::cout << "ERROR: " << (*iter) << std::endl; 620 + *out_stream << "ERROR: " << (*iter) << std::endl;
621 } 621 }
622 } 622 }
623 623
@@ -627,7 +627,7 @@ QPDF::checkLinearizationInternal() @@ -627,7 +627,7 @@ QPDF::checkLinearizationInternal()
627 for (std::list<std::string>::iterator iter = warnings.begin(); 627 for (std::list<std::string>::iterator iter = warnings.begin();
628 iter != warnings.end(); ++iter) 628 iter != warnings.end(); ++iter)
629 { 629 {
630 - std::cout << "WARNING: " << (*iter) << std::endl; 630 + *out_stream << "WARNING: " << (*iter) << std::endl;
631 } 631 }
632 } 632 }
633 633
@@ -1008,17 +1008,17 @@ QPDF::showLinearizationData() @@ -1008,17 +1008,17 @@ QPDF::showLinearizationData()
1008 } 1008 }
1009 catch (QPDFExc& e) 1009 catch (QPDFExc& e)
1010 { 1010 {
1011 - std::cout << e.what() << std::endl; 1011 + *out_stream << e.what() << std::endl;
1012 } 1012 }
1013 } 1013 }
1014 1014
1015 void 1015 void
1016 QPDF::dumpLinearizationDataInternal() 1016 QPDF::dumpLinearizationDataInternal()
1017 { 1017 {
1018 - std::cout << this->file->getName() << ": linearization data:" << std::endl  
1019 - << std::endl; 1018 + *out_stream << this->file->getName() << ": linearization data:" << std::endl
  1019 + << std::endl;
1020 1020
1021 - std::cout 1021 + *out_stream
1022 << "file_size: " << this->linp.file_size << std::endl 1022 << "file_size: " << this->linp.file_size << std::endl
1023 << "first_page_object: " << this->linp.first_page_object << std::endl 1023 << "first_page_object: " << this->linp.first_page_object << std::endl
1024 << "first_page_end: " << this->linp.first_page_end << std::endl 1024 << "first_page_end: " << this->linp.first_page_end << std::endl
@@ -1029,19 +1029,19 @@ QPDF::dumpLinearizationDataInternal() @@ -1029,19 +1029,19 @@ QPDF::dumpLinearizationDataInternal()
1029 << "H_length: " << this->linp.H_length << std::endl 1029 << "H_length: " << this->linp.H_length << std::endl
1030 << std::endl; 1030 << std::endl;
1031 1031
1032 - std::cout << "Page Offsets Hint Table" << std::endl  
1033 - << std::endl; 1032 + *out_stream << "Page Offsets Hint Table" << std::endl
  1033 + << std::endl;
1034 dumpHPageOffset(); 1034 dumpHPageOffset();
1035 - std::cout << std::endl  
1036 - << "Shared Objects Hint Table" << std::endl  
1037 - << std::endl; 1035 + *out_stream << std::endl
  1036 + << "Shared Objects Hint Table" << std::endl
  1037 + << std::endl;
1038 dumpHSharedObject(); 1038 dumpHSharedObject();
1039 1039
1040 if (this->outline_hints.nobjects > 0) 1040 if (this->outline_hints.nobjects > 0)
1041 { 1041 {
1042 - std::cout << std::endl  
1043 - << "Outlines Hint Table" << std::endl  
1044 - << std::endl; 1042 + *out_stream << std::endl
  1043 + << "Outlines Hint Table" << std::endl
  1044 + << std::endl;
1045 dumpHGeneric(this->outline_hints); 1045 dumpHGeneric(this->outline_hints);
1046 } 1046 }
1047 } 1047 }
@@ -1064,7 +1064,7 @@ void @@ -1064,7 +1064,7 @@ void
1064 QPDF::dumpHPageOffset() 1064 QPDF::dumpHPageOffset()
1065 { 1065 {
1066 HPageOffset& t = this->page_offset_hints; 1066 HPageOffset& t = this->page_offset_hints;
1067 - std::cout 1067 + *out_stream
1068 << "min_nobjects: " << t.min_nobjects 1068 << "min_nobjects: " << t.min_nobjects
1069 << std::endl 1069 << std::endl
1070 << "first_page_offset: " << adjusted_offset(t.first_page_offset) 1070 << "first_page_offset: " << adjusted_offset(t.first_page_offset)
@@ -1095,7 +1095,7 @@ QPDF::dumpHPageOffset() @@ -1095,7 +1095,7 @@ QPDF::dumpHPageOffset()
1095 for (int i1 = 0; i1 < this->linp.npages; ++i1) 1095 for (int i1 = 0; i1 < this->linp.npages; ++i1)
1096 { 1096 {
1097 HPageOffsetEntry& pe = t.entries[i1]; 1097 HPageOffsetEntry& pe = t.entries[i1];
1098 - std::cout 1098 + *out_stream
1099 << "Page " << i1 << ":" << std::endl 1099 << "Page " << i1 << ":" << std::endl
1100 << " nobjects: " << pe.delta_nobjects + t.min_nobjects 1100 << " nobjects: " << pe.delta_nobjects + t.min_nobjects
1101 << std::endl 1101 << std::endl
@@ -1109,10 +1109,10 @@ QPDF::dumpHPageOffset() @@ -1109,10 +1109,10 @@ QPDF::dumpHPageOffset()
1109 << " nshared_objects: " << pe.nshared_objects << std::endl; 1109 << " nshared_objects: " << pe.nshared_objects << std::endl;
1110 for (int i2 = 0; i2 < pe.nshared_objects; ++i2) 1110 for (int i2 = 0; i2 < pe.nshared_objects; ++i2)
1111 { 1111 {
1112 - std::cout << " identifier " << i2 << ": "  
1113 - << pe.shared_identifiers[i2] << std::endl;  
1114 - std::cout << " numerator " << i2 << ": "  
1115 - << pe.shared_numerators[i2] << std::endl; 1112 + *out_stream << " identifier " << i2 << ": "
  1113 + << pe.shared_identifiers[i2] << std::endl;
  1114 + *out_stream << " numerator " << i2 << ": "
  1115 + << pe.shared_numerators[i2] << std::endl;
1116 } 1116 }
1117 } 1117 }
1118 } 1118 }
@@ -1121,7 +1121,7 @@ void @@ -1121,7 +1121,7 @@ void
1121 QPDF::dumpHSharedObject() 1121 QPDF::dumpHSharedObject()
1122 { 1122 {
1123 HSharedObject& t = this->shared_object_hints; 1123 HSharedObject& t = this->shared_object_hints;
1124 - std::cout 1124 + *out_stream
1125 << "first_shared_obj: " << t.first_shared_obj 1125 << "first_shared_obj: " << t.first_shared_obj
1126 << std::endl 1126 << std::endl
1127 << "first_shared_offset: " << adjusted_offset(t.first_shared_offset) 1127 << "first_shared_offset: " << adjusted_offset(t.first_shared_offset)
@@ -1140,19 +1140,19 @@ QPDF::dumpHSharedObject() @@ -1140,19 +1140,19 @@ QPDF::dumpHSharedObject()
1140 for (int i = 0; i < t.nshared_total; ++i) 1140 for (int i = 0; i < t.nshared_total; ++i)
1141 { 1141 {
1142 HSharedObjectEntry& se = t.entries[i]; 1142 HSharedObjectEntry& se = t.entries[i];
1143 - std::cout << "Shared Object " << i << ":" << std::endl;  
1144 - std::cout << " group length: "  
1145 - << se.delta_group_length + t.min_group_length << std::endl; 1143 + *out_stream << "Shared Object " << i << ":" << std::endl;
  1144 + *out_stream << " group length: "
  1145 + << se.delta_group_length + t.min_group_length << std::endl;
1146 // PDF spec says signature present nobjects_minus_one are 1146 // PDF spec says signature present nobjects_minus_one are
1147 // always 0, so print them only if they have a non-zero value. 1147 // always 0, so print them only if they have a non-zero value.
1148 if (se.signature_present) 1148 if (se.signature_present)
1149 { 1149 {
1150 - std::cout << " signature present" << std::endl; 1150 + *out_stream << " signature present" << std::endl;
1151 } 1151 }
1152 if (se.nobjects_minus_one != 0) 1152 if (se.nobjects_minus_one != 0)
1153 { 1153 {
1154 - std::cout << " nobjects: "  
1155 - << se.nobjects_minus_one + 1 << std::endl; 1154 + *out_stream << " nobjects: "
  1155 + << se.nobjects_minus_one + 1 << std::endl;
1156 } 1156 }
1157 } 1157 }
1158 } 1158 }
@@ -1160,7 +1160,7 @@ QPDF::dumpHSharedObject() @@ -1160,7 +1160,7 @@ QPDF::dumpHSharedObject()
1160 void 1160 void
1161 QPDF::dumpHGeneric(HGeneric& t) 1161 QPDF::dumpHGeneric(HGeneric& t)
1162 { 1162 {
1163 - std::cout 1163 + *out_stream
1164 << "first_object: " << t.first_object 1164 << "first_object: " << t.first_object
1165 << std::endl 1165 << std::endl
1166 << "first_object_offset: " << adjusted_offset(t.first_object_offset) 1166 << "first_object_offset: " << adjusted_offset(t.first_object_offset)
manual/qpdf-manual.xml
@@ -2075,6 +2075,61 @@ print &quot;\n&quot;; @@ -2075,6 +2075,61 @@ print &quot;\n&quot;;
2075 </para> 2075 </para>
2076 <variablelist> 2076 <variablelist>
2077 <varlistentry> 2077 <varlistentry>
  2078 + <term>2.2.1: XXX</term>
  2079 + <listitem>
  2080 + <itemizedlist>
  2081 + <listitem>
  2082 + <para>
  2083 + Add new method <classname>QPDF::processMemoryFile</classname>
  2084 + for operating on PDF files that are loaded into memory rather
  2085 + than in a file on disk.
  2086 + </para>
  2087 + </listitem>
  2088 + <listitem>
  2089 + <para>
  2090 + Add new method <classname>QPDF::setOutputStreams</classname>
  2091 + to replace <varname>std::cout</varname> and
  2092 + <varname>std::cerr</varname> with other streams for generation
  2093 + of diagnostic messages and error messages. This can be useful
  2094 + for GUIs or other applications that want to capture any output
  2095 + generated by the library to present to the user in some other
  2096 + way. Note that QPDF does not write to
  2097 + <varname>std::cout</varname> (or the specified output stream)
  2098 + except where explicitly mentioned in
  2099 + <filename>QPDF.hh</filename>, and that the only use of the
  2100 + error stream is for warnings. Note also that output of
  2101 + warnings is suppressed when
  2102 + <literal>setSuppressWarnings(true)</literal> is called.
  2103 + </para>
  2104 + </listitem>
  2105 + <listitem>
  2106 + <para>
  2107 + Give a warning but otherwise ignore empty PDF objects by
  2108 + treating them as null. Empty object are not permitted by the
  2109 + PDF specification but have been known to appear in some actual
  2110 + PDF files.
  2111 + </para>
  2112 + </listitem>
  2113 + <listitem>
  2114 + <para>
  2115 + Handle inline image filter abbreviations when the appear as
  2116 + stream filter abbreviations. The PDF specification does not
  2117 + allow use of stream filter abbreviations in this way, but
  2118 + Adobe Reader and some other PDF readers accept them since they
  2119 + sometimes appear incorrectly in actual PDF files.
  2120 + </para>
  2121 + </listitem>
  2122 + <listitem>
  2123 + <para>
  2124 + Implement miscellaneous enhancements to
  2125 + <classname>PointerHolder</classname> and
  2126 + <classname>Buffer</classname> to support other changes.
  2127 + </para>
  2128 + </listitem>
  2129 + </itemizedlist>
  2130 + </listitem>
  2131 + </varlistentry>
  2132 + <varlistentry>
2078 <term>2.2.0: August 14, 2010</term> 2133 <term>2.2.0: August 14, 2010</term>
2079 <listitem> 2134 <listitem>
2080 <itemizedlist> 2135 <itemizedlist>
qpdf/qtest/qpdf.test
@@ -111,7 +111,7 @@ $td-&gt;runtest(&quot;new stream&quot;, @@ -111,7 +111,7 @@ $td-&gt;runtest(&quot;new stream&quot;,
111 show_ntests(); 111 show_ntests();
112 # ---------- 112 # ----------
113 $td->notify("--- Miscellaneous Tests ---"); 113 $td->notify("--- Miscellaneous Tests ---");
114 -$n_tests += 26; 114 +$n_tests += 28;
115 115
116 $td->runtest("qpdf version", 116 $td->runtest("qpdf version",
117 {$td->COMMAND => "qpdf --version"}, 117 {$td->COMMAND => "qpdf --version"},
@@ -245,6 +245,18 @@ $td-&gt;runtest(&quot;empty object&quot;, @@ -245,6 +245,18 @@ $td-&gt;runtest(&quot;empty object&quot;,
245 $td->EXIT_STATUS => 3}, 245 $td->EXIT_STATUS => 3},
246 $td->NORMALIZE_NEWLINES); 246 $td->NORMALIZE_NEWLINES);
247 247
  248 +$td->runtest("error/output redirection to null",
  249 + {$td->COMMAND => "test_driver 12 linearized-and-warnings.pdf"},
  250 + {$td->FILE => "linearized-and-warnings-1.out",
  251 + $td->EXIT_STATUS => 0},
  252 + $td->NORMALIZE_NEWLINES);
  253 +
  254 +$td->runtest("error/output redirection to strings",
  255 + {$td->COMMAND => "test_driver 13 linearized-and-warnings.pdf"},
  256 + {$td->FILE => "linearized-and-warnings-2.out",
  257 + $td->EXIT_STATUS => 0},
  258 + $td->NORMALIZE_NEWLINES);
  259 +
248 show_ntests(); 260 show_ntests();
249 # ---------- 261 # ----------
250 $td->notify("--- Error Condition Tests ---"); 262 $td->notify("--- Error Condition Tests ---");
qpdf/qtest/qpdf/linearized-and-warnings-1.out 0 → 100644
  1 +WARNING: linearized-and-warnings.pdf (object 2 0, file position 1117): empty object treated as null
  2 +linearized-and-warnings.pdf: linearization data:
  3 +
  4 +file_size: 1310
  5 +first_page_object: 6
  6 +first_page_end: 1044
  7 +npages: 1
  8 +xref_zero_offset: 1132
  9 +first_page: 0
  10 +H_offset: 528
  11 +H_length: 118
  12 +
  13 +Page Offsets Hint Table
  14 +
  15 +min_nobjects: 4
  16 +first_page_offset: 646
  17 +nbits_delta_nobjects: 0
  18 +min_page_length: 398
  19 +nbits_delta_page_length: 0
  20 +min_content_offset: 0
  21 +nbits_delta_content_offset: 0
  22 +min_content_length: 398
  23 +nbits_delta_content_length: 0
  24 +nbits_nshared_objects: 0
  25 +nbits_shared_identifier: 3
  26 +nbits_shared_numerator: 0
  27 +shared_denominator: 4
  28 +Page 0:
  29 + nobjects: 4
  30 + length: 398
  31 + content_offset: 0
  32 + content_length: 398
  33 + nshared_objects: 0
  34 +
  35 +Shared Objects Hint Table
  36 +
  37 +first_shared_obj: 0
  38 +first_shared_offset: 0
  39 +nshared_first_page: 4
  40 +nshared_total: 4
  41 +nbits_nobjects: 0
  42 +min_group_length: 30
  43 +nbits_delta_group_length: 7
  44 +Shared Object 0:
  45 + group length: 143
  46 +Shared Object 1:
  47 + group length: 118
  48 +Shared Object 2:
  49 + group length: 30
  50 +Shared Object 3:
  51 + group length: 107
  52 +test 12 done
qpdf/qtest/qpdf/linearized-and-warnings-2.out 0 → 100644
  1 +---output---
  2 +linearized-and-warnings.pdf: linearization data:
  3 +
  4 +file_size: 1310
  5 +first_page_object: 6
  6 +first_page_end: 1044
  7 +npages: 1
  8 +xref_zero_offset: 1132
  9 +first_page: 0
  10 +H_offset: 528
  11 +H_length: 118
  12 +
  13 +Page Offsets Hint Table
  14 +
  15 +min_nobjects: 4
  16 +first_page_offset: 646
  17 +nbits_delta_nobjects: 0
  18 +min_page_length: 398
  19 +nbits_delta_page_length: 0
  20 +min_content_offset: 0
  21 +nbits_delta_content_offset: 0
  22 +min_content_length: 398
  23 +nbits_delta_content_length: 0
  24 +nbits_nshared_objects: 0
  25 +nbits_shared_identifier: 3
  26 +nbits_shared_numerator: 0
  27 +shared_denominator: 4
  28 +Page 0:
  29 + nobjects: 4
  30 + length: 398
  31 + content_offset: 0
  32 + content_length: 398
  33 + nshared_objects: 0
  34 +
  35 +Shared Objects Hint Table
  36 +
  37 +first_shared_obj: 0
  38 +first_shared_offset: 0
  39 +nshared_first_page: 4
  40 +nshared_total: 4
  41 +nbits_nobjects: 0
  42 +min_group_length: 30
  43 +nbits_delta_group_length: 7
  44 +Shared Object 0:
  45 + group length: 143
  46 +Shared Object 1:
  47 + group length: 118
  48 +Shared Object 2:
  49 + group length: 30
  50 +Shared Object 3:
  51 + group length: 107
  52 +---error---
  53 +WARNING: linearized-and-warnings.pdf (object 2 0, file position 1117): empty object treated as null
  54 +test 13 done
qpdf/qtest/qpdf/linearized-and-warnings.pdf 0 → 100644
No preview for this file type
qpdf/test_driver.cc
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 #include <qpdf/Pl_Flate.hh> 10 #include <qpdf/Pl_Flate.hh>
11 #include <qpdf/QPDFWriter.hh> 11 #include <qpdf/QPDFWriter.hh>
12 #include <iostream> 12 #include <iostream>
  13 +#include <sstream>
13 #include <stdio.h> 14 #include <stdio.h>
14 #include <string.h> 15 #include <string.h>
15 #include <stdlib.h> 16 #include <stdlib.h>
@@ -502,6 +503,22 @@ void runtest(int n, char const* filename) @@ -502,6 +503,22 @@ void runtest(int n, char const* filename)
502 std::cout << "raw stream data okay" << std::endl; 503 std::cout << "raw stream data okay" << std::endl;
503 } 504 }
504 } 505 }
  506 + else if (n == 12)
  507 + {
  508 + pdf.setOutputStreams(0, 0);
  509 + pdf.showLinearizationData();
  510 + }
  511 + else if (n == 13)
  512 + {
  513 + std::ostringstream out;
  514 + std::ostringstream err;
  515 + pdf.setOutputStreams(&out, &err);
  516 + pdf.showLinearizationData();
  517 + std::cout << "---output---" << std::endl
  518 + << out.str()
  519 + << "---error---" << std::endl
  520 + << err.str();
  521 + }
505 else 522 else
506 { 523 {
507 throw std::runtime_error(std::string("invalid test ") + 524 throw std::runtime_error(std::string("invalid test ") +