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,9 +156,14 @@ CODING RULES
156 156
157 * Use QPDF_DLL on all methods that are to be exported in the shared 157 * Use QPDF_DLL on all methods that are to be exported in the shared
158 library/DLL. Use QPDF_DLL_CLASS for all classes whose type 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 * Put private member variables in std::shared_ptr<Members> for all 168 * Put private member variables in std::shared_ptr<Members> for all
164 public classes. Remember to use QPDF_DLL on ~Members(). Exception: 169 public classes. Remember to use QPDF_DLL on ~Members(). Exception:
include/qpdf/BufferInputSource.hh
@@ -25,7 +25,7 @@ @@ -25,7 +25,7 @@
25 #include <qpdf/Buffer.hh> 25 #include <qpdf/Buffer.hh>
26 #include <qpdf/InputSource.hh> 26 #include <qpdf/InputSource.hh>
27 27
28 -class BufferInputSource: public InputSource 28 +class QPDF_DLL_CLASS BufferInputSource: public InputSource
29 { 29 {
30 public: 30 public:
31 // If own_memory is true, BufferInputSource will delete the buffer 31 // If own_memory is true, BufferInputSource will delete the buffer
@@ -54,7 +54,7 @@ class BufferInputSource: public InputSource @@ -54,7 +54,7 @@ class BufferInputSource: public InputSource
54 virtual void unreadCh(char ch); 54 virtual void unreadCh(char ch);
55 55
56 private: 56 private:
57 - class Members 57 + class QPDF_DLL_PRIVATE Members
58 { 58 {
59 friend class BufferInputSource; 59 friend class BufferInputSource;
60 60
include/qpdf/ClosedFileInputSource.hh
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 35
36 class FileInputSource; 36 class FileInputSource;
37 37
38 -class ClosedFileInputSource: public InputSource 38 +class QPDF_DLL_CLASS ClosedFileInputSource: public InputSource
39 { 39 {
40 public: 40 public:
41 QPDF_DLL 41 QPDF_DLL
@@ -71,7 +71,7 @@ class ClosedFileInputSource: public InputSource @@ -71,7 +71,7 @@ class ClosedFileInputSource: public InputSource
71 void before(); 71 void before();
72 void after(); 72 void after();
73 73
74 - class Members 74 + class QPDF_DLL_PRIVATE Members
75 { 75 {
76 friend class ClosedFileInputSource; 76 friend class ClosedFileInputSource;
77 77
include/qpdf/FileInputSource.hh
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 24
25 #include <qpdf/InputSource.hh> 25 #include <qpdf/InputSource.hh>
26 26
27 -class FileInputSource: public InputSource 27 +class QPDF_DLL_CLASS FileInputSource: public InputSource
28 { 28 {
29 public: 29 public:
30 QPDF_DLL 30 QPDF_DLL
@@ -54,7 +54,7 @@ class FileInputSource: public InputSource @@ -54,7 +54,7 @@ class FileInputSource: public InputSource
54 FileInputSource(FileInputSource const&) = delete; 54 FileInputSource(FileInputSource const&) = delete;
55 FileInputSource& operator=(FileInputSource const&) = delete; 55 FileInputSource& operator=(FileInputSource const&) = delete;
56 56
57 - class Members 57 + class QPDF_DLL_PRIVATE Members
58 { 58 {
59 friend class FileInputSource; 59 friend class FileInputSource;
60 60
include/qpdf/InputSource.hh
@@ -30,6 +30,9 @@ @@ -30,6 +30,9 @@
30 #include <stdio.h> 30 #include <stdio.h>
31 #include <string> 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 class QPDF_DLL_CLASS InputSource 36 class QPDF_DLL_CLASS InputSource
34 { 37 {
35 public: 38 public:
include/qpdf/Pipeline.hh
@@ -50,6 +50,8 @@ @@ -50,6 +50,8 @@
50 #include <memory> 50 #include <memory>
51 #include <string> 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 class QPDF_DLL_CLASS Pipeline 55 class QPDF_DLL_CLASS Pipeline
54 { 56 {
55 public: 57 public:
include/qpdf/Pl_Buffer.hh
@@ -39,7 +39,7 @@ @@ -39,7 +39,7 @@
39 39
40 #include <memory> 40 #include <memory>
41 41
42 -class Pl_Buffer: public Pipeline 42 +class QPDF_DLL_CLASS Pl_Buffer: public Pipeline
43 { 43 {
44 public: 44 public:
45 QPDF_DLL 45 QPDF_DLL
@@ -71,7 +71,7 @@ class Pl_Buffer: public Pipeline @@ -71,7 +71,7 @@ class Pl_Buffer: public Pipeline
71 void getMallocBuffer(unsigned char** buf, size_t* len); 71 void getMallocBuffer(unsigned char** buf, size_t* len);
72 72
73 private: 73 private:
74 - class Members 74 + class QPDF_DLL_PRIVATE Members
75 { 75 {
76 friend class Pl_Buffer; 76 friend class Pl_Buffer;
77 77
include/qpdf/Pl_Concatenate.hh
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 30
31 #include <qpdf/Pipeline.hh> 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 public: 35 public:
36 QPDF_DLL 36 QPDF_DLL
@@ -50,7 +50,7 @@ class Pl_Concatenate: public Pipeline @@ -50,7 +50,7 @@ class Pl_Concatenate: public Pipeline
50 void manualFinish(); 50 void manualFinish();
51 51
52 private: 52 private:
53 - class Members 53 + class QPDF_DLL_PRIVATE Members
54 { 54 {
55 friend class Pl_Concatenate; 55 friend class Pl_Concatenate;
56 56
include/qpdf/Pl_Count.hh
@@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
28 #include <qpdf/Pipeline.hh> 28 #include <qpdf/Pipeline.hh>
29 #include <qpdf/Types.h> 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 public: 33 public:
34 QPDF_DLL 34 QPDF_DLL
@@ -48,7 +48,7 @@ class Pl_Count: public Pipeline @@ -48,7 +48,7 @@ class Pl_Count: public Pipeline
48 unsigned char getLastChar() const; 48 unsigned char getLastChar() const;
49 49
50 private: 50 private:
51 - class Members 51 + class QPDF_DLL_PRIVATE Members
52 { 52 {
53 friend class Pl_Count; 53 friend class Pl_Count;
54 54
include/qpdf/Pl_DCT.hh
@@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
31 // definition of size_t. 31 // definition of size_t.
32 #include <jpeglib.h> 32 #include <jpeglib.h>
33 33
34 -class Pl_DCT: public Pipeline 34 +class QPDF_DLL_CLASS Pl_DCT: public Pipeline
35 { 35 {
36 public: 36 public:
37 // Constructor for decompressing image data 37 // Constructor for decompressing image data
@@ -75,7 +75,7 @@ class Pl_DCT: public Pipeline @@ -75,7 +75,7 @@ class Pl_DCT: public Pipeline
75 75
76 enum action_e { a_compress, a_decompress }; 76 enum action_e { a_compress, a_decompress };
77 77
78 - class Members 78 + class QPDF_DLL_PRIVATE Members
79 { 79 {
80 friend class Pl_DCT; 80 friend class Pl_DCT;
81 81
include/qpdf/Pl_Discard.hh
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 30
31 #include <qpdf/Pipeline.hh> 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 public: 35 public:
36 QPDF_DLL 36 QPDF_DLL
@@ -43,7 +43,7 @@ class Pl_Discard: public Pipeline @@ -43,7 +43,7 @@ class Pl_Discard: public Pipeline
43 virtual void finish(); 43 virtual void finish();
44 44
45 private: 45 private:
46 - class Members 46 + class QPDF_DLL_PRIVATE Members
47 { 47 {
48 friend class Pl_Discard; 48 friend class Pl_Discard;
49 49
include/qpdf/Pl_Flate.hh
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 #include <functional> 26 #include <functional>
27 #include <memory> 27 #include <memory>
28 28
29 -class Pl_Flate: public Pipeline 29 +class QPDF_DLL_CLASS Pl_Flate: public Pipeline
30 { 30 {
31 public: 31 public:
32 static unsigned int const def_bufsize = 65536; 32 static unsigned int const def_bufsize = 65536;
@@ -65,7 +65,7 @@ class Pl_Flate: public Pipeline @@ -65,7 +65,7 @@ class Pl_Flate: public Pipeline
65 void checkError(char const* prefix, int error_code); 65 void checkError(char const* prefix, int error_code);
66 void warn(char const*, int error_code); 66 void warn(char const*, int error_code);
67 67
68 - class Members 68 + class QPDF_DLL_PRIVATE Members
69 { 69 {
70 friend class Pl_Flate; 70 friend class Pl_Flate;
71 71
include/qpdf/Pl_QPDFTokenizer.hh
@@ -41,7 +41,7 @@ @@ -41,7 +41,7 @@
41 // QPDFObjectHandle::addTokenFilter. See QPDFObjectHandle.hh for 41 // QPDFObjectHandle::addTokenFilter. See QPDFObjectHandle.hh for
42 // details. 42 // details.
43 43
44 -class Pl_QPDFTokenizer: public Pipeline 44 +class QPDF_DLL_CLASS Pl_QPDFTokenizer: public Pipeline
45 { 45 {
46 public: 46 public:
47 // Whatever pipeline is provided as "next" will be set as the 47 // Whatever pipeline is provided as "next" will be set as the
@@ -60,7 +60,7 @@ class Pl_QPDFTokenizer: public Pipeline @@ -60,7 +60,7 @@ class Pl_QPDFTokenizer: public Pipeline
60 virtual void finish(); 60 virtual void finish();
61 61
62 private: 62 private:
63 - class Members 63 + class QPDF_DLL_PRIVATE Members
64 { 64 {
65 friend class Pl_QPDFTokenizer; 65 friend class Pl_QPDFTokenizer;
66 66
include/qpdf/Pl_RunLength.hh
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 24
25 #include <qpdf/Pipeline.hh> 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 public: 29 public:
30 enum action_e { a_encode, a_decode }; 30 enum action_e { a_encode, a_decode };
@@ -46,7 +46,7 @@ class Pl_RunLength: public Pipeline @@ -46,7 +46,7 @@ class Pl_RunLength: public Pipeline
46 46
47 enum state_e { st_top, st_copying, st_run }; 47 enum state_e { st_top, st_copying, st_run };
48 48
49 - class Members 49 + class QPDF_DLL_PRIVATE Members
50 { 50 {
51 friend class Pl_RunLength; 51 friend class Pl_RunLength;
52 52
include/qpdf/Pl_StdioFile.hh
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 // This pipeline is reusable. 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 public: 37 public:
38 // f is externally maintained; this class just writes to and 38 // f is externally maintained; this class just writes to and
@@ -48,7 +48,7 @@ class Pl_StdioFile: public Pipeline @@ -48,7 +48,7 @@ class Pl_StdioFile: public Pipeline
48 virtual void finish(); 48 virtual void finish();
49 49
50 private: 50 private:
51 - class Members 51 + class QPDF_DLL_PRIVATE Members
52 { 52 {
53 friend class Pl_StdioFile; 53 friend class Pl_StdioFile;
54 54
qpdf/test_driver.cc
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 3
4 #include <qpdf/QPDF.hh> 4 #include <qpdf/QPDF.hh>
5 5
  6 +#include <qpdf/BufferInputSource.hh>
6 #include <qpdf/Pl_Buffer.hh> 7 #include <qpdf/Pl_Buffer.hh>
7 #include <qpdf/Pl_Discard.hh> 8 #include <qpdf/Pl_Discard.hh>
8 #include <qpdf/Pl_Flate.hh> 9 #include <qpdf/Pl_Flate.hh>
@@ -2314,8 +2315,9 @@ test_60(QPDF&amp; pdf, char const* arg2) @@ -2314,8 +2315,9 @@ test_60(QPDF&amp; pdf, char const* arg2)
2314 static void 2315 static void
2315 test_61(QPDF& pdf, char const* arg2) 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 pdf.setAttemptRecovery(false); 2321 pdf.setAttemptRecovery(false);
2320 pdf.setSuppressWarnings(true); 2322 pdf.setSuppressWarnings(true);
2321 try { 2323 try {
@@ -2338,6 +2340,17 @@ test_61(QPDF&amp; pdf, char const* arg2) @@ -2338,6 +2340,17 @@ test_61(QPDF&amp; pdf, char const* arg2)
2338 } catch (std::runtime_error const&) { 2340 } catch (std::runtime_error const&) {
2339 std::cout << "Caught runtime_error as expected" << std::endl; 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 static void 2356 static void