Commit 759c56e1fed2849b77bff18f2a50639876395e5e

Authored by Jay Berkenbilt
1 parent 655c55f8

implement ability to save PDF to memory, also update ChangeLog

ChangeLog
  1 +2011-08-10 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * include/qpdf/QPDFWriter.hh: add a new constructor that takes
  4 + only a QPDF reference and leaves specification of output for
  5 + later. Add methods setOutputFilename() to set the output to a
  6 + filename or stdout, and setOutputMemory() to indicate that output
  7 + should go to a memory buffer. Add method getBuffer() to retrieve
  8 + the buffer used if output was saved to a memory buffer.
  9 +
  10 + * include/qpdf/QPDF.hh: add methods replaceObject() and
  11 + swapObjects() to allow replacement of an object and swapping of
  12 + two objects by object ID.
  13 +
  14 + * include/qpdf/QPDFObjectHandle.hh: add new methods getDictAsMap()
  15 + and getArrayAsVector() for returning the elements of a dictionary
  16 + or an array as a map or vector.
  17 +
1 2011-06-25 Jay Berkenbilt <ejb@ql.org> 18 2011-06-25 Jay Berkenbilt <ejb@ql.org>
2 19
3 * 2.2.4: release 20 * 2.2.4: release
include/qpdf/QPDFWriter.hh
@@ -24,6 +24,7 @@ @@ -24,6 +24,7 @@
24 24
25 #include <qpdf/QPDFXRefEntry.hh> 25 #include <qpdf/QPDFXRefEntry.hh>
26 26
  27 +#include <qpdf/Pl_Buffer.hh>
