2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-23 03:18:59 +00:00

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.
This commit is contained in:
Jay Berkenbilt 2022-04-10 09:29:11 -04:00
parent 90cfe80bac
commit 5525c93124
16 changed files with 52 additions and 29 deletions

View File

@ -156,9 +156,14 @@ CODING RULES
* Use QPDF_DLL on all methods that are to be exported in the shared * Use QPDF_DLL on all methods that are to be exported in the shared
library/DLL. Use QPDF_DLL_CLASS for all classes whose type library/DLL. Use QPDF_DLL_CLASS for all classes whose type
information is needed. This is important for exception classes and information is needed. This is important for classes that are used
it seems also for classes that are intended to be subclassed across as exceptions, subclassed, or tested with dynamic_cast across the
the shared library boundary. the shared object boundary (or "shared library boundary" -- we may
use either term in comments and documentation). In particular,
anything new derived from Pipeline or InputSource should be marked
with QPDF_DLL_CLASS, but we don't need to do it for QPDFObjectHelper
or QPDFDocumentHelper subclasses since there's no reason to use
dynamic_cast with those.
* Put private member variables in std::shared_ptr<Members> for all * Put private member variables in std::shared_ptr<Members> for all
public classes. Remember to use QPDF_DLL on ~Members(). Exception: public classes. Remember to use QPDF_DLL on ~Members(). Exception:

View File

