Commit 5525c9312420cf002aef78fa1d52219724d3fc20
1 parent
90cfe80b
Use QPDF_DLL_CLASS with Pipeline and InputSource subclasses
This enables RTTI so we can use dynamic_cast on them across the shared object boundary.
Showing
16 changed files
with
52 additions
and
29 deletions
README-maintainer
| ... | ... | @@ -156,9 +156,14 @@ CODING RULES |
| 156 | 156 | |
| 157 | 157 | * Use QPDF_DLL on all methods that are to be exported in the shared |
| 158 | 158 | library/DLL. Use QPDF_DLL_CLASS for all classes whose type |
| 159 | - information is needed. This is important for exception classes and | |
| 160 | - it seems also for classes that are intended to be subclassed across | |
| 161 | - the shared library boundary. | |
| 159 | + information is needed. This is important for classes that are used | |
| 160 | + as exceptions, subclassed, or tested with dynamic_cast across the | |
| 161 | + the shared object boundary (or "shared library boundary" -- we may | |
| 162 | + use either term in comments and documentation). In particular, | |
| 163 | + anything new derived from Pipeline or InputSource should be marked | |
| 164 | + with QPDF_DLL_CLASS, but we don't need to do it for QPDFObjectHelper | |
| 165 | + or QPDFDocumentHelper subclasses since there's no reason to use | |
| 166 | + dynamic_cast with those. | |
| 162 | 167 | |
| 163 | 168 | * Put private member variables in std::shared_ptr<Members> for all |
| 164 | 169 | public classes. Remember to use QPDF_DLL on ~Members(). Exception: | ... | ... |
include/qpdf/BufferInputSource.hh
| ... | ... | @@ -25,7 +25,7 @@ |
| 25 | 25 | #include <qpdf/Buffer.hh> |
| 26 | 26 | #include <qpdf/InputSource.hh> |
| 27 | 27 | |
| 28 | -class BufferInputSource: public InputSource | |
| 28 | +class QPDF_DLL_CLASS BufferInputSource: public InputSource | |
| 29 | 29 | { |
| 30 | 30 | public: |
| 31 | 31 | // If own_memory is true, BufferInputSource will delete the buffer |
| ... | ... | @@ -54,7 +54,7 @@ class BufferInputSource: public InputSource |
| 54 | 54 | virtual void unreadCh(char ch); |
| 55 | 55 | |
| 56 | 56 | private: |
| 57 | - class Members | |
| 57 | + class QPDF_DLL_PRIVATE Members | |
| 58 | 58 | { |
| 59 | 59 | friend class BufferInputSource; |
| 60 | 60 | ... | ... |
include/qpdf/ClosedFileInputSource.hh
| ... | ... | @@ -35,7 +35,7 @@ |
| 35 | 35 | |
| 36 | 36 | class FileInputSource; |
| 37 | 37 | |
| 38 | -class ClosedFileInputSource: public InputSource | |
| 38 | +class QPDF_DLL_CLASS ClosedFileInputSource: public InputSource | |
| 39 | 39 | { |
| 40 | 40 | public: |
| 41 | 41 | QPDF_DLL |
| ... | ... | @@ -71,7 +71,7 @@ class ClosedFileInputSource: public InputSource |
| 71 | 71 | void before(); |
| 72 | 72 | void after(); |
| 73 | 73 | |
| 74 | - class Members | |
| 74 | + class QPDF_DLL_PRIVATE Members | |
| 75 | 75 | { |
| 76 | 76 | friend class ClosedFileInputSource; |
| 77 | 77 | ... | ... |
include/qpdf/FileInputSource.hh
| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | |
| 25 | 25 | #include <qpdf/InputSource.hh> |
| 26 | 26 | |
| 27 | -class FileInputSource: public InputSource | |
| 27 | +class QPDF_DLL_CLASS FileInputSource: public InputSource | |
| 28 | 28 | { |
| 29 | 29 | public: |
| 30 | 30 | QPDF_DLL |
| ... | ... | @@ -54,7 +54,7 @@ class FileInputSource: public InputSource |
| 54 | 54 | FileInputSource(FileInputSource const&) = delete; |
| 55 | 55 | FileInputSource& operator=(FileInputSource const&) = delete; |
| 56 | 56 | |
| 57 | - class Members | |
| 57 | + class QPDF_DLL_PRIVATE Members | |
| 58 | 58 | { |
| 59 | 59 | friend class FileInputSource; |
| 60 | 60 | ... | ... |
include/qpdf/InputSource.hh
| ... | ... | @@ -30,6 +30,9 @@ |
| 30 | 30 | #include <stdio.h> |
| 31 | 31 | #include <string> |
| 32 | 32 | |
| 33 | +// Remember to use QPDF_DLL_CLASS on anything derived from InputSource | |
| 34 | +// so it will work with dynamic_cast across the shared object | |
| 35 | +// boundary. | |
| 33 | 36 | class QPDF_DLL_CLASS InputSource |
| 34 | 37 | { |
| 35 | 38 | public: | ... | ... |
include/qpdf/Pipeline.hh
include/qpdf/Pl_Buffer.hh
| ... | ... | @@ -39,7 +39,7 @@ |
| 39 | 39 | |
| 40 | 40 | #include <memory> |
| 41 | 41 | |
| 42 | -class Pl_Buffer: public Pipeline | |
| 42 | +class QPDF_DLL_CLASS Pl_Buffer: public Pipeline | |
| 43 | 43 | { |
| 44 | 44 | public: |
| 45 | 45 | QPDF_DLL |
| ... | ... | @@ -71,7 +71,7 @@ class Pl_Buffer: public Pipeline |
| 71 | 71 | void getMallocBuffer(unsigned char** buf, size_t* len); |
| 72 | 72 | |
| 73 | 73 | private: |
| 74 | - class Members | |
| 74 | + class QPDF_DLL_PRIVATE Members | |
| 75 | 75 | { |
| 76 | 76 | friend class Pl_Buffer; |
| 77 | 77 | ... | ... |
include/qpdf/Pl_Concatenate.hh
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | |
| 31 | 31 | #include <qpdf/Pipeline.hh> |
| 32 | 32 | |
| 33 | -class Pl_Concatenate: public Pipeline | |
| 33 | +class QPDF_DLL_CLASS Pl_Concatenate: public Pipeline | |
| 34 | 34 | { |
| 35 | 35 | public: |
| 36 | 36 | QPDF_DLL |
| ... | ... | @@ -50,7 +50,7 @@ class Pl_Concatenate: public Pipeline |
| 50 | 50 | void manualFinish(); |
| 51 | 51 | |
| 52 | 52 | private: |
| 53 | - class Members | |
| 53 | + class QPDF_DLL_PRIVATE Members | |
| 54 | 54 | { |
| 55 | 55 | friend class Pl_Concatenate; |
| 56 | 56 | ... | ... |
include/qpdf/Pl_Count.hh
| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | #include <qpdf/Pipeline.hh> |
| 29 | 29 | #include <qpdf/Types.h> |
| 30 | 30 | |
| 31 | -class Pl_Count: public Pipeline | |
| 31 | +class QPDF_DLL_CLASS Pl_Count: public Pipeline | |
| 32 | 32 | { |
| 33 | 33 | public: |
| 34 | 34 | QPDF_DLL |
| ... | ... | @@ -48,7 +48,7 @@ class Pl_Count: public Pipeline |
| 48 | 48 | unsigned char getLastChar() const; |
| 49 | 49 | |
| 50 | 50 | private: |
| 51 | - class Members | |
| 51 | + class QPDF_DLL_PRIVATE Members | |
| 52 | 52 | { |
| 53 | 53 | friend class Pl_Count; |
| 54 | 54 | ... | ... |
include/qpdf/Pl_DCT.hh
| ... | ... | @@ -31,7 +31,7 @@ |
| 31 | 31 | // definition of size_t. |
| 32 | 32 | #include <jpeglib.h> |
| 33 | 33 | |
| 34 | -class Pl_DCT: public Pipeline | |
| 34 | +class QPDF_DLL_CLASS Pl_DCT: public Pipeline | |
| 35 | 35 | { |
| 36 | 36 | public: |
| 37 | 37 | // Constructor for decompressing image data |
| ... | ... | @@ -75,7 +75,7 @@ class Pl_DCT: public Pipeline |
| 75 | 75 | |
| 76 | 76 | enum action_e { a_compress, a_decompress }; |
| 77 | 77 | |
| 78 | - class Members | |
| 78 | + class QPDF_DLL_PRIVATE Members | |
| 79 | 79 | { |
| 80 | 80 | friend class Pl_DCT; |
| 81 | 81 | ... | ... |
include/qpdf/Pl_Discard.hh
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | |
| 31 | 31 | #include <qpdf/Pipeline.hh> |
| 32 | 32 | |
| 33 | -class Pl_Discard: public Pipeline | |
| 33 | +class QPDF_DLL_CLASS Pl_Discard: public Pipeline | |
| 34 | 34 | { |
| 35 | 35 | public: |
| 36 | 36 | QPDF_DLL |
| ... | ... | @@ -43,7 +43,7 @@ class Pl_Discard: public Pipeline |
| 43 | 43 | virtual void finish(); |
| 44 | 44 | |
| 45 | 45 | private: |
| 46 | - class Members | |
| 46 | + class QPDF_DLL_PRIVATE Members | |
| 47 | 47 | { |
| 48 | 48 | friend class Pl_Discard; |
| 49 | 49 | ... | ... |
include/qpdf/Pl_Flate.hh
| ... | ... | @@ -26,7 +26,7 @@ |
| 26 | 26 | #include <functional> |
| 27 | 27 | #include <memory> |
| 28 | 28 | |
| 29 | -class Pl_Flate: public Pipeline | |
| 29 | +class QPDF_DLL_CLASS Pl_Flate: public Pipeline | |
| 30 | 30 | { |
| 31 | 31 | public: |
| 32 | 32 | static unsigned int const def_bufsize = 65536; |
| ... | ... | @@ -65,7 +65,7 @@ class Pl_Flate: public Pipeline |
| 65 | 65 | void checkError(char const* prefix, int error_code); |
| 66 | 66 | void warn(char const*, int error_code); |
| 67 | 67 | |
| 68 | - class Members | |
| 68 | + class QPDF_DLL_PRIVATE Members | |
| 69 | 69 | { |
| 70 | 70 | friend class Pl_Flate; |
| 71 | 71 | ... | ... |
include/qpdf/Pl_QPDFTokenizer.hh
| ... | ... | @@ -41,7 +41,7 @@ |
| 41 | 41 | // QPDFObjectHandle::addTokenFilter. See QPDFObjectHandle.hh for |
| 42 | 42 | // details. |
| 43 | 43 | |
| 44 | -class Pl_QPDFTokenizer: public Pipeline | |
| 44 | +class QPDF_DLL_CLASS Pl_QPDFTokenizer: public Pipeline | |
| 45 | 45 | { |
| 46 | 46 | public: |
| 47 | 47 | // Whatever pipeline is provided as "next" will be set as the |
| ... | ... | @@ -60,7 +60,7 @@ class Pl_QPDFTokenizer: public Pipeline |
| 60 | 60 | virtual void finish(); |
| 61 | 61 | |
| 62 | 62 | private: |
| 63 | - class Members | |
| 63 | + class QPDF_DLL_PRIVATE Members | |
| 64 | 64 | { |
| 65 | 65 | friend class Pl_QPDFTokenizer; |
| 66 | 66 | ... | ... |
include/qpdf/Pl_RunLength.hh
| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | |
| 25 | 25 | #include <qpdf/Pipeline.hh> |
| 26 | 26 | |
| 27 | -class Pl_RunLength: public Pipeline | |
| 27 | +class QPDF_DLL_CLASS Pl_RunLength: public Pipeline | |
| 28 | 28 | { |
| 29 | 29 | public: |
| 30 | 30 | enum action_e { a_encode, a_decode }; |
| ... | ... | @@ -46,7 +46,7 @@ class Pl_RunLength: public Pipeline |
| 46 | 46 | |
| 47 | 47 | enum state_e { st_top, st_copying, st_run }; |
| 48 | 48 | |
| 49 | - class Members | |
| 49 | + class QPDF_DLL_PRIVATE Members | |
| 50 | 50 | { |
| 51 | 51 | friend class Pl_RunLength; |
| 52 | 52 | ... | ... |
include/qpdf/Pl_StdioFile.hh
| ... | ... | @@ -32,7 +32,7 @@ |
| 32 | 32 | // This pipeline is reusable. |
| 33 | 33 | // |
| 34 | 34 | |
| 35 | -class Pl_StdioFile: public Pipeline | |
| 35 | +class QPDF_DLL_CLASS Pl_StdioFile: public Pipeline | |
| 36 | 36 | { |
| 37 | 37 | public: |
| 38 | 38 | // f is externally maintained; this class just writes to and |
| ... | ... | @@ -48,7 +48,7 @@ class Pl_StdioFile: public Pipeline |
| 48 | 48 | virtual void finish(); |
| 49 | 49 | |
| 50 | 50 | private: |
| 51 | - class Members | |
| 51 | + class QPDF_DLL_PRIVATE Members | |
| 52 | 52 | { |
| 53 | 53 | friend class Pl_StdioFile; |
| 54 | 54 | ... | ... |
qpdf/test_driver.cc
| ... | ... | @@ -3,6 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | #include <qpdf/QPDF.hh> |
| 5 | 5 | |
| 6 | +#include <qpdf/BufferInputSource.hh> | |
| 6 | 7 | #include <qpdf/Pl_Buffer.hh> |
| 7 | 8 | #include <qpdf/Pl_Discard.hh> |
| 8 | 9 | #include <qpdf/Pl_Flate.hh> |
| ... | ... | @@ -2314,8 +2315,9 @@ test_60(QPDF& pdf, char const* arg2) |
| 2314 | 2315 | static void |
| 2315 | 2316 | test_61(QPDF& pdf, char const* arg2) |
| 2316 | 2317 | { |
| 2317 | - // Test to make sure exceptions can be caught properly across | |
| 2318 | - // shared library boundaries. | |
| 2318 | + // Test to make sure type information is passed across shared | |
| 2319 | + // library boundaries. This includes exception handling, dynamic | |
| 2320 | + // cast, and subclassing. | |
| 2319 | 2321 | pdf.setAttemptRecovery(false); |
| 2320 | 2322 | pdf.setSuppressWarnings(true); |
| 2321 | 2323 | try { |
| ... | ... | @@ -2338,6 +2340,17 @@ test_61(QPDF& pdf, char const* arg2) |
| 2338 | 2340 | } catch (std::runtime_error const&) { |
| 2339 | 2341 | std::cout << "Caught runtime_error as expected" << std::endl; |
| 2340 | 2342 | } |
| 2343 | + | |
| 2344 | + // Spot check RTTI for dynamic cast. We intend to have pipelines | |
| 2345 | + // and input sources be testable, but adding comprehensive tests | |
| 2346 | + // for everything doesn't add value as it wouldn't catch | |
| 2347 | + // forgetting QPDF_DLL_CLASS on a new subclass. | |
| 2348 | + BufferInputSource b("x", "y"); | |
| 2349 | + InputSource* is = &b; | |
| 2350 | + assert(dynamic_cast<BufferInputSource*>(is) != nullptr); | |
| 2351 | + Pl_Discard pd; | |
| 2352 | + Pipeline* p = &pd; | |
| 2353 | + assert(dynamic_cast<Pl_Discard*>(p) != nullptr); | |
| 2341 | 2354 | } |
| 2342 | 2355 | |
| 2343 | 2356 | static void | ... | ... |