Commit 5525c9312420cf002aef78fa1d52219724d3fc20

Authored by Jay Berkenbilt
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.
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
... ... @@ -50,6 +50,8 @@
50 50 #include <memory>
51 51 #include <string>
52 52  
  53 +// Remember to use QPDF_DLL_CLASS on anything derived from Pipeline so
  54 +// it will work with dynamic_cast across the shared object boundary.
53 55 class QPDF_DLL_CLASS Pipeline
54 56 {
55 57 public:
... ...
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&amp; 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&amp; 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
... ...