27 #include <qpdf/PointerHolder.hh> 28 #include <qpdf/PointerHolder.hh>
28 #include <qpdf/Pipeline.hh> 29 #include <qpdf/Pipeline.hh>
29 #include <qpdf/Buffer.hh> 30 #include <qpdf/Buffer.hh>
@@ -35,6 +36,24 @@ class Pl_Count; @@ -35,6 +36,24 @@ class Pl_Count;
35 class QPDFWriter 36 class QPDFWriter
36 { 37 {
37 public: 38 public:
  39 + // Construct a QPDFWriter object without specifying output. You
  40 + // must call one of the output setting routines defined below.
  41 + QPDF_DLL
  42 + QPDFWriter(QPDF& pdf);
  43 +
  44 + // Create a QPDFWriter object that writes its output to a file or
  45 + // to stdout. This is equivalent to using the previous
  46 + // constructor and then calling setOutputFilename(). See
  47 + // setOutputFilename() for details.
  48 + QPDF_DLL
  49 + QPDFWriter(QPDF& pdf, char const* filename);
  50 + QPDF_DLL
  51 + ~QPDFWriter();
  52 +
  53 + // Setting Output. Output may be set only one time. If you don't
  54 + // use the filename version of the QPDFWriter constructor, you
  55 + // must call exactly one of these methods.
  56 +
38 // Passing null as filename means write to stdout. QPDFWriter 57 // Passing null as filename means write to stdout. QPDFWriter
39 // will create a zero-length output file upon construction. If 58 // will create a zero-length output file upon construction. If
40 // write fails, the empty or partially written file will not be 59 // write fails, the empty or partially written file will not be
@@ -42,10 +61,20 @@ class QPDFWriter @@ -42,10 +61,20 @@ class QPDFWriter
42 // useful for tracking down problems. If your application doesn't 61 // useful for tracking down problems. If your application doesn't
43 // want the partially written file to be left behind, you should 62 // want the partially written file to be left behind, you should
44 // delete it the eventual call to write fails. 63 // delete it the eventual call to write fails.
45 - QPDF_DLL  
46 - QPDFWriter(QPDF& pdf, char const* filename);  
47 - QPDF_DLL  
48 - ~QPDFWriter(); 64 + void setOutputFilename(char const* filename);
  65 +
  66 + // Indicate that QPDFWriter should create a memory buffer to
  67 + // contain the final PDF file. Obtain the memory by calling
  68 + // getBuffer().
  69 + void setOutputMemory();
  70 +
  71 + // Return the buffer object containing the PDF file. If
  72 + // setOutputMemory() has been called, this method may be called
  73 + // exactly one time after write() has returned. The caller is
  74 + // responsible for deleting the buffer when done.
  75 + Buffer* getBuffer();
  76 +
  77 + // Setting Parameters
49 78
50 // Set the value of object stream mode. In disable mode, we never 79 // Set the value of object stream mode. In disable mode, we never
51 // generate any object streams. In preserve mode, we preserve 80 // generate any object streams. In preserve mode, we preserve
@@ -177,6 +206,7 @@ class QPDFWriter @@ -177,6 +206,7 @@ class QPDFWriter
177 206
178 enum trailer_e { t_normal, t_lin_first, t_lin_second }; 207 enum trailer_e { t_normal, t_lin_first, t_lin_second };
179 208
  209 + void init();
180 int bytesNeeded(unsigned long n); 210 int bytesNeeded(unsigned long n);
181 void writeBinary(unsigned long val, unsigned int bytes); 211 void writeBinary(unsigned long val, unsigned int bytes);
182 void writeString(std::string const& str); 212 void writeString(std::string const& str);
@@ -253,6 +283,7 @@ class QPDFWriter @@ -253,6 +283,7 @@ class QPDFWriter
253 // clearPipelineStack is called. 283 // clearPipelineStack is called.
254 Pipeline* pushPipeline(Pipeline*); 284 Pipeline* pushPipeline(Pipeline*);
255 void activatePipelineStack(); 285 void activatePipelineStack();
  286 + void initializePipelineStack(Pipeline *);
256 287
257 // Calls finish on the current pipeline and pops the pipeline 288 // Calls finish on the current pipeline and pops the pipeline
258 // stack until the top of stack is a previous active top of stack, 289 // stack until the top of stack is a previous active top of stack,
@@ -269,6 +300,8 @@ class QPDFWriter @@ -269,6 +300,8 @@ class QPDFWriter
269 char const* filename; 300 char const* filename;
270 FILE* file; 301 FILE* file;
271 bool close_file; 302 bool close_file;
  303 + Pl_Buffer* buffer_pipeline;
  304 + Buffer* output_buffer;
272 bool normalize_content_set; 305 bool normalize_content_set;
273 bool normalize_content; 306 bool normalize_content;
274 bool stream_data_mode_set; 307 bool stream_data_mode_set;
libqpdf/QPDFWriter.cc
@@ -4,7 +4,6 @@ @@ -4,7 +4,6 @@
4 #include <qpdf/Pl_StdioFile.hh> 4 #include <qpdf/Pl_StdioFile.hh>
5 #include <qpdf/Pl_Count.hh> 5 #include <qpdf/Pl_Count.hh>
6 #include <qpdf/Pl_Discard.hh> 6 #include <qpdf/Pl_Discard.hh>
7 -#include <qpdf/Pl_Buffer.hh>  
8 #include <qpdf/Pl_RC4.hh> 7 #include <qpdf/Pl_RC4.hh>
9 #include <qpdf/Pl_AES_PDF.hh> 8 #include <qpdf/Pl_AES_PDF.hh>
10 #include <qpdf/Pl_Flate.hh> 9 #include <qpdf/Pl_Flate.hh>
@@ -21,32 +20,65 @@ @@ -21,32 +20,65 @@
21 20
22 #include <stdlib.h> 21 #include <stdlib.h>
23 22
  23 +QPDFWriter::QPDFWriter(QPDF& pdf) :
  24 + pdf(pdf)
  25 +{
  26 + init();
  27 +}
  28 +
24 QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) : 29 QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) :
25 - pdf(pdf),  
26 - filename(filename),  
27 - file(0),  
28 - close_file(false),  
29 - normalize_content_set(false),  
30 - normalize_content(false),  
31 - stream_data_mode_set(false),  
32 - stream_data_mode(qpdf_s_compress),  
33 - qdf_mode(false),  
34 - static_id(false),  
35 - suppress_original_object_ids(false),  
36 - direct_stream_lengths(true),  
37 - encrypted(false),  
38 - preserve_encryption(true),  
39 - linearized(false),  
40 - object_stream_mode(qpdf_o_preserve),  
41 - encrypt_metadata(true),  
42 - encrypt_use_aes(false),  
43 - encryption_dict_objid(0),  
44 - next_objid(1),  
45 - cur_stream_length_id(0),  
46 - cur_stream_length(0),  
47 - added_newline(false),  
48 - max_ostream_index(0) 30 + pdf(pdf)
  31 +{
  32 + init();
  33 + setOutputFilename(filename);
  34 +}
  35 +
  36 +void
  37 +QPDFWriter::init()
  38 +{
  39 + filename = 0;
  40 + file = 0;
  41 + close_file = false;
  42 + buffer_pipeline = 0;
  43 + output_buffer = 0;
  44 + normalize_content_set = false;
  45 + normalize_content = false;
  46 + stream_data_mode_set = false;
  47 + stream_data_mode = qpdf_s_compress;
  48 + qdf_mode = false;
  49 + static_id = false;
  50 + suppress_original_object_ids = false;
  51 + direct_stream_lengths = true;
  52 + encrypted = false;
  53 + preserve_encryption = true;
  54 + linearized = false;
  55 + object_stream_mode = qpdf_o_preserve;
  56 + encrypt_metadata = true;
  57 + encrypt_use_aes = false;
  58 + encryption_dict_objid = 0;
  59 + next_objid = 1;
  60 + cur_stream_length_id = 0;
  61 + cur_stream_length = 0;
  62 + added_newline = false;
  63 + max_ostream_index = 0;
  64 +}
  65 +
  66 +QPDFWriter::~QPDFWriter()
  67 +{
  68 + if (file && close_file)
  69 + {
  70 + fclose(file);
  71 + }
  72 + if (output_buffer)
  73 + {
  74 + delete output_buffer;
  75 + }
  76 +}
  77 +
  78 +void
  79 +QPDFWriter::setOutputFilename(char const* filename)
