2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 10:58:58 +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
library/DLL. Use QPDF_DLL_CLASS for all classes whose type
information is needed. This is important for exception classes and
it seems also for classes that are intended to be subclassed across
the shared library boundary.
information is needed. This is important for classes that are used
as exceptions, subclassed, or tested with dynamic_cast across the
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
public classes. Remember to use QPDF_DLL on ~Members(). Exception:

View File

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

View File

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

View File

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

View File

@ -30,6 +30,9 @@
#include <stdio.h>
#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
{
public:

View File

@ -50,6 +50,8 @@
#include <memory>
#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
{
public:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,7 +26,7 @@
#include <functional>
#include <memory>
class Pl_Flate: public Pipeline
class QPDF_DLL_CLASS Pl_Flate: public Pipeline
{
public:
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 warn(char const*, int error_code);
class Members
class QPDF_DLL_PRIVATE Members
{
friend class Pl_Flate;

View File

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

View File

@ -24,7 +24,7 @@
#include <qpdf/Pipeline.hh>
class Pl_RunLength: public Pipeline
class QPDF_DLL_CLASS Pl_RunLength: public Pipeline
{
public:
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 };
class Members
class QPDF_DLL_PRIVATE Members
{
friend class Pl_RunLength;

View File

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

View File

@ -3,6 +3,7 @@
#include <qpdf/QPDF.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_Flate.hh>
@ -2314,8 +2315,9 @@ test_60(QPDF& pdf, char const* arg2)
static void
test_61(QPDF& pdf, char const* arg2)
{
// Test to make sure exceptions can be caught properly across
// shared library boundaries.
// Test to make sure type information is passed across shared
// library boundaries. This includes exception handling, dynamic
// cast, and subclassing.
pdf.setAttemptRecovery(false);
pdf.setSuppressWarnings(true);
try {
@ -2338,6 +2340,17 @@ test_61(QPDF& pdf, char const* arg2)
} catch (std::runtime_error const&) {
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