mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 19:08:59 +00:00
enhance PointerHolder so that it can explicitly be told to use delete [] instead of delete, thus making it useful to run valgrind over qpdf during its test suite
This commit is contained in:
parent
14fe2e6de3
commit
76b1659177
@ -1,6 +1,27 @@
|
||||
Release Reminders
|
||||
=================
|
||||
|
||||
* Consider running tests with latest gcc and/or valgrind. To do
|
||||
this, replace, build with debugging and without shared libraries.
|
||||
In build, create z and move each executable into z. Then create a
|
||||
script called exec-z that contains:
|
||||
|
||||
#!/bin/sh
|
||||
exec valgrind --suppressions=/tmp/a.supp -q \
|
||||
`dirname $0`/z/`basename $0` ${1+"$@"}
|
||||
|
||||
Symlink exec-v to each executable. /tmp/a.supp can be populated
|
||||
with suppressions for libraries, for example:
|
||||
|
||||
{
|
||||
zlib1
|
||||
Memcheck:Cond
|
||||
fun:inflateReset2
|
||||
fun:inflateInit2_
|
||||
}
|
||||
|
||||
You can generate these by running valgrind with --gen-suppressions=yes.
|
||||
|
||||
* Check all open issues in the sourceforge trackers.
|
||||
|
||||
* If any interfaces were added or changed, check C API to see whether
|
||||
|
2
TODO
2
TODO
@ -3,8 +3,6 @@
|
||||
|
||||
* Provide an example of using replace and swap. Maybe.
|
||||
|
||||
* Add C API for writing to memory if possible
|
||||
|
||||
General
|
||||
=======
|
||||
|
||||
|
@ -8,8 +8,6 @@
|
||||
#ifndef __POINTERHOLDER_HH__
|
||||
#define __POINTERHOLDER_HH__
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// This class is basically boost::shared_pointer but predates that by
|
||||
// several years.
|
||||
|
||||
@ -45,43 +43,42 @@ class PointerHolder
|
||||
class Data
|
||||
{
|
||||
public:
|
||||
Data(T* pointer, bool tracing) :
|
||||
Data(T* pointer, bool array) :
|
||||
pointer(pointer),
|
||||
tracing(tracing),
|
||||
array(array),
|
||||
refcount(0)
|
||||
{
|
||||
static int next_id = 0;
|
||||
this->unique_id = ++next_id;
|
||||
}
|
||||
~Data()
|
||||
{
|
||||
if (this->tracing)
|
||||
if (array)
|
||||
{
|
||||
std::cerr << "PointerHolder deleting pointer "
|
||||
<< (void*)pointer
|
||||
<< std::endl;
|
||||
delete [] this->pointer;
|
||||
}
|
||||
delete this->pointer;
|
||||
if (this->tracing)
|
||||
else
|
||||
{
|
||||
std::cerr << "PointerHolder done deleting pointer "
|
||||
<< (void*)pointer
|
||||
<< std::endl;
|
||||
delete this->pointer;
|
||||
}
|
||||
}
|
||||
T* pointer;
|
||||
bool tracing;
|
||||
bool array;
|
||||
int refcount;
|
||||
int unique_id;
|
||||
private:
|
||||
Data(Data const&);
|
||||
Data& operator=(Data const&);
|
||||
};
|
||||
|
||||
public:
|
||||
// "tracing" is not used but is kept for interface backward compatbility
|
||||
PointerHolder(T* pointer = 0, bool tracing = false)
|
||||
{
|
||||
this->init(new Data(pointer, tracing));
|
||||
this->init(new Data(pointer, false));
|
||||
}
|
||||
// Special constructor indicating to free memory with delete []
|
||||
// instead of delete
|
||||
PointerHolder(bool, T* pointer)
|
||||
{
|
||||
this->init(new Data(pointer, true));
|
||||
}
|
||||
PointerHolder(PointerHolder const& rhs)
|
||||
{
|
||||
@ -148,12 +145,6 @@ class PointerHolder
|
||||
this->data = data;
|
||||
{
|
||||
++this->data->refcount;
|
||||
if (this->data->tracing)
|
||||
{
|
||||
std::cerr << "PointerHolder " << this->data->unique_id
|
||||
<< " refcount increased to " << this->data->refcount
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
void copy(PointerHolder const& rhs)
|
||||
@ -168,13 +159,6 @@ class PointerHolder
|
||||
{
|
||||
gone = true;
|
||||
}
|
||||
if (this->data->tracing)
|
||||
{
|
||||
std::cerr << "PointerHolder " << this->data->unique_id
|
||||
<< " refcount decreased to "
|
||||
<< this->data->refcount
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (gone)
|
||||
{
|
||||
|
@ -285,6 +285,25 @@ extern "C" {
|
||||
QPDF_DLL
|
||||
QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename);
|
||||
|
||||
/* Initialize for writing but indicate that the PDF file should be
|
||||
* written to memory. Call qpdf_get_buffer_length and
|
||||
* qpdf_get_buffer to retrieve the resulting buffer. The memory
|
||||
* containing the PDF file will be destroyed when qpdf_cleanup is
|
||||
* called.
|
||||
*/
|
||||
QPDF_DLL
|
||||
QPDF_ERROR_CODE qpdf_init_write_memory(qpdf_data qpdf);
|
||||
|
||||
/* Retrieve the buffer used if the file was written to memory.
|
||||
* qpdf_get_buffer returns a null pointer if data was not written
|
||||
* to memory. The memory is freed when qpdf_cleanup is called or
|
||||
* if a subsequent call to qpdf_init_write or
|
||||
* qpdf_init_write_memory is called. */
|
||||
QPDF_DLL
|
||||
unsigned long qpdf_get_buffer_length(qpdf_data qpdf);
|
||||
QPDF_DLL
|
||||
unsigned char const* qpdf_get_buffer(qpdf_data qpdf);
|
||||
|
||||
QPDF_DLL
|
||||
void qpdf_set_object_stream_mode(qpdf_data qpdf,
|
||||
enum qpdf_object_stream_e mode);
|
||||
|
@ -403,10 +403,9 @@ QPDF::parse(char const* password)
|
||||
this->file->rewind();
|
||||
}
|
||||
char* buf = new char[tbuf_size + 1];
|
||||
// Put buf in a PointerHolder to guarantee deletion of buf. This
|
||||
// calls delete rather than delete [], but it's okay since buf is
|
||||
// an array of fundamental types.
|
||||
PointerHolder<char> b(buf);
|
||||
// Put buf in an array-style PointerHolder to guarantee deletion
|
||||
// of buf.
|
||||
PointerHolder<char> b(true, buf);
|
||||
memset(buf, '\0', tbuf_size + 1);
|
||||
this->file->read(buf, tbuf_size);
|
||||
|
||||
|
@ -589,12 +589,9 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF_encryption rc4 decode string");
|
||||
unsigned int vlen = str.length();
|
||||
// Using PointerHolder will cause a new char[] to be deleted
|
||||
// with delete instead of delete [], but it's okay since the
|
||||
// array is of a fundamental type, so there is no destructor
|
||||
// to be called. Using PointerHolder guarantees that tmp will
|
||||
// Using PointerHolder guarantees that tmp will
|
||||
// be freed even if rc4.process throws an exception.
|
||||
PointerHolder<char> tmp = QUtil::copy_string(str);
|
||||
PointerHolder<char> tmp(true, QUtil::copy_string(str));
|
||||
RC4 rc4((unsigned char const*)key.c_str(), key.length());
|
||||
rc4.process((unsigned char*)tmp.getPointer(), vlen);
|
||||
str = std::string(tmp.getPointer(), vlen);
|
||||
|
@ -88,7 +88,7 @@ QPDF::isLinearized()
|
||||
|
||||
char* buf = new char[tbuf_size];
|
||||
this->file->seek(0, SEEK_SET);
|
||||
PointerHolder<char> b(buf); // guarantee deletion
|
||||
PointerHolder<char> b(true, buf);
|
||||
memset(buf, '\0', tbuf_size);
|
||||
this->file->read(buf, tbuf_size - 1);
|
||||
|
||||
|
@ -33,11 +33,15 @@ struct _qpdf_data
|
||||
char const* buffer;
|
||||
unsigned long size;
|
||||
char const* password;
|
||||
bool write_memory;
|
||||
Buffer* output_buffer;
|
||||
};
|
||||
|
||||
_qpdf_data::_qpdf_data() :
|
||||
qpdf(0),
|
||||
qpdf_writer(0)
|
||||
qpdf_writer(0),
|
||||
write_memory(false),
|
||||
output_buffer(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -45,6 +49,7 @@ _qpdf_data::~_qpdf_data()
|
||||
{
|
||||
delete qpdf_writer;
|
||||
delete qpdf;
|
||||
delete output_buffer;
|
||||
}
|
||||
|
||||
// must set qpdf->filename and qpdf->password
|
||||
@ -66,6 +71,12 @@ static void call_init_write(qpdf_data qpdf)
|
||||
qpdf->qpdf_writer = new QPDFWriter(*(qpdf->qpdf), qpdf->filename);
|
||||
}
|
||||
|
||||
static void call_init_write_memory(qpdf_data qpdf)
|
||||
{
|
||||
qpdf->qpdf_writer = new QPDFWriter(*(qpdf->qpdf));
|
||||
qpdf->qpdf_writer->setOutputMemory();
|
||||
}
|
||||
|
||||
static void call_write(qpdf_data qpdf)
|
||||
{
|
||||
qpdf->qpdf_writer->write();
|
||||
@ -408,21 +419,71 @@ QPDF_BOOL qpdf_allow_modify_all(qpdf_data qpdf)
|
||||
return qpdf->qpdf->allowModifyAll();
|
||||
}
|
||||
|
||||
QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename)
|
||||
static void qpdf_init_write_internal(qpdf_data qpdf)
|
||||
{
|
||||
QPDF_ERROR_CODE status = QPDF_SUCCESS;
|
||||
if (qpdf->qpdf_writer)
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_init_write multiple times");
|
||||
delete qpdf->qpdf_writer;
|
||||
qpdf->qpdf_writer = 0;
|
||||
if (qpdf->output_buffer)
|
||||
{
|
||||
delete qpdf->output_buffer;
|
||||
qpdf->output_buffer = 0;
|
||||
qpdf->write_memory = false;
|
||||
qpdf->filename = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename)
|
||||
{
|
||||
qpdf_init_write_internal(qpdf);
|
||||
qpdf->filename = filename;
|
||||
status = trap_errors(qpdf, &call_init_write);
|
||||
QPDF_ERROR_CODE status = trap_errors(qpdf, &call_init_write);
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_init_write", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
QPDF_ERROR_CODE qpdf_init_write_memory(qpdf_data qpdf)
|
||||
{
|
||||
qpdf_init_write_internal(qpdf);
|
||||
QPDF_ERROR_CODE status = trap_errors(qpdf, &call_init_write_memory);
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_init_write_memory");
|
||||
qpdf->write_memory = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
static void qpdf_get_buffer_internal(qpdf_data qpdf)
|
||||
{
|
||||
if (qpdf->write_memory && (qpdf->output_buffer == 0))
|
||||
{
|
||||
qpdf->output_buffer = qpdf->qpdf_writer->getBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long qpdf_get_buffer_length(qpdf_data qpdf)
|
||||
{
|
||||
qpdf_get_buffer_internal(qpdf);
|
||||
unsigned long result = 0L;
|
||||
if (qpdf->output_buffer)
|
||||
{
|
||||
result = qpdf->output_buffer->getSize();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned char const* qpdf_get_buffer(qpdf_data qpdf)
|
||||
{
|
||||
unsigned char const* result = 0;
|
||||
qpdf_get_buffer_internal(qpdf);
|
||||
if (qpdf->output_buffer)
|
||||
{
|
||||
result = qpdf->output_buffer->getBuffer();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void qpdf_set_object_stream_mode(qpdf_data qpdf, qpdf_object_stream_e mode)
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_set_object_stream_mode");
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <qpdf/Pl_Discard.hh>
|
||||
#include <stdlib.h>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
typedef unsigned char* uc;
|
||||
|
||||
|
@ -2131,6 +2131,14 @@ print "\n";
|
||||
<literal>/Info</literal> dictionary.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Add functions <function>qpdf_init_write_memory</function>,
|
||||
<function>qpdf_get_buffer_length</function>, and
|
||||
<function>qpdf_get_buffer</function> to the C API for writing
|
||||
PDF files to a memory buffer instead of a file.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -337,6 +337,10 @@ static void test16(char const* infile,
|
||||
char const* outfile,
|
||||
char const* outfile2)
|
||||
{
|
||||
unsigned long buflen = 0L;
|
||||
unsigned char const* buf = 0;
|
||||
FILE* f = 0;
|
||||
|
||||
qpdf_read(qpdf, infile, password);
|
||||
print_info("/Author");
|
||||
print_info("/Producer");
|
||||
@ -347,11 +351,22 @@ static void test16(char const* infile,
|
||||
print_info("/Author");
|
||||
print_info("/Producer");
|
||||
print_info("/Creator");
|
||||
qpdf_init_write(qpdf, outfile);
|
||||
qpdf_init_write_memory(qpdf);
|
||||
qpdf_set_static_ID(qpdf, QPDF_TRUE);
|
||||
qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
|
||||
qpdf_set_stream_data_mode(qpdf, qpdf_s_uncompress);
|
||||
qpdf_write(qpdf);
|
||||
f = fopen(outfile, "wb");
|
||||
if (f == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to open %s: %s\n",
|
||||
whoami, outfile, strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
buflen = qpdf_get_buffer_length(qpdf);
|
||||
buf = qpdf_get_buffer(qpdf);
|
||||
fwrite(buf, 1, buflen, f);
|
||||
fclose(f);
|
||||
report_errors();
|
||||
}
|
||||
|
||||
|
@ -199,3 +199,4 @@ qpdf-c set_info_key to value 0
|
||||
qpdf-c set_info_key to null 0
|
||||
qpdf-c set-info-key use existing info 0
|
||||
qpdf-c add info to trailer 0
|
||||
qpdf-c called qpdf_init_write_memory 0
|
||||
|
@ -76,7 +76,7 @@ void runtest(int n, char const* filename)
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t size = (size_t) ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
file_buf = new char[size];
|
||||
file_buf = PointerHolder<char>(true, new char[size]);
|
||||
char* buf_p = file_buf.getPointer();
|
||||
size_t bytes_read = 0;
|
||||
size_t len = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user