diff --git a/ChangeLog b/ChangeLog index 16cfd204..60e3c0c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2021-12-17 Jay Berkenbilt + + * Add Pl_Buffer::getMallocBuffer() to initialize a buffer with + malloc in support of the C API + 2021-12-16 Jay Berkenbilt * Add several functions to the C API for working with pages. C diff --git a/include/qpdf/Pl_Buffer.hh b/include/qpdf/Pl_Buffer.hh index 07bc2372..8c402cd4 100644 --- a/include/qpdf/Pl_Buffer.hh +++ b/include/qpdf/Pl_Buffer.hh @@ -55,6 +55,15 @@ class Pl_Buffer: public Pipeline QPDF_DLL Buffer* getBuffer(); + // getMallocBuffer behaves in the same was as getBuffer except the + // buffer is allocated with malloc(), making it suitable for use + // when calling from other languages. If there is no data, *buf is + // set to a null pointer and *len is set to 0. Otherwise, *buf is + // a buffer of size *len allocated with malloc(). It is the + // caller's responsibility to call free() on the buffer. + QPDF_DLL + void getMallocBuffer(unsigned char **buf, size_t* len); + private: class Members { diff --git a/libqpdf/Pl_Buffer.cc b/libqpdf/Pl_Buffer.cc index 70d906ea..0743de75 100644 --- a/libqpdf/Pl_Buffer.cc +++ b/libqpdf/Pl_Buffer.cc @@ -3,6 +3,7 @@ #include #include #include +#include Pl_Buffer::Members::Members() : ready(true), @@ -80,3 +81,25 @@ Pl_Buffer::getBuffer() this->m = new Members(); return b; } + +void +Pl_Buffer::getMallocBuffer(unsigned char **buf, size_t* len) +{ + if (! this->m->ready) + { + throw std::logic_error( + "Pl_Buffer::getMallocBuffer() called when not ready"); + } + + *len = this->m->total_size; + if (this->m->total_size > 0) + { + *buf = reinterpret_cast(malloc(this->m->total_size)); + memcpy(*buf, this->m->data->getBuffer(), this->m->total_size); + } + else + { + *buf = nullptr; + } + this->m = new Members(); +} diff --git a/libtests/buffer.cc b/libtests/buffer.cc index bd28746f..23d82e7b 100644 --- a/libtests/buffer.cc +++ b/libtests/buffer.cc @@ -6,6 +6,7 @@ #include #include #include +#include static unsigned char* uc(char const* s) { @@ -98,6 +99,31 @@ int main() b = bp3.getBuffer(); std::cout << "size: " << b->getSize() << std::endl; delete b; + + // Malloc buffer should behave similarly. + Pl_Buffer bp4("bp4"); + bp4.write(uc("asdf"), 4); + unsigned char* mbuf; + size_t len; + try + { + bp4.getMallocBuffer(&mbuf, &len); + assert(false); + } + catch (std::logic_error& e) + { + std::cout << "malloc buffer logic error: " << e.what() << std::endl; + } + bp4.finish(); + bp4.getMallocBuffer(&mbuf, &len); + assert(len == 4); + assert(memcmp(mbuf, uc("asdf"), 4) == 0); + free(mbuf); + bp4.write(uc(""), 0); + bp4.finish(); + bp4.getMallocBuffer(&mbuf, &len); + assert(mbuf == nullptr); + assert(len == 0); } catch (std::exception& e) { diff --git a/libtests/qtest/buffer/buffer.out b/libtests/qtest/buffer/buffer.out index e1e404b1..4143e58f 100644 --- a/libtests/qtest/buffer/buffer.out +++ b/libtests/qtest/buffer/buffer.out @@ -11,4 +11,5 @@ data: mooquack size: 0 size: 0 size: 0 +malloc buffer logic error: Pl_Buffer::getMallocBuffer() called when not ready done diff --git a/manual/index.rst b/manual/index.rst index 155d64b0..a77fae29 100644 --- a/manual/index.rst +++ b/manual/index.rst @@ -3622,10 +3622,14 @@ For a detailed list of changes, please see the file object is not of the expected type. These warnings now have an error code of ``qpdf_e_object`` instead of ``qpdf_e_damaged_pdf``. Also, comments have been added to - :file:`QPDFObjectHandle.hh` to explain in - more detail what the behavior is. See :ref:`ref.object-accessors` for a more in-depth + :file:`QPDFObjectHandle.hh` to explain in more detail what the + behavior is. See :ref:`ref.object-accessors` for a more in-depth discussion. + - Add ``Pl_Buffer::getMallocBuffer()`` to initialize a buffer + allocated with ``malloc()`` for better cross-language + interoperability. + - C API Enhancements - Overhaul error handling for the object handle functions