@ -25,7 +25,7 @@
#include <qpdf/Buffer.hh> #include <qpdf/Buffer.hh>
#include <qpdf/InputSource.hh> #include <qpdf/InputSource.hh>
class BufferInputSource: public InputSource class QPDF_DLL_CLASS BufferInputSource: public InputSource
{ {
public: public:
// If own_memory is true, BufferInputSource will delete the buffer // If own_memory is true, BufferInputSource will delete the buffer
@ -54,7 +54,7 @@ class BufferInputSource: public InputSource
virtual void unreadCh(char ch); virtual void unreadCh(char ch);
private: private:
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class BufferInputSource; friend class BufferInputSource;

View File

@ -35,7 +35,7 @@
class FileInputSource; class FileInputSource;
class ClosedFileInputSource: public InputSource class QPDF_DLL_CLASS ClosedFileInputSource: public InputSource
{ {
public: public:
QPDF_DLL QPDF_DLL
@ -71,7 +71,7 @@ class ClosedFileInputSource: public InputSource
void before(); void before();
void after(); void after();
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class ClosedFileInputSource; friend class ClosedFileInputSource;

View File

@ -24,7 +24,7 @@
#include <qpdf/InputSource.hh> #include <qpdf/InputSource.hh>
class FileInputSource: public InputSource class QPDF_DLL_CLASS FileInputSource: public InputSource
{ {
public: public:
QPDF_DLL QPDF_DLL
@ -54,7 +54,7 @@ class FileInputSource: public InputSource
FileInputSource(FileInputSource const&) = delete; FileInputSource(FileInputSource const&) = delete;
FileInputSource& operator=(FileInputSource const&) = delete; FileInputSource& operator=(FileInputSource const&) = delete;
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class FileInputSource; friend class FileInputSource;

View File

@ -30,6 +30,9 @@
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
// Remember to use QPDF_DLL_CLASS on anything derived from InputSource
// so it will work with dynamic_cast across the shared object
// boundary.
class QPDF_DLL_CLASS InputSource class QPDF_DLL_CLASS InputSource
{ {
public: public:

View File

@ -50,6 +50,8 @@
#include <memory> #include <memory>
#include <string> #include <string>
// Remember to use QPDF_DLL_CLASS on anything derived from Pipeline so
// it will work with dynamic_cast across the shared object boundary.
class QPDF_DLL_CLASS Pipeline class QPDF_DLL_CLASS Pipeline
{ {
public: public:

View File

@ -39,7 +39,7 @@
#include <memory> #include <memory>
class Pl_Buffer: public Pipeline class QPDF_DLL_CLASS Pl_Buffer: public Pipeline
{ {
public: public:
QPDF_DLL QPDF_DLL
@ -71,7 +71,7 @@ class Pl_Buffer: public Pipeline
void getMallocBuffer(unsigned char** buf, size_t* len); void getMallocBuffer(unsigned char** buf, size_t* len);
private: private:
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_Buffer; friend class Pl_Buffer;

View File

@ -30,7 +30,7 @@
#include <qpdf/Pipeline.hh> #include <qpdf/Pipeline.hh>
class Pl_Concatenate: public Pipeline class QPDF_DLL_CLASS Pl_Concatenate: public Pipeline
{ {
public: public:
QPDF_DLL QPDF_DLL
@ -50,7 +50,7 @@ class Pl_Concatenate: public Pipeline
void manualFinish(); void manualFinish();
private: private:
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_Concatenate; friend class Pl_Concatenate;

View File

@ -28,7 +28,7 @@
#include <qpdf/Pipeline.hh> #include <qpdf/Pipeline.hh>
#include <qpdf/Types.h> #include <qpdf/Types.h>
class Pl_Count: public Pipeline class QPDF_DLL_CLASS Pl_Count: public Pipeline
{ {
public: public:
QPDF_DLL QPDF_DLL
@ -48,7 +48,7 @@ class Pl_Count: public Pipeline
unsigned char getLastChar() const; unsigned char getLastChar() const;
private: private:
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_Count; friend class Pl_Count;

View File

@ -31,7 +31,7 @@
// definition of size_t. // definition of size_t.
#include <jpeglib.h> #include <jpeglib.h>
class Pl_DCT: public Pipeline class QPDF_DLL_CLASS Pl_DCT: public Pipeline
{ {
public: public:
// Constructor for decompressing image data // Constructor for decompressing image data
@ -75,7 +75,7 @@ class Pl_DCT: public Pipeline
enum action_e { a_compress, a_decompress }; enum action_e { a_compress, a_decompress };
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_DCT; friend class Pl_DCT;

View File

@ -30,7 +30,7 @@
#include <qpdf/Pipeline.hh> #include <qpdf/Pipeline.hh>
class Pl_Discard: public Pipeline class QPDF_DLL_CLASS Pl_Discard: public Pipeline
{ {
public: public:
QPDF_DLL QPDF_DLL
@ -43,7 +43,7 @@ class Pl_Discard: public Pipeline
virtual void finish(); virtual void finish();
private: private:
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_Discard; friend class Pl_Discard;

View File

@ -26,7 +26,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
class Pl_Flate: public Pipeline class QPDF_DLL_CLASS Pl_Flate: public Pipeline
{ {
public: public:
static unsigned int const def_bufsize = 65536; static unsigned int const def_bufsize = 65536;
@ -65,7 +65,7 @@ class Pl_Flate: public Pipeline
void checkError(char const* prefix, int error_code); void checkError(char const* prefix, int error_code);
void warn(char const*, int error_code); void warn(char const*, int error_code);
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_Flate; friend class Pl_Flate;

View File

@ -41,7 +41,7 @@
// QPDFObjectHandle::addTokenFilter. See QPDFObjectHandle.hh for // QPDFObjectHandle::addTokenFilter. See QPDFObjectHandle.hh for
// details. // details.
class Pl_QPDFTokenizer: public Pipeline class QPDF_DLL_CLASS Pl_QPDFTokenizer: public Pipeline
{ {
public: public:
// Whatever pipeline is provided as "next" will be set as the // Whatever pipeline is provided as "next" will be set as the
@ -60,7 +60,7 @@ class Pl_QPDFTokenizer: public Pipeline
virtual void finish(); virtual void finish();
private: private:
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_QPDFTokenizer; friend class Pl_QPDFTokenizer;

View File

@ -24,7 +24,7 @@
#include <qpdf/Pipeline.hh> #include <qpdf/Pipeline.hh>
class Pl_RunLength: public Pipeline class QPDF_DLL_CLASS Pl_RunLength: public Pipeline
{ {
public: public:
enum action_e { a_encode, a_decode }; enum action_e { a_encode, a_decode };
@ -46,7 +46,7 @@ class Pl_RunLength: public Pipeline
enum state_e { st_top, st_copying, st_run }; enum state_e { st_top, st_copying, st_run };
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_RunLength; friend class Pl_RunLength;

View File

@ -32,7 +32,7 @@
// This pipeline is reusable. // This pipeline is reusable.
// //
class Pl_StdioFile: public Pipeline class QPDF_DLL_CLASS Pl_StdioFile: public Pipeline
{ {
public: public:
// f is externally maintained; this class just writes to and // f is externally maintained; this class just writes to and
@ -48,7 +48,7 @@ class Pl_StdioFile: public Pipeline
virtual void finish(); virtual void finish();
private: private:
class Members class QPDF_DLL_PRIVATE Members
{ {
friend class Pl_StdioFile; friend class Pl_StdioFile;

View File

@ -3,6 +3,7 @@
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/Pl_Buffer.hh> #include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_Discard.hh> #include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_Flate.hh> #include <qpdf/Pl_Flate.hh>
@ -2314,8 +2315,9 @@ test_60(QPDF& pdf, char const* arg2)
static void static void
test_61(QPDF& pdf, char const* arg2) test_61(QPDF& pdf, char const* arg2)
{ {
// Test to make sure exceptions can be caught properly across // Test to make sure type information is passed across shared
// shared library boundaries. // library boundaries. This includes exception handling, dynamic
// cast, and subclassing.
pdf.setAttemptRecovery(false); pdf.setAttemptRecovery(false);
pdf.setSuppressWarnings(true); pdf.setSuppressWarnings(true);
try { try {
@ -2338,6 +2340,17 @@ test_61(QPDF& pdf, char const* arg2)
} catch (std::runtime_error const&) { } catch (std::runtime_error const&) {
std::cout << "Caught runtime_error as expected" << std::endl; std::cout << "Caught runtime_error as expected" << std::endl;
} }
// Spot check RTTI for dynamic cast. We intend to have pipelines
// and input sources be testable, but adding comprehensive tests
// for everything doesn't add value as it wouldn't catch
// forgetting QPDF_DLL_CLASS on a new subclass.
BufferInputSource b("x", "y");
InputSource* is = &b;
assert(dynamic_cast<BufferInputSource*>(is) != nullptr);
Pl_Discard pd;
Pipeline* p = &pd;
assert(dynamic_cast<Pl_Discard*>(p) != nullptr);
} }
static void static void