49 { 80 {
  81 + this->filename = filename;
50 if (filename == 0) 82 if (filename == 0)
51 { 83 {
52 this->filename = "standard output"; 84 this->filename = "standard output";
@@ -61,19 +93,25 @@ QPDFWriter::QPDFWriter(QPDF&amp; pdf, char const* filename) : @@ -61,19 +93,25 @@ QPDFWriter::QPDFWriter(QPDF&amp; pdf, char const* filename) :
61 fopen(filename, "wb+")); 93 fopen(filename, "wb+"));
62 close_file = true; 94 close_file = true;
63 } 95 }
64 - Pipeline* p = new Pl_StdioFile("qdf output", file); 96 + Pipeline* p = new Pl_StdioFile("qpdf output", file);
65 to_delete.push_back(p); 97 to_delete.push_back(p);
66 - pipeline = new Pl_Count("qdf count", p);  
67 - to_delete.push_back(pipeline);  
68 - pipeline_stack.push_back(pipeline); 98 + initializePipelineStack(p);
69 } 99 }
70 100
71 -QPDFWriter::~QPDFWriter() 101 +void
  102 +QPDFWriter::setOutputMemory()
72 { 103 {
73 - if (file && close_file)  
74 - {  
75 - fclose(file);  
76 - } 104 + this->buffer_pipeline = new Pl_Buffer("qpdf output");
  105 + to_delete.push_back(this->buffer_pipeline);
  106 + initializePipelineStack(this->buffer_pipeline);
  107 +}
  108 +
  109 +Buffer*
  110 +QPDFWriter::getBuffer()
  111 +{
  112 + Buffer* result = this->output_buffer;
  113 + this->output_buffer = 0;
  114 + return result;
77 } 115 }
78 116
79 void 117 void
@@ -566,6 +604,14 @@ QPDFWriter::pushPipeline(Pipeline* p) @@ -566,6 +604,14 @@ QPDFWriter::pushPipeline(Pipeline* p)
566 } 604 }
567 605
568 void 606 void
  607 +QPDFWriter::initializePipelineStack(Pipeline *p)
  608 +{
  609 + this->pipeline = new Pl_Count("qpdf count", p);
  610 + to_delete.push_back(this->pipeline);
  611 + this->pipeline_stack.push_back(this->pipeline);
  612 +}
  613 +
  614 +void
569 QPDFWriter::activatePipelineStack() 615 QPDFWriter::activatePipelineStack()
570 { 616 {
571 Pl_Count* c = new Pl_Count("count", this->pipeline_stack.back()); 617 Pl_Count* c = new Pl_Count("count", this->pipeline_stack.back());
@@ -1503,6 +1549,8 @@ QPDFWriter::generateObjectStreams() @@ -1503,6 +1549,8 @@ QPDFWriter::generateObjectStreams()
1503 void 1549 void
1504 QPDFWriter::write() 1550 QPDFWriter::write()
1505 { 1551 {
  1552 + // XXX Check output
  1553 +
1506 // Do preliminary setup 1554 // Do preliminary setup
1507 1555
1508 if (this->linearized) 1556 if (this->linearized)
@@ -1656,6 +1704,11 @@ QPDFWriter::write() @@ -1656,6 +1704,11 @@ QPDFWriter::write()
1656 fclose(this->file); 1704 fclose(this->file);
1657 } 1705 }
1658 this->file = 0; 1706 this->file = 0;
  1707 + if (this->buffer_pipeline)
  1708 + {
  1709 + this->output_buffer = this->buffer_pipeline->getBuffer();
  1710 + this->buffer_pipeline = 0;
  1711 + }
1659 } 1712 }
1660 1713
1661 void 1714 void
qpdf/test_driver.cc
@@ -584,10 +584,18 @@ void runtest(int n, char const* filename) @@ -584,10 +584,18 @@ void runtest(int n, char const* filename)
584 << std::endl; 584 << std::endl;
585 } 585 }
586 586
587 - QPDFWriter w(pdf, "a.pdf"); 587 + // Exercise writing to memory buffer
  588 + QPDFWriter w(pdf);
  589 + w.setOutputMemory();
588 w.setStaticID(true); 590 w.setStaticID(true);
589 w.setStreamDataMode(qpdf_s_preserve); 591 w.setStreamDataMode(qpdf_s_preserve);
590 w.write(); 592 w.write();
  593 + Buffer* b = w.getBuffer();
  594 + FILE* f = QUtil::fopen_wrapper(std::string("open a.pdf"),
  595 + fopen("a.pdf", "wb"));
  596 + fwrite(b->getBuffer(), b->getSize(), 1, f);
  597 + fclose(f);
  598 + delete b;
591 } 599 }
592 else 600 else
593 { 601 {