mirror of
https://github.com/qpdf/qpdf.git
synced 2025-02-07 14:18:24 +00:00
1877 lines
70 KiB
C++
1877 lines
70 KiB
C++
// Copyright (c) 2005-2023 Jay Berkenbilt
|
|
//
|
|
// 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_HH
|
|
#define QPDFOBJECTHANDLE_HH
|
|
|
|
#include <qpdf/Constants.h>
|
|
#include <qpdf/DLL.h>
|
|
#include <qpdf/Types.h>
|
|
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <qpdf/Buffer.hh>
|
|
#include <qpdf/InputSource.hh>
|
|
#include <qpdf/JSON.hh>
|
|
#include <qpdf/PointerHolder.hh> // unused -- remove in qpdf 12 (see #785)
|
|
#include <qpdf/QPDFObjGen.hh>
|
|
#include <qpdf/QPDFTokenizer.hh>
|
|
|
|
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
|
|
inline bool isInitialized() const;
|
|
|
|
// 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;
|
|
|
|
// 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_DLL
|
|
char const* getTypeName();
|
|
|
|
// Exactly one of these will return true for any initialized
|
|
// object. Operator and InlineImage are only allowed in content
|
|
// streams.
|
|
QPDF_DLL
|
|
bool isBool();
|
|
QPDF_DLL
|
|
bool isNull();
|
|
QPDF_DLL
|
|
bool isInteger();
|
|
QPDF_DLL
|
|
bool isReal();
|
|
QPDF_DLL
|
|
bool isName();
|
|
QPDF_DLL
|
|
bool isString();
|
|
QPDF_DLL
|
|
bool isOperator();
|
|
QPDF_DLL
|
|
bool isInlineImage();
|
|
QPDF_DLL
|
|
bool isArray();
|
|
QPDF_DLL
|
|
bool isDictionary();
|
|
QPDF_DLL
|
|
bool isStream();
|
|
QPDF_DLL
|
|
bool isReserved();
|
|
|
|
// 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();
|
|
|
|
// True for everything except array, dictionary, stream, word, and
|
|
// inline image.
|
|
QPDF_DLL
|
|
bool isScalar();
|
|
|
|
// True if the object is a name object representing the provided name.
|
|
QPDF_DLL
|
|
bool isNameAndEquals(std::string const& name);
|
|
|
|
// 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 = "");
|
|
|
|
// 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 = "");
|
|
|
|
// 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<InputSource> 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();
|
|
|
|
// 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<TokenFilter> 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<TokenFilter> 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<QPDFObjectHandle> 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<std::string, QPDFObjectHandle> 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<Buffer> 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<Buffer> 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.
|
|
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();
|
|
|
|
// 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();
|
|
QPDF_DLL
|
|
bool getValueAsBool(bool&);
|
|
|
|
// 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();
|
|
QPDF_DLL
|
|
bool getValueAsInt(long long&);
|
|
QPDF_DLL
|
|
int getIntValueAsInt();
|
|
QPDF_DLL
|
|
bool getValueAsInt(int&);
|
|
QPDF_DLL
|
|
unsigned long long getUIntValue();
|
|
QPDF_DLL
|
|
bool getValueAsUInt(unsigned long long&);
|
|
QPDF_DLL
|
|
unsigned int getUIntValueAsUInt();
|
|
QPDF_DLL
|
|
bool getValueAsUInt(unsigned int&);
|
|
|
|
// Methods for real objects
|
|
QPDF_DLL
|
|
std::string getRealValue();
|
|
QPDF_DLL
|
|
bool getValueAsReal(std::string&);
|
|
|
|
// Methods that work for both integer and real objects
|
|
QPDF_DLL
|
|
bool isNumber();
|
|
QPDF_DLL
|
|
double getNumericValue();
|
|
QPDF_DLL
|
|
bool getValueAsNumber(double&);
|
|
|
|
// 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();
|
|
QPDF_DLL
|
|
bool getValueAsName(std::string&);
|
|
|
|
// Methods for string objects
|
|
QPDF_DLL
|
|
std::string getStringValue();
|
|
QPDF_DLL
|
|
bool getValueAsString(std::string&);
|
|
|
|
// 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();
|
|
QPDF_DLL
|
|
bool getValueAsUTF8(std::string&);
|
|
|
|
// Methods for content stream objects
|
|
QPDF_DLL
|
|
std::string getOperatorValue();
|
|
QPDF_DLL
|
|
bool getValueAsOperator(std::string&);
|
|
QPDF_DLL
|
|
std::string getInlineImageValue();
|
|
QPDF_DLL
|
|
bool getValueAsInlineImage(std::string&);
|
|
|
|
// 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();
|
|
QPDF_DLL
|
|
QPDFObjectHandle getArrayItem(int n);
|
|
// 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<QPDFObjectHandle> getArrayAsVector();
|
|
QPDF_DLL
|
|
bool isRectangle();
|
|
// 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();
|
|
QPDF_DLL
|
|
bool isMatrix();
|
|
// 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();
|
|
|
|
// 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&);
|
|
// Return the value for the key. If the key is not present, null is
|
|
// returned.
|
|
QPDF_DLL
|
|
QPDFObjectHandle getKey(std::string 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&);
|
|
// 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<std::string> getKeys();
|
|
// Return dictionary as a map. Entries with null values are included.
|
|
QPDF_DLL
|
|
std::map<std::string, QPDFObjectHandle> getDictAsMap();
|
|
|
|
// 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&);
|
|
|
|
// 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<std::string, std::map<std::string, std::string>>* 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<std::string> getResourceNames();
|
|
|
|
// 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<std::string>* resource_names = nullptr);
|
|
|
|
// 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<QPDFObjectHandle> 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();
|
|
|
|
// 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<Buffer>
|
|
getStreamData(qpdf_stream_decode_level_e level = qpdf_dl_generalized);
|
|
|
|
// Returns unfiltered (raw) stream data.
|
|
QPDF_DLL
|
|
std::shared_ptr<Buffer> 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<Buffer> 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<Buffer> 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<StreamDataProvider> 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<void(Pipeline*)> 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<bool(Pipeline*, bool suppress_warnings, bool will_retry)>
|
|
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();
|
|
QPDF_DLL
|
|
std::string unparseResolved();
|
|
// For strings only, force binary representation. Otherwise, same
|
|
// as unparse.
|
|
QPDF_DLL
|
|
std::string unparseBinary();
|
|
|
|
// 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 bidrectionally mapped two 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 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);
|
|
|
|
// 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);
|
|
|
|
// 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<std::string, QPDFObjectHandle> getPageImages();
|
|
QPDF_DLL
|
|
std::vector<QPDFObjectHandle> 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);
|
|
|
|
// 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();
|
|
QPDF_DLL
|
|
void assertBool();
|
|
QPDF_DLL
|
|
void assertInteger();
|
|
QPDF_DLL
|
|
void assertReal();
|
|
QPDF_DLL
|
|
void assertName();
|
|
QPDF_DLL
|
|
void assertString();
|
|
QPDF_DLL
|
|
void assertOperator();
|
|
QPDF_DLL
|
|
void assertInlineImage();
|
|
QPDF_DLL
|
|
void assertArray();
|
|
QPDF_DLL
|
|
void assertDictionary();
|
|
QPDF_DLL
|
|
void assertStream();
|
|
QPDF_DLL
|
|
void assertReserved();
|
|
|
|
QPDF_DLL
|
|
void assertIndirect();
|
|
QPDF_DLL
|
|
void assertScalar();
|
|
QPDF_DLL
|
|
void assertNumber();
|
|
|
|
// 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();
|
|
QPDF_DLL
|
|
bool isPagesObject();
|
|
QPDF_DLL
|
|
void assertPageObject();
|
|
|
|
QPDF_DLL
|
|
bool isFormXObject();
|
|
|
|
// 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);
|
|
|
|
// The following methods do not form part of the public API and are for
|
|
// internal use only.
|
|
|
|
QPDFObjectHandle(std::shared_ptr<QPDFObject> const& obj) :
|
|
obj(obj)
|
|
{
|
|
}
|
|
std::shared_ptr<QPDFObject>
|
|
getObj()
|
|
{
|
|
return obj;
|
|
}
|
|
std::shared_ptr<QPDFObject>
|
|
getObj() const
|
|
{
|
|
return obj;
|
|
}
|
|
QPDFObject*
|
|
getObjectPtr()
|
|
{
|
|
return obj.get();
|
|
}
|
|
QPDFObject* const
|
|
getObjectPtr() const
|
|
{
|
|
return obj.get();
|
|
}
|
|
|
|
private:
|
|
QPDF_Array* asArray();
|
|
QPDF_Bool* asBool();
|
|
QPDF_Dictionary* asDictionary();
|
|
QPDF_InlineImage* asInlineImage();
|
|
QPDF_Integer* asInteger();
|
|
QPDF_Name* asName();
|
|
QPDF_Null* asNull();
|
|
QPDF_Operator* asOperator();
|
|
QPDF_Real* asReal();
|
|
QPDF_Reserved* asReserved();
|
|
QPDF_Stream* asStream();
|
|
QPDF_Stream* asStreamWithAssert();
|
|
QPDF_String* asString();
|
|
|
|
void typeWarning(char const* expected_type, std::string const& warning);
|
|
void objectWarning(std::string const& warning);
|
|
void assertType(char const* type_name, bool istype);
|
|
inline bool dereference();
|
|
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<Buffer>,
|
|
std::string const& description,
|
|
ParserCallbacks* callbacks,
|
|
QPDF* context);
|
|
std::vector<QPDFObjectHandle> 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<QPDFObject> 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<std::string, 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 QPDFDictItems::iterator;
|
|
|
|
public:
|
|
QPDF_DLL
|
|
~Members() = default;
|
|
|
|
private:
|
|
Members(QPDFObjectHandle& oh, bool for_begin);
|
|
Members() = delete;
|
|
Members(Members const&) = delete;
|
|
|
|
QPDFObjectHandle& oh;
|
|
std::set<std::string> keys;
|
|
std::set<std::string>::iterator iter;
|
|
bool is_end;
|
|
};
|
|
std::shared_ptr<Members> 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<Members> 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
|
|
{
|
|
return obj != nullptr;
|
|
}
|
|
|
|
#endif // QPDFOBJECTHANDLE_HH
|