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 18 2011-06-25 Jay Berkenbilt <ejb@ql.org>
2 19  
3 20 * 2.2.4: release
... ...
include/qpdf/QPDFWriter.hh
... ... @@ -24,6 +24,7 @@
24 24  
25 25 #include <qpdf/QPDFXRefEntry.hh>
26 26  
  27 +#include <qpdf/Pl_Buffer.hh>
27 28 #include <qpdf/PointerHolder.hh>
28 29 #include <qpdf/Pipeline.hh>
29 30 #include <qpdf/Buffer.hh>
... ... @@ -35,6 +36,24 @@ class Pl_Count;
35 36 class QPDFWriter
36 37 {
37 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 57 // Passing null as filename means write to stdout. QPDFWriter
39 58 // will create a zero-length output file upon construction. If
40 59 // write fails, the empty or partially written file will not be
... ... @@ -42,10 +61,20 @@ class QPDFWriter
42 61 // useful for tracking down problems. If your application doesn't
43 62 // want the partially written file to be left behind, you should
44 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 79 // Set the value of object stream mode. In disable mode, we never
51 80 // generate any object streams. In preserve mode, we preserve
... ... @@ -177,6 +206,7 @@ class QPDFWriter
177 206  
178 207 enum trailer_e { t_normal, t_lin_first, t_lin_second };
179 208  
  209 + void init();
180 210 int bytesNeeded(unsigned long n);
181 211 void writeBinary(unsigned long val, unsigned int bytes);
182 212 void writeString(std::string const& str);
... ... @@ -253,6 +283,7 @@ class QPDFWriter
253 283 // clearPipelineStack is called.
254 284 Pipeline* pushPipeline(Pipeline*);
255 285 void activatePipelineStack();
  286 + void initializePipelineStack(Pipeline *);
256 287  
257 288 // Calls finish on the current pipeline and pops the pipeline
258 289 // stack until the top of stack is a previous active top of stack,
... ... @@ -269,6 +300,8 @@ class QPDFWriter
269 300 char const* filename;
270 301 FILE* file;
271 302 bool close_file;
  303 + Pl_Buffer* buffer_pipeline;
  304 + Buffer* output_buffer;
272 305 bool normalize_content_set;
273 306 bool normalize_content;
274 307 bool stream_data_mode_set;
... ...
libqpdf/QPDFWriter.cc
... ... @@ -4,7 +4,6 @@
4 4 #include <qpdf/Pl_StdioFile.hh>
5 5 #include <qpdf/Pl_Count.hh>
6 6 #include <qpdf/Pl_Discard.hh>
7   -#include <qpdf/Pl_Buffer.hh>
8 7 #include <qpdf/Pl_RC4.hh>
9 8 #include <qpdf/Pl_AES_PDF.hh>
10 9 #include <qpdf/Pl_Flate.hh>
... ... @@ -21,32 +20,65 @@
21 20  
22 21 #include <stdlib.h>
23 22  
  23 +QPDFWriter::QPDFWriter(QPDF& pdf) :
  24 + pdf(pdf)
  25 +{
  26 + init();
  27 +}
  28 +
24 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 82 if (filename == 0)
51 83 {
52 84 this->filename = "standard output";
... ... @@ -61,19 +93,25 @@ QPDFWriter::QPDFWriter(QPDF&amp; pdf, char const* filename) :
61 93 fopen(filename, "wb+"));
62 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 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 117 void
... ... @@ -566,6 +604,14 @@ QPDFWriter::pushPipeline(Pipeline* p)
566 604 }
567 605  
568 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 615 QPDFWriter::activatePipelineStack()
570 616 {
571 617 Pl_Count* c = new Pl_Count("count", this->pipeline_stack.back());
... ... @@ -1503,6 +1549,8 @@ QPDFWriter::generateObjectStreams()
1503 1549 void
1504 1550 QPDFWriter::write()
1505 1551 {
  1552 + // XXX Check output
  1553 +
1506 1554 // Do preliminary setup
1507 1555  
1508 1556 if (this->linearized)
... ... @@ -1656,6 +1704,11 @@ QPDFWriter::write()
1656 1704 fclose(this->file);
1657 1705 }
1658 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 1714 void
... ...
qpdf/test_driver.cc
... ... @@ -584,10 +584,18 @@ void runtest(int n, char const* filename)
584 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 590 w.setStaticID(true);
589 591 w.setStreamDataMode(qpdf_s_preserve);
590 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 600 else
593 601 {
... ...