Commit fee7489ee4c90c6dbd11e57ecc8e888c8f038716
1 parent
8c4ad6b9
Add Pl_Buffer::getMallocBuffer
Showing
6 changed files
with
70 additions
and
2 deletions
ChangeLog
| 1 | +2021-12-17 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * Add Pl_Buffer::getMallocBuffer() to initialize a buffer with | ||
| 4 | + malloc in support of the C API | ||
| 5 | + | ||
| 1 | 2021-12-16 Jay Berkenbilt <ejb@ql.org> | 6 | 2021-12-16 Jay Berkenbilt <ejb@ql.org> |
| 2 | 7 | ||
| 3 | * Add several functions to the C API for working with pages. C | 8 | * Add several functions to the C API for working with pages. C |
include/qpdf/Pl_Buffer.hh
| @@ -55,6 +55,15 @@ class Pl_Buffer: public Pipeline | @@ -55,6 +55,15 @@ class Pl_Buffer: public Pipeline | ||
| 55 | QPDF_DLL | 55 | QPDF_DLL |
| 56 | Buffer* getBuffer(); | 56 | Buffer* getBuffer(); |
| 57 | 57 | ||
| 58 | + // getMallocBuffer behaves in the same was as getBuffer except the | ||
| 59 | + // buffer is allocated with malloc(), making it suitable for use | ||
| 60 | + // when calling from other languages. If there is no data, *buf is | ||
| 61 | + // set to a null pointer and *len is set to 0. Otherwise, *buf is | ||
| 62 | + // a buffer of size *len allocated with malloc(). It is the | ||
| 63 | + // caller's responsibility to call free() on the buffer. | ||
| 64 | + QPDF_DLL | ||
| 65 | + void getMallocBuffer(unsigned char **buf, size_t* len); | ||
| 66 | + | ||
| 58 | private: | 67 | private: |
| 59 | class Members | 68 | class Members |
| 60 | { | 69 | { |
libqpdf/Pl_Buffer.cc
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | #include <algorithm> | 3 | #include <algorithm> |
| 4 | #include <assert.h> | 4 | #include <assert.h> |
| 5 | #include <string.h> | 5 | #include <string.h> |
| 6 | +#include <stdlib.h> | ||
| 6 | 7 | ||
| 7 | Pl_Buffer::Members::Members() : | 8 | Pl_Buffer::Members::Members() : |
| 8 | ready(true), | 9 | ready(true), |
| @@ -80,3 +81,25 @@ Pl_Buffer::getBuffer() | @@ -80,3 +81,25 @@ Pl_Buffer::getBuffer() | ||
| 80 | this->m = new Members(); | 81 | this->m = new Members(); |
| 81 | return b; | 82 | return b; |
| 82 | } | 83 | } |
| 84 | + | ||
| 85 | +void | ||
| 86 | +Pl_Buffer::getMallocBuffer(unsigned char **buf, size_t* len) | ||
| 87 | +{ | ||
| 88 | + if (! this->m->ready) | ||
| 89 | + { | ||
| 90 | + throw std::logic_error( | ||
| 91 | + "Pl_Buffer::getMallocBuffer() called when not ready"); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + *len = this->m->total_size; | ||
| 95 | + if (this->m->total_size > 0) | ||
| 96 | + { | ||
| 97 | + *buf = reinterpret_cast<unsigned char*>(malloc(this->m->total_size)); | ||
| 98 | + memcpy(*buf, this->m->data->getBuffer(), this->m->total_size); | ||
| 99 | + } | ||
| 100 | + else | ||
| 101 | + { | ||
| 102 | + *buf = nullptr; | ||
| 103 | + } | ||
| 104 | + this->m = new Members(); | ||
| 105 | +} |
libtests/buffer.cc
| @@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
| 6 | #include <stdexcept> | 6 | #include <stdexcept> |
| 7 | #include <iostream> | 7 | #include <iostream> |
| 8 | #include <cassert> | 8 | #include <cassert> |
| 9 | +#include <cstring> | ||
| 9 | 10 | ||
| 10 | static unsigned char* uc(char const* s) | 11 | static unsigned char* uc(char const* s) |
| 11 | { | 12 | { |
| @@ -98,6 +99,31 @@ int main() | @@ -98,6 +99,31 @@ int main() | ||
| 98 | b = bp3.getBuffer(); | 99 | b = bp3.getBuffer(); |
| 99 | std::cout << "size: " << b->getSize() << std::endl; | 100 | std::cout << "size: " << b->getSize() << std::endl; |
| 100 | delete b; | 101 | delete b; |
| 102 | + | ||
| 103 | + // Malloc buffer should behave similarly. | ||
| 104 | + Pl_Buffer bp4("bp4"); | ||
| 105 | + bp4.write(uc("asdf"), 4); | ||
| 106 | + unsigned char* mbuf; | ||
| 107 | + size_t len; | ||
| 108 | + try | ||
| 109 | + { | ||
| 110 | + bp4.getMallocBuffer(&mbuf, &len); | ||
| 111 | + assert(false); | ||
| 112 | + } | ||
| 113 | + catch (std::logic_error& e) | ||
| 114 | + { | ||
| 115 | + std::cout << "malloc buffer logic error: " << e.what() << std::endl; | ||
| 116 | + } | ||
| 117 | + bp4.finish(); | ||
| 118 | + bp4.getMallocBuffer(&mbuf, &len); | ||
| 119 | + assert(len == 4); | ||
| 120 | + assert(memcmp(mbuf, uc("asdf"), 4) == 0); | ||
| 121 | + free(mbuf); | ||
| 122 | + bp4.write(uc(""), 0); | ||
| 123 | + bp4.finish(); | ||
| 124 | + bp4.getMallocBuffer(&mbuf, &len); | ||
| 125 | + assert(mbuf == nullptr); | ||
| 126 | + assert(len == 0); | ||
| 101 | } | 127 | } |
| 102 | catch (std::exception& e) | 128 | catch (std::exception& e) |
| 103 | { | 129 | { |
libtests/qtest/buffer/buffer.out
manual/index.rst
| @@ -3622,10 +3622,14 @@ For a detailed list of changes, please see the file | @@ -3622,10 +3622,14 @@ For a detailed list of changes, please see the file | ||
| 3622 | object is not of the expected type. These warnings now have an | 3622 | object is not of the expected type. These warnings now have an |
| 3623 | error code of ``qpdf_e_object`` instead of | 3623 | error code of ``qpdf_e_object`` instead of |
| 3624 | ``qpdf_e_damaged_pdf``. Also, comments have been added to | 3624 | ``qpdf_e_damaged_pdf``. Also, comments have been added to |
| 3625 | - :file:`QPDFObjectHandle.hh` to explain in | ||
| 3626 | - more detail what the behavior is. See :ref:`ref.object-accessors` for a more in-depth | 3625 | + :file:`QPDFObjectHandle.hh` to explain in more detail what the |
| 3626 | + behavior is. See :ref:`ref.object-accessors` for a more in-depth | ||
| 3627 | discussion. | 3627 | discussion. |
| 3628 | 3628 | ||
| 3629 | + - Add ``Pl_Buffer::getMallocBuffer()`` to initialize a buffer | ||
| 3630 | + allocated with ``malloc()`` for better cross-language | ||
| 3631 | + interoperability. | ||
| 3632 | + | ||
| 3629 | - C API Enhancements | 3633 | - C API Enhancements |
| 3630 | 3634 | ||
| 3631 | - Overhaul error handling for the object handle functions | 3635 | - Overhaul error handling for the object handle functions |