aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2011-08-10 22:34:29 +0200
committerJay Berkenbilt <ejb@ql.org>2011-08-10 22:34:29 +0200
commit759c56e1fed2849b77bff18f2a50639876395e5e (patch)
treef8c899bf5fdfd4ef4f546addf16180d6c6694152
parent655c55f84830190f9fa4777c615b8a622254648a (diff)
downloadqpdf-759c56e1fed2849b77bff18f2a50639876395e5e.tar.zst
implement ability to save PDF to memory, also update ChangeLog
-rw-r--r--ChangeLog17
-rw-r--r--include/qpdf/QPDFWriter.hh41
-rw-r--r--libqpdf/QPDFWriter.cc121
-rw-r--r--qpdf/test_driver.cc10
4 files changed, 150 insertions, 39 deletions
diff --git a/ChangeLog b/ChangeLog
index ed12c9bc..5fdb0464 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2011-08-10 Jay Berkenbilt <ejb@ql.org>
+
+ * include/qpdf/QPDFWriter.hh: add a new constructor that takes
+ only a QPDF reference and leaves specification of output for
+ later. Add methods setOutputFilename() to set the output to a
+ filename or stdout, and setOutputMemory() to indicate that output
+ should go to a memory buffer. Add method getBuffer() to retrieve
+ the buffer used if output was saved to a memory buffer.
+
+ * include/qpdf/QPDF.hh: add methods replaceObject() and
+ swapObjects() to allow replacement of an object and swapping of
+ two objects by object ID.
+
+ * include/qpdf/QPDFObjectHandle.hh: add new methods getDictAsMap()
+ and getArrayAsVector() for returning the elements of a dictionary
+ or an array as a map or vector.
+
2011-06-25 Jay Berkenbilt <ejb@ql.org>
* 2.2.4: release
diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh
index 7a919b0d..a14ae514 100644
--- a/include/qpdf/QPDFWriter.hh
+++ b/include/qpdf/QPDFWriter.hh
@@ -24,6 +24,7 @@
#include <qpdf/QPDFXRefEntry.hh>
+#include <qpdf/Pl_Buffer.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Buffer.hh>
@@ -35,6 +36,24 @@ class Pl_Count;
class QPDFWriter
{
public:
+ // Construct a QPDFWriter object without specifying output. You
+ // must call one of the output setting routines defined below.
+ QPDF_DLL
+ QPDFWriter(QPDF& pdf);
+
+ // Create a QPDFWriter object that writes its output to a file or
+ // to stdout. This is equivalent to using the previous
+ // constructor and then calling setOutputFilename(). See
+ // setOutputFilename() for details.
+ QPDF_DLL
+ QPDFWriter(QPDF& pdf, char const* filename);
+ QPDF_DLL
+ ~QPDFWriter();
+
+ // Setting Output. Output may be set only one time. If you don't
+ // use the filename version of the QPDFWriter constructor, you
+ // must call exactly one of these methods.
+
// Passing null as filename means write to stdout. QPDFWriter
// will create a zero-length output file upon construction. If
// write fails, the empty or partially written file will not be
@@ -42,10 +61,20 @@ class QPDFWriter
// useful for tracking down problems. If your application doesn't
// want the partially written file to be left behind, you should
// delete it the eventual call to write fails.
- QPDF_DLL
- QPDFWriter(QPDF& pdf, char const* filename);
- QPDF_DLL
- ~QPDFWriter();
+ void setOutputFilename(char const* filename);
+
+ // Indicate that QPDFWriter should create a memory buffer to
+ // contain the final PDF file. Obtain the memory by calling
+ // getBuffer().
+ void setOutputMemory();
+
+ // Return the buffer object containing the PDF file. If
+ // setOutputMemory() has been called, this method may be called
+ // exactly one time after write() has returned. The caller is
+ // responsible for deleting the buffer when done.
+ Buffer* getBuffer();
+
+ // Setting Parameters
// Set the value of object stream mode. In disable mode, we never
// generate any object streams. In preserve mode, we preserve
@@ -177,6 +206,7 @@ class QPDFWriter
enum trailer_e { t_normal, t_lin_first, t_lin_second };
+ void init();
int bytesNeeded(unsigned long n);
void writeBinary(unsigned long val, unsigned int bytes);
void writeString(std::string const& str);
@@ -253,6 +283,7 @@ class QPDFWriter
// clearPipelineStack is called.
Pipeline* pushPipeline(Pipeline*);
void activatePipelineStack();
+ void initializePipelineStack(Pipeline *);
// Calls finish on the current pipeline and pops the pipeline
// stack until the top of stack is a previous active top of stack,
@@ -269,6 +300,8 @@ class QPDFWriter
char const* filename;
FILE* file;
bool close_file;
+ Pl_Buffer* buffer_pipeline;
+ Buffer* output_buffer;
bool normalize_content_set;
bool normalize_content;
bool stream_data_mode_set;
diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc
index 40368f69..7217ded7 100644
--- a/libqpdf/QPDFWriter.cc
+++ b/libqpdf/QPDFWriter.cc
@@ -4,7 +4,6 @@
#include <qpdf/Pl_StdioFile.hh>
#include <qpdf/Pl_Count.hh>
#include <qpdf/Pl_Discard.hh>
-#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_RC4.hh>
#include <qpdf/Pl_AES_PDF.hh>
#include <qpdf/Pl_Flate.hh>
@@ -21,32 +20,65 @@
#include <stdlib.h>
+QPDFWriter::QPDFWriter(QPDF& pdf) :
+ pdf(pdf)
+{
+ init();
+}
+
QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) :
- pdf(pdf),
- filename(filename),
- file(0),
- close_file(false),
- normalize_content_set(false),
- normalize_content(false),
- stream_data_mode_set(false),
- stream_data_mode(qpdf_s_compress),
- qdf_mode(false),
- static_id(false),
- suppress_original_object_ids(false),
- direct_stream_lengths(true),
- encrypted(false),
- preserve_encryption(true),
- linearized(false),
- object_stream_mode(qpdf_o_preserve),
- encrypt_metadata(true),
- encrypt_use_aes(false),
- encryption_dict_objid(0),
- next_objid(1),
- cur_stream_length_id(0),
- cur_stream_length(0),
- added_newline(false),
- max_ostream_index(0)
+ pdf(pdf)
+{
+ init();
+ setOutputFilename(filename);
+}
+
+void
+QPDFWriter::init()
+{
+ filename = 0;
+ file = 0;
+ close_file = false;
+ buffer_pipeline = 0;
+ output_buffer = 0;
+ normalize_content_set = false;
+ normalize_content = false;
+ stream_data_mode_set = false;
+ stream_data_mode = qpdf_s_compress;
+ qdf_mode = false;
+ static_id = false;
+ suppress_original_object_ids = false;
+ direct_stream_lengths = true;
+ encrypted = false;
+ preserve_encryption = true;
+ linearized = false;
+ object_stream_mode = qpdf_o_preserve;
+ encrypt_metadata = true;
+ encrypt_use_aes = false;
+ encryption_dict_objid = 0;
+ next_objid = 1;
+ cur_stream_length_id = 0;
+ cur_stream_length = 0;
+ added_newline = false;
+ max_ostream_index = 0;
+}
+
+QPDFWriter::~QPDFWriter()
+{
+ if (file && close_file)
+ {
+ fclose(file);
+ }
+ if (output_buffer)
+ {
+ delete output_buffer;
+ }
+}
+
+void
+QPDFWriter::setOutputFilename(char const* filename)
{
+ this->filename = filename;
if (filename == 0)
{
this->filename = "standard output";
@@ -61,19 +93,25 @@ QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) :
fopen(filename, "wb+"));
close_file = true;
}
- Pipeline* p = new Pl_StdioFile("qdf output", file);
+ Pipeline* p = new Pl_StdioFile("qpdf output", file);
to_delete.push_back(p);
- pipeline = new Pl_Count("qdf count", p);
- to_delete.push_back(pipeline);
- pipeline_stack.push_back(pipeline);
+ initializePipelineStack(p);
}
-QPDFWriter::~QPDFWriter()
+void
+QPDFWriter::setOutputMemory()
{
- if (file && close_file)
- {
- fclose(file);
- }
+ this->buffer_pipeline = new Pl_Buffer("qpdf output");
+ to_delete.push_back(this->buffer_pipeline);
+ initializePipelineStack(this->buffer_pipeline);
+}
+
+Buffer*
+QPDFWriter::getBuffer()
+{
+ Buffer* result = this->output_buffer;
+ this->output_buffer = 0;
+ return result;
}
void
@@ -566,6 +604,14 @@ QPDFWriter::pushPipeline(Pipeline* p)
}
void
+QPDFWriter::initializePipelineStack(Pipeline *p)
+{
+ this->pipeline = new Pl_Count("qpdf count", p);
+ to_delete.push_back(this->pipeline);
+ this->pipeline_stack.push_back(this->pipeline);
+}
+
+void
QPDFWriter::activatePipelineStack()
{
Pl_Count* c = new Pl_Count("count", this->pipeline_stack.back());
@@ -1503,6 +1549,8 @@ QPDFWriter::generateObjectStreams()
void
QPDFWriter::write()
{
+ // XXX Check output
+
// Do preliminary setup
if (this->linearized)
@@ -1656,6 +1704,11 @@ QPDFWriter::write()
fclose(this->file);
}
this->file = 0;
+ if (this->buffer_pipeline)
+ {
+ this->output_buffer = this->buffer_pipeline->getBuffer();
+ this->buffer_pipeline = 0;
+ }
}
void
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index d551d6f2..89da9144 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -584,10 +584,18 @@ void runtest(int n, char const* filename)
<< std::endl;
}
- QPDFWriter w(pdf, "a.pdf");
+ // Exercise writing to memory buffer
+ QPDFWriter w(pdf);
+ w.setOutputMemory();
w.setStaticID(true);
w.setStreamDataMode(qpdf_s_preserve);
w.write();
+ Buffer* b = w.getBuffer();
+ FILE* f = QUtil::fopen_wrapper(std::string("open a.pdf"),
+ fopen("a.pdf", "wb"));
+ fwrite(b->getBuffer(), b->getSize(), 1, f);
+ fclose(f);
+ delete b;
}
else
{