mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-23 03:18: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
|
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.
|
* Check all open issues in the sourceforge trackers.
|
||||||
|
|
||||||
* If any interfaces were added or changed, check C API to see whether
|
* 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.
|
* Provide an example of using replace and swap. Maybe.
|
||||||
|
|
||||||
* Add C API for writing to memory if possible
|
|
||||||
|
|
||||||
General
|
General
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
#ifndef __POINTERHOLDER_HH__
|
#ifndef __POINTERHOLDER_HH__
|
||||||
#define __POINTERHOLDER_HH__
|
#define __POINTERHOLDER_HH__
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
// This class is basically boost::shared_pointer but predates that by
|
// This class is basically boost::shared_pointer but predates that by
|
||||||
// several years.
|
// several years.
|
||||||
|
|
||||||
@ -45,43 +43,42 @@ class PointerHolder
|
|||||||
class Data
|
class Data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Data(T* pointer, bool tracing) :
|
Data(T* pointer, bool array) :
|
||||||
pointer(pointer),
|
pointer(pointer),
|
||||||
tracing(tracing),
|
array(array),
|
||||||
refcount(0)
|
refcount(0)
|
||||||
{
|
{
|
||||||
static int next_id = 0;
|
|
||||||
this->unique_id = ++next_id;
|
|
||||||
}
|
}
|
||||||
~Data()
|
~Data()
|
||||||
{
|
{
|
||||||
if (this->tracing)
|
if (array)
|
||||||
{
|
{
|
||||||
std::cerr << "PointerHolder deleting pointer "
|
delete [] this->pointer;
|
||||||
<< (void*)pointer
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
delete this->pointer;
|
else
|
||||||
if (this->tracing)
|
|
||||||
{
|
{
|
||||||
std::cerr << "PointerHolder done deleting pointer "
|
delete this->pointer;
|
||||||
<< (void*)pointer
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
T* pointer;
|
T* pointer;
|
||||||
bool tracing;
|
bool array;
|
||||||
int refcount;
|
int refcount;
|
||||||
int unique_id;
|
|
||||||
private:
|
private:
|
||||||
Data(Data const&);
|
Data(Data const&);
|
||||||
Data& operator=(Data const&);
|
Data& operator=(Data const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// "tracing" is not used but is kept for interface backward compatbility
|
||||||
PointerHolder(T* pointer = 0, bool tracing = false)
|
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)
|
PointerHolder(PointerHolder const& rhs)
|
||||||
{
|
{
|
||||||
@ -148,12 +145,6 @@ class PointerHolder
|
|||||||
this->data = data;
|
this->data = data;
|
||||||
{
|
{
|
||||||
++this->data->refcount;
|
++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)
|
void copy(PointerHolder const& rhs)
|
||||||
@ -168,13 +159,6 @@ class PointerHolder
|
|||||||
{
|
{
|
||||||
gone = true;
|
gone = true;
|
||||||
}
|
}
|
||||||
if (this->data->tracing)
|
|
||||||
{
|
|
||||||
std::cerr << "PointerHolder " << this->data->unique_id
|
|
||||||
<< " refcount decreased to "
|
|
||||||
<< this->data->refcount
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (gone)
|
if (gone)
|
||||||
{
|
{
|
||||||
|
@ -285,6 +285,25 @@ extern "C" {
|
|||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename);
|
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
|
QPDF_DLL
|
||||||
void qpdf_set_object_stream_mode(qpdf_data qpdf,
|
void qpdf_set_object_stream_mode(qpdf_data qpdf,
|
||||||
enum qpdf_object_stream_e mode);
|
enum qpdf_object_stream_e mode);
|
||||||
|
@ -403,10 +403,9 @@ QPDF::parse(char const* password)
|
|||||||
this->file->rewind();
|
this->file->rewind();
|
||||||
}
|
}
|
||||||
char* buf = new char[tbuf_size + 1];
|
char* buf = new char[tbuf_size + 1];
|
||||||
// Put buf in a PointerHolder to guarantee deletion of buf. This
|
// Put buf in an array-style PointerHolder to guarantee deletion
|
||||||
// calls delete rather than delete [], but it's okay since buf is
|
// of buf.
|
||||||
// an array of fundamental types.
|
PointerHolder<char> b(true, buf);
|
||||||
PointerHolder<char> b(buf);
|
|
||||||
memset(buf, '\0', tbuf_size + 1);
|
memset(buf, '\0', tbuf_size + 1);
|
||||||
this->file->read(buf, tbuf_size);
|
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");
|
QTC::TC("qpdf", "QPDF_encryption rc4 decode string");
|
||||||
unsigned int vlen = str.length();
|
unsigned int vlen = str.length();
|
||||||
// Using PointerHolder will cause a new char[] to be deleted
|
// Using PointerHolder guarantees that tmp will
|
||||||
// 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
|
|
||||||
// be freed even if rc4.process throws an exception.
|
// 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 rc4((unsigned char const*)key.c_str(), key.length());
|
||||||
rc4.process((unsigned char*)tmp.getPointer(), vlen);
|
rc4.process((unsigned char*)tmp.getPointer(), vlen);
|
||||||
str = std::string(tmp.getPointer(), vlen);
|
str = std::string(tmp.getPointer(), vlen);
|
||||||
|
@ -88,7 +88,7 @@ QPDF::isLinearized()
|
|||||||
|
|
||||||
char* buf = new char[tbuf_size];
|
char* buf = new char[tbuf_size];
|
||||||
this->file->seek(0, SEEK_SET);
|
this->file->seek(0, SEEK_SET);
|
||||||
PointerHolder<char> b(buf); // guarantee deletion
|
PointerHolder<char> b(true, buf);
|
||||||
memset(buf, '\0', tbuf_size);
|
memset(buf, '\0', tbuf_size);
|
||||||
this->file->read(buf, tbuf_size - 1);
|
this->file->read(buf, tbuf_size - 1);
|
||||||
|
|
||||||
|
@ -33,11 +33,15 @@ struct _qpdf_data
|
|||||||
char const* buffer;
|
char const* buffer;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
char const* password;
|
char const* password;
|
||||||
|
bool write_memory;
|
||||||
|
Buffer* output_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
_qpdf_data::_qpdf_data() :
|
_qpdf_data::_qpdf_data() :
|
||||||
qpdf(0),
|
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_writer;
|
||||||
delete qpdf;
|
delete qpdf;
|
||||||
|
delete output_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// must set qpdf->filename and qpdf->password
|
// 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);
|
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)
|
static void call_write(qpdf_data qpdf)
|
||||||
{
|
{
|
||||||
qpdf->qpdf_writer->write();
|
qpdf->qpdf_writer->write();
|
||||||
@ -408,21 +419,71 @@ QPDF_BOOL qpdf_allow_modify_all(qpdf_data qpdf)
|
|||||||
return qpdf->qpdf->allowModifyAll();
|
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)
|
if (qpdf->qpdf_writer)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_init_write multiple times");
|
QTC::TC("qpdf", "qpdf-c called qpdf_init_write multiple times");
|
||||||
delete qpdf->qpdf_writer;
|
delete qpdf->qpdf_writer;
|
||||||
qpdf->qpdf_writer = 0;
|
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;
|
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);
|
QTC::TC("qpdf", "qpdf-c called qpdf_init_write", status);
|
||||||
return 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)
|
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");
|
QTC::TC("qpdf", "qpdf-c called qpdf_set_object_stream_mode");
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <qpdf/Pl_Discard.hh>
|
#include <qpdf/Pl_Discard.hh>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
typedef unsigned char* uc;
|
typedef unsigned char* uc;
|
||||||
|
|
||||||
|
@ -2131,6 +2131,14 @@ print "\n";
|
|||||||
<literal>/Info</literal> dictionary.
|
<literal>/Info</literal> dictionary.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</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>
|
</itemizedlist>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -337,6 +337,10 @@ static void test16(char const* infile,
|
|||||||
char const* outfile,
|
char const* outfile,
|
||||||
char const* outfile2)
|
char const* outfile2)
|
||||||
{
|
{
|
||||||
|
unsigned long buflen = 0L;
|
||||||
|
unsigned char const* buf = 0;
|
||||||
|
FILE* f = 0;
|
||||||
|
|
||||||
qpdf_read(qpdf, infile, password);
|
qpdf_read(qpdf, infile, password);
|
||||||
print_info("/Author");
|
print_info("/Author");
|
||||||
print_info("/Producer");
|
print_info("/Producer");
|
||||||
@ -347,11 +351,22 @@ static void test16(char const* infile,
|
|||||||
print_info("/Author");
|
print_info("/Author");
|
||||||
print_info("/Producer");
|
print_info("/Producer");
|
||||||
print_info("/Creator");
|
print_info("/Creator");
|
||||||
qpdf_init_write(qpdf, outfile);
|
qpdf_init_write_memory(qpdf);
|
||||||
qpdf_set_static_ID(qpdf, QPDF_TRUE);
|
qpdf_set_static_ID(qpdf, QPDF_TRUE);
|
||||||
qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
|
qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
|
||||||
qpdf_set_stream_data_mode(qpdf, qpdf_s_uncompress);
|
qpdf_set_stream_data_mode(qpdf, qpdf_s_uncompress);
|
||||||
qpdf_write(qpdf);
|
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();
|
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 to null 0
|
||||||
qpdf-c set-info-key use existing info 0
|
qpdf-c set-info-key use existing info 0
|
||||||
qpdf-c add info to trailer 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);
|
fseek(f, 0, SEEK_END);
|
||||||
size_t size = (size_t) ftell(f);
|
size_t size = (size_t) ftell(f);
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
file_buf = new char[size];
|
file_buf = PointerHolder<char>(true, new char[size]);
|
||||||
char* buf_p = file_buf.getPointer();
|
char* buf_p = file_buf.getPointer();
|
||||||
size_t bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user