diff --git a/CMakeLists.txt b/CMakeLists.txt index d5b9845..051b25e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.16) # also find the version number here. generate_auto_job also reads the # version from here. project(qpdf - VERSION 11.10.1 + VERSION 12.0.0 LANGUAGES C CXX) # Enable correct rpath handling for MacOSX @@ -120,7 +120,6 @@ if(NOT (BUILD_STATIC_LIBS OR BUILD_SHARED_LIBS)) endif() set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) -add_compile_definitions($<$:POINTERHOLDER_TRANSITION=4>) if(ENABLE_QTC) set(ENABLE_QTC_ARG) diff --git a/ChangeLog b/ChangeLog index b1adc76..01935c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2025-02-15 Jay Berkenbilt + * Disable PointerHolder by default. + +2025-02-15 Jay Berkenbilt + * 11.10.1: release * Detect cygwin as Windows for fix-qdf tests that don't work on diff --git a/cSpell.json b/cSpell.json index 4f9b3e0..2122d85 100644 --- a/cSpell.json +++ b/cSpell.json @@ -643,7 +643,6 @@ "submatches", "subparsers", "subramanyam", - "substract", "swversion", "sysnow", "sysroot", diff --git a/examples/pdf-custom-filter.cc b/examples/pdf-custom-filter.cc index e3cdf16..1a8f14e 100644 --- a/examples/pdf-custom-filter.cc +++ b/examples/pdf-custom-filter.cc @@ -179,7 +179,7 @@ class StreamReplacer: public QPDFObjectHandle::StreamDataProvider private: bool maybeReplace( - QPDFObjGen const& og, + QPDFObjGen og, QPDFObjectHandle& stream, Pipeline* pipeline, QPDFObjectHandle* dict_updates); @@ -204,10 +204,7 @@ StreamReplacer::StreamReplacer(QPDF* pdf) : bool StreamReplacer::maybeReplace( - QPDFObjGen const& og, - QPDFObjectHandle& stream, - Pipeline* pipeline, - QPDFObjectHandle* dict_updates) + QPDFObjGen og, QPDFObjectHandle& stream, Pipeline* pipeline, QPDFObjectHandle* dict_updates) { // As described in the class comments, this method is called twice. Before writing has started // pipeline is nullptr, and dict_updates is provided. In this mode, we figure out whether we diff --git a/include/qpdf/Buffer.hh b/include/qpdf/Buffer.hh index c988178..928821e 100644 --- a/include/qpdf/Buffer.hh +++ b/include/qpdf/Buffer.hh @@ -21,7 +21,6 @@ #define BUFFER_HH #include -#include // unused -- remove in qpdf 12 (see #785) #include #include @@ -47,15 +46,13 @@ class Buffer QPDF_DLL Buffer(std::string& content); - [[deprecated("Move Buffer or use Buffer::copy instead")]] QPDF_DLL Buffer(Buffer const&); - [[deprecated("Move Buffer or use Buffer::copy instead")]] QPDF_DLL Buffer& - operator=(Buffer const&); - QPDF_DLL Buffer(Buffer&&) noexcept; QPDF_DLL Buffer& operator=(Buffer&&) noexcept; QPDF_DLL + ~Buffer(); + QPDF_DLL size_t getSize() const; QPDF_DLL unsigned char const* getBuffer() const; @@ -66,29 +63,8 @@ class Buffer QPDF_DLL Buffer copy() const; - // Only used during CI testing. - // ABI: remove when removing copy constructor / assignment operator - static void setTestMode() noexcept; - private: - class Members - { - friend class Buffer; - - public: - QPDF_DLL - ~Members(); - - private: - Members(size_t size, unsigned char* buf, bool own_memory); - Members(std::string&& content); - Members(Members const&) = delete; - - std::string str; - bool own_memory; - size_t size; - unsigned char* buf; - }; + class Members; void copy(Buffer const&); diff --git a/include/qpdf/ClosedFileInputSource.hh b/include/qpdf/ClosedFileInputSource.hh index 6e819e6..b8f58fd 100644 --- a/include/qpdf/ClosedFileInputSource.hh +++ b/include/qpdf/ClosedFileInputSource.hh @@ -26,7 +26,6 @@ // merging large numbers of files. #include -#include // unused -- remove in qpdf 12 (see #785) #include diff --git a/include/qpdf/DLL.h b/include/qpdf/DLL.h index 2a2b0a4..d575784 100644 --- a/include/qpdf/DLL.h +++ b/include/qpdf/DLL.h @@ -25,14 +25,14 @@ #define QPDF_DLL_HH /* The first version of qpdf to include the version constants is 10.6.0. */ -#define QPDF_MAJOR_VERSION 11 -#define QPDF_MINOR_VERSION 10 -#define QPDF_PATCH_VERSION 1 +#define QPDF_MAJOR_VERSION 12 +#define QPDF_MINOR_VERSION 0 +#define QPDF_PATCH_VERSION 0 #ifdef QPDF_FUTURE -# define QPDF_VERSION "11.10.1+future" +# define QPDF_VERSION "12.0.0+future" #else -# define QPDF_VERSION "11.10.1" +# define QPDF_VERSION "12.0.0" #endif /* diff --git a/include/qpdf/InputSource.hh b/include/qpdf/InputSource.hh index 77fb9e2..37d1303 100644 --- a/include/qpdf/InputSource.hh +++ b/include/qpdf/InputSource.hh @@ -21,7 +21,6 @@ #define QPDF_INPUTSOURCE_HH #include -#include // unused -- remove in qpdf 12 (see #785) #include #include diff --git a/include/qpdf/JSON.hh b/include/qpdf/JSON.hh index 73b46d4..90fbce8 100644 --- a/include/qpdf/JSON.hh +++ b/include/qpdf/JSON.hh @@ -30,7 +30,6 @@ // is also a good reason not to use this as a general-purpose JSON package. #include -#include // unused -- remove in qpdf 12 (see #785) #include #include diff --git a/include/qpdf/Pipeline.hh b/include/qpdf/Pipeline.hh index b6696cc..d3ab189 100644 --- a/include/qpdf/Pipeline.hh +++ b/include/qpdf/Pipeline.hh @@ -37,7 +37,6 @@ #define PIPELINE_HH #include -#include // unused -- remove in qpdf 12 (see #785) #include #include diff --git a/include/qpdf/Pl_Buffer.hh b/include/qpdf/Pl_Buffer.hh index 9499497..7e275d0 100644 --- a/include/qpdf/Pl_Buffer.hh +++ b/include/qpdf/Pl_Buffer.hh @@ -31,7 +31,6 @@ #include #include -#include // unused -- remove in qpdf 12 (see #785) #include #include diff --git a/include/qpdf/Pl_QPDFTokenizer.hh b/include/qpdf/Pl_QPDFTokenizer.hh index bba177a..b2b77fc 100644 --- a/include/qpdf/Pl_QPDFTokenizer.hh +++ b/include/qpdf/Pl_QPDFTokenizer.hh @@ -23,7 +23,6 @@ #include #include -#include // unused -- remove in qpdf 12 (see #785) #include #include diff --git a/include/qpdf/PointerHolder.hh b/include/qpdf/PointerHolder.hh index 36cdccf..a9563a0 100644 --- a/include/qpdf/PointerHolder.hh +++ b/include/qpdf/PointerHolder.hh @@ -26,18 +26,12 @@ #define POINTERHOLDER_IS_SHARED_POINTER #ifndef POINTERHOLDER_TRANSITION - -// #define POINTERHOLDER_TRANSITION 0 to suppress this warning, and see below. -// See also https://qpdf.readthedocs.io/en/stable/design.html#smart-pointers -# warning "POINTERHOLDER_TRANSITION is not defined -- see qpdf/PointerHolder.hh" - -// undefined = define as 0 and issue a warning // 0 = no deprecation warnings, backward-compatible API // 1 = make PointerHolder(T*) explicit // 2 = warn for use of getPointer() and getRefcount() // 3 = warn for all use of PointerHolder // 4 = don't define PointerHolder at all -# define POINTERHOLDER_TRANSITION 0 +# define POINTERHOLDER_TRANSITION 4 #endif // !defined(POINTERHOLDER_TRANSITION) #if POINTERHOLDER_TRANSITION < 4 @@ -50,15 +44,19 @@ // interface and is mutually assignable with std::shared_ptr. Code // that uses containers of PointerHolder will require adjustment. +// In qpdf 11, a backward-compatible PointerHolder was provided with a +// warning if POINTERHOLDER_TRANSITION was not defined. Starting in +// qpdf 12, PointerHolder is absent if POINTERHOLDER_TRANSITION is not +// defined. In a future version of qpdf, PointerHolder will be removed +// outright if it becomes inconvenient to keep it around. + // *** HOW TO TRANSITION *** // The symbol POINTERHOLDER_TRANSITION can be defined to help you // transition your code away from PointerHolder. You can define it // before including any qpdf header files or including its definition // in your build configuration. If not defined, it automatically gets -// defined to 0 (with a warning), which enables full backward -// compatibility. That way, you don't have to take action for your -// code to continue to work. +// defined to 4, which excludes PointerHolder entirely. // If you want to work gradually to transition your code away from // PointerHolder, you can define POINTERHOLDER_TRANSITION and fix the @@ -123,7 +121,8 @@ // POINTERHOLDER_TRANSITION = 4 // -// Suppress definition of the PointerHolder type entirely. +// Suppress definition of the PointerHolder type entirely. This is +// the default behavior starting with qpdf 12. // CONST BEHAVIOR diff --git a/include/qpdf/QIntC.hh b/include/qpdf/QIntC.hh index 3558d81..f0cf411 100644 --- a/include/qpdf/QIntC.hh +++ b/include/qpdf/QIntC.hh @@ -278,10 +278,9 @@ namespace QIntC // QIntC = qpdf Integer Conversion QIntC::range_check_error(cur, delta); } - // ABI: fix spelling error in function name. Also remove "substract" from spelling dictionary. template void - range_check_substract_error(T const& cur, T const& delta) + range_check_subtract_error(T const& cur, T const& delta) { if ((delta > 0) && ((std::numeric_limits::min() + delta) > cur)) { std::ostringstream msg; @@ -297,15 +296,14 @@ namespace QIntC // QIntC = qpdf Integer Conversion } } - // ABI: fix typo in function name template inline void - range_check_substract(T const& cur, T const& delta) + range_check_subtract(T const& cur, T const& delta) { if ((delta >= 0) == (cur >= 0)) { return; } - QIntC::range_check_substract_error(cur, delta); + QIntC::range_check_subtract_error(cur, delta); } }; // namespace QIntC diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 6353522..0e79967 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -367,13 +367,13 @@ class QPDF // Retrieve an object by object ID and generation. Returns an indirect reference to it. The // getObject() methods were added for qpdf 11. QPDF_DLL - QPDFObjectHandle getObject(QPDFObjGen const&); + QPDFObjectHandle getObject(QPDFObjGen); QPDF_DLL QPDFObjectHandle getObject(int objid, int generation); // These are older methods, but there is no intention to deprecate // them. QPDF_DLL - QPDFObjectHandle getObjectByObjGen(QPDFObjGen const&); + QPDFObjectHandle getObjectByObjGen(QPDFObjGen); QPDF_DLL QPDFObjectHandle getObjectByID(int objid, int generation); @@ -387,14 +387,14 @@ class QPDF // object is treated as a null object. To replace a reserved object, call replaceReserved // instead. QPDF_DLL - void replaceObject(QPDFObjGen const& og, QPDFObjectHandle); + void replaceObject(QPDFObjGen og, QPDFObjectHandle); QPDF_DLL void replaceObject(int objid, int generation, QPDFObjectHandle); // Swap two objects given by ID. Prior to qpdf 10.2.1, existing QPDFObjectHandle instances that // reference them objects not notice the swap, but this was fixed in 10.2.1. QPDF_DLL - void swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2); + void swapObjects(QPDFObjGen og1, QPDFObjGen og2); QPDF_DLL void swapObjects(int objid1, int generation1, int objid2, int generation2); @@ -694,7 +694,7 @@ class QPDF // into the array returned by getAllPages() for that page. An exception is thrown if the page is // not found. QPDF_DLL - int findPage(QPDFObjGen const& og); + int findPage(QPDFObjGen og); QPDF_DLL int findPage(QPDFObjectHandle& page); @@ -859,7 +859,7 @@ class QPDF static bool pipeStreamData( QPDF* qpdf, - QPDFObjGen const& og, + QPDFObjGen og, qpdf_offset_t offset, size_t length, QPDFObjectHandle dict, @@ -964,7 +964,7 @@ class QPDF ForeignStreamData( std::shared_ptr encp, std::shared_ptr file, - QPDFObjGen const& foreign_og, + QPDFObjGen foreign_og, qpdf_offset_t offset, size_t length, QPDFObjectHandle local_dict); @@ -1002,7 +1002,7 @@ class QPDF friend class QPDF; public: - StringDecrypter(QPDF* qpdf, QPDFObjGen const& og); + StringDecrypter(QPDF* qpdf, QPDFObjGen og); ~StringDecrypter() override = default; void decryptString(std::string& val) override; @@ -1014,7 +1014,7 @@ class QPDF class ResolveRecorder { public: - ResolveRecorder(QPDF* qpdf, QPDFObjGen const& og) : + ResolveRecorder(QPDF* qpdf, QPDFObjGen og) : qpdf(qpdf), iter(qpdf->m->resolving.insert(og).first) { @@ -1054,14 +1054,14 @@ class QPDF void insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2); void insertFreeXrefEntry(QPDFObjGen); void insertReconstructedXrefEntry(int obj, qpdf_offset_t f1, int f2); - void setLastObjectDescription(std::string const& description, QPDFObjGen const& og); + void setLastObjectDescription(std::string const& description, QPDFObjGen og); QPDFObjectHandle readTrailer(); QPDFObjectHandle readObject(std::string const& description, QPDFObjGen og); void readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset); void validateStreamLineEnd(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset); QPDFObjectHandle readObjectInStream(std::shared_ptr& input, int obj); size_t recoverStreamLength( - std::shared_ptr input, QPDFObjGen const& og, qpdf_offset_t stream_offset); + std::shared_ptr input, QPDFObjGen og, qpdf_offset_t stream_offset); QPDFTokenizer::Token readToken(InputSource&, size_t max_len = 0); QPDFObjectHandle readObjectAtOffset( @@ -1075,15 +1075,15 @@ class QPDF void resolveObjectsInStream(int obj_stream_number); void stopOnError(std::string const& message); QPDFObjGen nextObjGen(); - QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr const&); + QPDFObjectHandle newIndirect(QPDFObjGen, std::shared_ptr const&); QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr const& obj); - bool isCached(QPDFObjGen const& og); - bool isUnresolved(QPDFObjGen const& og); + bool isCached(QPDFObjGen og); + bool isUnresolved(QPDFObjGen og); std::shared_ptr getObjectForParser(int id, int gen, bool parse_pdf); std::shared_ptr getObjectForJSON(int id, int gen); void removeObject(QPDFObjGen og); void updateCache( - QPDFObjGen const& og, + QPDFObjGen og, std::shared_ptr const& object, qpdf_offset_t end_before_space, qpdf_offset_t end_after_space); @@ -1100,7 +1100,7 @@ class QPDF // Calls finish() on the pipeline when done but does not delete it bool pipeStreamData( - QPDFObjGen const& og, + QPDFObjGen og, qpdf_offset_t offset, size_t length, QPDFObjectHandle dict, @@ -1113,7 +1113,7 @@ class QPDF std::shared_ptr encp, std::shared_ptr file, QPDF& qpdf_for_warning, - QPDFObjGen const& og, + QPDFObjGen og, qpdf_offset_t offset, size_t length, QPDFObjectHandle dict, @@ -1174,8 +1174,8 @@ class QPDF interpretCF(std::shared_ptr encp, QPDFObjectHandle); void initializeEncryption(); static std::string - getKeyForObject(std::shared_ptr encp, QPDFObjGen const& og, bool use_aes); - void decryptString(std::string&, QPDFObjGen const& og); + getKeyForObject(std::shared_ptr encp, QPDFObjGen og, bool use_aes); + void decryptString(std::string&, QPDFObjGen og); static std::string compute_encryption_key_from_password(std::string const& password, EncryptionData const& data); static std::string @@ -1187,7 +1187,7 @@ class QPDF std::shared_ptr file, QPDF& qpdf_for_warning, Pipeline*& pipeline, - QPDFObjGen const& og, + QPDFObjGen og, QPDFObjectHandle& stream_dict, std::unique_ptr& heap); @@ -1408,7 +1408,7 @@ class QPDF void readHSharedObject(BitStream); void readHGeneric(BitStream, HGeneric&); qpdf_offset_t maxEnd(ObjUser const& ou); - qpdf_offset_t getLinearizationOffset(QPDFObjGen const&); + qpdf_offset_t getLinearizationOffset(QPDFObjGen); QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, std::map const& object_stream_data); QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, QPDFWriter::ObjTable const& obj); diff --git a/include/qpdf/QPDFObjGen.hh b/include/qpdf/QPDFObjGen.hh index c37531b..3553ff3 100644 --- a/include/qpdf/QPDFObjGen.hh +++ b/include/qpdf/QPDFObjGen.hh @@ -21,8 +21,10 @@ #define QPDFOBJGEN_HH #include + #include #include +#include class QPDFObjectHandle; class QPDFObjectHelper; @@ -33,13 +35,10 @@ class QPDFObjectHelper; class QPDFObjGen { public: - // ABI: change to default. QPDF_DLL - QPDFObjGen() - { - } + QPDFObjGen() = default; QPDF_DLL - explicit QPDFObjGen(int obj, int gen) : + QPDFObjGen(int obj, int gen) : obj(obj), gen(gen) { @@ -48,19 +47,19 @@ class QPDFObjGen bool operator<(QPDFObjGen const& rhs) const { - return (obj < rhs.obj) || ((obj == rhs.obj) && (gen < rhs.gen)); + return (obj < rhs.obj) || (obj == rhs.obj && gen < rhs.gen); } QPDF_DLL bool operator==(QPDFObjGen const& rhs) const { - return (obj == rhs.obj) && (gen == rhs.gen); + return obj == rhs.obj && gen == rhs.gen; } QPDF_DLL bool operator!=(QPDFObjGen const& rhs) const { - return (obj != rhs.obj) || (gen != rhs.gen); + return !(*this == rhs); } QPDF_DLL int @@ -81,9 +80,18 @@ class QPDFObjGen return obj != 0; } QPDF_DLL - std::string unparse(char separator = ',') const; + std::string + unparse(char separator = ',') const + { + return std::to_string(obj) + separator + std::to_string(gen); + } QPDF_DLL - friend std::ostream& operator<<(std::ostream& os, const QPDFObjGen& og); + friend std::ostream& + operator<<(std::ostream& os, QPDFObjGen og) + { + os << og.obj << "," << og.gen; + return os; + } // Convenience class for loop detection when processing objects. // diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index cd0f91c..80bd797 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -23,27 +23,22 @@ #ifndef QPDFOBJECTHANDLE_HH #define QPDFOBJECTHANDLE_HH -#ifdef QPDF_FUTURE -# include -#else - -# include -# include -# include - -# include -# include -# include -# include -# include -# include - -# include -# include -# include -# include // unused -- remove in qpdf 12 (see #785) -# include -# include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include class Pipeline; class QPDF; @@ -296,53 +291,58 @@ class QPDFObjectHandle QPDF_DLL QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default; + QPDF_DLL + QPDFObjectHandle(QPDFObjectHandle&&) = default; + QPDF_DLL + QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default; + // Return true if the QPDFObjectHandle is initialized. This allows object handles to be used in // if statements with initializer. QPDF_DLL explicit inline operator bool() const noexcept; - [[deprecated("use operator bool()")]] QPDF_DLL inline bool isInitialized() const; + [[deprecated("use operator bool()")]] QPDF_DLL inline bool isInitialized() const noexcept; // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying // object, meaning that changes to one are reflected in the other, or "if you paint one, the // other one changes color." This does not perform a structural comparison of the contents of // the objects. QPDF_DLL - bool isSameObjectAs(QPDFObjectHandle const&) const; + bool isSameObjectAs(QPDFObjectHandle const&) const noexcept; // Return type code and type name of underlying object. These are useful for doing rapid type // tests (like switch statements) or for testing and debugging. QPDF_DLL - qpdf_object_type_e getTypeCode(); + qpdf_object_type_e getTypeCode() const; QPDF_DLL - char const* getTypeName(); + char const* getTypeName() const; // Exactly one of these will return true for any initialized object. Operator and InlineImage // are only allowed in content streams. QPDF_DLL - bool isBool(); + bool isBool() const; QPDF_DLL - bool isNull(); + bool isNull() const; QPDF_DLL - bool isInteger(); + bool isInteger() const; QPDF_DLL - bool isReal(); + bool isReal() const; QPDF_DLL - bool isName(); + bool isName() const; QPDF_DLL - bool isString(); + bool isString() const; QPDF_DLL - bool isOperator(); + bool isOperator() const; QPDF_DLL - bool isInlineImage(); + bool isInlineImage() const; QPDF_DLL - bool isArray(); + bool isArray() const; QPDF_DLL - bool isDictionary(); + bool isDictionary() const; QPDF_DLL - bool isStream(); + bool isStream() const; QPDF_DLL - bool isReserved(); + bool isReserved() const; // True for objects that are direct nulls. Does not attempt to resolve objects. This is intended // for internal use, but it can be used as an efficient way to check for nulls that are not @@ -357,23 +357,23 @@ class QPDFObjectHandle // This returns true for indirect objects from a QPDF that has been destroyed. Trying unparse // such an object will throw a logic_error. QPDF_DLL - bool isDestroyed(); + bool isDestroyed() const; // True for everything except array, dictionary, stream, word, and inline image. QPDF_DLL - bool isScalar(); + bool isScalar() const; // True if the object is a name object representing the provided name. QPDF_DLL - bool isNameAndEquals(std::string const& name); + bool isNameAndEquals(std::string const& name) const; // True if the object is a dictionary of the specified type and subtype, if any. QPDF_DLL - bool isDictionaryOfType(std::string const& type, std::string const& subtype = ""); + bool isDictionaryOfType(std::string const& type, std::string const& subtype = "") const; // True if the object is a stream of the specified type and subtype, if any. QPDF_DLL - bool isStreamOfType(std::string const& type, std::string const& subtype = ""); + bool isStreamOfType(std::string const& type, std::string const& subtype = "") const; // Public factory methods @@ -418,7 +418,7 @@ class QPDFObjectHandle // object was created without parsing. If the object is in a stream, the offset is from the // beginning of the stream. Otherwise, the offset is from the beginning of the file. QPDF_DLL - qpdf_offset_t getParsedOffset(); + qpdf_offset_t getParsedOffset() const; // Older method: stream_or_array should be the value of /Contents from a page object. It's more // convenient to just call QPDFPageObjectHelper::parsePageContents on the page object, and error @@ -590,7 +590,7 @@ class QPDFObjectHandle QPDF_DLL void setObjectDescription(QPDF* owning_qpdf, std::string const& object_description); QPDF_DLL - bool hasObjectDescription(); + bool hasObjectDescription() const; // Accessor methods // @@ -640,57 +640,57 @@ class QPDFObjectHandle // Methods for bool objects QPDF_DLL - bool getBoolValue(); + bool getBoolValue() const; QPDF_DLL - bool getValueAsBool(bool&); + bool getValueAsBool(bool&) const; // Methods for integer objects. Note: if an integer value is too big (too far away from zero in // either direction) to fit in the requested return type, the maximum or minimum value for that // return type may be returned. For example, on a system with 32-bit int, a numeric object with // a value of 2^40 (or anything too big for 32 bits) will be returned as INT_MAX. QPDF_DLL - long long getIntValue(); + long long getIntValue() const; QPDF_DLL - bool getValueAsInt(long long&); + bool getValueAsInt(long long&) const; QPDF_DLL - int getIntValueAsInt(); + int getIntValueAsInt() const; QPDF_DLL - bool getValueAsInt(int&); + bool getValueAsInt(int&) const; QPDF_DLL - unsigned long long getUIntValue(); + unsigned long long getUIntValue() const; QPDF_DLL - bool getValueAsUInt(unsigned long long&); + bool getValueAsUInt(unsigned long long&) const; QPDF_DLL - unsigned int getUIntValueAsUInt(); + unsigned int getUIntValueAsUInt() const; QPDF_DLL - bool getValueAsUInt(unsigned int&); + bool getValueAsUInt(unsigned int&) const; // Methods for real objects QPDF_DLL - std::string getRealValue(); + std::string getRealValue() const; QPDF_DLL - bool getValueAsReal(std::string&); + bool getValueAsReal(std::string&) const; // Methods that work for both integer and real objects QPDF_DLL - bool isNumber(); + bool isNumber() const; QPDF_DLL - double getNumericValue(); + double getNumericValue() const; QPDF_DLL - bool getValueAsNumber(double&); + bool getValueAsNumber(double&) const; // Methods for name objects. The returned name value is in qpdf's canonical form with all // escaping resolved. See comments for newName() for details. QPDF_DLL - std::string getName(); + std::string getName() const; QPDF_DLL - bool getValueAsName(std::string&); + bool getValueAsName(std::string&) const; // Methods for string objects QPDF_DLL - std::string getStringValue(); + std::string getStringValue() const; QPDF_DLL - bool getValueAsString(std::string&); + bool getValueAsString(std::string&) const; // If a string starts with the UTF-16 marker, it is converted from UTF-16 to UTF-8. Otherwise, // it is treated as a string encoded with PDF Doc Encoding. PDF Doc Encoding is identical to @@ -698,19 +698,19 @@ class QPDFObjectHandle // to Unicode. QPDF versions prior to version 8.0.0 erroneously left characters in that range // unmapped. QPDF_DLL - std::string getUTF8Value(); + std::string getUTF8Value() const; QPDF_DLL - bool getValueAsUTF8(std::string&); + bool getValueAsUTF8(std::string&) const; // Methods for content stream objects QPDF_DLL - std::string getOperatorValue(); + std::string getOperatorValue() const; QPDF_DLL - bool getValueAsOperator(std::string&); + bool getValueAsOperator(std::string&) const; QPDF_DLL - std::string getInlineImageValue(); + std::string getInlineImageValue() const; QPDF_DLL - bool getValueAsInlineImage(std::string&); + bool getValueAsInlineImage(std::string&) const; // Methods for array objects; see also name and array objects. @@ -725,26 +725,26 @@ class QPDFObjectHandle QPDFArrayItems aitems(); QPDF_DLL - int getArrayNItems(); + int getArrayNItems() const; QPDF_DLL - QPDFObjectHandle getArrayItem(int n); + QPDFObjectHandle getArrayItem(int n) const; // Note: QPDF arrays internally optimize memory for arrays containing lots of nulls. Calling // getArrayAsVector may cause a lot of memory to be allocated for very large arrays with lots of // nulls. QPDF_DLL - std::vector getArrayAsVector(); + std::vector getArrayAsVector() const; QPDF_DLL - bool isRectangle(); + bool isRectangle() const; // If the array is an array of four numeric values, return as a rectangle. Otherwise, return the // rectangle [0, 0, 0, 0] QPDF_DLL - Rectangle getArrayAsRectangle(); + Rectangle getArrayAsRectangle() const; QPDF_DLL - bool isMatrix(); + bool isMatrix() const; // If the array is an array of six numeric values, return as a matrix. Otherwise, return the // matrix [1, 0, 0, 1, 0, 0] QPDF_DLL - Matrix getArrayAsMatrix(); + Matrix getArrayAsMatrix() const; // Methods for dictionary objects. In all dictionary methods, keys are specified/represented as // canonical name strings starting with a leading slash and not containing any PDF syntax @@ -764,27 +764,27 @@ class QPDFObjectHandle // Return true if key is present. Keys with null values are treated as if they are not present. // This is as per the PDF spec. QPDF_DLL - bool hasKey(std::string const&); + bool hasKey(std::string const&) const; // Return the value for the key. If the key is not present, null is returned. QPDF_DLL - QPDFObjectHandle getKey(std::string const&); + QPDFObjectHandle getKey(std::string const&) const; // If the object is null, return null. Otherwise, call getKey(). This makes it easier to access // lower-level dictionaries, as in // auto font = page.getKeyIfDict("/Resources").getKeyIfDict("/Font"); QPDF_DLL - QPDFObjectHandle getKeyIfDict(std::string const&); + QPDFObjectHandle getKeyIfDict(std::string const&) const; // Return all keys. Keys with null values are treated as if they are not present. This is as // per the PDF spec. QPDF_DLL - std::set getKeys(); + std::set getKeys() const; // Return dictionary as a map. Entries with null values are included. QPDF_DLL - std::map getDictAsMap(); + std::map getDictAsMap() const; // Methods for name and array objects. The name value is in qpdf's canonical form with all // escaping resolved. See comments for newName() for details. QPDF_DLL - bool isOrHasName(std::string const&); + bool isOrHasName(std::string const&) const; // Make all resources in a resource dictionary indirect. This just goes through all entries of // top-level subdictionaries and converts any direct objects to indirect objects. This can be @@ -834,7 +834,7 @@ class QPDFObjectHandle // method returns a set of all the keys in all top-level subdictionaries. For resources // dictionaries, this is the collection of names that may be referenced in the content stream. QPDF_DLL - std::set getResourceNames(); + std::set getResourceNames() const; // Find a unique name within a resource dictionary starting with a given prefix. This method // works by appending a number to the given prefix. It searches starting with min_suffix and @@ -849,7 +849,7 @@ class QPDFObjectHandle std::string getUniqueResourceName( std::string const& prefix, int& min_suffix, - std::set* resource_names = nullptr); + std::set* resource_names = nullptr) const; // A QPDFObjectHandle has an owning QPDF if it is associated with ("owned by") a specific QPDF // object. Indirect objects always have an owning QPDF. Direct objects that are read from the @@ -969,7 +969,7 @@ class QPDFObjectHandle // Methods for stream objects QPDF_DLL - QPDFObjectHandle getDict(); + QPDFObjectHandle getDict() const; // By default, or if true passed, QPDFWriter will attempt to filter a stream based on decode // level, whether compression is enabled, and its ability to filter. Passing false will prevent @@ -1158,12 +1158,12 @@ class QPDFObjectHandle inline int getGeneration() const; QPDF_DLL - std::string unparse(); + std::string unparse() const; QPDF_DLL - std::string unparseResolved(); + std::string unparseResolved() const; // For strings only, force binary representation. Otherwise, same as unparse. QPDF_DLL - std::string unparseBinary(); + std::string unparseBinary() const; // Return encoded as JSON. The constant JSON::LATEST can be used to specify the latest available // JSON version. The JSON is generated as follows: @@ -1197,19 +1197,14 @@ class QPDFObjectHandle // the object. The effect of dereference_indirect applies only to this object. It is not // recursive. QPDF_DLL - JSON getJSON(int json_version, bool dereference_indirect = false); + JSON getJSON(int json_version, bool dereference_indirect = false) const; // Write the object encoded as JSON to a pipeline. This is equivalent to, but more efficient // than, calling getJSON(json_version, dereference_indirect).write(p, depth). See the // documentation for getJSON and JSON::write for further detail. QPDF_DLL - void - writeJSON(int json_version, Pipeline* p, bool dereference_indirect = false, size_t depth = 0); - - // Deprecated version uses v1 for backward compatibility. - // ABI: remove for qpdf 12 - [[deprecated("Use getJSON(int version)")]] QPDF_DLL JSON - getJSON(bool dereference_indirect = false); + void writeJSON( + int json_version, Pipeline* p, bool dereference_indirect = false, size_t depth = 0) const; // This method can be called on a stream to get a more extended JSON representation of the // stream that includes the stream's data. The JSON object returned is always a dictionary whose @@ -1262,7 +1257,7 @@ class QPDFObjectHandle // normally from the file have descriptions. See comments on setObjectDescription for additional // details. QPDF_DLL - void warnIfPossible(std::string const& warning); + void warnIfPossible(std::string const& warning) const; // Provide access to specific classes for recursive disconnected(). class DisconnectAccess @@ -1285,55 +1280,55 @@ class QPDFObjectHandle void assertInitialized() const; QPDF_DLL - void assertNull(); + void assertNull() const; QPDF_DLL - void assertBool(); + void assertBool() const; QPDF_DLL - void assertInteger(); + void assertInteger() const; QPDF_DLL - void assertReal(); + void assertReal() const; QPDF_DLL - void assertName(); + void assertName() const; QPDF_DLL - void assertString(); + void assertString() const; QPDF_DLL - void assertOperator(); + void assertOperator() const; QPDF_DLL - void assertInlineImage(); + void assertInlineImage() const; QPDF_DLL - void assertArray(); + void assertArray() const; QPDF_DLL - void assertDictionary(); + void assertDictionary() const; QPDF_DLL - void assertStream(); + void assertStream() const; QPDF_DLL - void assertReserved(); + void assertReserved() const; QPDF_DLL - void assertIndirect(); + void assertIndirect() const; QPDF_DLL - void assertScalar(); + void assertScalar() const; QPDF_DLL - void assertNumber(); + void assertNumber() const; // The isPageObject method checks the /Type key of the object. This is not completely reliable // as there are some otherwise valid files whose /Type is wrong for page objects. qpdf is // slightly more accepting but may still return false here when treating the object as a page // would work. Use this sparingly. QPDF_DLL - bool isPageObject(); + bool isPageObject() const; QPDF_DLL - bool isPagesObject(); + bool isPagesObject() const; QPDF_DLL - void assertPageObject(); + void assertPageObject() const; QPDF_DLL - bool isFormXObject(); + bool isFormXObject() const; // Indicate if this is an image. If exclude_imagemask is true, don't count image masks as // images. QPDF_DLL - bool isImage(bool exclude_imagemask = true); + bool isImage(bool exclude_imagemask = true) const; // The following methods do not form part of the public API and are for internal use only. @@ -1362,7 +1357,7 @@ class QPDFObjectHandle return obj.get(); } - void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false); + void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false) const; private: QPDF_Array* asArray() const; @@ -1401,7 +1396,7 @@ class QPDFObjectHandle std::shared_ptr obj; }; -# ifndef QPDF_NO_QPDF_STRING +#ifndef QPDF_NO_QPDF_STRING // This is short for QPDFObjectHandle::parse, so you can do // auto oh = "<< /Key (value) >>"_qpdf; @@ -1410,14 +1405,14 @@ class QPDFObjectHandle // from being here. /* clang-format off */ -// Disable formatting for this declaration: emacs font-lock in cc-mode (as of 28.1) treats the rest -// of the file as a string if clang-format removes the space after "operator", and as of -// clang-format 15, there's no way to prevent it from doing so. -QPDF_DLL -QPDFObjectHandle operator ""_qpdf(char const* v, size_t len); + // Disable formatting for this declaration: emacs font-lock in cc-mode (as of 28.1) treats the rest + // of the file as a string if clang-format removes the space after "operator", and as of + // clang-format 15, there's no way to prevent it from doing so. + QPDF_DLL + QPDFObjectHandle operator ""_qpdf(char const* v, size_t len); /* clang-format on */ -# endif // QPDF_NO_QPDF_STRING +#endif // QPDF_NO_QPDF_STRING class QPDFObjectHandle::QPDFDictItems { @@ -1634,7 +1629,7 @@ QPDFObjectHandle::isIndirect() const } inline bool -QPDFObjectHandle::isInitialized() const +QPDFObjectHandle::isInitialized() const noexcept { return obj != nullptr; } @@ -1645,5 +1640,4 @@ operator bool() const noexcept return static_cast(obj); } -#endif // QPDF_FUTURE #endif // QPDFOBJECTHANDLE_HH diff --git a/include/qpdf/QPDFObjectHandle_future.hh b/include/qpdf/QPDFObjectHandle_future.hh index 539bb52..e69de29 100644 --- a/include/qpdf/QPDFObjectHandle_future.hh +++ b/include/qpdf/QPDFObjectHandle_future.hh @@ -1,1648 +0,0 @@ -// Copyright (c) 2005-2021 Jay Berkenbilt -// Copyright (c) 2022-2025 Jay Berkenbilt and Manfred Holger -// -// This file is part of qpdf. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Versions of qpdf prior to version 7 were released under the terms -// of version 2.0 of the Artistic License. At your option, you may -// continue to consider qpdf to be licensed under those terms. Please -// see the manual for additional information. - -#ifndef QPDFOBJECTHANDLE_FUTURE_HH -#define QPDFOBJECTHANDLE_FUTURE_HH - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -class Pipeline; -class QPDF; -class QPDF_Array; -class QPDF_Bool; -class QPDF_Dictionary; -class QPDF_InlineImage; -class QPDF_Integer; -class QPDF_Name; -class QPDF_Null; -class QPDF_Operator; -class QPDF_Real; -class QPDF_Reserved; -class QPDF_Stream; -class QPDF_String; -class QPDFObject; -class QPDFTokenizer; -class QPDFExc; -class Pl_QPDFTokenizer; -class QPDFMatrix; -class QPDFParser; - -class QPDFObjectHandle -{ - friend class QPDFParser; - - public: - // This class is used by replaceStreamData. It provides an alternative way of associating - // stream data with a stream. See comments on replaceStreamData and newStream for additional - // details. - class QPDF_DLL_CLASS StreamDataProvider - { - public: - QPDF_DLL - StreamDataProvider(bool supports_retry = false); - - QPDF_DLL - virtual ~StreamDataProvider(); - // The implementation of this function must write stream data to the given pipeline. The - // stream data must conform to whatever filters are explicitly associated with the stream. - // QPDFWriter may, in some cases, add compression, but if it does, it will update the - // filters as needed. Every call to provideStreamData for a given stream must write the same - // data. Note that, when writing linearized files, qpdf will call your provideStreamData - // twice, and if it generates different output, you risk generating invalid output or having - // qpdf throw an exception. The object ID and generation passed to this method are those - // that belong to the stream on behalf of which the provider is called. They may be ignored - // or used by the implementation for indexing or other purposes. This information is made - // available just to make it more convenient to use a single StreamDataProvider object to - // provide data for multiple streams. - - // A few things to keep in mind: - // - // * Stream data providers must not modify any objects since they may be called after some - // parts of the file have already been written. - // - // * Since qpdf may call provideStreamData multiple times when writing linearized files, if - // the work done by your stream data provider is slow or computationally intensive, you - // might want to implement your own cache. - // - // * Once you have called replaceStreamData, the original stream data is no longer directly - // accessible from the stream, but this is easy to work around by copying the stream to - // a separate QPDF object. The qpdf library implements this very efficiently without - // actually making a copy of the stream data. You can find examples of this pattern in - // some of the examples, including pdf-custom-filter.cc and pdf-invert-images.cc. - - // Prior to qpdf 10.0.0, it was not possible to handle errors the way pipeStreamData does or - // to pass back success. Starting in qpdf 10.0.0, those capabilities have been added by - // allowing an alternative provideStreamData to be implemented. You must implement at least - // one of the versions of provideStreamData below. If you implement the version that - // supports retry and returns a value, you should pass true as the value of supports_retry - // in the base class constructor. This will cause the library to call that version of the - // method, which should also return a boolean indicating whether it ran without errors. - QPDF_DLL - virtual void provideStreamData(QPDFObjGen const& og, Pipeline* pipeline); - QPDF_DLL - virtual bool provideStreamData( - QPDFObjGen const& og, Pipeline* pipeline, bool suppress_warnings, bool will_retry); - QPDF_DLL virtual void provideStreamData(int objid, int generation, Pipeline* pipeline); - QPDF_DLL virtual bool provideStreamData( - int objid, int generation, Pipeline* pipeline, bool suppress_warnings, bool will_retry); - QPDF_DLL - bool supportsRetry(); - - private: - bool supports_retry; - }; - - // The TokenFilter class provides a way to filter content streams in a lexically aware fashion. - // TokenFilters can be attached to streams using the addTokenFilter or addContentTokenFilter - // methods or can be applied on the spot by filterPageContents. You may also use - // Pl_QPDFTokenizer directly if you need full control. - // - // The handleToken method is called for each token, including the eof token, and then handleEOF - // is called at the very end. Handlers may call write (or writeToken) to pass data downstream. - // Please see examples/pdf-filter-tokens.cc and examples/pdf-count-strings.cc for examples of - // using TokenFilters. - // - // Please note that when you call token.getValue() on a token of type tt_string or tt_name, you - // get the canonical, "parsed" representation of the token. For a string, this means that there - // are no delimiters, and for a name, it means that all escaping (# followed by two hex digits) - // has been resolved. qpdf's internal representation of a name includes the leading slash. As - // such, you can't write the value of token.getValue() directly to output that is supposed to be - // valid PDF syntax. If you want to do that, you need to call writeToken() instead, or you can - // retrieve the token as it appeared in the input with token.getRawValue(). To construct a new - // string or name token from a canonical representation, use - // QPDFTokenizer::Token(QPDFTokenizer::tt_string, "parsed-str") or - // QPDFTokenizer::Token(QPDFTokenizer::tt_name, - // "/Canonical-Name"). Tokens created this way won't have a PDF-syntax raw value, but you can - // still write them with writeToken(). Example: - // writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_name, "/text/plain")) - // would write `/text#2fplain`, and - // writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_string, "a\\(b")) would write `(a\(b)`. - class QPDF_DLL_CLASS TokenFilter - { - public: - QPDF_DLL - TokenFilter() = default; - QPDF_DLL - virtual ~TokenFilter() = default; - virtual void handleToken(QPDFTokenizer::Token const&) = 0; - QPDF_DLL - virtual void handleEOF(); - - class PipelineAccessor - { - friend class Pl_QPDFTokenizer; - - private: - static void - setPipeline(TokenFilter* f, Pipeline* p) - { - f->setPipeline(p); - } - }; - - protected: - QPDF_DLL - void write(char const* data, size_t len); - QPDF_DLL - void write(std::string const& str); - QPDF_DLL - void writeToken(QPDFTokenizer::Token const&); - - private: - QPDF_DLL_PRIVATE - void setPipeline(Pipeline*); - - Pipeline* pipeline; - }; - - // This class is used by parse to decrypt strings when reading an object that contains encrypted - // strings. - class StringDecrypter - { - public: - QPDF_DLL - virtual ~StringDecrypter() = default; - virtual void decryptString(std::string& val) = 0; - }; - - // This class is used by parsePageContents. Callers must instantiate a subclass of this with - // handlers defined to accept QPDFObjectHandles that are parsed from the stream. - class QPDF_DLL_CLASS ParserCallbacks - { - public: - QPDF_DLL - virtual ~ParserCallbacks() = default; - // One of the handleObject methods must be overridden. - QPDF_DLL - virtual void handleObject(QPDFObjectHandle); - QPDF_DLL - virtual void handleObject(QPDFObjectHandle, size_t offset, size_t length); - - virtual void handleEOF() = 0; - - // Override this if you want to know the full size of the contents, possibly after - // concatenation of multiple streams. This is called before the first call to handleObject. - QPDF_DLL - virtual void contentSize(size_t); - - protected: - // Implementors may call this method during parsing to terminate parsing early. This method - // throws an exception that is caught by parsePageContents, so its effect is immediate. - QPDF_DLL - void terminateParsing(); - }; - - // Convenience object for rectangles - class Rectangle - { - public: - Rectangle() : - llx(0.0), - lly(0.0), - urx(0.0), - ury(0.0) - { - } - Rectangle(double llx, double lly, double urx, double ury) : - llx(llx), - lly(lly), - urx(urx), - ury(ury) - { - } - - double llx; - double lly; - double urx; - double ury; - }; - - // Convenience object for transformation matrices. See also QPDFMatrix. Unfortunately we can't - // replace this with QPDFMatrix because QPDFMatrix's default constructor creates the identity - // transform matrix and this one is all zeroes. - class Matrix - { - public: - Matrix() : - a(0.0), - b(0.0), - c(0.0), - d(0.0), - e(0.0), - f(0.0) - { - } - Matrix(double a, double b, double c, double d, double e, double f) : - a(a), - b(b), - c(c), - d(d), - e(e), - f(f) - { - } - - double a; - double b; - double c; - double d; - double e; - double f; - }; - - QPDF_DLL - QPDFObjectHandle() = default; - QPDF_DLL - QPDFObjectHandle(QPDFObjectHandle const&) = default; - QPDF_DLL - QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default; - - QPDF_DLL - QPDFObjectHandle(QPDFObjectHandle&&) = default; - QPDF_DLL - QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default; - - // Return true if the QPDFObjectHandle is initialized. This allows object handles to be used in - // if statements with initializer. - QPDF_DLL - explicit inline operator bool() const noexcept; - - [[deprecated("use operator bool()")]] QPDF_DLL inline bool isInitialized() const noexcept; - - // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying - // object, meaning that changes to one are reflected in the other, or "if you paint one, the - // other one changes color." This does not perform a structural comparison of the contents of - // the objects. - QPDF_DLL - bool isSameObjectAs(QPDFObjectHandle const&) const noexcept; - - // Return type code and type name of underlying object. These are useful for doing rapid type - // tests (like switch statements) or for testing and debugging. - QPDF_DLL - qpdf_object_type_e getTypeCode() const; - QPDF_DLL - char const* getTypeName() const; - - // Exactly one of these will return true for any initialized object. Operator and InlineImage - // are only allowed in content streams. - QPDF_DLL - bool isBool() const; - QPDF_DLL - bool isNull() const; - QPDF_DLL - bool isInteger() const; - QPDF_DLL - bool isReal() const; - QPDF_DLL - bool isName() const; - QPDF_DLL - bool isString() const; - QPDF_DLL - bool isOperator() const; - QPDF_DLL - bool isInlineImage() const; - QPDF_DLL - bool isArray() const; - QPDF_DLL - bool isDictionary() const; - QPDF_DLL - bool isStream() const; - QPDF_DLL - bool isReserved() const; - - // True for objects that are direct nulls. Does not attempt to resolve objects. This is intended - // for internal use, but it can be used as an efficient way to check for nulls that are not - // indirect objects. - QPDF_DLL - bool isDirectNull() const; - - // This returns true in addition to the query for the specific type for indirect objects. - QPDF_DLL - inline bool isIndirect() const; - - // This returns true for indirect objects from a QPDF that has been destroyed. Trying unparse - // such an object will throw a logic_error. - QPDF_DLL - bool isDestroyed() const; - - // True for everything except array, dictionary, stream, word, and inline image. - QPDF_DLL - bool isScalar() const; - - // True if the object is a name object representing the provided name. - QPDF_DLL - bool isNameAndEquals(std::string const& name) const; - - // True if the object is a dictionary of the specified type and subtype, if any. - QPDF_DLL - bool isDictionaryOfType(std::string const& type, std::string const& subtype = "") const; - - // True if the object is a stream of the specified type and subtype, if any. - QPDF_DLL - bool isStreamOfType(std::string const& type, std::string const& subtype = "") const; - - // Public factory methods - - // Wrap an object in an array if it is not already an array. This is a helper for cases in which - // something in a PDF may either be a single item or an array of items, which is a common idiom. - QPDF_DLL - QPDFObjectHandle wrapInArray(); - - // Construct an object of any type from a string representation of the object. Throws QPDFExc - // with an empty filename and an offset into the string if there is an error. Any indirect - // object syntax (obj gen R) will cause a logic_error exception to be thrown. If - // object_description is provided, it will appear in the message of any QPDFExc exception thrown - // for invalid syntax. See also the global `operator ""_qpdf` defined below. - QPDF_DLL - static QPDFObjectHandle - parse(std::string const& object_str, std::string const& object_description = ""); - - // Construct an object of any type from a string representation of the object. Indirect object - // syntax (obj gen R) is allowed and will create indirect references within the passed-in - // context. If object_description is provided, it will appear in the message of any QPDFExc - // exception thrown for invalid syntax. Note that you can't parse an indirect object reference - // all by itself as parse will stop at the end of the first complete object, which will just be - // the first number and will report that there is trailing data at the end of the string. - QPDF_DLL - static QPDFObjectHandle - parse(QPDF* context, std::string const& object_str, std::string const& object_description = ""); - - // Construct an object as above by reading from the given InputSource at its current position - // and using the tokenizer you supply. Indirect objects and encrypted strings are permitted. - // This method was intended to be called by QPDF for parsing objects that are ready from the - // object's input stream. - QPDF_DLL - static QPDFObjectHandle parse( - std::shared_ptr input, - std::string const& object_description, - QPDFTokenizer&, - bool& empty, - StringDecrypter* decrypter, - QPDF* context); - - // Return the offset where the object was found when parsed. A negative value means that the - // object was created without parsing. If the object is in a stream, the offset is from the - // beginning of the stream. Otherwise, the offset is from the beginning of the file. - QPDF_DLL - qpdf_offset_t getParsedOffset() const; - - // Older method: stream_or_array should be the value of /Contents from a page object. It's more - // convenient to just call QPDFPageObjectHelper::parsePageContents on the page object, and error - // messages will also be more useful because the page object information will be known. - QPDF_DLL - static void parseContentStream(QPDFObjectHandle stream_or_array, ParserCallbacks* callbacks); - - // When called on a stream or stream array that is some page's content streams, do the same as - // pipePageContents. This method is a lower level way to do what - // QPDFPageObjectHelper::pipePageContents does, but it allows you to perform this operation on a - // contents object that is disconnected from a page object. The description argument should - // describe the containing page and is used in error messages. The all_description argument is - // initialized to something that could be used to describe the result of the pipeline. It is the - // description amended with the identifiers of the underlying objects. Please note that if there - // is an array of content streams, p->finish() is called after each stream. If you pass a - // pipeline that doesn't allow write() to be called after finish(), you can wrap it in an - // instance of Pl_Concatenate and then call manualFinish() on the Pl_Concatenate pipeline at the - // end. - QPDF_DLL - void - pipeContentStreams(Pipeline* p, std::string const& description, std::string& all_description); - - // As of qpdf 8, it is possible to add custom token filters to a stream. The tokenized stream - // data is passed through the token filter after all original filters but before content stream - // normalization if requested. This is a low-level interface to add it to a stream. You will - // usually want to call QPDFPageObjectHelper::addContentTokenFilter instead, which can be - // applied to a page object, and which will automatically handle the case of pages whose - // contents are split across multiple streams. - QPDF_DLL - void addTokenFilter(std::shared_ptr token_filter); - - // Legacy helpers for parsing content streams. These methods are not going away, but newer code - // should call the correspond methods in QPDFPageObjectHelper instead. The specification and - // behavior of these methods are the same as the identically named methods in that class, but - // newer functionality will be added there. - QPDF_DLL - void parsePageContents(ParserCallbacks* callbacks); - QPDF_DLL - void filterPageContents(TokenFilter* filter, Pipeline* next = nullptr); - // See comments for QPDFPageObjectHelper::pipeContents. - QPDF_DLL - void pipePageContents(Pipeline* p); - QPDF_DLL - void addContentTokenFilter(std::shared_ptr token_filter); - // End legacy content stream helpers - - // Called on a stream to filter the stream as if it were page contents. This can be used to - // apply a TokenFilter to a form XObject, whose data is in the same format as a content stream. - QPDF_DLL - void filterAsContents(TokenFilter* filter, Pipeline* next = nullptr); - // Called on a stream to parse the stream as page contents. This can be used to parse a form - // XObject. - QPDF_DLL - void parseAsContents(ParserCallbacks* callbacks); - - // Type-specific factories - QPDF_DLL - static QPDFObjectHandle newNull(); - QPDF_DLL - static QPDFObjectHandle newBool(bool value); - QPDF_DLL - static QPDFObjectHandle newInteger(long long value); - QPDF_DLL - static QPDFObjectHandle newReal(std::string const& value); - QPDF_DLL - static QPDFObjectHandle - newReal(double value, int decimal_places = 0, bool trim_trailing_zeroes = true); - // Note about name objects: qpdf's internal representation of a PDF name is a sequence of bytes, - // excluding the NUL character, and starting with a slash. Name objects as represented in the - // PDF specification can contain characters escaped with #, but such escaping is not of concern - // when calling QPDFObjectHandle methods not directly relating to parsing. For example, - // newName("/text/plain").getName() and parse("/text#2fplain").getName() both return - // "/text/plain", while newName("/text/plain").unparse() and parse("/text#2fplain").unparse() - // both return "/text#2fplain". When working with the qpdf API for creating, retrieving, and - // modifying objects, you want to work with the internal, canonical representation. For names - // containing alphanumeric characters, dashes, and underscores, there is no difference between - // the two representations. For a lengthy discussion, see - // https://github.com/qpdf/qpdf/discussions/625. - QPDF_DLL - static QPDFObjectHandle newName(std::string const& name); - QPDF_DLL - static QPDFObjectHandle newString(std::string const& str); - // Create a string encoded from the given utf8-encoded string appropriately encoded to appear in - // PDF files outside of content streams, such as in document metadata form field values, page - // labels, outlines, and similar locations. We try ASCII first, then PDFDocEncoding, then UTF-16 - // as needed to successfully encode all the characters. - QPDF_DLL - static QPDFObjectHandle newUnicodeString(std::string const& utf8_str); - QPDF_DLL - static QPDFObjectHandle newOperator(std::string const&); - QPDF_DLL - static QPDFObjectHandle newInlineImage(std::string const&); - QPDF_DLL - static QPDFObjectHandle newArray(); - QPDF_DLL - static QPDFObjectHandle newArray(std::vector const& items); - QPDF_DLL - static QPDFObjectHandle newArray(Rectangle const&); - QPDF_DLL - static QPDFObjectHandle newArray(Matrix const&); - QPDF_DLL - static QPDFObjectHandle newArray(QPDFMatrix const&); - QPDF_DLL - static QPDFObjectHandle newDictionary(); - QPDF_DLL - static QPDFObjectHandle newDictionary(std::map const& items); - - // Create an array from a rectangle. Equivalent to the rectangle form of newArray. - QPDF_DLL - static QPDFObjectHandle newFromRectangle(Rectangle const&); - // Create an array from a matrix. Equivalent to the matrix form of newArray. - QPDF_DLL - static QPDFObjectHandle newFromMatrix(Matrix const&); - QPDF_DLL - static QPDFObjectHandle newFromMatrix(QPDFMatrix const&); - - // Note: new stream creation methods have were added to the QPDF class starting with - // version 11.2.0. The ones in this class are here for backward compatibility. - - // Create a new stream and associate it with the given qpdf object. A subsequent call must be - // made to replaceStreamData() to provide data for the stream. The stream's dictionary may be - // retrieved by calling getDict(), and the resulting dictionary may be modified. Alternatively, - // you can create a new dictionary and call replaceDict to install it. From QPDF 11.2, you can - // call QPDF::newStream() instead. - QPDF_DLL - static QPDFObjectHandle newStream(QPDF* qpdf); - - // Create a new stream and associate it with the given qpdf object. Use the given buffer as the - // stream data. The stream dictionary's /Length key will automatically be set to the size of the - // data buffer. If additional keys are required, the stream's dictionary may be retrieved by - // calling getDict(), and the resulting dictionary may be modified. This method is just a - // convenient wrapper around the newStream() and replaceStreamData(). It is a convenience - // methods for streams that require no parameters beyond the stream length. Note that you don't - // have to deal with compression yourself if you use QPDFWriter. By default, QPDFWriter will - // automatically compress uncompressed stream data. Example programs are provided that - // illustrate this. From QPDF 11.2, you can call QPDF::newStream() - // instead. - QPDF_DLL - static QPDFObjectHandle newStream(QPDF* qpdf, std::shared_ptr data); - - // Create new stream with data from string. This method will create a copy of the data rather - // than using the user-provided buffer as in the std::shared_ptr version of newStream. - // From QPDF 11.2, you can call QPDF::newStream() instead. - QPDF_DLL - static QPDFObjectHandle newStream(QPDF* qpdf, std::string const& data); - - // A reserved object is a special sentinel used for qpdf to reserve a spot for an object that is - // going to be added to the QPDF object. Normally you don't have to use this type since you can - // just call QPDF::makeIndirectObject. However, in some cases, if you have to create objects - // with circular references, you may need to create a reserved object so that you can have a - // reference to it and then replace the object later. Reserved objects have the special - // property that they can't be resolved to direct objects. This makes it possible to replace a - // reserved object with a new object while preserving existing references to them. When you are - // ready to replace a reserved object with its replacement, use QPDF::replaceReserved for this - // purpose rather than the more general QPDF::replaceObject. It is an error to try to write a - // QPDF with QPDFWriter if it has any reserved objects in it. From QPDF 11.4, you can call - // QPDF::newReserved() instead. - QPDF_DLL - static QPDFObjectHandle newReserved(QPDF* qpdf); - - // Provide an owning qpdf and object description. The library does this automatically with - // objects that are read from the input PDF and with objects that are created programmatically - // and inserted into the QPDF as a new indirect object. Most end user code will not need to call - // this. If an object has an owning qpdf and object description, it enables qpdf to give - // warnings with proper context in some cases where it would otherwise raise exceptions. It is - // okay to add objects without an owning_qpdf to objects that have one, but it is an error to - // have a QPDF contain objects with owning_qpdf set to something else. To add objects from - // another qpdf, use copyForeignObject instead. - QPDF_DLL - void setObjectDescription(QPDF* owning_qpdf, std::string const& object_description); - QPDF_DLL - bool hasObjectDescription() const; - - // Accessor methods - // - // (Note: this comment is referenced in qpdf-c.h and the manual.) - // - // In PDF files, objects have specific types, but there is nothing that prevents PDF files from - // containing objects of types that aren't expected by the specification. - // - // There are two flavors of accessor methods: - // - // * getSomethingValue() returns the value and issues a type warning if the type is incorrect. - // - // * getValueAsSomething() returns false if the value is the wrong type. Otherwise, it returns - // true and initializes a reference of the appropriate type. These methods never issue type - // warnings. - // - // The getSomethingValue() accessors and some of the other methods expect objects of a - // particular type. Prior to qpdf 8, calling an accessor on a method of the wrong type, such as - // trying to get a dictionary key from an array, trying to get the string value of a number, - // etc., would throw an exception, but since qpdf 8, qpdf issues a warning and recovers using - // the following behavior: - // - // * Requesting a value of the wrong type (int value from string, array item from a scalar or - // dictionary, etc.) will return a zero-like value for that type: false for boolean, 0 for - // number, the empty string for string, or the null object for an object handle. - // - // * Accessing an array item that is out of bounds will return a null object. - // - // * Attempts to mutate an object of the wrong type (e.g., attempting to add a dictionary key to - // a scalar or array) will be ignored. - // - // When any of these fallback behaviors are used, qpdf issues a warning. Starting in qpdf 10.5, - // these warnings have the error code qpdf_e_object. Prior to 10.5, they had the error code - // qpdf_e_damaged_pdf. If the QPDFObjectHandle is associated with a QPDF object (as is the case - // for all objects whose origin was a PDF file), the warning is issued using the normal warning - // mechanism (as described in QPDF.hh), making it possible to suppress or otherwise detect them. - // If the QPDFObjectHandle is not associated with a QPDF object (meaning it was created - // programmatically), an exception will be thrown. - // - // The way to avoid getting any type warnings or exceptions, even when working with malformed - // PDF files, is to always check the type of a QPDFObjectHandle before accessing it (for - // example, make sure that isString() returns true before calling getStringValue()) and to - // always be sure that any array indices are in bounds. - // - // For additional discussion and rationale for this behavior, see the section in the QPDF manual - // entitled "Object Accessor Methods". - - // Methods for bool objects - QPDF_DLL - bool getBoolValue() const; - QPDF_DLL - bool getValueAsBool(bool&) const; - - // Methods for integer objects. Note: if an integer value is too big (too far away from zero in - // either direction) to fit in the requested return type, the maximum or minimum value for that - // return type may be returned. For example, on a system with 32-bit int, a numeric object with - // a value of 2^40 (or anything too big for 32 bits) will be returned as INT_MAX. - QPDF_DLL - long long getIntValue() const; - QPDF_DLL - bool getValueAsInt(long long&) const; - QPDF_DLL - int getIntValueAsInt() const; - QPDF_DLL - bool getValueAsInt(int&) const; - QPDF_DLL - unsigned long long getUIntValue() const; - QPDF_DLL - bool getValueAsUInt(unsigned long long&) const; - QPDF_DLL - unsigned int getUIntValueAsUInt() const; - QPDF_DLL - bool getValueAsUInt(unsigned int&) const; - - // Methods for real objects - QPDF_DLL - std::string getRealValue() const; - QPDF_DLL - bool getValueAsReal(std::string&) const; - - // Methods that work for both integer and real objects - QPDF_DLL - bool isNumber() const; - QPDF_DLL - double getNumericValue() const; - QPDF_DLL - bool getValueAsNumber(double&) const; - - // Methods for name objects. The returned name value is in qpdf's canonical form with all - // escaping resolved. See comments for newName() for details. - QPDF_DLL - std::string getName() const; - QPDF_DLL - bool getValueAsName(std::string&) const; - - // Methods for string objects - QPDF_DLL - std::string getStringValue() const; - QPDF_DLL - bool getValueAsString(std::string&) const; - - // If a string starts with the UTF-16 marker, it is converted from UTF-16 to UTF-8. Otherwise, - // it is treated as a string encoded with PDF Doc Encoding. PDF Doc Encoding is identical to - // ISO-8859-1 except in the range from 0200 through 0240, where there is a mapping of characters - // to Unicode. QPDF versions prior to version 8.0.0 erroneously left characters in that range - // unmapped. - QPDF_DLL - std::string getUTF8Value() const; - QPDF_DLL - bool getValueAsUTF8(std::string&) const; - - // Methods for content stream objects - QPDF_DLL - std::string getOperatorValue() const; - QPDF_DLL - bool getValueAsOperator(std::string&) const; - QPDF_DLL - std::string getInlineImageValue() const; - QPDF_DLL - bool getValueAsInlineImage(std::string&) const; - - // Methods for array objects; see also name and array objects. - - // Return an object that enables iteration over members. You can do - // - // for (auto iter: obj.aitems()) - // { - // // iter is an array element - // } - class QPDFArrayItems; - QPDF_DLL - QPDFArrayItems aitems(); - - QPDF_DLL - int getArrayNItems() const; - QPDF_DLL - QPDFObjectHandle getArrayItem(int n) const; - // Note: QPDF arrays internally optimize memory for arrays containing lots of nulls. Calling - // getArrayAsVector may cause a lot of memory to be allocated for very large arrays with lots of - // nulls. - QPDF_DLL - std::vector getArrayAsVector() const; - QPDF_DLL - bool isRectangle() const; - // If the array is an array of four numeric values, return as a rectangle. Otherwise, return the - // rectangle [0, 0, 0, 0] - QPDF_DLL - Rectangle getArrayAsRectangle() const; - QPDF_DLL - bool isMatrix() const; - // If the array is an array of six numeric values, return as a matrix. Otherwise, return the - // matrix [1, 0, 0, 1, 0, 0] - QPDF_DLL - Matrix getArrayAsMatrix() const; - - // Methods for dictionary objects. In all dictionary methods, keys are specified/represented as - // canonical name strings starting with a leading slash and not containing any PDF syntax - // escaping. See comments for getName() for details. - - // Return an object that enables iteration over members. You can do - // - // for (auto iter: obj.ditems()) - // { - // // iter.first is the key - // // iter.second is the value - // } - class QPDFDictItems; - QPDF_DLL - QPDFDictItems ditems(); - - // Return true if key is present. Keys with null values are treated as if they are not present. - // This is as per the PDF spec. - QPDF_DLL - bool hasKey(std::string const&) const; - // Return the value for the key. If the key is not present, null is returned. - QPDF_DLL - QPDFObjectHandle getKey(std::string const&) const; - // If the object is null, return null. Otherwise, call getKey(). This makes it easier to access - // lower-level dictionaries, as in - // auto font = page.getKeyIfDict("/Resources").getKeyIfDict("/Font"); - QPDF_DLL - QPDFObjectHandle getKeyIfDict(std::string const&) const; - // Return all keys. Keys with null values are treated as if they are not present. This is as - // per the PDF spec. - QPDF_DLL - std::set getKeys() const; - // Return dictionary as a map. Entries with null values are included. - QPDF_DLL - std::map getDictAsMap() const; - - // Methods for name and array objects. The name value is in qpdf's canonical form with all - // escaping resolved. See comments for newName() for details. - QPDF_DLL - bool isOrHasName(std::string const&) const; - - // Make all resources in a resource dictionary indirect. This just goes through all entries of - // top-level subdictionaries and converts any direct objects to indirect objects. This can be - // useful to call before mergeResources if it is going to be called multiple times to prevent - // resources from being copied multiple times. - QPDF_DLL - void makeResourcesIndirect(QPDF& owning_qpdf); - - // Merge resource dictionaries. If the "conflicts" parameter is provided, conflicts in - // dictionary subitems are resolved, and "conflicts" is initialized to a map such that - // conflicts[resource_type][old_key] == [new_key] - // - // See also makeResourcesIndirect, which can be useful to call before calling this. - // - // This method does nothing if both this object and the other object are not dictionaries. - // Otherwise, it has following behavior, where "object" refers to the object whose method is - // invoked, and "other" refers to the argument: - // - // * For each key in "other" whose value is an array: - // * If "object" does not have that entry, shallow copy it. - // * Otherwise, if "object" has an array in the same place, append to that array any objects - // in "other"'s array that are not already present. - // * For each key in "other" whose value is a dictionary: - // * If "object" does not have that entry, shallow copy it. - // * Otherwise, for each key in the subdictionary: - // * If key is not present in "object"'s entry, shallow copy it if direct or just add it if - // indirect. - // * Otherwise, if conflicts are being detected: - // * If there is a key (oldkey) already in the dictionary that points to the same indirect - // destination as key, indicate that key was replaced by oldkey. This would happen if - // these two resource dictionaries have previously been merged. - // * Otherwise pick a new key (newkey) that is unique within the resource dictionary, - // store that in the resource dictionary with key's destination as its destination, and - // indicate that key was replaced by newkey. - // - // The primary purpose of this method is to facilitate merging of resource dictionaries that are - // supposed to have the same scope as each other. For example, this can be used to merge a form - // XObject's /Resources dictionary with a form field's /DR or to merge two /DR dictionaries. The - // "conflicts" parameter may be previously initialized. This method adds to whatever is already - // there, which can be useful when merging with multiple things. - QPDF_DLL - void mergeResources( - QPDFObjectHandle other, - std::map>* conflicts = nullptr); - - // Get all resource names from a resource dictionary. If this object is a dictionary, this - // method returns a set of all the keys in all top-level subdictionaries. For resources - // dictionaries, this is the collection of names that may be referenced in the content stream. - QPDF_DLL - std::set getResourceNames() const; - - // Find a unique name within a resource dictionary starting with a given prefix. This method - // works by appending a number to the given prefix. It searches starting with min_suffix and - // sets min_suffix to selected value upon return. This can be used to increase efficiency if - // adding multiple items with the same prefix. (Why doesn't it set min_suffix to the next - // number? Well, maybe you aren't going to actually use the name it returns.) If you are calling - // this multiple times on the same resource dictionary, you can initialize resource_names by - // calling getResourceNames(), incrementally update it as you add resources, and keep passing it - // in so that getUniqueResourceName doesn't have to traverse the resource dictionary each time - // it's called. - QPDF_DLL - std::string getUniqueResourceName( - std::string const& prefix, - int& min_suffix, - std::set* resource_names = nullptr) const; - - // A QPDFObjectHandle has an owning QPDF if it is associated with ("owned by") a specific QPDF - // object. Indirect objects always have an owning QPDF. Direct objects that are read from the - // input source will also have an owning QPDF. Programmatically created objects will only have - // one if setObjectDescription was called. - // - // When the QPDF object that owns an object is destroyed, the object is changed into a null, and - // its owner is cleared. Therefore you should not retain the value of an owning QPDF beyond the - // life of the QPDF. If in doubt, ask for it each time you need it. - - // getOwningQPDF returns a pointer to the owning QPDF is the object has one. Otherwise, it - // returns a null pointer. Use this when you are able to handle the case of an object that - // doesn't have an owning QPDF. - QPDF_DLL - QPDF* getOwningQPDF() const; - // getQPDF, new in qpdf 11, returns a reference owning QPDF. If there is none, it throws a - // runtime_error. Use this when you know the object has to have an owning QPDF, such as when - // it's a known indirect object. Since streams are always indirect objects, this method can be - // used safely for streams. If error_msg is specified, it will be used at the contents of the - // runtime_error if there is now owner. - QPDF_DLL - QPDF& getQPDF(std::string const& error_msg = "") const; - - // Create a shallow copy of an object as a direct object, but do not traverse across indirect - // object boundaries. That means that, for dictionaries and arrays, any keys or items that were - // indirect objects will still be indirect objects that point to the same place. In the - // strictest sense, this is not a shallow copy because it recursively descends arrays and - // dictionaries; it just doesn't cross over indirect objects. See also unsafeShallowCopy(). You - // can't copy a stream this way. See copyStream() instead. - QPDF_DLL - QPDFObjectHandle shallowCopy(); - - // Create a true shallow copy of an array or dictionary, just copying the immediate items - // (array) or keys (dictionary). This is "unsafe" because, if you *modify* any of the items in - // the copy, you are modifying the original, which is almost never what you want. However, if - // your intention is merely to *replace* top-level items or keys and not to modify lower-level - // items in the copy, this method is much faster than shallowCopy(). - QPDF_DLL - QPDFObjectHandle unsafeShallowCopy(); - - // Create a copy of this stream. The new stream and the old stream are independent: after the - // copy, either the original or the copy's dictionary or data can be modified without affecting - // the other. This uses StreamDataProvider internally, so no unnecessary copies of the stream's - // data are made. If the source stream's data is already being provided by a StreamDataProvider, - // the new stream will use the same one, so you have to make sure your StreamDataProvider can - // handle that case. But if you're already using a StreamDataProvider, you probably don't need - // to call this method. - QPDF_DLL - QPDFObjectHandle copyStream(); - - // Mutator methods. - - // Since qpdf 11: for mutators that may add or remove an item, there are additional versions - // whose names contain "AndGet" that return the added or removed item. For example: - // - // auto new_dict = dict.replaceKeyAndGetNew( - // "/New", QPDFObjectHandle::newDictionary()); - // - // auto old_value = dict.replaceKeyAndGetOld( - // "/New", "(something)"_qpdf); - - // Recursively copy this object, making it direct. An exception is thrown if a loop is detected. - // With allow_streams true, keep indirect object references to streams. Otherwise, throw an - // exception if any sub-object is a stream. Note that, when allow_streams is true and a stream - // is found, the resulting object is still associated with the containing qpdf. When - // allow_streams is false, the object will no longer be connected to the original QPDF object - // after this call completes successfully. - QPDF_DLL - void makeDirect(bool allow_streams = false); - - // Mutator methods for array objects - QPDF_DLL - void setArrayItem(int, QPDFObjectHandle const&); - QPDF_DLL - void setArrayFromVector(std::vector const& items); - // Insert an item before the item at the given position ("at") so that it has that position - // after insertion. If "at" is equal to the size of the array, insert the item at the end. - QPDF_DLL - void insertItem(int at, QPDFObjectHandle const& item); - // Like insertItem but return the item that was inserted. - QPDF_DLL - QPDFObjectHandle insertItemAndGetNew(int at, QPDFObjectHandle const& item); - // Append an item to an array. - QPDF_DLL - void appendItem(QPDFObjectHandle const& item); - // Append an item, and return the newly added item. - QPDF_DLL - QPDFObjectHandle appendItemAndGetNew(QPDFObjectHandle const& item); - // Remove the item at that position, reducing the size of the array by one. - QPDF_DLL - void eraseItem(int at); - // Erase and item and return the item that was removed. - QPDF_DLL - QPDFObjectHandle eraseItemAndGetOld(int at); - - // Mutator methods for dictionary objects - - // Replace value of key, adding it if it does not exist. If value is null, remove the key. - QPDF_DLL - void replaceKey(std::string const& key, QPDFObjectHandle const& value); - // Replace value of key and return the value. - QPDF_DLL - QPDFObjectHandle replaceKeyAndGetNew(std::string const& key, QPDFObjectHandle const& value); - // Replace value of key and return the old value, or null if the key was previously not present. - QPDF_DLL - QPDFObjectHandle replaceKeyAndGetOld(std::string const& key, QPDFObjectHandle const& value); - // Remove key, doing nothing if key does not exist. - QPDF_DLL - void removeKey(std::string const& key); - // Remove key and return the old value. If the old value didn't exist, return a null object. - QPDF_DLL - QPDFObjectHandle removeKeyAndGetOld(std::string const& key); - - // ABI: Remove in qpdf 12 - [[deprecated("use replaceKey -- it does the same thing")]] QPDF_DLL void - replaceOrRemoveKey(std::string const& key, QPDFObjectHandle const&); - - // Methods for stream objects - QPDF_DLL - QPDFObjectHandle getDict() const; - - // By default, or if true passed, QPDFWriter will attempt to filter a stream based on decode - // level, whether compression is enabled, and its ability to filter. Passing false will prevent - // QPDFWriter from attempting to filter the stream even if it can. This includes both decoding - // and compressing. This makes it possible for you to prevent QPDFWriter from uncompressing and - // recompressing a stream that it knows how to operate on for any application-specific reason, - // such as that you have already optimized its filtering. Note that this doesn't affect any - // other ways to get the stream's data, such as pipeStreamData or getStreamData. - QPDF_DLL - void setFilterOnWrite(bool); - QPDF_DLL - bool getFilterOnWrite(); - - // If addTokenFilter has been called for this stream, then the original data should be - // considered to be modified. This means we should avoid optimizations such as not filtering a - // stream that is already compressed. - QPDF_DLL - bool isDataModified(); - - // Returns filtered (uncompressed) stream data. Throws an exception if the stream is filtered - // and we can't decode it. - QPDF_DLL - std::shared_ptr getStreamData(qpdf_stream_decode_level_e level = qpdf_dl_generalized); - - // Returns unfiltered (raw) stream data. - QPDF_DLL - std::shared_ptr getRawStreamData(); - - // Write stream data through the given pipeline. A null pipeline value may be used if all you - // want to do is determine whether a stream is filterable and would be filtered based on the - // provided flags. If flags is 0, write raw stream data and return false. Otherwise, the flags - // alter the behavior in the following way: - // - // encode_flags: - // - // qpdf_sf_compress -- compress data with /FlateDecode if no other compression filters are - // applied. - // - // qpdf_sf_normalize -- tokenize as content stream and normalize tokens - // - // decode_level: - // - // qpdf_dl_none -- do not decode any streams. - // - // qpdf_dl_generalized -- decode supported general-purpose filters. This includes - // /ASCIIHexDecode, /ASCII85Decode, /LZWDecode, and /FlateDecode. - // - // qpdf_dl_specialized -- in addition to generalized filters, also decode supported non-lossy - // specialized filters. This includes /RunLengthDecode. - // - // qpdf_dl_all -- in addition to generalized and non-lossy specialized filters, decode supported - // lossy filters. This includes /DCTDecode. - // - // If, based on the flags and the filters and decode parameters, we determine that we know how - // to apply all requested filters, do so and return true if we are successful. - // - // The exact meaning of the return value differs the different versions of this function, but - // for any version, the meaning has been the same. For the main version, added in qpdf 10, the - // return value indicates whether the overall operation succeeded. The filter parameter, if - // specified, will be set to whether or not filtering was attempted. If filtering was not - // requested, this value will be false even if the overall operation succeeded. - // - // If filtering is requested but this method returns false, it means there was some error in the - // filtering, in which case the resulting data is likely partially filtered and/or incomplete - // and may not be consistent with the configured filters. QPDFWriter handles this by attempting - // to get the stream data without filtering, but callers should consider a false return value - // when decode_level is not qpdf_dl_none to be a potential loss of data. If you intend to retry - // in that case, pass true as the value of will_retry. This changes the warning issued by the - // library to indicate that the operation will be retried without filtering to avoid data loss. - - // Return value is overall success, even if filtering is not requested. - QPDF_DLL - bool pipeStreamData( - Pipeline*, - bool* filtering_attempted, - int encode_flags, - qpdf_stream_decode_level_e decode_level, - bool suppress_warnings = false, - bool will_retry = false); - - // Legacy version. Return value is whether filtering was attempted. There is no way to determine - // success if filtering was not attempted. - QPDF_DLL - bool pipeStreamData( - Pipeline*, - int encode_flags, - qpdf_stream_decode_level_e decode_level, - bool suppress_warnings = false, - bool will_retry = false); - - // Legacy pipeStreamData. This maps to the the flags-based pipeStreamData as follows: - // filter = false -> encode_flags = 0 - // filter = true -> decode_level = qpdf_dl_generalized - // normalize = true -> encode_flags |= qpdf_sf_normalize - // compress = true -> encode_flags |= qpdf_sf_compress - // Return value is whether filtering was attempted. - QPDF_DLL - bool pipeStreamData(Pipeline*, bool filter, bool normalize, bool compress); - - // Replace a stream's dictionary. The new dictionary must be consistent with the stream's data. - // This is most appropriately used when creating streams from scratch that will use a stream - // data provider and therefore start with an empty dictionary. It may be more convenient in - // this case than calling getDict and modifying it for each key. The pdf-create example does - // this. - QPDF_DLL - void replaceDict(QPDFObjectHandle const&); - - // REPLACING STREAM DATA - - // Note about all replaceStreamData methods: whatever values are passed as filter and - // decode_parms will overwrite /Filter and /DecodeParms in the stream. Passing a null object - // (QPDFObjectHandle::newNull()) will remove those values from the stream dictionary. From qpdf - // 11, passing an *uninitialized* QPDFObjectHandle (QPDFObjectHandle()) will leave any existing - // values untouched. - - // Replace this stream's stream data with the given data buffer. The stream's /Length key is - // replaced with the length of the data buffer. The stream is interpreted as if the data read - // from the file, after any decryption filters have been applied, is as presented. - QPDF_DLL - void replaceStreamData( - std::shared_ptr data, - QPDFObjectHandle const& filter, - QPDFObjectHandle const& decode_parms); - - // Replace the stream's stream data with the given string. This method will create a copy of the - // data rather than using the user-provided buffer as in the std::shared_ptr version of - // replaceStreamData. - QPDF_DLL - void replaceStreamData( - std::string const& data, - QPDFObjectHandle const& filter, - QPDFObjectHandle const& decode_parms); - - // As above, replace this stream's stream data. Instead of directly providing a buffer with the - // stream data, call the given provider's provideStreamData method. See comments on the - // StreamDataProvider class (defined above) for details on the method. The data must be - // consistent with filter and decode_parms as provided. Although it is more complex to use this - // form of replaceStreamData than the one that takes a buffer, it makes it possible to avoid - // allocating memory for the stream data. Example programs are provided that use both forms of - // replaceStreamData. - - // Note about stream length: for any given stream, the provider must provide the same amount of - // data each time it is called. This is critical for making linearization work properly. - // Versions of qpdf before 3.0.0 required a length to be specified here. Starting with - // version 3.0.0, this is no longer necessary (or permitted). The first time the stream data - // provider is invoked for a given stream, the actual length is stored. Subsequent times, it is - // enforced that the length be the same as the first time. - - // If you have gotten a compile error here while building code that worked with older versions - // of qpdf, just omit the length parameter. You can also simplify your code by not having to - // compute the length in advance. - QPDF_DLL - void replaceStreamData( - std::shared_ptr provider, - QPDFObjectHandle const& filter, - QPDFObjectHandle const& decode_parms); - - // Starting in qpdf 10.2, you can use C++-11 function objects instead of StreamDataProvider. - - // The provider should write the stream data to the pipeline. For a one-liner to replace stream - // data with the contents of a file, pass QUtil::file_provider(filename) as provider. - QPDF_DLL - void replaceStreamData( - std::function provider, - QPDFObjectHandle const& filter, - QPDFObjectHandle const& decode_parms); - // The provider should write the stream data to the pipeline, returning true if it succeeded - // without errors. - QPDF_DLL - void replaceStreamData( - std::function provider, - QPDFObjectHandle const& filter, - QPDFObjectHandle const& decode_parms); - - // Access object ID and generation. For direct objects, return object ID 0. - - // NOTE: Be careful about calling getObjectID() and getGeneration() directly as this can lead to - // the pattern of depending on object ID or generation without the other. In general, when - // keeping track of object IDs, it's better to use QPDFObjGen instead. - - QPDF_DLL - QPDFObjGen getObjGen() const; - QPDF_DLL - inline int getObjectID() const; - QPDF_DLL - inline int getGeneration() const; - - QPDF_DLL - std::string unparse() const; - QPDF_DLL - std::string unparseResolved() const; - // For strings only, force binary representation. Otherwise, same as unparse. - QPDF_DLL - std::string unparseBinary() const; - - // Return encoded as JSON. The constant JSON::LATEST can be used to specify the latest available - // JSON version. The JSON is generated as follows: - // * Arrays, dictionaries, booleans, nulls, integers, and real numbers are represented by their - // native JSON types. - // * Names are encoded as strings representing the canonical representation (after parsing #xx) - // and preceded by a slash, just as unparse() returns. For example, the JSON for the - // PDF-syntax name /Text#2fPlain would be "/Text/Plain". - // * Indirect references are encoded as strings containing "obj gen R" - // * Strings - // * JSON v1: Strings are encoded as UTF-8 strings with unrepresentable binary characters - // encoded as \uHHHH. Characters in PDF Doc encoding that don't have bidirectional unicode - // mappings are not reversible. There is no way to tell the difference between a string that - // looks like a name or indirect object from an actual name or indirect object. - // * JSON v2: - // * Unicode strings and strings encoded with PDF Doc encoding that can be bidirectionally - // mapped to Unicode (which is all strings without undefined characters) are represented - // as "u:" followed by the UTF-8 encoded string. Example: - // "u:potato". - // * All other strings are represented as "b:" followed by a hexadecimal encoding of the - // string. Example: "b:0102cacb" - // * Streams - // * JSON v1: Only the stream's dictionary is encoded. There is no way to tell a stream from a - // dictionary other than context. - // * JSON v2: A stream is encoded as {"dict": {...}} with the value being the encoding of the - // stream's dictionary. Since "dict" does not otherwise represent anything, this is - // unambiguous. The getStreamJSON() call can be used to add encoding of the stream's data. - // * Object types that are only valid in content streams (inline image, operator) are serialized - // as "null". Attempting to serialize a "reserved" object is an error. - // If dereference_indirect is true and this is an indirect object, show the actual contents of - // the object. The effect of dereference_indirect applies only to this object. It is not - // recursive. - QPDF_DLL - JSON getJSON(int json_version, bool dereference_indirect = false) const; - - // Write the object encoded as JSON to a pipeline. This is equivalent to, but more efficient - // than, calling getJSON(json_version, dereference_indirect).write(p, depth). See the - // documentation for getJSON and JSON::write for further detail. - QPDF_DLL - void writeJSON( - int json_version, Pipeline* p, bool dereference_indirect = false, size_t depth = 0) const; - - // Deprecated version uses v1 for backward compatibility. - // ABI: remove for qpdf 12 - [[deprecated("Use getJSON(int version)")]] QPDF_DLL JSON - getJSON(bool dereference_indirect = false) const; - - // This method can be called on a stream to get a more extended JSON representation of the - // stream that includes the stream's data. The JSON object returned is always a dictionary whose - // "dict" key is an encoding of the stream's dictionary. The representation of the data is - // determined by the json_data field. - // - // The json_data field may have the value qpdf_sj_none, qpdf_sj_inline, or qpdf_sj_file. - // - // If json_data is qpdf_sj_none, stream data is not represented. - // - // If json_data is qpdf_sj_inline or qpdf_sj_file, then stream data is filtered or not based on - // the value of decode_level, which has the same meaning as with pipeStreamData. - // - // If json_data is qpdf_sj_inline, the base64-encoded stream data is included in the "data" - // field of the dictionary that is returned. - // - // If json_data is qpdf_sj_file, then the Pipeline ("p") and data_filename argument must be - // supplied. The value of data_filename is stored in the resulting json in the "datafile" key - // but is not otherwise use. The stream data itself (raw or filtered depending on decode level), - // is written to the pipeline via pipeStreamData(). - // - // NOTE: When json_data is qpdf_sj_inline, the QPDF object from which the stream originates must - // remain valid until after the JSON object is written. - QPDF_DLL - JSON getStreamJSON( - int json_version, - qpdf_json_stream_data_e json_data, - qpdf_stream_decode_level_e decode_level, - Pipeline* p, - std::string const& data_filename); - - // Legacy helper methods for commonly performed operations on pages. Newer code should use - // QPDFPageObjectHelper instead. The specification and behavior of these methods are the same as - // the identically named methods in that class, but newer functionality will be added there. - QPDF_DLL - std::map getPageImages(); - QPDF_DLL - std::vector getPageContents(); - QPDF_DLL - void addPageContents(QPDFObjectHandle contents, bool first); - QPDF_DLL - void rotatePage(int angle, bool relative); - QPDF_DLL - void coalesceContentStreams(); - // End legacy page helpers - - // Issue a warning about this object if possible. If the object has a description, a warning - // will be issued using the owning QPDF as context. Otherwise, a message will be written to the - // default logger's error stream, which is standard error if not overridden. Objects read - // normally from the file have descriptions. See comments on setObjectDescription for additional - // details. - QPDF_DLL - void warnIfPossible(std::string const& warning) const; - - // Provide access to specific classes for recursive disconnected(). - class DisconnectAccess - { - friend class QPDF_Dictionary; - friend class QPDF_Stream; - - private: - static void - disconnect(QPDFObjectHandle o) - { - o.disconnect(); - } - }; - - // Convenience routine: Throws if the assumption is violated. Your code will be better if you - // call one of the isType methods and handle the case of the type being wrong, but these can be - // convenient if you have already verified the type. - QPDF_DLL - void assertInitialized() const; - - QPDF_DLL - void assertNull() const; - QPDF_DLL - void assertBool() const; - QPDF_DLL - void assertInteger() const; - QPDF_DLL - void assertReal() const; - QPDF_DLL - void assertName() const; - QPDF_DLL - void assertString() const; - QPDF_DLL - void assertOperator() const; - QPDF_DLL - void assertInlineImage() const; - QPDF_DLL - void assertArray() const; - QPDF_DLL - void assertDictionary() const; - QPDF_DLL - void assertStream() const; - QPDF_DLL - void assertReserved() const; - - QPDF_DLL - void assertIndirect() const; - QPDF_DLL - void assertScalar() const; - QPDF_DLL - void assertNumber() const; - - // The isPageObject method checks the /Type key of the object. This is not completely reliable - // as there are some otherwise valid files whose /Type is wrong for page objects. qpdf is - // slightly more accepting but may still return false here when treating the object as a page - // would work. Use this sparingly. - QPDF_DLL - bool isPageObject() const; - QPDF_DLL - bool isPagesObject() const; - QPDF_DLL - void assertPageObject() const; - - QPDF_DLL - bool isFormXObject() const; - - // Indicate if this is an image. If exclude_imagemask is true, don't count image masks as - // images. - QPDF_DLL - bool isImage(bool exclude_imagemask = true) const; - - // The following methods do not form part of the public API and are for internal use only. - - QPDFObjectHandle(std::shared_ptr const& obj) : - obj(obj) - { - } - std::shared_ptr - getObj() - { - return obj; - } - std::shared_ptr - getObj() const - { - return obj; - } - QPDFObject* - getObjectPtr() - { - return obj.get(); - } - QPDFObject* const - getObjectPtr() const - { - return obj.get(); - } - - void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false) const; - - private: - QPDF_Array* asArray() const; - QPDF_Bool* asBool() const; - QPDF_Dictionary* asDictionary() const; - QPDF_InlineImage* asInlineImage() const; - QPDF_Integer* asInteger() const; - QPDF_Name* asName() const; - QPDF_Null* asNull() const; - QPDF_Operator* asOperator() const; - QPDF_Real* asReal() const; - QPDF_Reserved* asReserved() const; - QPDF_Stream* asStream() const; - QPDF_Stream* asStreamWithAssert() const; - QPDF_String* asString() const; - - void typeWarning(char const* expected_type, std::string const& warning) const; - void objectWarning(std::string const& warning) const; - void assertType(char const* type_name, bool istype) const; - void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams); - void disconnect(); - void setParsedOffset(qpdf_offset_t offset); - void parseContentStream_internal(std::string const& description, ParserCallbacks* callbacks); - static void parseContentStream_data( - std::shared_ptr, - std::string const& description, - ParserCallbacks* callbacks, - QPDF* context); - std::vector - arrayOrStreamToStreamArray(std::string const& description, std::string& all_description); - static void warn(QPDF*, QPDFExc const&); - void checkOwnership(QPDFObjectHandle const&) const; - - // Moving members of QPDFObjectHandle into a smart pointer incurs a substantial performance - // penalty since QPDFObjectHandle objects are copied around so frequently. - std::shared_ptr obj; -}; - -#ifndef QPDF_NO_QPDF_STRING -// This is short for QPDFObjectHandle::parse, so you can do - -// auto oh = "<< /Key (value) >>"_qpdf; - -// If this is causing problems in your code, define QPDF_NO_QPDF_STRING to prevent the declaration -// from being here. - -/* clang-format off */ - // Disable formatting for this declaration: emacs font-lock in cc-mode (as of 28.1) treats the rest - // of the file as a string if clang-format removes the space after "operator", and as of - // clang-format 15, there's no way to prevent it from doing so. - QPDF_DLL - QPDFObjectHandle operator ""_qpdf(char const* v, size_t len); -/* clang-format on */ - -#endif // QPDF_NO_QPDF_STRING - -class QPDFObjectHandle::QPDFDictItems -{ - // This class allows C++-style iteration, including range-for iteration, around dictionaries. - // You can write - - // for (auto iter: QPDFDictItems(dictionary_obj)) - // { - // // iter.first is a string - // // iter.second is a QPDFObjectHandle - // } - - // See examples/pdf-name-number-tree.cc for a demonstration of using this API. - - public: - QPDF_DLL - QPDFDictItems(QPDFObjectHandle const& oh); - - class iterator - { - friend class QPDFDictItems; - - public: - typedef std::pair T; - using iterator_category = std::bidirectional_iterator_tag; - using value_type = T; - using difference_type = long; - using pointer = T*; - using reference = T&; - - QPDF_DLL - virtual ~iterator() = default; - QPDF_DLL - iterator& operator++(); - QPDF_DLL - iterator - operator++(int) - { - iterator t = *this; - ++(*this); - return t; - } - QPDF_DLL - iterator& operator--(); - QPDF_DLL - iterator - operator--(int) - { - iterator t = *this; - --(*this); - return t; - } - QPDF_DLL - reference operator*(); - QPDF_DLL - pointer operator->(); - QPDF_DLL - bool operator==(iterator const& other) const; - QPDF_DLL - bool - operator!=(iterator const& other) const - { - return !operator==(other); - } - - private: - iterator(QPDFObjectHandle& oh, bool for_begin); - void updateIValue(); - - class Members - { - friend class QPDFDictItems::iterator; - - public: - QPDF_DLL - ~Members() = default; - - private: - Members(QPDFObjectHandle& oh, bool for_begin); - Members() = delete; - Members(Members const&) = delete; - - QPDFObjectHandle& oh; - std::set keys; - std::set::iterator iter; - bool is_end; - }; - std::shared_ptr m; - value_type ivalue; - }; - - QPDF_DLL - iterator begin(); - QPDF_DLL - iterator end(); - - private: - QPDFObjectHandle oh; -}; - -class QPDFObjectHandle::QPDFArrayItems -{ - // This class allows C++-style iteration, including range-for iteration, around arrays. You can - // write - - // for (auto iter: QPDFArrayItems(array_obj)) - // { - // // iter is a QPDFObjectHandle - // } - - // See examples/pdf-name-number-tree.cc for a demonstration of using this API. - - public: - QPDF_DLL - QPDFArrayItems(QPDFObjectHandle const& oh); - - class iterator - { - friend class QPDFArrayItems; - - public: - typedef QPDFObjectHandle T; - using iterator_category = std::bidirectional_iterator_tag; - using value_type = T; - using difference_type = long; - using pointer = T*; - using reference = T&; - - QPDF_DLL - virtual ~iterator() = default; - QPDF_DLL - iterator& operator++(); - QPDF_DLL - iterator - operator++(int) - { - iterator t = *this; - ++(*this); - return t; - } - QPDF_DLL - iterator& operator--(); - QPDF_DLL - iterator - operator--(int) - { - iterator t = *this; - --(*this); - return t; - } - QPDF_DLL - reference operator*(); - QPDF_DLL - pointer operator->(); - QPDF_DLL - bool operator==(iterator const& other) const; - QPDF_DLL - bool - operator!=(iterator const& other) const - { - return !operator==(other); - } - - private: - iterator(QPDFObjectHandle& oh, bool for_begin); - void updateIValue(); - - class Members - { - friend class QPDFArrayItems::iterator; - - public: - QPDF_DLL - ~Members() = default; - - private: - Members(QPDFObjectHandle& oh, bool for_begin); - Members() = delete; - Members(Members const&) = delete; - - QPDFObjectHandle& oh; - int item_number; - bool is_end; - }; - std::shared_ptr m; - value_type ivalue; - }; - - QPDF_DLL - iterator begin(); - QPDF_DLL - iterator end(); - - private: - QPDFObjectHandle oh; -}; - -inline int -QPDFObjectHandle::getObjectID() const -{ - return getObjGen().getObj(); -} - -inline int -QPDFObjectHandle::getGeneration() const -{ - return getObjGen().getGen(); -} - -inline bool -QPDFObjectHandle::isIndirect() const -{ - return (obj != nullptr) && (getObjectID() != 0); -} - -inline bool -QPDFObjectHandle::isInitialized() const noexcept -{ - return obj != nullptr; -} - -inline QPDFObjectHandle:: -operator bool() const noexcept -{ - return static_cast(obj); -} - -#endif // QPDFOBJECTHANDLE_FUTURE_HH diff --git a/include/qpdf/QPDFOutlineDocumentHelper.hh b/include/qpdf/QPDFOutlineDocumentHelper.hh index c3c3f5e..1f152d5 100644 --- a/include/qpdf/QPDFOutlineDocumentHelper.hh +++ b/include/qpdf/QPDFOutlineDocumentHelper.hh @@ -58,16 +58,14 @@ class QPDFOutlineDocumentHelper: public QPDFDocumentHelper // Return a list outlines that are known to target the specified page. QPDF_DLL - std::vector getOutlinesForPage(QPDFObjGen const&); + std::vector getOutlinesForPage(QPDFObjGen); class Accessor { friend class QPDFOutlineObjectHelper; - // ABI: remove QPDF_DLL and pass og by value. - QPDF_DLL static bool - checkSeen(QPDFOutlineDocumentHelper& dh, QPDFObjGen const& og) + checkSeen(QPDFOutlineDocumentHelper& dh, QPDFObjGen og) { return !dh.m->seen.add(og); } diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index 0cde221..6b79a7f 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -485,7 +485,7 @@ class QPDFWriter void writeStringQDF(std::string_view str); void writeStringNoQDF(std::string_view str); void writePad(size_t nspaces); - void assignCompressedObjectNumbers(QPDFObjGen const& og); + void assignCompressedObjectNumbers(QPDFObjGen og); void enqueueObject(QPDFObjectHandle object); void writeObjectStreamOffsets(std::vector& offsets, int first_obj); void writeObjectStream(QPDFObjectHandle object); diff --git a/job.sums b/job.sums index c5b53e5..6b11e1d 100644 --- a/job.sums +++ b/job.sums @@ -1,5 +1,5 @@ # Generated by generate_auto_job -CMakeLists.txt e08751e992a61aee8a2944c98c4a2c7574edc1138133f81b5a3340512da0f24c +CMakeLists.txt f0819695e4867e4f4389d38b0c124e79aa3ec9ace50f16ad8c751ff7f1ec6690 generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a86 include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 @@ -16,5 +16,5 @@ libqpdf/qpdf/auto_job_json_init.hh 344c2fb473f88fe829c93b1efe6c70a0e4796537b8eb3 libqpdf/qpdf/auto_job_schema.hh 6d3eef5137b8828eaa301a1b3cf75cb7bb812aa6e2d8301de865b42d238d7a7c manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 manual/cli.rst 67357688f9a52fafa9a4f231fe4ce74c3cd8977130da7501efe54439a1ee22d4 -manual/qpdf.1 50102b93fd9afa8d605702ff2d19440dbed369c1c4660f14b71a4a162227c58e +manual/qpdf.1 78bad33f9b3f246f1800bce365f7be06d3545d89f08b8923dd8489031b5af43e manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b diff --git a/libqpdf/Buffer.cc b/libqpdf/Buffer.cc index 20453a4..26041af 100644 --- a/libqpdf/Buffer.cc +++ b/libqpdf/Buffer.cc @@ -4,16 +4,23 @@ #include -bool test_mode = false; - -// During CI the Buffer copy constructor and copy assignment operator throw an assertion error to -// detect their accidental use. Call setTestMode to surpress the assertion errors for testing of -// copy construction and assignment. -void -Buffer::setTestMode() noexcept +class Buffer::Members { - test_mode = true; -} + friend class Buffer; + + public: + ~Members(); + + private: + Members(size_t size, unsigned char* buf, bool own_memory); + Members(std::string&& content); + Members(Members const&) = delete; + + std::string str; + bool own_memory; + size_t size; + unsigned char* buf; +}; Buffer::Members::Members(size_t size, unsigned char* buf, bool own_memory) : own_memory(own_memory), @@ -67,20 +74,6 @@ Buffer::Buffer(std::string& content) : { } -Buffer::Buffer(Buffer const& rhs) -{ - assert(test_mode); - copy(rhs); -} - -Buffer& -Buffer::operator=(Buffer const& rhs) -{ - assert(test_mode); - copy(rhs); - return *this; -} - Buffer::Buffer(Buffer&& rhs) noexcept : m(std::move(rhs.m)) { @@ -93,6 +86,8 @@ Buffer::operator=(Buffer&& rhs) noexcept return *this; } +Buffer::~Buffer() = default; + void Buffer::copy(Buffer const& rhs) { diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 70bdf62..60303d1 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -112,7 +112,7 @@ namespace QPDF::ForeignStreamData::ForeignStreamData( std::shared_ptr encp, std::shared_ptr file, - QPDFObjGen const& foreign_og, + QPDFObjGen foreign_og, qpdf_offset_t offset, size_t length, QPDFObjectHandle local_dict) : @@ -164,7 +164,7 @@ QPDF::CopiedStreamDataProvider::registerForeignStream( this->foreign_stream_data[local_og] = foreign_stream; } -QPDF::StringDecrypter::StringDecrypter(QPDF* qpdf, QPDFObjGen const& og) : +QPDF::StringDecrypter::StringDecrypter(QPDF* qpdf, QPDFObjGen og) : qpdf(qpdf), og(og) { @@ -1463,7 +1463,7 @@ QPDF::getAllObjects() } void -QPDF::setLastObjectDescription(std::string const& description, QPDFObjGen const& og) +QPDF::setLastObjectDescription(std::string const& description, QPDFObjGen og) { m->last_object_description.clear(); if (!description.empty()) { @@ -1650,7 +1650,7 @@ QPDF::findEndstream() size_t QPDF::recoverStreamLength( - std::shared_ptr input, QPDFObjGen const& og, qpdf_offset_t stream_offset) + std::shared_ptr input, QPDFObjGen og, qpdf_offset_t stream_offset) { // Try to reconstruct stream length by looking for endstream or endobj warn(damagedPDF(*input, stream_offset, "attempting to recover stream length")); @@ -2023,7 +2023,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) } QPDFObjectHandle -QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr const& obj) +QPDF::newIndirect(QPDFObjGen og, std::shared_ptr const& obj) { obj->setDefaultDescription(this, og); return {obj}; @@ -2031,7 +2031,7 @@ QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr const& obj) void QPDF::updateCache( - QPDFObjGen const& og, + QPDFObjGen og, std::shared_ptr const& object, qpdf_offset_t end_before_space, qpdf_offset_t end_after_space) @@ -2048,13 +2048,13 @@ QPDF::updateCache( } bool -QPDF::isCached(QPDFObjGen const& og) +QPDF::isCached(QPDFObjGen og) { return m->obj_cache.count(og) != 0; } bool -QPDF::isUnresolved(QPDFObjGen const& og) +QPDF::isUnresolved(QPDFObjGen og) { return !isCached(og) || m->obj_cache[og].object->isUnresolved(); } @@ -2152,7 +2152,7 @@ QPDF::getObjectForJSON(int id, int gen) } QPDFObjectHandle -QPDF::getObject(QPDFObjGen const& og) +QPDF::getObject(QPDFObjGen og) { if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) { return {it->second.object}; @@ -2171,7 +2171,7 @@ QPDF::getObject(int objid, int generation) } QPDFObjectHandle -QPDF::getObjectByObjGen(QPDFObjGen const& og) +QPDF::getObjectByObjGen(QPDFObjGen og) { return getObject(og); } @@ -2189,7 +2189,7 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh) } void -QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh) +QPDF::replaceObject(QPDFObjGen og, QPDFObjectHandle oh) { if (!oh || (oh.isIndirect() && !(oh.isStream() && oh.getObjGen() == og))) { QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); @@ -2493,7 +2493,7 @@ QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2) } void -QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2) +QPDF::swapObjects(QPDFObjGen og1, QPDFObjGen og2) { // Force objects to be read from the input source if needed, then swap them in the cache. resolve(og1); @@ -2727,7 +2727,7 @@ QPDF::pipeStreamData( std::shared_ptr encp, std::shared_ptr file, QPDF& qpdf_for_warning, - QPDFObjGen const& og, + QPDFObjGen og, qpdf_offset_t offset, size_t length, QPDFObjectHandle stream_dict, @@ -2789,7 +2789,7 @@ QPDF::pipeStreamData( bool QPDF::pipeStreamData( - QPDFObjGen const& og, + QPDFObjGen og, qpdf_offset_t offset, size_t length, QPDFObjectHandle stream_dict, diff --git a/libqpdf/QPDFNumberTreeObjectHelper.cc b/libqpdf/QPDFNumberTreeObjectHelper.cc index 478a188..adf3ddd 100644 --- a/libqpdf/QPDFNumberTreeObjectHelper.cc +++ b/libqpdf/QPDFNumberTreeObjectHelper.cc @@ -218,7 +218,7 @@ QPDFNumberTreeObjectHelper::findObjectAtOrBelow( return false; } oh = i->second; - QIntC::range_check_substract(idx, i->first); + QIntC::range_check_subtract(idx, i->first); offset = idx - i->first; return true; } diff --git a/libqpdf/QPDFObjGen.cc b/libqpdf/QPDFObjGen.cc index f3b19f6..5242f4f 100644 --- a/libqpdf/QPDFObjGen.cc +++ b/libqpdf/QPDFObjGen.cc @@ -6,21 +6,6 @@ #include -// ABI: inline and pass og by value -std::ostream& -operator<<(std::ostream& os, const QPDFObjGen& og) -{ - os << og.obj << "," << og.gen; - return os; -} - -// ABI: inline -std::string -QPDFObjGen::unparse(char separator) const -{ - return std::to_string(obj) + separator + std::to_string(gen); -} - bool QPDFObjGen::set::add(QPDFObjectHandle const& oh) { diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index b3de030..6fd62f2 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -221,19 +221,11 @@ LastChar::getLastChar() return this->last_char; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const -{ - return this->obj == rhs.obj; -} -#else bool QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const noexcept { return this->obj == rhs.obj; } -#endif void QPDFObjectHandle::disconnect() { @@ -245,24 +237,14 @@ QPDFObjectHandle::disconnect() } } -#ifndef QPDF_FUTURE -qpdf_object_type_e -QPDFObjectHandle::getTypeCode() -#else qpdf_object_type_e QPDFObjectHandle::getTypeCode() const -#endif { return obj ? obj->getResolvedTypeCode() : ::ot_uninitialized; } -#ifndef QPDF_FUTURE -char const* -QPDFObjectHandle::getTypeName() -#else char const* QPDFObjectHandle::getTypeName() const -#endif { static constexpr std::array tn{ "uninitialized", @@ -363,24 +345,14 @@ QPDFObjectHandle::asString() const return obj ? obj->as() : nullptr; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isDestroyed() -#else bool QPDFObjectHandle::isDestroyed() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_destroyed; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isBool() -#else bool QPDFObjectHandle::isBool() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_boolean; } @@ -393,57 +365,32 @@ QPDFObjectHandle::isDirectNull() const return (obj && getObjectID() == 0 && obj->getTypeCode() == ::ot_null); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isNull() -#else bool QPDFObjectHandle::isNull() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_null; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isInteger() -#else bool QPDFObjectHandle::isInteger() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_integer; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isReal() -#else bool QPDFObjectHandle::isReal() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_real; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isNumber() -#else bool QPDFObjectHandle::isNumber() const -#endif { return (isInteger() || isReal()); } -#ifndef QPDF_FUTURE -double -QPDFObjectHandle::getNumericValue() -#else double QPDFObjectHandle::getNumericValue() const -#endif { if (isInteger()) { return static_cast(getIntValue()); @@ -456,13 +403,8 @@ QPDFObjectHandle::getNumericValue() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsNumber(double& value) -#else bool QPDFObjectHandle::getValueAsNumber(double& value) const -#endif { if (!isNumber()) { return false; @@ -471,148 +413,83 @@ QPDFObjectHandle::getValueAsNumber(double& value) const return true; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isName() -#else bool QPDFObjectHandle::isName() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_name; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isString() -#else bool QPDFObjectHandle::isString() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_string; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isOperator() -#else bool QPDFObjectHandle::isOperator() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_operator; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isInlineImage() -#else bool QPDFObjectHandle::isInlineImage() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_inlineimage; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isArray() -#else bool QPDFObjectHandle::isArray() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_array; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isDictionary() -#else bool QPDFObjectHandle::isDictionary() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_dictionary; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isStream() -#else bool QPDFObjectHandle::isStream() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_stream; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isReserved() -#else bool QPDFObjectHandle::isReserved() const -#endif { return obj && obj->getResolvedTypeCode() == ::ot_reserved; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isScalar() -#else bool QPDFObjectHandle::isScalar() const -#endif { return isBool() || isInteger() || isName() || isNull() || isReal() || isString(); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isNameAndEquals(std::string const& name) -#else bool QPDFObjectHandle::isNameAndEquals(std::string const& name) const -#endif { return isName() && (getName() == name); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isDictionaryOfType(std::string const& type, std::string const& subtype) -#else bool QPDFObjectHandle::isDictionaryOfType(std::string const& type, std::string const& subtype) const -#endif { return isDictionary() && (type.empty() || getKey("/Type").isNameAndEquals(type)) && (subtype.empty() || getKey("/Subtype").isNameAndEquals(subtype)); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isStreamOfType(std::string const& type, std::string const& subtype) -#else bool QPDFObjectHandle::isStreamOfType(std::string const& type, std::string const& subtype) const -#endif { return isStream() && getDict().isDictionaryOfType(type, subtype); } // Bool accessors -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getBoolValue() -#else bool QPDFObjectHandle::getBoolValue() const -#endif { auto boolean = asBool(); if (boolean) { @@ -624,13 +501,8 @@ QPDFObjectHandle::getBoolValue() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsBool(bool& value) -#else bool QPDFObjectHandle::getValueAsBool(bool& value) const -#endif { auto boolean = asBool(); if (boolean == nullptr) { @@ -642,13 +514,8 @@ QPDFObjectHandle::getValueAsBool(bool& value) const // Integer accessors -#ifndef QPDF_FUTURE -long long -QPDFObjectHandle::getIntValue() -#else long long QPDFObjectHandle::getIntValue() const -#endif { auto integer = asInteger(); if (integer) { @@ -660,13 +527,8 @@ QPDFObjectHandle::getIntValue() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsInt(long long& value) -#else bool QPDFObjectHandle::getValueAsInt(long long& value) const -#endif { auto integer = asInteger(); if (integer == nullptr) { @@ -676,13 +538,8 @@ QPDFObjectHandle::getValueAsInt(long long& value) const return true; } -#ifndef QPDF_FUTURE -int -QPDFObjectHandle::getIntValueAsInt() -#else int QPDFObjectHandle::getIntValueAsInt() const -#endif { int result = 0; long long v = getIntValue(); @@ -700,13 +557,8 @@ QPDFObjectHandle::getIntValueAsInt() const return result; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsInt(int& value) -#else bool QPDFObjectHandle::getValueAsInt(int& value) const -#endif { if (!isInteger()) { return false; @@ -715,13 +567,8 @@ QPDFObjectHandle::getValueAsInt(int& value) const return true; } -#ifndef QPDF_FUTURE -unsigned long long -QPDFObjectHandle::getUIntValue() -#else unsigned long long QPDFObjectHandle::getUIntValue() const -#endif { long long v = getIntValue(); if (v < 0) { @@ -733,13 +580,8 @@ QPDFObjectHandle::getUIntValue() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsUInt(unsigned long long& value) -#else bool QPDFObjectHandle::getValueAsUInt(unsigned long long& value) const -#endif { if (!isInteger()) { return false; @@ -748,13 +590,8 @@ QPDFObjectHandle::getValueAsUInt(unsigned long long& value) const return true; } -#ifndef QPDF_FUTURE -unsigned int -QPDFObjectHandle::getUIntValueAsUInt() -#else unsigned int QPDFObjectHandle::getUIntValueAsUInt() const -#endif { long long v = getIntValue(); if (v < 0) { @@ -770,13 +607,8 @@ QPDFObjectHandle::getUIntValueAsUInt() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsUInt(unsigned int& value) -#else bool QPDFObjectHandle::getValueAsUInt(unsigned int& value) const -#endif { if (!isInteger()) { return false; @@ -787,13 +619,8 @@ QPDFObjectHandle::getValueAsUInt(unsigned int& value) const // Real accessors -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::getRealValue() -#else std::string QPDFObjectHandle::getRealValue() const -#endif { if (isReal()) { return obj->getStringValue(); @@ -804,13 +631,8 @@ QPDFObjectHandle::getRealValue() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsReal(std::string& value) -#else bool QPDFObjectHandle::getValueAsReal(std::string& value) const -#endif { if (!isReal()) { return false; @@ -821,13 +643,8 @@ QPDFObjectHandle::getValueAsReal(std::string& value) const // Name accessors -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::getName() -#else std::string QPDFObjectHandle::getName() const -#endif { if (isName()) { return obj->getStringValue(); @@ -838,13 +655,8 @@ QPDFObjectHandle::getName() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsName(std::string& value) -#else bool QPDFObjectHandle::getValueAsName(std::string& value) const -#endif { if (!isName()) { return false; @@ -855,13 +667,8 @@ QPDFObjectHandle::getValueAsName(std::string& value) const // String accessors -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::getStringValue() -#else std::string QPDFObjectHandle::getStringValue() const -#endif { if (isString()) { return obj->getStringValue(); @@ -872,13 +679,8 @@ QPDFObjectHandle::getStringValue() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsString(std::string& value) -#else bool QPDFObjectHandle::getValueAsString(std::string& value) const -#endif { if (!isString()) { return false; @@ -887,13 +689,8 @@ QPDFObjectHandle::getValueAsString(std::string& value) const return true; } -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::getUTF8Value() -#else std::string QPDFObjectHandle::getUTF8Value() const -#endif { auto str = asString(); if (str) { @@ -905,13 +702,8 @@ QPDFObjectHandle::getUTF8Value() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsUTF8(std::string& value) -#else bool QPDFObjectHandle::getValueAsUTF8(std::string& value) const -#endif { auto str = asString(); if (str == nullptr) { @@ -923,13 +715,8 @@ QPDFObjectHandle::getValueAsUTF8(std::string& value) const // Operator and Inline Image accessors -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::getOperatorValue() -#else std::string QPDFObjectHandle::getOperatorValue() const -#endif { if (isOperator()) { return obj->getStringValue(); @@ -940,13 +727,8 @@ QPDFObjectHandle::getOperatorValue() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsOperator(std::string& value) -#else bool QPDFObjectHandle::getValueAsOperator(std::string& value) const -#endif { if (!isOperator()) { return false; @@ -955,13 +737,8 @@ QPDFObjectHandle::getValueAsOperator(std::string& value) const return true; } -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::getInlineImageValue() -#else std::string QPDFObjectHandle::getInlineImageValue() const -#endif { if (isInlineImage()) { return obj->getStringValue(); @@ -972,13 +749,8 @@ QPDFObjectHandle::getInlineImageValue() const } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::getValueAsInlineImage(std::string& value) -#else bool QPDFObjectHandle::getValueAsInlineImage(std::string& value) const -#endif { if (!isInlineImage()) { return false; @@ -995,13 +767,8 @@ QPDFObjectHandle::aitems() return *this; } -#ifndef QPDF_FUTURE -int -QPDFObjectHandle::getArrayNItems() -#else int QPDFObjectHandle::getArrayNItems() const -#endif { if (auto array = asArray()) { return array->size(); @@ -1012,13 +779,8 @@ QPDFObjectHandle::getArrayNItems() const } } -#ifndef QPDF_FUTURE -QPDFObjectHandle -QPDFObjectHandle::getArrayItem(int n) -#else QPDFObjectHandle QPDFObjectHandle::getArrayItem(int n) const -#endif { if (auto array = asArray()) { auto result = array->at(n); @@ -1036,13 +798,8 @@ QPDFObjectHandle::getArrayItem(int n) const return QPDF_Null::create(obj, msg, ""); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isRectangle() -#else bool QPDFObjectHandle::isRectangle() const -#endif { if (auto array = asArray()) { for (int i = 0; i < 4; ++i) { @@ -1055,13 +812,8 @@ QPDFObjectHandle::isRectangle() const return false; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isMatrix() -#else bool QPDFObjectHandle::isMatrix() const -#endif { if (auto array = asArray()) { for (int i = 0; i < 6; ++i) { @@ -1074,13 +826,8 @@ QPDFObjectHandle::isMatrix() const return false; } -#ifndef QPDF_FUTURE -QPDFObjectHandle::Rectangle -QPDFObjectHandle::getArrayAsRectangle() -#else QPDFObjectHandle::Rectangle QPDFObjectHandle::getArrayAsRectangle() const -#endif { if (auto array = asArray()) { if (array->size() != 4) { @@ -1101,13 +848,8 @@ QPDFObjectHandle::getArrayAsRectangle() const return {}; } -#ifndef QPDF_FUTURE -QPDFObjectHandle::Matrix -QPDFObjectHandle::getArrayAsMatrix() -#else QPDFObjectHandle::Matrix QPDFObjectHandle::getArrayAsMatrix() const -#endif { if (auto array = asArray()) { if (array->size() != 6) { @@ -1124,13 +866,8 @@ QPDFObjectHandle::getArrayAsMatrix() const return {}; } -#ifndef QPDF_FUTURE -std::vector -QPDFObjectHandle::getArrayAsVector() -#else std::vector QPDFObjectHandle::getArrayAsVector() const -#endif { auto array = asArray(); if (array) { @@ -1238,13 +975,8 @@ QPDFObjectHandle::ditems() return {*this}; } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::hasKey(std::string const& key) -#else bool QPDFObjectHandle::hasKey(std::string const& key) const -#endif { auto dict = asDictionary(); if (dict) { @@ -1256,13 +988,8 @@ QPDFObjectHandle::hasKey(std::string const& key) const } } -#ifndef QPDF_FUTURE -QPDFObjectHandle -QPDFObjectHandle::getKey(std::string const& key) -#else QPDFObjectHandle QPDFObjectHandle::getKey(std::string const& key) const -#endif { if (auto dict = asDictionary()) { return dict->getKey(key); @@ -1274,24 +1001,14 @@ QPDFObjectHandle::getKey(std::string const& key) const } } -#ifndef QPDF_FUTURE -QPDFObjectHandle -QPDFObjectHandle::getKeyIfDict(std::string const& key) -#else QPDFObjectHandle QPDFObjectHandle::getKeyIfDict(std::string const& key) const -#endif { return isNull() ? newNull() : getKey(key); } -#ifndef QPDF_FUTURE -std::set -QPDFObjectHandle::getKeys() -#else std::set QPDFObjectHandle::getKeys() const -#endif { std::set result; auto dict = asDictionary(); @@ -1304,13 +1021,8 @@ QPDFObjectHandle::getKeys() const return result; } -#ifndef QPDF_FUTURE -std::map -QPDFObjectHandle::getDictAsMap() -#else std::map QPDFObjectHandle::getDictAsMap() const -#endif { std::map result; auto dict = asDictionary(); @@ -1324,13 +1036,9 @@ QPDFObjectHandle::getDictAsMap() const } // Array and Name accessors -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isOrHasName(std::string const& value) -#else + bool QPDFObjectHandle::isOrHasName(std::string const& value) const -#endif { if (isNameAndEquals(value)) { return true; @@ -1458,13 +1166,8 @@ QPDFObjectHandle::mergeResources( } } -#ifndef QPDF_FUTURE -std::set -QPDFObjectHandle::getResourceNames() -#else std::set QPDFObjectHandle::getResourceNames() const -#endif { // Return second-level dictionary keys std::set result; @@ -1482,16 +1185,9 @@ QPDFObjectHandle::getResourceNames() const return result; } -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::getUniqueResourceName( - std::string const& prefix, int& min_suffix, std::set* namesp) -#else std::string QPDFObjectHandle::getUniqueResourceName( std::string const& prefix, int& min_suffix, std::set* namesp) const -#endif - { std::set names = (namesp ? *namesp : getResourceNames()); int max_suffix = min_suffix + QIntC::to_int(names.size()); @@ -1573,13 +1269,9 @@ QPDFObjectHandle::replaceOrRemoveKey(std::string const& key, QPDFObjectHandle co } // Stream accessors -#ifndef QPDF_FUTURE -QPDFObjectHandle -QPDFObjectHandle::getDict() -#else + QPDFObjectHandle QPDFObjectHandle::getDict() const -#endif { return asStreamWithAssert()->getDict(); } @@ -1894,13 +1586,8 @@ QPDFObjectHandle::coalesceContentStreams() new_contents.replaceStreamData(provider, newNull(), newNull()); } -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::unparse() -#else std::string QPDFObjectHandle::unparse() const -#endif { if (this->isIndirect()) { return getObjGen().unparse(' ') + " R"; @@ -1909,13 +1596,8 @@ QPDFObjectHandle::unparse() const } } -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::unparseResolved() -#else std::string QPDFObjectHandle::unparseResolved() const -#endif { if (!obj) { throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); @@ -1923,13 +1605,8 @@ QPDFObjectHandle::unparseResolved() const return obj->unparse(); } -#ifndef QPDF_FUTURE -std::string -QPDFObjectHandle::unparseBinary() -#else std::string QPDFObjectHandle::unparseBinary() const -#endif { if (auto str = asString()) { return str->unparse(true); @@ -1938,25 +1615,8 @@ QPDFObjectHandle::unparseBinary() const } } -// Deprecated versionless getJSON to be removed in qpdf 12 -#ifndef QPDF_FUTURE -JSON -QPDFObjectHandle::getJSON(bool dereference_indirect) -#else -JSON -QPDFObjectHandle::getJSON(bool dereference_indirect) const -#endif -{ - return getJSON(1, dereference_indirect); -} - -#ifndef QPDF_FUTURE -JSON -QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) -#else JSON QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) const -#endif { if ((!dereference_indirect) && isIndirect()) { return JSON::makeString(unparse()); @@ -1971,13 +1631,8 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) const } } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect) -#else void QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect) const -#endif { if (!dereference_indirect && isIndirect()) { p << "\"" << getObjGen().unparse(' ') << " R\""; @@ -1988,14 +1643,9 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_ } } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::writeJSON(int json_version, Pipeline* p, bool dereference_indirect, size_t depth) -#else void QPDFObjectHandle::writeJSON( int json_version, Pipeline* p, bool dereference_indirect, size_t depth) const -#endif { JSON::Writer jw{p, depth}; writeJSON(json_version, jw, dereference_indirect); @@ -2229,13 +1879,8 @@ QPDFObjectHandle::parse( .parse(empty, false); } -#ifndef QPDF_FUTURE -qpdf_offset_t -QPDFObjectHandle::getParsedOffset() -#else qpdf_offset_t QPDFObjectHandle::getParsedOffset() const -#endif { return obj ? obj->getParsedOffset() : -1; } @@ -2420,13 +2065,8 @@ QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& obj } } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::hasObjectDescription() -#else bool QPDFObjectHandle::hasObjectDescription() const -#endif { return obj && obj->hasDescription(); } @@ -2550,13 +2190,8 @@ QPDFObjectHandle::typeWarning(char const* expected_type, std::string const& warn QPDFObjectHandle(*this).getTypeName() + ": " + warning)); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::warnIfPossible(std::string const& warning) -#else void QPDFObjectHandle::warnIfPossible(std::string const& warning) const -#endif { QPDF* context = nullptr; std::string description; @@ -2588,180 +2223,100 @@ QPDFObjectHandle::assertType(char const* type_name, bool istype) const } } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertNull() -#else void QPDFObjectHandle::assertNull() const -#endif { assertType("null", isNull()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertBool() -#else void QPDFObjectHandle::assertBool() const -#endif { assertType("boolean", isBool()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertInteger() -#else void QPDFObjectHandle::assertInteger() const -#endif { assertType("integer", isInteger()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertReal() -#else void QPDFObjectHandle::assertReal() const -#endif { assertType("real", isReal()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertName() -#else void QPDFObjectHandle::assertName() const -#endif { assertType("name", isName()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertString() -#else void QPDFObjectHandle::assertString() const -#endif { assertType("string", isString()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertOperator() -#else void QPDFObjectHandle::assertOperator() const -#endif { assertType("operator", isOperator()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertInlineImage() -#else void QPDFObjectHandle::assertInlineImage() const -#endif { assertType("inlineimage", isInlineImage()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertArray() -#else void QPDFObjectHandle::assertArray() const -#endif { assertType("array", isArray()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertDictionary() -#else void QPDFObjectHandle::assertDictionary() const -#endif { assertType("dictionary", isDictionary()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertStream() -#else void QPDFObjectHandle::assertStream() const -#endif { assertType("stream", isStream()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertReserved() -#else void QPDFObjectHandle::assertReserved() const -#endif { assertType("reserved", isReserved()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertIndirect() -#else void QPDFObjectHandle::assertIndirect() const -#endif { if (!isIndirect()) { throw std::logic_error("operation for indirect object attempted on direct object"); } } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertScalar() -#else void QPDFObjectHandle::assertScalar() const -#endif { assertType("scalar", isScalar()); } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertNumber() -#else void QPDFObjectHandle::assertNumber() const -#endif { assertType("number", isNumber()); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isPageObject() -#else bool QPDFObjectHandle::isPageObject() const -#endif { // See comments in QPDFObjectHandle.hh. if (getOwningQPDF() == nullptr) { @@ -2772,13 +2327,8 @@ QPDFObjectHandle::isPageObject() const return isDictionaryOfType("/Page"); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isPagesObject() -#else bool QPDFObjectHandle::isPagesObject() const -#endif { if (getOwningQPDF() == nullptr) { return false; @@ -2788,24 +2338,14 @@ QPDFObjectHandle::isPagesObject() const return isDictionaryOfType("/Pages"); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isFormXObject() -#else bool QPDFObjectHandle::isFormXObject() const -#endif { return isStreamOfType("", "/Form"); } -#ifndef QPDF_FUTURE -bool -QPDFObjectHandle::isImage(bool exclude_imagemask) -#else bool QPDFObjectHandle::isImage(bool exclude_imagemask) const -#endif { return ( isStreamOfType("", "/Image") && @@ -2827,13 +2367,8 @@ QPDFObjectHandle::checkOwnership(QPDFObjectHandle const& item) const } } -#ifndef QPDF_FUTURE -void -QPDFObjectHandle::assertPageObject() -#else void QPDFObjectHandle::assertPageObject() const -#endif { if (!isPageObject()) { throw std::runtime_error("page operation called on non-Page object"); diff --git a/libqpdf/QPDFOutlineDocumentHelper.cc b/libqpdf/QPDFOutlineDocumentHelper.cc index 51783b1..9028cd3 100644 --- a/libqpdf/QPDFOutlineDocumentHelper.cc +++ b/libqpdf/QPDFOutlineDocumentHelper.cc @@ -50,7 +50,7 @@ QPDFOutlineDocumentHelper::initializeByPage() } std::vector -QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen const& og) +QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen og) { if (m->by_page.empty()) { initializeByPage(); diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 6652a40..d0d9159 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -1058,7 +1058,7 @@ QPDFWriter::closeObject(int objid) } void -QPDFWriter::assignCompressedObjectNumbers(QPDFObjGen const& og) +QPDFWriter::assignCompressedObjectNumbers(QPDFObjGen og) { int objid = og.getObj(); if ((og.getGen() != 0) || (m->object_stream_to_objects.count(objid) == 0)) { diff --git a/libqpdf/QPDF_Unresolved.cc b/libqpdf/QPDF_Unresolved.cc index a322e57..ae0c6a6 100644 --- a/libqpdf/QPDF_Unresolved.cc +++ b/libqpdf/QPDF_Unresolved.cc @@ -3,13 +3,13 @@ #include #include -QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og) : +QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen og) : QPDFValue(::ot_unresolved, qpdf, og) { } std::shared_ptr -QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen const& og) +QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen og) { return do_create(new QPDF_Unresolved(qpdf, og)); } diff --git a/libqpdf/QPDF_encryption.cc b/libqpdf/QPDF_encryption.cc index 952b860..9f39345 100644 --- a/libqpdf/QPDF_encryption.cc +++ b/libqpdf/QPDF_encryption.cc @@ -952,8 +952,7 @@ QPDF::initializeEncryption() } std::string -QPDF::getKeyForObject( - std::shared_ptr encp, QPDFObjGen const& og, bool use_aes) +QPDF::getKeyForObject(std::shared_ptr encp, QPDFObjGen og, bool use_aes) { if (!encp->encrypted) { throw std::logic_error("request for encryption key in non-encrypted PDF"); @@ -974,7 +973,7 @@ QPDF::getKeyForObject( } void -QPDF::decryptString(std::string& str, QPDFObjGen const& og) +QPDF::decryptString(std::string& str, QPDFObjGen og) { if (!og.isIndirect()) { return; @@ -1048,7 +1047,7 @@ QPDF::decryptStream( std::shared_ptr file, QPDF& qpdf_for_warning, Pipeline*& pipeline, - QPDFObjGen const& og, + QPDFObjGen og, QPDFObjectHandle& stream_dict, std::unique_ptr& decrypt_pipeline) { diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc index 907734a..703617a 100644 --- a/libqpdf/QPDF_linearization.cc +++ b/libqpdf/QPDF_linearization.cc @@ -557,7 +557,7 @@ QPDF::maxEnd(ObjUser const& ou) } qpdf_offset_t -QPDF::getLinearizationOffset(QPDFObjGen const& og) +QPDF::getLinearizationOffset(QPDFObjGen og) { QPDFXRefEntry entry = m->xref_table[og]; qpdf_offset_t result = 0; diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index d64b08f..aa90f7f 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -323,7 +323,7 @@ QPDF::findPage(QPDFObjectHandle& page) } int -QPDF::findPage(QPDFObjGen const& og) +QPDF::findPage(QPDFObjGen og) { flattenPagesTree(); auto it = m->pageobj_to_pages_pos.find(og); diff --git a/libqpdf/qpdf/QPDFObject_private.hh b/libqpdf/qpdf/QPDFObject_private.hh index f323d95..d3f3821 100644 --- a/libqpdf/qpdf/QPDFObject_private.hh +++ b/libqpdf/qpdf/QPDFObject_private.hh @@ -132,13 +132,13 @@ class QPDFObject } void - setDefaultDescription(QPDF* qpdf, QPDFObjGen const& og) + setDefaultDescription(QPDF* qpdf, QPDFObjGen og) { // Intended for use by the QPDF class value->setDefaultDescription(qpdf, og); } void - setObjGen(QPDF* qpdf, QPDFObjGen const& og) + setObjGen(QPDF* qpdf, QPDFObjGen og) { value->qpdf = qpdf; value->og = og; diff --git a/libqpdf/qpdf/QPDFValue.hh b/libqpdf/qpdf/QPDFValue.hh index c2fc748..b247093 100644 --- a/libqpdf/qpdf/QPDFValue.hh +++ b/libqpdf/qpdf/QPDFValue.hh @@ -65,7 +65,7 @@ class QPDFValue: public std::enable_shared_from_this setParsedOffset(offset); } void - setDefaultDescription(QPDF* a_qpdf, QPDFObjGen const& a_og) + setDefaultDescription(QPDF* a_qpdf, QPDFObjGen a_og) { qpdf = a_qpdf; og = a_og; diff --git a/libqpdf/qpdf/QPDF_Unresolved.hh b/libqpdf/qpdf/QPDF_Unresolved.hh index df443d3..bcd5a63 100644 --- a/libqpdf/qpdf/QPDF_Unresolved.hh +++ b/libqpdf/qpdf/QPDF_Unresolved.hh @@ -7,14 +7,14 @@ class QPDF_Unresolved: public QPDFValue { public: ~QPDF_Unresolved() override = default; - static std::shared_ptr create(QPDF* qpdf, QPDFObjGen const& og); + static std::shared_ptr create(QPDF* qpdf, QPDFObjGen og); std::shared_ptr copy(bool shallow = false) override; std::string unparse() override; void writeJSON(int json_version, JSON::Writer& p) override; std::string getStringValue() const override; private: - QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og); + QPDF_Unresolved(QPDF* qpdf, QPDFObjGen og); }; #endif // QPDF_UNRESOLVED_HH diff --git a/libtests/buffer.cc b/libtests/buffer.cc index 1b87bb7..4326901 100644 --- a/libtests/buffer.cc +++ b/libtests/buffer.cc @@ -18,130 +18,65 @@ uc(char const* s) int main() { - { - // Test that buffers can be copied by value using Buffer::copy. - Buffer bc1(2); - unsigned char* bc1p = bc1.getBuffer(); - bc1p[0] = 'Q'; - bc1p[1] = 'W'; - Buffer bc2(bc1.copy()); - bc1p[0] = 'R'; - unsigned char* bc2p = bc2.getBuffer(); - assert(bc2p != bc1p); - assert(bc2p[0] == 'Q'); - assert(bc2p[1] == 'W'); - bc2 = bc1.copy(); - bc2p = bc2.getBuffer(); - assert(bc2p != bc1p); - assert(bc2p[0] == 'R'); - assert(bc2p[1] == 'W'); - - // Test Buffer(std:string&&) - Buffer bc3("QW"); - unsigned char* bc3p = bc3.getBuffer(); - Buffer bc4(bc3.copy()); - bc3p[0] = 'R'; - unsigned char* bc4p = bc4.getBuffer(); - assert(bc4p != bc3p); - assert(bc4p[0] == 'Q'); - assert(bc4p[1] == 'W'); - bc4 = bc3.copy(); - bc4p = bc4.getBuffer(); - assert(bc4p != bc3p); - assert(bc4p[0] == 'R'); - assert(bc4p[1] == 'W'); - } - -#ifdef _MSC_VER -# pragma warning(disable : 4996) -#endif -#if (defined(__GNUC__) || defined(__clang__)) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - { - // Test that buffers can be copied by value using copy construction / assignment. - Buffer::setTestMode(); - Buffer bc1(2); - unsigned char* bc1p = bc1.getBuffer(); - bc1p[0] = 'Q'; - bc1p[1] = 'W'; - Buffer bc2(bc1); - bc1p[0] = 'R'; - unsigned char* bc2p = bc2.getBuffer(); - assert(bc2p != bc1p); - assert(bc2p[0] == 'Q'); - assert(bc2p[1] == 'W'); - bc2 = bc1; - bc2p = bc2.getBuffer(); - assert(bc2p != bc1p); - assert(bc2p[0] == 'R'); - assert(bc2p[1] == 'W'); - - // Test Buffer(std:string&&) - Buffer bc3("QW"); - unsigned char* bc3p = bc3.getBuffer(); - Buffer bc4(bc3); - bc3p[0] = 'R'; - unsigned char* bc4p = bc4.getBuffer(); - assert(bc4p != bc3p); - assert(bc4p[0] == 'Q'); - assert(bc4p[1] == 'W'); - bc4 = bc3; - bc4p = bc4.getBuffer(); - assert(bc4p != bc3p); - assert(bc2p[0] == 'R'); - assert(bc2p[1] == 'W'); - - // Test Buffer(std:string&) - std::string s{"QW"}; - Buffer bc5(s); - unsigned char* bc5p = bc5.getBuffer(); - Buffer bc6(bc5); - bc5p[0] = 'R'; - unsigned char* bc6p = bc6.getBuffer(); - assert(bc6p != bc5p); - assert(bc6p[0] == 'Q'); - assert(bc6p[1] == 'W'); - bc6 = bc5; - bc6p = bc6.getBuffer(); - assert(bc6p != bc5p); - assert(bc2p[0] == 'R'); - assert(bc2p[1] == 'W'); - } -#if (defined(__GNUC__) || defined(__clang__)) -# pragma GCC diagnostic pop -#endif - - { - // Test that buffers can be moved. - Buffer bm1(2); - unsigned char* bm1p = bm1.getBuffer(); - bm1p[0] = 'Q'; - bm1p[1] = 'W'; - Buffer bm2(std::move(bm1)); - bm1p[0] = 'R'; - unsigned char* bm2p = bm2.getBuffer(); - assert(bm2p == bm1p); - assert(bm2p[0] == 'R'); - - Buffer bm3 = std::move(bm2); - unsigned char* bm3p = bm3.getBuffer(); - assert(bm3p == bm2p); - - // Test Buffer(dtd::string&&) - Buffer bm4("QW"); - unsigned char* bm4p = bm4.getBuffer(); - Buffer bm5(std::move(bm4)); - bm4p[0] = 'R'; - unsigned char* bm5p = bm5.getBuffer(); - assert(bm5p == bm4p); - assert(bm5p[0] == 'R'); - - Buffer bm6 = std::move(bm5); - unsigned char* bm6p = bm6.getBuffer(); - assert(bm6p == bm5p); - } + // Test that buffers can be copied by value using Buffer::copy. + Buffer bc1(2); + unsigned char* bc1p = bc1.getBuffer(); + bc1p[0] = 'Q'; + bc1p[1] = 'W'; + Buffer bc2(bc1.copy()); + bc1p[0] = 'R'; + unsigned char* bc2p = bc2.getBuffer(); + assert(bc2p != bc1p); + assert(bc2p[0] == 'Q'); + assert(bc2p[1] == 'W'); + bc2 = bc1.copy(); + bc2p = bc2.getBuffer(); + assert(bc2p != bc1p); + assert(bc2p[0] == 'R'); + assert(bc2p[1] == 'W'); + + // Test Buffer(std:string&&) + Buffer bc3("QW"); + unsigned char* bc3p = bc3.getBuffer(); + Buffer bc4(bc3.copy()); + bc3p[0] = 'R'; + unsigned char* bc4p = bc4.getBuffer(); + assert(bc4p != bc3p); + assert(bc4p[0] == 'Q'); + assert(bc4p[1] == 'W'); + bc4 = bc3.copy(); + bc4p = bc4.getBuffer(); + assert(bc4p != bc3p); + assert(bc4p[0] == 'R'); + assert(bc4p[1] == 'W'); + + // Test that buffers can be moved. + Buffer bm1(2); + unsigned char* bm1p = bm1.getBuffer(); + bm1p[0] = 'Q'; + bm1p[1] = 'W'; + Buffer bm2(std::move(bm1)); + bm1p[0] = 'R'; + unsigned char* bm2p = bm2.getBuffer(); + assert(bm2p == bm1p); + assert(bm2p[0] == 'R'); + + Buffer bm3 = std::move(bm2); + unsigned char* bm3p = bm3.getBuffer(); + assert(bm3p == bm2p); + + // Test Buffer(dtd::string&&) + Buffer bm4("QW"); + unsigned char* bm4p = bm4.getBuffer(); + Buffer bm5(std::move(bm4)); + bm4p[0] = 'R'; + unsigned char* bm5p = bm5.getBuffer(); + assert(bm5p == bm4p); + assert(bm5p[0] == 'R'); + + Buffer bm6 = std::move(bm5); + unsigned char* bm6p = bm6.getBuffer(); + assert(bm6p == bm5p); try { Pl_Discard discard; diff --git a/libtests/qintc.cc b/libtests/qintc.cc index d360dd4..d7711c2 100644 --- a/libtests/qintc.cc +++ b/libtests/qintc.cc @@ -48,7 +48,7 @@ try_range_check_subtract_real(char const* description, bool exp_pass, T const& a { bool passed = false; try { - QIntC::range_check_substract(a, b); + QIntC::range_check_subtract(a, b); std::cout << description << ": okay"; passed = true; } catch (std::range_error& e) { diff --git a/manual/design.rst b/manual/design.rst index 936d478..5902549 100644 --- a/manual/design.rst +++ b/manual/design.rst @@ -860,8 +860,8 @@ modification of code. The ``POINTERHOLDER_TRANSITION`` preprocessor symbol was introduced in qpdf 10.6.0 to help people transition from ``PointerHolder`` to -``std::shared_ptr``. If you don't define this, you will get a compiler -warning. Defining it to any value will suppress the warning. An +``std::shared_ptr``. If you don't define this, ``PointerHolder`` will +be completely excluded from the API (starting with qpdf 12).An explanation appears below of the different possible values for this symbol and what they mean. @@ -1003,7 +1003,7 @@ without consulting this manual. - meaning - - undefined - - Same as ``0`` but issues a warning + - Same as ``4``: ``PointerHolder`` is not defined. - - ``0`` - Provide a backward compatible ``PointerHolder`` and suppress diff --git a/manual/qpdf.1 b/manual/qpdf.1 index a2ba117..38e30a8 100644 --- a/manual/qpdf.1 +++ b/manual/qpdf.1 @@ -3,7 +3,7 @@ .\" Edits will be automatically overwritten if the build is .\" run in maintainer mode. .\" -.TH QPDF "1" "" "qpdf version 11.10.1" "User Commands" +.TH QPDF "1" "" "qpdf version 12.0.0" "User Commands" .SH NAME qpdf \- PDF transformation software .SH SYNOPSIS diff --git a/manual/release-notes.rst b/manual/release-notes.rst index 2d866f7..efc6e71 100644 --- a/manual/release-notes.rst +++ b/manual/release-notes.rst @@ -6,29 +6,45 @@ Release Notes For a detailed list of changes, please see the file :file:`ChangeLog` in the source distribution. -If you are a developer and want to test your code against future API -changes that are under consideration, you can build qpdf locally and -enable the ``FUTURE`` build option (see :ref:`build-options`). - -Planned changes for future 12.x (subject to change): - - ``QPDFObjectHandle`` will support move construction/assignment. - This change will be invisible to most developers but may break - your code if you rely on specific behavior around how many - references to a QPDFObjectHandle's underlying object exist. You - would have to write code specifically to do that, so if you're not - sure, then you shouldn't have to worry. - - - ``Buffer`` copy constructor and assignment operator will be - removed. ``Buffer`` copy operations are expensive as they always - involve copying the buffer content. Use ``buffer2 = - buffer1.copy();`` or ``Buffer buffer2{buffer1.copy()};`` to make - it explicit that copying is intended. - - - ``QIntC.hh`` contains the type ``substract``, which will be fixed - to ``subtract``. (Not enabled with ``FUTURE`` option.) - .. x.y.z: not yet released +12.0.0: not yet released + - API: breaking changes + + - Deprecated versionless overload of ``QPDFObjectHandle::getJSON`` + has been removed. + + - ``Buffer`` copy constructor and assignment operator have been + removed. ``Buffer`` copy operations are expensive as they always + involve copying the buffer content. Use ``buffer2 = buffer1.copy();`` + or ``Buffer buffer2{buffer1.copy()};`` to make it explicit that + copying is intended. + + - ``QIntC.hh`` contained the typ0 ``substract`` in function names, + which has been fixed to ``subtract``. + + - Library Enhancements + + - ``QPDFObjectHandle`` supports move construction/assignment. + This change is invisible to most developers but may break + your code if you rely on specific behavior around how many + references to a QPDFObjectHandle's underlying object exist. You + would have to write code specifically to do that, so if you're not + sure, then you shouldn't have to worry. + + - Most ``QPDFObjectHandle`` accessor methods are now const qualified. + + - Build Changes + + - If ``POINTERHOLDER_TRANSITION`` is not defined, define it to + ``4``, which completely removes ``PointerHolder`` from the API. + Stop including it from any headers that used to include it. This + means code that hasn't completed its ``PointerHolder`` + transition will get errors unless it defines + ``POINTERHOLDER_TRANSITION``, and any file that uses + ``PointerHolder`` will have to explicitly include it rather than + relying on other headers to bring it along. + 11.10.1: February 15, 2025 - Build fixes diff --git a/pkg-test/qpdf-version.cc b/pkg-test/qpdf-version.cc index 419b302..ab78ced 100644 --- a/pkg-test/qpdf-version.cc +++ b/pkg-test/qpdf-version.cc @@ -1,7 +1,3 @@ -#ifndef POINTERHOLDER_TRANSITION -# define POINTERHOLDER_TRANSITION 4 -#endif - #include #include