/src/qpdf/include/qpdf/QPDFObjectHandle.hh
Line | Count | Source |
1 | | // Copyright (c) 2005-2021 Jay Berkenbilt |
2 | | // Copyright (c) 2022-2026 Jay Berkenbilt and Manfred Holger |
3 | | // |
4 | | // This file is part of qpdf. |
5 | | // |
6 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
7 | | // you may not use this file except in compliance with the License. |
8 | | // You may obtain a copy of the License at |
9 | | // |
10 | | // http://www.apache.org/licenses/LICENSE-2.0 |
11 | | // |
12 | | // Unless required by applicable law or agreed to in writing, software |
13 | | // distributed under the License is distributed on an "AS IS" BASIS, |
14 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | | // See the License for the specific language governing permissions and |
16 | | // limitations under the License. |
17 | | // |
18 | | // Versions of qpdf prior to version 7 were released under the terms |
19 | | // of version 2.0 of the Artistic License. At your option, you may |
20 | | // continue to consider qpdf to be licensed under those terms. Please |
21 | | // see the manual for additional information. |
22 | | |
23 | | #ifndef QPDFOBJECTHANDLE_HH |
24 | | #define QPDFOBJECTHANDLE_HH |
25 | | |
26 | | #include <qpdf/ObjectHandle.hh> |
27 | | |
28 | | #include <qpdf/Constants.h> |
29 | | #include <qpdf/DLL.h> |
30 | | #include <qpdf/Types.h> |
31 | | |
32 | | #include <cinttypes> |
33 | | #include <functional> |
34 | | #include <map> |
35 | | #include <memory> |
36 | | #include <set> |
37 | | #include <string> |
38 | | #include <vector> |
39 | | |
40 | | #include <qpdf/Buffer.hh> |
41 | | #include <qpdf/InputSource.hh> |
42 | | #include <qpdf/JSON.hh> |
43 | | #include <qpdf/QPDFObjGen.hh> |
44 | | #include <qpdf/QPDFTokenizer.hh> |
45 | | |
46 | | class Pipeline; |
47 | | class QPDF_Array; |
48 | | class QPDF_Bool; |
49 | | class QPDF_Dictionary; |
50 | | class QPDF_InlineImage; |
51 | | class QPDF_Integer; |
52 | | class QPDF_Name; |
53 | | class QPDF_Null; |
54 | | class QPDF_Operator; |
55 | | class QPDF_Real; |
56 | | class QPDF_Reserved; |
57 | | class QPDF_Stream; |
58 | | class QPDF_String; |
59 | | class QPDFObject; |
60 | | class QPDFObjectHandle; |
61 | | class QPDFTokenizer; |
62 | | class QPDFExc; |
63 | | class Pl_QPDFTokenizer; |
64 | | class QPDFMatrix; |
65 | | namespace qpdf::impl |
66 | | { |
67 | | class Parser; |
68 | | } |
69 | | |
70 | | class QPDFObjectHandle: public qpdf::BaseHandle |
71 | | { |
72 | | friend class qpdf::impl::Parser; |
73 | | |
74 | | public: |
75 | | // This class is used by replaceStreamData. It provides an alternative way of associating |
76 | | // stream data with a stream. See comments on replaceStreamData and newStream for additional |
77 | | // details. |
78 | | class QPDF_DLL_CLASS StreamDataProvider |
79 | | { |
80 | | public: |
81 | | QPDF_DLL |
82 | | StreamDataProvider(bool supports_retry = false); |
83 | | |
84 | | QPDF_DLL |
85 | | virtual ~StreamDataProvider(); |
86 | | // The implementation of this function must write stream data to the given pipeline. The |
87 | | // stream data must conform to whatever filters are explicitly associated with the stream. |
88 | | // QPDFWriter may, in some cases, add compression, but if it does, it will update the |
89 | | // filters as needed. Every call to provideStreamData for a given stream must write the same |
90 | | // data. Note that, when writing linearized files, qpdf will call your provideStreamData |
91 | | // twice, and if it generates different output, you risk generating invalid output or having |
92 | | // qpdf throw an exception. The object ID and generation passed to this method are those |
93 | | // that belong to the stream on behalf of which the provider is called. They may be ignored |
94 | | // or used by the implementation for indexing or other purposes. This information is made |
95 | | // available just to make it more convenient to use a single StreamDataProvider object to |
96 | | // provide data for multiple streams. |
97 | | |
98 | | // A few things to keep in mind: |
99 | | // |
100 | | // * Stream data providers must not modify any objects since they may be called after some |
101 | | // parts of the file have already been written. |
102 | | // |
103 | | // * Since qpdf may call provideStreamData multiple times when writing linearized files, if |
104 | | // the work done by your stream data provider is slow or computationally intensive, you |
105 | | // might want to implement your own cache. |
106 | | // |
107 | | // * Once you have called replaceStreamData, the original stream data is no longer directly |
108 | | // accessible from the stream, but this is easy to work around by copying the stream to |
109 | | // a separate QPDF object. The qpdf library implements this very efficiently without |
110 | | // actually making a copy of the stream data. You can find examples of this pattern in |
111 | | // some of the examples, including pdf-custom-filter.cc and pdf-invert-images.cc. |
112 | | |
113 | | // Prior to qpdf 10.0.0, it was not possible to handle errors the way pipeStreamData does or |
114 | | // to pass back success. Starting in qpdf 10.0.0, those capabilities have been added by |
115 | | // allowing an alternative provideStreamData to be implemented. You must implement at least |
116 | | // one of the versions of provideStreamData below. If you implement the version that |
117 | | // supports retry and returns a value, you should pass true as the value of supports_retry |
118 | | // in the base class constructor. This will cause the library to call that version of the |
119 | | // method, which should also return a boolean indicating whether it ran without errors. |
120 | | QPDF_DLL |
121 | | virtual void provideStreamData(QPDFObjGen const& og, Pipeline* pipeline); |
122 | | QPDF_DLL |
123 | | virtual bool provideStreamData( |
124 | | QPDFObjGen const& og, Pipeline* pipeline, bool suppress_warnings, bool will_retry); |
125 | | QPDF_DLL virtual void provideStreamData(int objid, int generation, Pipeline* pipeline); |
126 | | QPDF_DLL virtual bool provideStreamData( |
127 | | int objid, int generation, Pipeline* pipeline, bool suppress_warnings, bool will_retry); |
128 | | QPDF_DLL |
129 | | bool supportsRetry(); |
130 | | |
131 | | private: |
132 | | bool supports_retry; |
133 | | }; |
134 | | |
135 | | // The TokenFilter class provides a way to filter content streams in a lexically aware fashion. |
136 | | // TokenFilters can be attached to streams using the addTokenFilter or addContentTokenFilter |
137 | | // methods or can be applied on the spot by filterPageContents. You may also use |
138 | | // Pl_QPDFTokenizer directly if you need full control. |
139 | | // |
140 | | // The handleToken method is called for each token, including the eof token, and then handleEOF |
141 | | // is called at the very end. Handlers may call write (or writeToken) to pass data downstream. |
142 | | // Please see examples/pdf-filter-tokens.cc and examples/pdf-count-strings.cc for examples of |
143 | | // using TokenFilters. |
144 | | // |
145 | | // Please note that when you call token.getValue() on a token of type tt_string or tt_name, you |
146 | | // get the canonical, "parsed" representation of the token. For a string, this means that there |
147 | | // are no delimiters, and for a name, it means that all escaping (# followed by two hex digits) |
148 | | // has been resolved. qpdf's internal representation of a name includes the leading slash. As |
149 | | // such, you can't write the value of token.getValue() directly to output that is supposed to be |
150 | | // valid PDF syntax. If you want to do that, you need to call writeToken() instead, or you can |
151 | | // retrieve the token as it appeared in the input with token.getRawValue(). To construct a new |
152 | | // string or name token from a canonical representation, use |
153 | | // QPDFTokenizer::Token(QPDFTokenizer::tt_string, "parsed-str") or |
154 | | // QPDFTokenizer::Token(QPDFTokenizer::tt_name, |
155 | | // "/Canonical-Name"). Tokens created this way won't have a PDF-syntax raw value, but you can |
156 | | // still write them with writeToken(). Example: |
157 | | // writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_name, "/text/plain")) |
158 | | // would write `/text#2fplain`, and |
159 | | // writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_string, "a\\(b")) would write `(a\(b)`. |
160 | | class QPDF_DLL_CLASS TokenFilter |
161 | | { |
162 | | public: |
163 | 0 | TokenFilter() = default; |
164 | 0 | virtual ~TokenFilter() = default; |
165 | | virtual void handleToken(QPDFTokenizer::Token const&) = 0; |
166 | | QPDF_DLL |
167 | | virtual void handleEOF(); |
168 | | |
169 | | class PipelineAccessor |
170 | | { |
171 | | friend class Pl_QPDFTokenizer; |
172 | | |
173 | | private: |
174 | | static void |
175 | | setPipeline(TokenFilter* f, Pipeline* p) |
176 | 0 | { |
177 | 0 | f->setPipeline(p); |
178 | 0 | } |
179 | | }; |
180 | | |
181 | | protected: |
182 | | QPDF_DLL |
183 | | void write(char const* data, size_t len); |
184 | | QPDF_DLL |
185 | | void write(std::string const& str); |
186 | | QPDF_DLL |
187 | | void writeToken(QPDFTokenizer::Token const&); |
188 | | |
189 | | private: |
190 | | QPDF_DLL_PRIVATE |
191 | | void setPipeline(Pipeline*); |
192 | | |
193 | | Pipeline* pipeline; |
194 | | }; |
195 | | |
196 | | // This class is used by parse to decrypt strings when reading an object that contains encrypted |
197 | | // strings. |
198 | | class StringDecrypter |
199 | | { |
200 | | public: |
201 | 0 | virtual ~StringDecrypter() = default; |
202 | | virtual void decryptString(std::string& val) = 0; |
203 | | }; |
204 | | |
205 | | // This class is used by parsePageContents. Callers must instantiate a subclass of this with |
206 | | // handlers defined to accept QPDFObjectHandles that are parsed from the stream. |
207 | | class QPDF_DLL_CLASS ParserCallbacks |
208 | | { |
209 | | public: |
210 | 0 | virtual ~ParserCallbacks() = default; |
211 | | // One of the handleObject methods must be overridden. |
212 | | QPDF_DLL |
213 | | virtual void handleObject(QPDFObjectHandle); |
214 | | QPDF_DLL |
215 | | virtual void handleObject(QPDFObjectHandle, size_t offset, size_t length); |
216 | | |
217 | | virtual void handleEOF() = 0; |
218 | | |
219 | | // Override this if you want to know the full size of the contents, possibly after |
220 | | // concatenation of multiple streams. This is called before the first call to handleObject. |
221 | | QPDF_DLL |
222 | | virtual void contentSize(size_t); |
223 | | |
224 | | protected: |
225 | | // Implementors may call this method during parsing to terminate parsing early. This method |
226 | | // throws an exception that is caught by parsePageContents, so its effect is immediate. |
227 | | QPDF_DLL |
228 | | void terminateParsing(); |
229 | | }; |
230 | | |
231 | | // Convenience object for rectangles |
232 | | class Rectangle |
233 | | { |
234 | | public: |
235 | | Rectangle() : |
236 | 0 | llx(0.0), |
237 | 0 | lly(0.0), |
238 | 0 | urx(0.0), |
239 | 0 | ury(0.0) |
240 | 0 | { |
241 | 0 | } |
242 | | Rectangle(double llx, double lly, double urx, double ury) : |
243 | 0 | llx(llx), |
244 | 0 | lly(lly), |
245 | 0 | urx(urx), |
246 | 0 | ury(ury) |
247 | 0 | { |
248 | 0 | } |
249 | | |
250 | | double llx; |
251 | | double lly; |
252 | | double urx; |
253 | | double ury; |
254 | | }; |
255 | | |
256 | | // Convenience object for transformation matrices. See also QPDFMatrix. Unfortunately we can't |
257 | | // replace this with QPDFMatrix because QPDFMatrix's default constructor creates the identity |
258 | | // transform matrix and this one is all zeroes. |
259 | | class Matrix |
260 | | { |
261 | | public: |
262 | | Matrix() : |
263 | 0 | a(0.0), |
264 | 0 | b(0.0), |
265 | 0 | c(0.0), |
266 | 0 | d(0.0), |
267 | 0 | e(0.0), |
268 | 0 | f(0.0) |
269 | 0 | { |
270 | 0 | } |
271 | | Matrix(double a, double b, double c, double d, double e, double f) : |
272 | 0 | a(a), |
273 | 0 | b(b), |
274 | 0 | c(c), |
275 | 0 | d(d), |
276 | 0 | e(e), |
277 | 0 | f(f) |
278 | 0 | { |
279 | 0 | } |
280 | | |
281 | | double a; |
282 | | double b; |
283 | | double c; |
284 | | double d; |
285 | | double e; |
286 | | double f; |
287 | | }; |
288 | | |
289 | 2.62M | QPDFObjectHandle() = default; |
290 | 2.75M | QPDFObjectHandle(QPDFObjectHandle const&) = default; |
291 | 159k | QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default; |
292 | 3.16M | QPDFObjectHandle(QPDFObjectHandle&&) = default; |
293 | 2.48M | QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default; |
294 | | |
295 | | // This method is provided for backward compatibility only. New code should convert to bool |
296 | | // instead. |
297 | | inline bool isInitialized() const; |
298 | | |
299 | | // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying |
300 | | // object, meaning that changes to one are reflected in the other, or "if you paint one, the |
301 | | // other one changes color." This does not perform a structural comparison of the contents of |
302 | | // the objects. |
303 | | QPDF_DLL |
304 | | bool isSameObjectAs(QPDFObjectHandle const&) const; |
305 | | |
306 | | // Return type code and type name of underlying object. These are useful for doing rapid type |
307 | | // tests (like switch statements) or for testing and debugging. |
308 | | QPDF_DLL |
309 | | qpdf_object_type_e getTypeCode() const; |
310 | | QPDF_DLL |
311 | | char const* getTypeName() const; |
312 | | |
313 | | // Exactly one of these will return true for any initialized object. Operator and InlineImage |
314 | | // are only allowed in content streams. |
315 | | QPDF_DLL |
316 | | bool isBool() const; |
317 | | QPDF_DLL |
318 | | bool isNull() const; |
319 | | QPDF_DLL |
320 | | bool isInteger() const; |
321 | | QPDF_DLL |
322 | | bool isReal() const; |
323 | | QPDF_DLL |
324 | | bool isName() const; |
325 | | QPDF_DLL |
326 | | bool isString() const; |
327 | | QPDF_DLL |
328 | | bool isOperator() const; |
329 | | QPDF_DLL |
330 | | bool isInlineImage() const; |
331 | | QPDF_DLL |
332 | | bool isArray() const; |
333 | | QPDF_DLL |
334 | | bool isDictionary() const; |
335 | | QPDF_DLL |
336 | | bool isStream() const; |
337 | | QPDF_DLL |
338 | | bool isReserved() const; |
339 | | |
340 | | // True for objects that are direct nulls. Does not attempt to resolve objects. This is intended |
341 | | // for internal use, but it can be used as an efficient way to check for nulls that are not |
342 | | // indirect objects. |
343 | | QPDF_DLL |
344 | | bool isDirectNull() const; |
345 | | |
346 | | // This returns true in addition to the query for the specific type for indirect objects. |
347 | | QPDF_DLL |
348 | | bool isIndirect() const; |
349 | | |
350 | | // This returns true for indirect objects from a QPDF that has been destroyed. Trying unparse |
351 | | // such an object will throw a logic_error. |
352 | | QPDF_DLL |
353 | | bool isDestroyed() const; |
354 | | |
355 | | // True for everything except array, dictionary, stream, word, and inline image. |
356 | | QPDF_DLL |
357 | | bool isScalar() const; |
358 | | |
359 | | // True if the object is a name object representing the provided name. |
360 | | QPDF_DLL |
361 | | bool isNameAndEquals(std::string const& name) const; |
362 | | |
363 | | // True if the object is a dictionary of the specified type and subtype, if any. |
364 | | QPDF_DLL |
365 | | bool isDictionaryOfType(std::string const& type, std::string const& subtype = "") const; |
366 | | |
367 | | // True if the object is a stream of the specified type and subtype, if any. |
368 | | QPDF_DLL |
369 | | bool isStreamOfType(std::string const& type, std::string const& subtype = "") const; |
370 | | |
371 | | // Public factory methods |
372 | | |
373 | | // Wrap an object in an array if it is not already an array. This is a helper for cases in which |
374 | | // something in a PDF may either be a single item or an array of items, which is a common idiom. |
375 | | QPDF_DLL |
376 | | QPDFObjectHandle wrapInArray(); |
377 | | |
378 | | // Construct an object of any type from a string representation of the object. Throws QPDFExc |
379 | | // with an empty filename and an offset into the string if there is an error. Any indirect |
380 | | // object syntax (obj gen R) will cause a logic_error exception to be thrown. If |
381 | | // object_description is provided, it will appear in the message of any QPDFExc exception thrown |
382 | | // for invalid syntax. See also the global `operator ""_qpdf` defined below. |
383 | | QPDF_DLL |
384 | | static QPDFObjectHandle |
385 | | parse(std::string const& object_str, std::string const& object_description = ""); |
386 | | |
387 | | // Construct an object of any type from a string representation of the object. Indirect object |
388 | | // syntax (obj gen R) is allowed and will create indirect references within the passed-in |
389 | | // context. If object_description is provided, it will appear in the message of any QPDFExc |
390 | | // exception thrown for invalid syntax. Note that you can't parse an indirect object reference |
391 | | // all by itself as parse will stop at the end of the first complete object, which will just be |
392 | | // the first number and will report that there is trailing data at the end of the string. |
393 | | QPDF_DLL |
394 | | static QPDFObjectHandle |
395 | | parse(QPDF* context, std::string const& object_str, std::string const& object_description = ""); |
396 | | |
397 | | // Construct an object as above by reading from the given InputSource at its current position |
398 | | // and using the tokenizer you supply. Indirect objects and encrypted strings are permitted. |
399 | | // This method was intended to be called by QPDF for parsing objects that are read from the |
400 | | // object's input stream. To be removed in qpdf 13. See |
401 | | // <https:manual.qpdf.org/release-notes.html#r12-0-0-deprecate>. |
402 | | [[deprecated("to be removed in qpdf 13")]] QPDF_DLL static QPDFObjectHandle parse( |
403 | | std::shared_ptr<InputSource> input, |
404 | | std::string const& object_description, |
405 | | QPDFTokenizer&, |
406 | | bool& empty, |
407 | | StringDecrypter* decrypter, |
408 | | QPDF* context); |
409 | | |
410 | | // Return the offset where the object was found when parsed. A negative value means that the |
411 | | // object was created without parsing. If the object is in a stream, the offset is from the |
412 | | // beginning of the stream. Otherwise, the offset is from the beginning of the file. |
413 | | QPDF_DLL |
414 | | qpdf_offset_t getParsedOffset() const; |
415 | | |
416 | | // Older method: stream_or_array should be the value of /Contents from a page object. It's more |
417 | | // convenient to just call QPDFPageObjectHelper::parsePageContents on the page object, and error |
418 | | // messages will also be more useful because the page object information will be known. |
419 | | QPDF_DLL |
420 | | static void parseContentStream(QPDFObjectHandle stream_or_array, ParserCallbacks* callbacks); |
421 | | |
422 | | // When called on a stream or stream array that is some page's content streams, do the same as |
423 | | // pipePageContents. This method is a lower level way to do what |
424 | | // QPDFPageObjectHelper::pipePageContents does, but it allows you to perform this operation on a |
425 | | // contents object that is disconnected from a page object. The description argument should |
426 | | // describe the containing page and is used in error messages. The all_description argument is |
427 | | // initialized to something that could be used to describe the result of the pipeline. It is the |
428 | | // description amended with the identifiers of the underlying objects. Please note that if there |
429 | | // is an array of content streams, p->finish() is called after each stream. If you pass a |
430 | | // pipeline that doesn't allow write() to be called after finish(), you can wrap it in an |
431 | | // instance of Pl_Concatenate and then call manualFinish() on the Pl_Concatenate pipeline at the |
432 | | // end. |
433 | | QPDF_DLL |
434 | | void |
435 | | pipeContentStreams(Pipeline* p, std::string const& description, std::string& all_description); |
436 | | |
437 | | // As of qpdf 8, it is possible to add custom token filters to a stream. The tokenized stream |
438 | | // data is passed through the token filter after all original filters but before content stream |
439 | | // normalization if requested. This is a low-level interface to add it to a stream. You will |
440 | | // usually want to call QPDFPageObjectHelper::addContentTokenFilter instead, which can be |
441 | | // applied to a page object, and which will automatically handle the case of pages whose |
442 | | // contents are split across multiple streams. |
443 | | QPDF_DLL |
444 | | void addTokenFilter(std::shared_ptr<TokenFilter> token_filter); |
445 | | |
446 | | // Legacy helpers for parsing content streams. These methods are not going away, but newer code |
447 | | // should call the correspond methods in QPDFPageObjectHelper instead. The specification and |
448 | | // behavior of these methods are the same as the identically named methods in that class, but |
449 | | // newer functionality will be added there. |
450 | | QPDF_DLL |
451 | | void parsePageContents(ParserCallbacks* callbacks); |
452 | | QPDF_DLL |
453 | | void filterPageContents(TokenFilter* filter, Pipeline* next = nullptr); |
454 | | // See comments for QPDFPageObjectHelper::pipeContents. |
455 | | QPDF_DLL |
456 | | void pipePageContents(Pipeline* p); |
457 | | QPDF_DLL |
458 | | void addContentTokenFilter(std::shared_ptr<TokenFilter> token_filter); |
459 | | // End legacy content stream helpers |
460 | | |
461 | | // Called on a stream to filter the stream as if it were page contents. This can be used to |
462 | | // apply a TokenFilter to a form XObject, whose data is in the same format as a content stream. |
463 | | QPDF_DLL |
464 | | void filterAsContents(TokenFilter* filter, Pipeline* next = nullptr); |
465 | | // Called on a stream to parse the stream as page contents. This can be used to parse a form |
466 | | // XObject. |
467 | | QPDF_DLL |
468 | | void parseAsContents(ParserCallbacks* callbacks); |
469 | | |
470 | | // Type-specific factories |
471 | | QPDF_DLL |
472 | | static QPDFObjectHandle newNull(); |
473 | | QPDF_DLL |
474 | | static QPDFObjectHandle newBool(bool value); |
475 | | QPDF_DLL |
476 | | static QPDFObjectHandle newInteger(long long value); |
477 | | QPDF_DLL |
478 | | static QPDFObjectHandle newReal(std::string const& value); |
479 | | QPDF_DLL |
480 | | static QPDFObjectHandle |
481 | | newReal(double value, int decimal_places = 0, bool trim_trailing_zeroes = true); |
482 | | // Note about name objects: qpdf's internal representation of a PDF name is a sequence of bytes, |
483 | | // excluding the NUL character, and starting with a slash. Name objects as represented in the |
484 | | // PDF specification can contain characters escaped with #, but such escaping is not of concern |
485 | | // when calling QPDFObjectHandle methods not directly relating to parsing. For example, |
486 | | // newName("/text/plain").getName() and parse("/text#2fplain").getName() both return |
487 | | // "/text/plain", while newName("/text/plain").unparse() and parse("/text#2fplain").unparse() |
488 | | // both return "/text#2fplain". When working with the qpdf API for creating, retrieving, and |
489 | | // modifying objects, you want to work with the internal, canonical representation. For names |
490 | | // containing alphanumeric characters, dashes, and underscores, there is no difference between |
491 | | // the two representations. For a lengthy discussion, see |
492 | | // https://github.com/qpdf/qpdf/discussions/625. |
493 | | QPDF_DLL |
494 | | static QPDFObjectHandle newName(std::string const& name); |
495 | | QPDF_DLL |
496 | | static QPDFObjectHandle newString(std::string const& str); |
497 | | // Create a string encoded from the given utf8-encoded string appropriately encoded to appear in |
498 | | // PDF files outside of content streams, such as in document metadata form field values, page |
499 | | // labels, outlines, and similar locations. We try ASCII first, then PDFDocEncoding, then UTF-16 |
500 | | // as needed to successfully encode all the characters. |
501 | | QPDF_DLL |
502 | | static QPDFObjectHandle newUnicodeString(std::string const& utf8_str); |
503 | | QPDF_DLL |
504 | | static QPDFObjectHandle newOperator(std::string const&); |
505 | | QPDF_DLL |
506 | | static QPDFObjectHandle newInlineImage(std::string const&); |
507 | | QPDF_DLL |
508 | | static QPDFObjectHandle newArray(); |
509 | | QPDF_DLL |
510 | | static QPDFObjectHandle newArray(std::vector<QPDFObjectHandle> const& items); |
511 | | QPDF_DLL |
512 | | static QPDFObjectHandle newArray(Rectangle const&); |
513 | | QPDF_DLL |
514 | | static QPDFObjectHandle newArray(Matrix const&); |
515 | | QPDF_DLL |
516 | | static QPDFObjectHandle newArray(QPDFMatrix const&); |
517 | | QPDF_DLL |
518 | | static QPDFObjectHandle newDictionary(); |
519 | | QPDF_DLL |
520 | | static QPDFObjectHandle newDictionary(std::map<std::string, QPDFObjectHandle> const& items); |
521 | | |
522 | | // Create an array from a rectangle. Equivalent to the rectangle form of newArray. |
523 | | QPDF_DLL |
524 | | static QPDFObjectHandle newFromRectangle(Rectangle const&); |
525 | | // Create an array from a matrix. Equivalent to the matrix form of newArray. |
526 | | QPDF_DLL |
527 | | static QPDFObjectHandle newFromMatrix(Matrix const&); |
528 | | QPDF_DLL |
529 | | static QPDFObjectHandle newFromMatrix(QPDFMatrix const&); |
530 | | |
531 | | // Note: new stream creation methods have were added to the QPDF class starting with |
532 | | // version 11.2.0. The ones in this class are here for backward compatibility. |
533 | | |
534 | | // Create a new stream and associate it with the given qpdf object. A subsequent call must be |
535 | | // made to replaceStreamData() to provide data for the stream. The stream's dictionary may be |
536 | | // retrieved by calling getDict(), and the resulting dictionary may be modified. Alternatively, |
537 | | // you can create a new dictionary and call replaceDict to install it. From QPDF 11.2, you can |
538 | | // call QPDF::newStream() instead. |
539 | | QPDF_DLL |
540 | | static QPDFObjectHandle newStream(QPDF* qpdf); |
541 | | |
542 | | // Create a new stream and associate it with the given qpdf object. Use the given buffer as the |
543 | | // stream data. The stream dictionary's /Length key will automatically be set to the size of the |
544 | | // data buffer. If additional keys are required, the stream's dictionary may be retrieved by |
545 | | // calling getDict(), and the resulting dictionary may be modified. This method is just a |
546 | | // convenient wrapper around the newStream() and replaceStreamData(). It is a convenience |
547 | | // methods for streams that require no parameters beyond the stream length. Note that you don't |
548 | | // have to deal with compression yourself if you use QPDFWriter. By default, QPDFWriter will |
549 | | // automatically compress uncompressed stream data. Example programs are provided that |
550 | | // illustrate this. From QPDF 11.2, you can call QPDF::newStream() |
551 | | // instead. |
552 | | QPDF_DLL |
553 | | static QPDFObjectHandle newStream(QPDF* qpdf, std::shared_ptr<Buffer> data); |
554 | | |
555 | | // Create new stream with data from string. This method will create a copy of the data rather |
556 | | // than using the user-provided buffer as in the std::shared_ptr<Buffer> version of newStream. |
557 | | // From QPDF 11.2, you can call QPDF::newStream() instead. |
558 | | QPDF_DLL |
559 | | static QPDFObjectHandle newStream(QPDF* qpdf, std::string const& data); |
560 | | |
561 | | // A reserved object is a special sentinel used for qpdf to reserve a spot for an object that is |
562 | | // going to be added to the QPDF object. Normally you don't have to use this type since you can |
563 | | // just call QPDF::makeIndirectObject. However, in some cases, if you have to create objects |
564 | | // with circular references, you may need to create a reserved object so that you can have a |
565 | | // reference to it and then replace the object later. Reserved objects have the special |
566 | | // property that they can't be resolved to direct objects. This makes it possible to replace a |
567 | | // reserved object with a new object while preserving existing references to them. When you are |
568 | | // ready to replace a reserved object with its replacement, use QPDF::replaceReserved for this |
569 | | // purpose rather than the more general QPDF::replaceObject. It is an error to try to write a |
570 | | // QPDF with QPDFWriter if it has any reserved objects in it. From QPDF 11.4, you can call |
571 | | // QPDF::newReserved() instead. |
572 | | QPDF_DLL |
573 | | static QPDFObjectHandle newReserved(QPDF* qpdf); |
574 | | |
575 | | // Provide an owning qpdf and object description. The library does this automatically with |
576 | | // objects that are read from the input PDF and with objects that are created programmatically |
577 | | // and inserted into the QPDF as a new indirect object. Most end user code will not need to call |
578 | | // this. If an object has an owning qpdf and object description, it enables qpdf to give |
579 | | // warnings with proper context in some cases where it would otherwise raise exceptions. It is |
580 | | // okay to add objects without an owning_qpdf to objects that have one, but it is an error to |
581 | | // have a QPDF contain objects with owning_qpdf set to something else. To add objects from |
582 | | // another qpdf, use copyForeignObject instead. |
583 | | QPDF_DLL |
584 | | void setObjectDescription(QPDF* owning_qpdf, std::string const& object_description); |
585 | | QPDF_DLL |
586 | | bool hasObjectDescription() const; |
587 | | |
588 | | // Accessor methods |
589 | | // |
590 | | // (Note: this comment is referenced in qpdf-c.h and the manual.) |
591 | | // |
592 | | // In PDF files, objects have specific types, but there is nothing that prevents PDF files from |
593 | | // containing objects of types that aren't expected by the specification. |
594 | | // |
595 | | // There are two flavors of accessor methods: |
596 | | // |
597 | | // * getSomethingValue() returns the value and issues a type warning if the type is incorrect. |
598 | | // |
599 | | // * getValueAsSomething() returns false if the value is the wrong type. Otherwise, it returns |
600 | | // true and initializes a reference of the appropriate type. These methods never issue type |
601 | | // warnings. |
602 | | // |
603 | | // The getSomethingValue() accessors and some of the other methods expect objects of a |
604 | | // particular type. Prior to qpdf 8, calling an accessor on a method of the wrong type, such as |
605 | | // trying to get a dictionary key from an array, trying to get the string value of a number, |
606 | | // etc., would throw an exception, but since qpdf 8, qpdf issues a warning and recovers using |
607 | | // the following behavior: |
608 | | // |
609 | | // * Requesting a value of the wrong type (int value from string, array item from a scalar or |
610 | | // dictionary, etc.) will return a zero-like value for that type: false for boolean, 0 for |
611 | | // number, the empty string for string, or the null object for an object handle. |
612 | | // |
613 | | // * Accessing an array item that is out of bounds will return a null object. |
614 | | // |
615 | | // * Attempts to mutate an object of the wrong type (e.g., attempting to add a dictionary key to |
616 | | // a scalar or array) will be ignored. |
617 | | // |
618 | | // When any of these fallback behaviors are used, qpdf issues a warning. Starting in qpdf 10.5, |
619 | | // these warnings have the error code qpdf_e_object. Prior to 10.5, they had the error code |
620 | | // qpdf_e_damaged_pdf. If the QPDFObjectHandle is associated with a QPDF object (as is the case |
621 | | // for all objects whose origin was a PDF file), the warning is issued using the normal warning |
622 | | // mechanism (as described in QPDF.hh), making it possible to suppress or otherwise detect them. |
623 | | // If the QPDFObjectHandle is not associated with a QPDF object (meaning it was created |
624 | | // programmatically), an exception will be thrown. |
625 | | // |
626 | | // The way to avoid getting any type warnings or exceptions, even when working with malformed |
627 | | // PDF files, is to always check the type of a QPDFObjectHandle before accessing it (for |
628 | | // example, make sure that isString() returns true before calling getStringValue()) and to |
629 | | // always be sure that any array indices are in bounds. |
630 | | // |
631 | | // For additional discussion and rationale for this behavior, see the section in the QPDF manual |
632 | | // entitled "Object Accessor Methods". |
633 | | |
634 | | // Methods for bool objects |
635 | | QPDF_DLL |
636 | | bool getBoolValue() const; |
637 | | QPDF_DLL |
638 | | bool getValueAsBool(bool&) const; |
639 | | |
640 | | // Methods for integer objects. Note: if an integer value is too big (too far away from zero in |
641 | | // either direction) to fit in the requested return type, the maximum or minimum value for that |
642 | | // return type may be returned. For example, on a system with 32-bit int, a numeric object with |
643 | | // a value of 2^40 (or anything too big for 32 bits) will be returned as INT_MAX. |
644 | | QPDF_DLL |
645 | | long long getIntValue() const; |
646 | | QPDF_DLL |
647 | | bool getValueAsInt(long long&) const; |
648 | | QPDF_DLL |
649 | | int getIntValueAsInt() const; |
650 | | QPDF_DLL |
651 | | bool getValueAsInt(int&) const; |
652 | | QPDF_DLL |
653 | | unsigned long long getUIntValue() const; |
654 | | QPDF_DLL |
655 | | bool getValueAsUInt(unsigned long long&) const; |
656 | | QPDF_DLL |
657 | | unsigned int getUIntValueAsUInt() const; |
658 | | QPDF_DLL |
659 | | bool getValueAsUInt(unsigned int&) const; |
660 | | |
661 | | // Methods for real objects |
662 | | QPDF_DLL |
663 | | std::string getRealValue() const; |
664 | | QPDF_DLL |
665 | | bool getValueAsReal(std::string&) const; |
666 | | |
667 | | // Methods that work for both integer and real objects |
668 | | QPDF_DLL |
669 | | bool isNumber() const; |
670 | | QPDF_DLL |
671 | | double getNumericValue() const; |
672 | | QPDF_DLL |
673 | | bool getValueAsNumber(double&) const; |
674 | | |
675 | | // Methods for name objects. The returned name value is in qpdf's canonical form with all |
676 | | // escaping resolved. See comments for newName() for details. |
677 | | QPDF_DLL |
678 | | std::string getName() const; |
679 | | QPDF_DLL |
680 | | bool getValueAsName(std::string&) const; |
681 | | |
682 | | // Methods for string objects |
683 | | QPDF_DLL |
684 | | std::string getStringValue() const; |
685 | | QPDF_DLL |
686 | | bool getValueAsString(std::string&) const; |
687 | | |
688 | | // If a string starts with the UTF-16 marker, it is converted from UTF-16 to UTF-8. Otherwise, |
689 | | // it is treated as a string encoded with PDF Doc Encoding. PDF Doc Encoding is identical to |
690 | | // ISO-8859-1 except in the range from 0200 through 0240, where there is a mapping of characters |
691 | | // to Unicode. QPDF versions prior to version 8.0.0 erroneously left characters in that range |
692 | | // unmapped. |
693 | | QPDF_DLL |
694 | | std::string getUTF8Value() const; |
695 | | QPDF_DLL |
696 | | bool getValueAsUTF8(std::string&) const; |
697 | | |
698 | | // Methods for content stream objects |
699 | | QPDF_DLL |
700 | | std::string getOperatorValue() const; |
701 | | QPDF_DLL |
702 | | bool getValueAsOperator(std::string&) const; |
703 | | QPDF_DLL |
704 | | std::string getInlineImageValue() const; |
705 | | QPDF_DLL |
706 | | bool getValueAsInlineImage(std::string&) const; |
707 | | |
708 | | // Methods for array objects; see also name and array objects. |
709 | | |
710 | | // Return an object that enables iteration over members. You can do |
711 | | // |
712 | | // for (auto iter: obj.aitems()) |
713 | | // { |
714 | | // // iter is an array element |
715 | | // } |
716 | | class QPDFArrayItems; |
717 | | QPDF_DLL |
718 | | QPDFArrayItems aitems(); |
719 | | |
720 | | QPDF_DLL |
721 | | int getArrayNItems() const; |
722 | | QPDF_DLL |
723 | | QPDFObjectHandle getArrayItem(int n) const; |
724 | | // Note: QPDF arrays internally optimize memory for arrays containing lots of nulls. Calling |
725 | | // getArrayAsVector may cause a lot of memory to be allocated for very large arrays with lots of |
726 | | // nulls. |
727 | | QPDF_DLL |
728 | | std::vector<QPDFObjectHandle> getArrayAsVector() const; |
729 | | QPDF_DLL |
730 | | bool isRectangle() const; |
731 | | // If the array is an array of four numeric values, return as a rectangle. Otherwise, return the |
732 | | // rectangle [0, 0, 0, 0] |
733 | | QPDF_DLL |
734 | | Rectangle getArrayAsRectangle() const; |
735 | | QPDF_DLL |
736 | | bool isMatrix() const; |
737 | | // If the array is an array of six numeric values, return as a matrix. Otherwise, return the |
738 | | // matrix [1, 0, 0, 1, 0, 0] |
739 | | QPDF_DLL |
740 | | Matrix getArrayAsMatrix() const; |
741 | | |
742 | | // Methods for dictionary objects. In all dictionary methods, keys are specified/represented as |
743 | | // canonical name strings starting with a leading slash and not containing any PDF syntax |
744 | | // escaping. See comments for getName() for details. |
745 | | |
746 | | // Return an object that enables iteration over members. You can do |
747 | | // |
748 | | // for (auto iter: obj.ditems()) |
749 | | // { |
750 | | // // iter.first is the key |
751 | | // // iter.second is the value |
752 | | // } |
753 | | class QPDFDictItems; |
754 | | QPDF_DLL |
755 | | QPDFDictItems ditems(); |
756 | | |
757 | | // Return true if key is present. Keys with null values are treated as if they are not present. |
758 | | // This is as per the PDF spec. |
759 | | QPDF_DLL |
760 | | bool hasKey(std::string const&) const; |
761 | | // Return the value for the key. If the key is not present, null is returned. |
762 | | QPDF_DLL |
763 | | QPDFObjectHandle getKey(std::string const&) const; |
764 | | // If the object is null, return null. Otherwise, call getKey(). This makes it easier to access |
765 | | // lower-level dictionaries, as in |
766 | | // auto font = page.getKeyIfDict("/Resources").getKeyIfDict("/Font"); |
767 | | QPDF_DLL |
768 | | QPDFObjectHandle getKeyIfDict(std::string const&) const; |
769 | | // Return all keys. Keys with null values are treated as if they are not present. This is as |
770 | | // per the PDF spec. |
771 | | QPDF_DLL |
772 | | std::set<std::string> getKeys() const; |
773 | | // Return dictionary as a map. Entries with null values are included. |
774 | | QPDF_DLL |
775 | | std::map<std::string, QPDFObjectHandle> getDictAsMap() const; |
776 | | |
777 | | // Methods for name and array objects. The name value is in qpdf's canonical form with all |
778 | | // escaping resolved. See comments for newName() for details. |
779 | | QPDF_DLL |
780 | | bool isOrHasName(std::string const&) const; |
781 | | |
782 | | // Make all resources in a resource dictionary indirect. This just goes through all entries of |
783 | | // top-level subdictionaries and converts any direct objects to indirect objects. This can be |
784 | | // useful to call before mergeResources if it is going to be called multiple times to prevent |
785 | | // resources from being copied multiple times. |
786 | | QPDF_DLL |
787 | | void makeResourcesIndirect(QPDF& owning_qpdf); |
788 | | |
789 | | // Merge resource dictionaries. If the "conflicts" parameter is provided, conflicts in |
790 | | // dictionary subitems are resolved, and "conflicts" is initialized to a map such that |
791 | | // conflicts[resource_type][old_key] == [new_key] |
792 | | // |
793 | | // See also makeResourcesIndirect, which can be useful to call before calling this. |
794 | | // |
795 | | // This method does nothing if both this object and the other object are not dictionaries. |
796 | | // Otherwise, it has following behavior, where "object" refers to the object whose method is |
797 | | // invoked, and "other" refers to the argument: |
798 | | // |
799 | | // * For each key in "other" whose value is an array: |
800 | | // * If "object" does not have that entry, shallow copy it. |
801 | | // * Otherwise, if "object" has an array in the same place, append to that array any objects |
802 | | // in "other"'s array that are not already present. |
803 | | // * For each key in "other" whose value is a dictionary: |
804 | | // * If "object" does not have that entry, shallow copy it. |
805 | | // * Otherwise, for each key in the subdictionary: |
806 | | // * If key is not present in "object"'s entry, shallow copy it if direct or just add it if |
807 | | // indirect. |
808 | | // * Otherwise, if conflicts are being detected: |
809 | | // * If there is a key (oldkey) already in the dictionary that points to the same indirect |
810 | | // destination as key, indicate that key was replaced by oldkey. This would happen if |
811 | | // these two resource dictionaries have previously been merged. |
812 | | // * Otherwise pick a new key (newkey) that is unique within the resource dictionary, |
813 | | // store that in the resource dictionary with key's destination as its destination, and |
814 | | // indicate that key was replaced by newkey. |
815 | | // |
816 | | // The primary purpose of this method is to facilitate merging of resource dictionaries that are |
817 | | // supposed to have the same scope as each other. For example, this can be used to merge a form |
818 | | // XObject's /Resources dictionary with a form field's /DR or to merge two /DR dictionaries. The |
819 | | // "conflicts" parameter may be previously initialized. This method adds to whatever is already |
820 | | // there, which can be useful when merging with multiple things. |
821 | | QPDF_DLL |
822 | | void mergeResources( |
823 | | QPDFObjectHandle other, |
824 | | std::map<std::string, std::map<std::string, std::string>>* conflicts = nullptr); |
825 | | |
826 | | // Get all resource names from a resource dictionary. If this object is a dictionary, this |
827 | | // method returns a set of all the keys in all top-level subdictionaries. For resources |
828 | | // dictionaries, this is the collection of names that may be referenced in the content stream. |
829 | | QPDF_DLL |
830 | | std::set<std::string> getResourceNames() const; |
831 | | |
832 | | // Find a unique name within a resource dictionary starting with a given prefix. This method |
833 | | // works by appending a number to the given prefix. It searches starting with min_suffix and |
834 | | // sets min_suffix to selected value upon return. This can be used to increase efficiency if |
835 | | // adding multiple items with the same prefix. (Why doesn't it set min_suffix to the next |
836 | | // number? Well, maybe you aren't going to actually use the name it returns.) If you are calling |
837 | | // this multiple times on the same resource dictionary, you can initialize resource_names by |
838 | | // calling getResourceNames(), incrementally update it as you add resources, and keep passing it |
839 | | // in so that getUniqueResourceName doesn't have to traverse the resource dictionary each time |
840 | | // it's called. |
841 | | QPDF_DLL |
842 | | std::string getUniqueResourceName( |
843 | | std::string const& prefix, |
844 | | int& min_suffix, |
845 | | std::set<std::string>* resource_names = nullptr) const; |
846 | | |
847 | | // A QPDFObjectHandle has an owning QPDF if it is associated with ("owned by") a specific QPDF |
848 | | // object. Indirect objects always have an owning QPDF. Direct objects that are read from the |
849 | | // input source will also have an owning QPDF. Programmatically created objects will only have |
850 | | // one if setObjectDescription was called. |
851 | | // |
852 | | // When the QPDF object that owns an object is destroyed, the object is changed into a null, and |
853 | | // its owner is cleared. Therefore you should not retain the value of an owning QPDF beyond the |
854 | | // life of the QPDF. If in doubt, ask for it each time you need it. |
855 | | |
856 | | // getOwningQPDF returns a pointer to the owning QPDF is the object has one. Otherwise, it |
857 | | // returns a null pointer. Use this when you are able to handle the case of an object that |
858 | | // doesn't have an owning QPDF. |
859 | | QPDF_DLL |
860 | | QPDF* getOwningQPDF() const; |
861 | | // getQPDF, new in qpdf 11, returns a reference owning QPDF. If there is none, it throws a |
862 | | // runtime_error. Use this when you know the object has to have an owning QPDF, such as when |
863 | | // it's a known indirect object. Since streams are always indirect objects, this method can be |
864 | | // used safely for streams. If error_msg is specified, it will be used at the contents of the |
865 | | // runtime_error if there is now owner. |
866 | | QPDF_DLL |
867 | | QPDF& getQPDF(std::string const& error_msg = "") const; |
868 | | |
869 | | // Create a shallow copy of an object as a direct object, but do not traverse across indirect |
870 | | // object boundaries. That means that, for dictionaries and arrays, any keys or items that were |
871 | | // indirect objects will still be indirect objects that point to the same place. In the |
872 | | // strictest sense, this is not a shallow copy because it recursively descends arrays and |
873 | | // dictionaries; it just doesn't cross over indirect objects. See also unsafeShallowCopy(). You |
874 | | // can't copy a stream this way. See copyStream() instead. |
875 | | QPDF_DLL |
876 | | QPDFObjectHandle shallowCopy(); |
877 | | |
878 | | // Create a true shallow copy of an array or dictionary, just copying the immediate items |
879 | | // (array) or keys (dictionary). This is "unsafe" because, if you *modify* any of the items in |
880 | | // the copy, you are modifying the original, which is almost never what you want. However, if |
881 | | // your intention is merely to *replace* top-level items or keys and not to modify lower-level |
882 | | // items in the copy, this method is much faster than shallowCopy(). |
883 | | QPDF_DLL |
884 | | QPDFObjectHandle unsafeShallowCopy(); |
885 | | |
886 | | // Create a copy of this stream. The new stream and the old stream are independent: after the |
887 | | // copy, either the original or the copy's dictionary or data can be modified without affecting |
888 | | // the other. This uses StreamDataProvider internally, so no unnecessary copies of the stream's |
889 | | // data are made. If the source stream's data is already being provided by a StreamDataProvider, |
890 | | // the new stream will use the same one, so you have to make sure your StreamDataProvider can |
891 | | // handle that case. But if you're already using a StreamDataProvider, you probably don't need |
892 | | // to call this method. |
893 | | QPDF_DLL |
894 | | QPDFObjectHandle copyStream(); |
895 | | |
896 | | // Mutator methods. |
897 | | |
898 | | // Since qpdf 11: for mutators that may add or remove an item, there are additional versions |
899 | | // whose names contain "AndGet" that return the added or removed item. For example: |
900 | | // |
901 | | // auto new_dict = dict.replaceKeyAndGetNew( |
902 | | // "/New", QPDFObjectHandle::newDictionary()); |
903 | | // |
904 | | // auto old_value = dict.replaceKeyAndGetOld( |
905 | | // "/New", "(something)"_qpdf); |
906 | | |
907 | | // Recursively copy this object, making it direct. An exception is thrown if a loop is detected. |
908 | | // With allow_streams true, keep indirect object references to streams. Otherwise, throw an |
909 | | // exception if any sub-object is a stream. Note that, when allow_streams is true and a stream |
910 | | // is found, the resulting object is still associated with the containing qpdf. When |
911 | | // allow_streams is false, the object will no longer be connected to the original QPDF object |
912 | | // after this call completes successfully. |
913 | | QPDF_DLL |
914 | | void makeDirect(bool allow_streams = false); |
915 | | |
916 | | // Mutator methods for array objects |
917 | | QPDF_DLL |
918 | | void setArrayItem(int, QPDFObjectHandle const&); |
919 | | QPDF_DLL |
920 | | void setArrayFromVector(std::vector<QPDFObjectHandle> const& items); |
921 | | // Insert an item before the item at the given position ("at") so that it has that position |
922 | | // after insertion. If "at" is equal to the size of the array, insert the item at the end. |
923 | | QPDF_DLL |
924 | | void insertItem(int at, QPDFObjectHandle const& item); |
925 | | // Like insertItem but return the item that was inserted. |
926 | | QPDF_DLL |
927 | | QPDFObjectHandle insertItemAndGetNew(int at, QPDFObjectHandle const& item); |
928 | | // Append an item to an array. |
929 | | QPDF_DLL |
930 | | void appendItem(QPDFObjectHandle const& item); |
931 | | // Append an item, and return the newly added item. |
932 | | QPDF_DLL |
933 | | QPDFObjectHandle appendItemAndGetNew(QPDFObjectHandle const& item); |
934 | | // Remove the item at that position, reducing the size of the array by one. |
935 | | QPDF_DLL |
936 | | void eraseItem(int at); |
937 | | // Erase and item and return the item that was removed. |
938 | | QPDF_DLL |
939 | | QPDFObjectHandle eraseItemAndGetOld(int at); |
940 | | |
941 | | // Mutator methods for dictionary objects |
942 | | |
943 | | // Replace value of key, adding it if it does not exist. If value is null, remove the key. |
944 | | QPDF_DLL |
945 | | void replaceKey(std::string const& key, QPDFObjectHandle const& value); |
946 | | // Replace value of key and return the value. |
947 | | QPDF_DLL |
948 | | QPDFObjectHandle replaceKeyAndGetNew(std::string const& key, QPDFObjectHandle const& value); |
949 | | // Replace value of key and return the old value, or null if the key was previously not present. |
950 | | QPDF_DLL |
951 | | QPDFObjectHandle replaceKeyAndGetOld(std::string const& key, QPDFObjectHandle const& value); |
952 | | // Remove key, doing nothing if key does not exist. |
953 | | QPDF_DLL |
954 | | void removeKey(std::string const& key); |
955 | | // Remove key and return the old value. If the old value didn't exist, return a null object. |
956 | | QPDF_DLL |
957 | | QPDFObjectHandle removeKeyAndGetOld(std::string const& key); |
958 | | |
959 | | // Methods for stream objects |
960 | | QPDF_DLL |
961 | | QPDFObjectHandle getDict() const; |
962 | | |
963 | | // By default, or if true passed, QPDFWriter will attempt to filter a stream based on decode |
964 | | // level, whether compression is enabled, and its ability to filter. Passing false will prevent |
965 | | // QPDFWriter from attempting to filter the stream even if it can. This includes both decoding |
966 | | // and compressing. This makes it possible for you to prevent QPDFWriter from uncompressing and |
967 | | // recompressing a stream that it knows how to operate on for any application-specific reason, |
968 | | // such as that you have already optimized its filtering. Note that this doesn't affect any |
969 | | // other ways to get the stream's data, such as pipeStreamData or getStreamData. |
970 | | QPDF_DLL |
971 | | void setFilterOnWrite(bool); |
972 | | QPDF_DLL |
973 | | bool getFilterOnWrite(); |
974 | | |
975 | | // If addTokenFilter has been called for this stream, then the original data should be |
976 | | // considered to be modified. This means we should avoid optimizations such as not filtering a |
977 | | // stream that is already compressed. |
978 | | QPDF_DLL |
979 | | bool isDataModified(); |
980 | | |
981 | | // Returns filtered (uncompressed) stream data. Throws an exception if the stream is filtered |
982 | | // and we can't decode it. |
983 | | QPDF_DLL |
984 | | std::shared_ptr<Buffer> getStreamData(qpdf_stream_decode_level_e level = qpdf_dl_generalized); |
985 | | |
986 | | // Returns unfiltered (raw) stream data. |
987 | | QPDF_DLL |
988 | | std::shared_ptr<Buffer> getRawStreamData(); |
989 | | |
990 | | // Write stream data through the given pipeline. A null pipeline value may be used if all you |
991 | | // want to do is determine whether a stream is filterable and would be filtered based on the |
992 | | // provided flags. If flags is 0, write raw stream data and return false. Otherwise, the flags |
993 | | // alter the behavior in the following way: |
994 | | // |
995 | | // encode_flags: |
996 | | // |
997 | | // qpdf_sf_compress -- compress data with /FlateDecode if no other compression filters are |
998 | | // applied. |
999 | | // |
1000 | | // qpdf_sf_normalize -- tokenize as content stream and normalize tokens |
1001 | | // |
1002 | | // decode_level: |
1003 | | // |
1004 | | // qpdf_dl_none -- do not decode any streams. |
1005 | | // |
1006 | | // qpdf_dl_generalized -- decode supported general-purpose filters. This includes |
1007 | | // /ASCIIHexDecode, /ASCII85Decode, /LZWDecode, and /FlateDecode. |
1008 | | // |
1009 | | // qpdf_dl_specialized -- in addition to generalized filters, also decode supported non-lossy |
1010 | | // specialized filters. This includes /RunLengthDecode. |
1011 | | // |
1012 | | // qpdf_dl_all -- in addition to generalized and non-lossy specialized filters, decode supported |
1013 | | // lossy filters. This includes /DCTDecode. |
1014 | | // |
1015 | | // If, based on the flags and the filters and decode parameters, we determine that we know how |
1016 | | // to apply all requested filters, do so and return true if we are successful. |
1017 | | // |
1018 | | // The exact meaning of the return value differs the different versions of this function, but |
1019 | | // for any version, the meaning has been the same. For the main version, added in qpdf 10, the |
1020 | | // return value indicates whether the overall operation succeeded. The filter parameter, if |
1021 | | // specified, will be set to whether or not filtering was attempted. If filtering was not |
1022 | | // requested, this value will be false even if the overall operation succeeded. |
1023 | | // |
1024 | | // If filtering is requested but this method returns false, it means there was some error in the |
1025 | | // filtering, in which case the resulting data is likely partially filtered and/or incomplete |
1026 | | // and may not be consistent with the configured filters. QPDFWriter handles this by attempting |
1027 | | // to get the stream data without filtering, but callers should consider a false return value |
1028 | | // when decode_level is not qpdf_dl_none to be a potential loss of data. If you intend to retry |
1029 | | // in that case, pass true as the value of will_retry. This changes the warning issued by the |
1030 | | // library to indicate that the operation will be retried without filtering to avoid data loss. |
1031 | | |
1032 | | // Return value is overall success, even if filtering is not requested. |
1033 | | QPDF_DLL |
1034 | | bool pipeStreamData( |
1035 | | Pipeline*, |
1036 | | bool* filtering_attempted, |
1037 | | int encode_flags, |
1038 | | qpdf_stream_decode_level_e decode_level, |
1039 | | bool suppress_warnings = false, |
1040 | | bool will_retry = false); |
1041 | | |
1042 | | // Legacy version. Return value is whether filtering was attempted. There is no way to determine |
1043 | | // success if filtering was not attempted. |
1044 | | QPDF_DLL |
1045 | | bool pipeStreamData( |
1046 | | Pipeline*, |
1047 | | int encode_flags, |
1048 | | qpdf_stream_decode_level_e decode_level, |
1049 | | bool suppress_warnings = false, |
1050 | | bool will_retry = false); |
1051 | | |
1052 | | // Legacy pipeStreamData. This maps to the the flags-based pipeStreamData as follows: |
1053 | | // filter = false -> encode_flags = 0 |
1054 | | // filter = true -> decode_level = qpdf_dl_generalized |
1055 | | // normalize = true -> encode_flags |= qpdf_sf_normalize |
1056 | | // compress = true -> encode_flags |= qpdf_sf_compress |
1057 | | // Return value is whether filtering was attempted. |
1058 | | QPDF_DLL |
1059 | | bool pipeStreamData(Pipeline*, bool filter, bool normalize, bool compress); |
1060 | | |
1061 | | // Replace a stream's dictionary. The new dictionary must be consistent with the stream's data. |
1062 | | // This is most appropriately used when creating streams from scratch that will use a stream |
1063 | | // data provider and therefore start with an empty dictionary. It may be more convenient in |
1064 | | // this case than calling getDict and modifying it for each key. The pdf-create example does |
1065 | | // this. |
1066 | | QPDF_DLL |
1067 | | void replaceDict(QPDFObjectHandle const&); |
1068 | | |
1069 | | // Test whether a stream is the root XMP /Metadata object of its owning QPDF. |
1070 | | QPDF_DLL |
1071 | | bool isRootMetadata() const; |
1072 | | |
1073 | | // REPLACING STREAM DATA |
1074 | | |
1075 | | // Note about all replaceStreamData methods: whatever values are passed as filter and |
1076 | | // decode_parms will overwrite /Filter and /DecodeParms in the stream. Passing a null object |
1077 | | // (QPDFObjectHandle::newNull()) will remove those values from the stream dictionary. From qpdf |
1078 | | // 11, passing an *uninitialized* QPDFObjectHandle (QPDFObjectHandle()) will leave any existing |
1079 | | // values untouched. |
1080 | | |
1081 | | // Replace this stream's stream data with the given data buffer. The stream's /Length key is |
1082 | | // replaced with the length of the data buffer. The stream is interpreted as if the data read |
1083 | | // from the file, after any decryption filters have been applied, is as presented. |
1084 | | QPDF_DLL |
1085 | | void replaceStreamData( |
1086 | | std::shared_ptr<Buffer> data, |
1087 | | QPDFObjectHandle const& filter, |
1088 | | QPDFObjectHandle const& decode_parms); |
1089 | | |
1090 | | // Replace the stream's stream data with the given string. This method will create a copy of the |
1091 | | // data rather than using the user-provided buffer as in the std::shared_ptr<Buffer> version of |
1092 | | // replaceStreamData. |
1093 | | QPDF_DLL |
1094 | | void replaceStreamData( |
1095 | | std::string const& data, |
1096 | | QPDFObjectHandle const& filter, |
1097 | | QPDFObjectHandle const& decode_parms); |
1098 | | |
1099 | | // As above, replace this stream's stream data. Instead of directly providing a buffer with the |
1100 | | // stream data, call the given provider's provideStreamData method. See comments on the |
1101 | | // StreamDataProvider class (defined above) for details on the method. The data must be |
1102 | | // consistent with filter and decode_parms as provided. Although it is more complex to use this |
1103 | | // form of replaceStreamData than the one that takes a buffer, it makes it possible to avoid |
1104 | | // allocating memory for the stream data. Example programs are provided that use both forms of |
1105 | | // replaceStreamData. |
1106 | | |
1107 | | // Note about stream length: for any given stream, the provider must provide the same amount of |
1108 | | // data each time it is called. This is critical for making linearization work properly. |
1109 | | // Versions of qpdf before 3.0.0 required a length to be specified here. Starting with |
1110 | | // version 3.0.0, this is no longer necessary (or permitted). The first time the stream data |
1111 | | // provider is invoked for a given stream, the actual length is stored. Subsequent times, it is |
1112 | | // enforced that the length be the same as the first time. |
1113 | | |
1114 | | // If you have gotten a compile error here while building code that worked with older versions |
1115 | | // of qpdf, just omit the length parameter. You can also simplify your code by not having to |
1116 | | // compute the length in advance. |
1117 | | QPDF_DLL |
1118 | | void replaceStreamData( |
1119 | | std::shared_ptr<StreamDataProvider> provider, |
1120 | | QPDFObjectHandle const& filter, |
1121 | | QPDFObjectHandle const& decode_parms); |
1122 | | |
1123 | | // Starting in qpdf 10.2, you can use C++-11 function objects instead of StreamDataProvider. |
1124 | | |
1125 | | // The provider should write the stream data to the pipeline. For a one-liner to replace stream |
1126 | | // data with the contents of a file, pass QUtil::file_provider(filename) as provider. |
1127 | | QPDF_DLL |
1128 | | void replaceStreamData( |
1129 | | std::function<void(Pipeline*)> provider, |
1130 | | QPDFObjectHandle const& filter, |
1131 | | QPDFObjectHandle const& decode_parms); |
1132 | | // The provider should write the stream data to the pipeline, returning true if it succeeded |
1133 | | // without errors. |
1134 | | QPDF_DLL |
1135 | | void replaceStreamData( |
1136 | | std::function<bool(Pipeline*, bool suppress_warnings, bool will_retry)> provider, |
1137 | | QPDFObjectHandle const& filter, |
1138 | | QPDFObjectHandle const& decode_parms); |
1139 | | |
1140 | | // Access object ID and generation. For direct objects, return object ID 0. |
1141 | | |
1142 | | // NOTE: Be careful about calling getObjectID() and getGeneration() directly as this can lead to |
1143 | | // the pattern of depending on object ID or generation without the other. In general, when |
1144 | | // keeping track of object IDs, it's better to use QPDFObjGen instead. |
1145 | | |
1146 | | QPDF_DLL |
1147 | | QPDFObjGen getObjGen() const; |
1148 | | QPDF_DLL |
1149 | | int getObjectID() const; |
1150 | | QPDF_DLL |
1151 | | int getGeneration() const; |
1152 | | |
1153 | | QPDF_DLL |
1154 | | std::string unparse() const; |
1155 | | QPDF_DLL |
1156 | | std::string unparseResolved() const; |
1157 | | // For strings only, force binary representation. Otherwise, same as unparse. |
1158 | | QPDF_DLL |
1159 | | std::string unparseBinary() const; |
1160 | | |
1161 | | // Return encoded as JSON. The constant JSON::LATEST can be used to specify the latest available |
1162 | | // JSON version. The JSON is generated as follows: |
1163 | | // * Arrays, dictionaries, booleans, nulls, integers, and real numbers are represented by their |
1164 | | // native JSON types. |
1165 | | // * Names are encoded as strings representing the canonical representation (after parsing #xx) |
1166 | | // and preceded by a slash, just as unparse() returns. For example, the JSON for the |
1167 | | // PDF-syntax name /Text#2fPlain would be "/Text/Plain". |
1168 | | // * Indirect references are encoded as strings containing "obj gen R" |
1169 | | // * Strings |
1170 | | // * JSON v1: Strings are encoded as UTF-8 strings with unrepresentable binary characters |
1171 | | // encoded as \uHHHH. Characters in PDF Doc encoding that don't have bidirectional unicode |
1172 | | // mappings are not reversible. There is no way to tell the difference between a string that |
1173 | | // looks like a name or indirect object from an actual name or indirect object. |
1174 | | // * JSON v2: |
1175 | | // * Unicode strings and strings encoded with PDF Doc encoding that can be bidirectionally |
1176 | | // mapped to Unicode (which is all strings without undefined characters) are represented |
1177 | | // as "u:" followed by the UTF-8 encoded string. Example: |
1178 | | // "u:potato". |
1179 | | // * All other strings are represented as "b:" followed by a hexadecimal encoding of the |
1180 | | // string. Example: "b:0102cacb" |
1181 | | // * Streams |
1182 | | // * JSON v1: Only the stream's dictionary is encoded. There is no way to tell a stream from a |
1183 | | // dictionary other than context. |
1184 | | // * JSON v2: A stream is encoded as {"dict": {...}} with the value being the encoding of the |
1185 | | // stream's dictionary. Since "dict" does not otherwise represent anything, this is |
1186 | | // unambiguous. The getStreamJSON() call can be used to add encoding of the stream's data. |
1187 | | // * Object types that are only valid in content streams (inline image, operator) are serialized |
1188 | | // as "null". Attempting to serialize a "reserved" object is an error. |
1189 | | // If dereference_indirect is true and this is an indirect object, show the actual contents of |
1190 | | // the object. The effect of dereference_indirect applies only to this object. It is not |
1191 | | // recursive. |
1192 | | QPDF_DLL |
1193 | | JSON getJSON(int json_version, bool dereference_indirect = false) const; |
1194 | | |
1195 | | // Write the object encoded as JSON to a pipeline. This is equivalent to, but more efficient |
1196 | | // than, calling getJSON(json_version, dereference_indirect).write(p, depth). See the |
1197 | | // documentation for getJSON and JSON::write for further detail. |
1198 | | QPDF_DLL |
1199 | | void writeJSON( |
1200 | | int json_version, Pipeline* p, bool dereference_indirect = false, size_t depth = 0) const; |
1201 | | |
1202 | | // This method can be called on a stream to get a more extended JSON representation of the |
1203 | | // stream that includes the stream's data. The JSON object returned is always a dictionary whose |
1204 | | // "dict" key is an encoding of the stream's dictionary. The representation of the data is |
1205 | | // determined by the json_data field. |
1206 | | // |
1207 | | // The json_data field may have the value qpdf_sj_none, qpdf_sj_inline, or qpdf_sj_file. |
1208 | | // |
1209 | | // If json_data is qpdf_sj_none, stream data is not represented. |
1210 | | // |
1211 | | // If json_data is qpdf_sj_inline or qpdf_sj_file, then stream data is filtered or not based on |
1212 | | // the value of decode_level, which has the same meaning as with pipeStreamData. |
1213 | | // |
1214 | | // If json_data is qpdf_sj_inline, the base64-encoded stream data is included in the "data" |
1215 | | // field of the dictionary that is returned. |
1216 | | // |
1217 | | // If json_data is qpdf_sj_file, then the Pipeline ("p") and data_filename argument must be |
1218 | | // supplied. The value of data_filename is stored in the resulting json in the "datafile" key |
1219 | | // but is not otherwise use. The stream data itself (raw or filtered depending on decode level), |
1220 | | // is written to the pipeline via pipeStreamData(). |
1221 | | // |
1222 | | // NOTE: When json_data is qpdf_sj_inline, the QPDF object from which the stream originates must |
1223 | | // remain valid until after the JSON object is written. |
1224 | | QPDF_DLL |
1225 | | JSON getStreamJSON( |
1226 | | int json_version, |
1227 | | qpdf_json_stream_data_e json_data, |
1228 | | qpdf_stream_decode_level_e decode_level, |
1229 | | Pipeline* p, |
1230 | | std::string const& data_filename); |
1231 | | |
1232 | | // Legacy helper methods for commonly performed operations on pages. Newer code should use |
1233 | | // QPDFPageObjectHelper instead. The specification and behavior of these methods are the same as |
1234 | | // the identically named methods in that class, but newer functionality will be added there. |
1235 | | QPDF_DLL |
1236 | | std::map<std::string, QPDFObjectHandle> getPageImages(); |
1237 | | QPDF_DLL |
1238 | | std::vector<QPDFObjectHandle> getPageContents(); |
1239 | | QPDF_DLL |
1240 | | void addPageContents(QPDFObjectHandle contents, bool first); |
1241 | | QPDF_DLL |
1242 | | void rotatePage(int angle, bool relative); |
1243 | | QPDF_DLL |
1244 | | void coalesceContentStreams(); |
1245 | | // End legacy page helpers |
1246 | | |
1247 | | // Issue a warning about this object if possible. If the object has a description, a warning |
1248 | | // will be issued using the owning QPDF as context. Otherwise, a message will be written to the |
1249 | | // default logger's error stream, which is standard error if not overridden. Objects read |
1250 | | // normally from the file have descriptions. See comments on setObjectDescription for additional |
1251 | | // details. |
1252 | | QPDF_DLL |
1253 | | void warnIfPossible(std::string const& warning) const; |
1254 | | |
1255 | | // Convenience routine: Throws if the assumption is violated. Your code will be better if you |
1256 | | // call one of the isType methods and handle the case of the type being wrong, but these can be |
1257 | | // convenient if you have already verified the type. |
1258 | | QPDF_DLL |
1259 | | void assertInitialized() const; |
1260 | | |
1261 | | QPDF_DLL |
1262 | | void assertNull() const; |
1263 | | QPDF_DLL |
1264 | | void assertBool() const; |
1265 | | QPDF_DLL |
1266 | | void assertInteger() const; |
1267 | | QPDF_DLL |
1268 | | void assertReal() const; |
1269 | | QPDF_DLL |
1270 | | void assertName() const; |
1271 | | QPDF_DLL |
1272 | | void assertString() const; |
1273 | | QPDF_DLL |
1274 | | void assertOperator() const; |
1275 | | QPDF_DLL |
1276 | | void assertInlineImage() const; |
1277 | | QPDF_DLL |
1278 | | void assertArray() const; |
1279 | | QPDF_DLL |
1280 | | void assertDictionary() const; |
1281 | | QPDF_DLL |
1282 | | void assertStream() const; |
1283 | | QPDF_DLL |
1284 | | void assertReserved() const; |
1285 | | |
1286 | | QPDF_DLL |
1287 | | void assertIndirect() const; |
1288 | | QPDF_DLL |
1289 | | void assertScalar() const; |
1290 | | QPDF_DLL |
1291 | | void assertNumber() const; |
1292 | | |
1293 | | // The isPageObject method checks the /Type key of the object. This is not completely reliable |
1294 | | // as there are some otherwise valid files whose /Type is wrong for page objects. qpdf is |
1295 | | // slightly more accepting but may still return false here when treating the object as a page |
1296 | | // would work. Use this sparingly. |
1297 | | QPDF_DLL |
1298 | | bool isPageObject() const; |
1299 | | QPDF_DLL |
1300 | | bool isPagesObject() const; |
1301 | | QPDF_DLL |
1302 | | void assertPageObject() const; |
1303 | | |
1304 | | QPDF_DLL |
1305 | | bool isFormXObject() const; |
1306 | | |
1307 | | // Indicate if this is an image. If exclude_imagemask is true, don't count image masks as |
1308 | | // images. |
1309 | | QPDF_DLL |
1310 | | bool isImage(bool exclude_imagemask = true) const; |
1311 | | |
1312 | | // The following methods do not form part of the public API and are for internal use only. |
1313 | | |
1314 | | QPDFObjectHandle(std::shared_ptr<QPDFObject> const& obj) : |
1315 | 36.4k | qpdf::BaseHandle(obj) |
1316 | 36.4k | { |
1317 | 36.4k | } |
1318 | | QPDFObjectHandle(std::shared_ptr<QPDFObject>&& obj) : |
1319 | 2.41M | qpdf::BaseHandle(std::move(obj)) |
1320 | 2.41M | { |
1321 | 2.41M | } |
1322 | | std::shared_ptr<QPDFObject> |
1323 | | getObj() |
1324 | 0 | { |
1325 | 0 | return obj; |
1326 | 0 | } |
1327 | | |
1328 | | void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false) const; |
1329 | | |
1330 | | inline qpdf::Array as_array(qpdf::typed options = qpdf::typed::any) const; |
1331 | | inline qpdf::Dictionary as_dictionary(qpdf::typed options = qpdf::typed::any) const; |
1332 | | inline qpdf::Stream as_stream(qpdf::typed options = qpdf::typed::strict) const; |
1333 | | |
1334 | | private: |
1335 | | void typeWarning(char const* expected_type, std::string const& warning) const; |
1336 | | void objectWarning(std::string const& warning) const; |
1337 | | void assertType(char const* type_name, bool istype) const; |
1338 | | void makeDirect(uint32_t level, QPDFObjGen::set& visited, bool stop_at_streams); |
1339 | | void setParsedOffset(qpdf_offset_t offset); |
1340 | | void parseContentStream_internal(std::string const& description, ParserCallbacks* callbacks); |
1341 | | static void parseContentStream_data( |
1342 | | std::string_view stream_data, |
1343 | | std::string const& description, |
1344 | | ParserCallbacks* callbacks, |
1345 | | QPDF* context); |
1346 | | std::vector<QPDFObjectHandle> |
1347 | | arrayOrStreamToStreamArray(std::string const& description, std::string& all_description); |
1348 | | void checkOwnership(QPDFObjectHandle const&) const; |
1349 | | }; |
1350 | | |
1351 | | #ifndef QPDF_NO_QPDF_STRING |
1352 | | // This is short for QPDFObjectHandle::parse, so you can do |
1353 | | |
1354 | | // auto oh = "<< /Key (value) >>"_qpdf; |
1355 | | |
1356 | | // If this is causing problems in your code, define QPDF_NO_QPDF_STRING to prevent the declaration |
1357 | | // from being here. |
1358 | | |
1359 | | /* clang-format off */ |
1360 | | // Disable formatting for this declaration: emacs font-lock in cc-mode (as of 28.1) treats the rest |
1361 | | // of the file as a string if clang-format removes the space after "operator", and as of |
1362 | | // clang-format 15, there's no way to prevent it from doing so. |
1363 | | QPDF_DLL |
1364 | | QPDFObjectHandle operator ""_qpdf(char const* v, size_t len); |
1365 | | /* clang-format on */ |
1366 | | |
1367 | | #endif // QPDF_NO_QPDF_STRING |
1368 | | |
1369 | | class QPDFObjectHandle::QPDFDictItems |
1370 | | { |
1371 | | // This class allows C++-style iteration, including range-for iteration, around dictionaries. |
1372 | | // You can write |
1373 | | |
1374 | | // for (auto iter: QPDFDictItems(dictionary_obj)) |
1375 | | // { |
1376 | | // // iter.first is a string |
1377 | | // // iter.second is a QPDFObjectHandle |
1378 | | // } |
1379 | | |
1380 | | // See examples/pdf-name-number-tree.cc for a demonstration of using this API. |
1381 | | |
1382 | | public: |
1383 | | QPDF_DLL |
1384 | | QPDFDictItems(QPDFObjectHandle const& oh); |
1385 | | |
1386 | | class iterator |
1387 | | { |
1388 | | friend class QPDFDictItems; |
1389 | | |
1390 | | public: |
1391 | | typedef std::pair<std::string, QPDFObjectHandle> T; |
1392 | | using iterator_category = std::bidirectional_iterator_tag; |
1393 | | using value_type = T; |
1394 | | using difference_type = long; |
1395 | | using pointer = T*; |
1396 | | using reference = T&; |
1397 | | |
1398 | 0 | virtual ~iterator() = default; |
1399 | | QPDF_DLL |
1400 | | iterator& operator++(); |
1401 | | iterator |
1402 | | operator++(int) |
1403 | 0 | { |
1404 | 0 | iterator t = *this; |
1405 | 0 | ++(*this); |
1406 | 0 | return t; |
1407 | 0 | } |
1408 | | QPDF_DLL |
1409 | | iterator& operator--(); |
1410 | | iterator |
1411 | | operator--(int) |
1412 | 0 | { |
1413 | 0 | iterator t = *this; |
1414 | 0 | --(*this); |
1415 | 0 | return t; |
1416 | 0 | } |
1417 | | QPDF_DLL |
1418 | | reference operator*(); |
1419 | | QPDF_DLL |
1420 | | pointer operator->(); |
1421 | | QPDF_DLL |
1422 | | bool operator==(iterator const& other) const; |
1423 | | bool |
1424 | | operator!=(iterator const& other) const |
1425 | 0 | { |
1426 | 0 | return !operator==(other); |
1427 | 0 | } |
1428 | | |
1429 | | private: |
1430 | | iterator(QPDFObjectHandle& oh, bool for_begin); |
1431 | | void updateIValue(); |
1432 | | |
1433 | | class Members |
1434 | | { |
1435 | | friend class QPDFDictItems::iterator; |
1436 | | |
1437 | | public: |
1438 | 0 | ~Members() = default; |
1439 | | |
1440 | | private: |
1441 | | Members(QPDFObjectHandle& oh, bool for_begin); |
1442 | | Members() = delete; |
1443 | | Members(Members const&) = delete; |
1444 | | |
1445 | | QPDFObjectHandle& oh; |
1446 | | std::set<std::string> keys; |
1447 | | std::set<std::string>::iterator iter; |
1448 | | bool is_end; |
1449 | | }; |
1450 | | std::shared_ptr<Members> m; |
1451 | | value_type ivalue; |
1452 | | }; |
1453 | | |
1454 | | QPDF_DLL |
1455 | | iterator begin(); |
1456 | | QPDF_DLL |
1457 | | iterator end(); |
1458 | | |
1459 | | private: |
1460 | | QPDFObjectHandle oh; |
1461 | | }; |
1462 | | |
1463 | | class QPDFObjectHandle::QPDFArrayItems |
1464 | | { |
1465 | | // This class allows C++-style iteration, including range-for iteration, around arrays. You can |
1466 | | // write |
1467 | | |
1468 | | // for (auto iter: QPDFArrayItems(array_obj)) |
1469 | | // { |
1470 | | // // iter is a QPDFObjectHandle |
1471 | | // } |
1472 | | |
1473 | | // See examples/pdf-name-number-tree.cc for a demonstration of using this API. |
1474 | | |
1475 | | public: |
1476 | | QPDF_DLL |
1477 | | QPDFArrayItems(QPDFObjectHandle const& oh); |
1478 | | |
1479 | | class iterator |
1480 | | { |
1481 | | friend class QPDFArrayItems; |
1482 | | |
1483 | | public: |
1484 | | typedef QPDFObjectHandle T; |
1485 | | using iterator_category = std::bidirectional_iterator_tag; |
1486 | | using value_type = T; |
1487 | | using difference_type = long; |
1488 | | using pointer = T*; |
1489 | | using reference = T&; |
1490 | | |
1491 | 0 | virtual ~iterator() = default; |
1492 | | QPDF_DLL |
1493 | | iterator& operator++(); |
1494 | | iterator |
1495 | | operator++(int) |
1496 | 0 | { |
1497 | 0 | iterator t = *this; |
1498 | 0 | ++(*this); |
1499 | 0 | return t; |
1500 | 0 | } |
1501 | | QPDF_DLL |
1502 | | iterator& operator--(); |
1503 | | iterator |
1504 | | operator--(int) |
1505 | 0 | { |
1506 | 0 | iterator t = *this; |
1507 | 0 | --(*this); |
1508 | 0 | return t; |
1509 | 0 | } |
1510 | | QPDF_DLL |
1511 | | reference operator*(); |
1512 | | QPDF_DLL |
1513 | | pointer operator->(); |
1514 | | QPDF_DLL |
1515 | | bool operator==(iterator const& other) const; |
1516 | | bool |
1517 | | operator!=(iterator const& other) const |
1518 | 0 | { |
1519 | 0 | return !operator==(other); |
1520 | 0 | } |
1521 | | |
1522 | | private: |
1523 | | iterator(QPDFObjectHandle& oh, bool for_begin); |
1524 | | void updateIValue(); |
1525 | | |
1526 | | class Members |
1527 | | { |
1528 | | friend class QPDFArrayItems::iterator; |
1529 | | |
1530 | | public: |
1531 | | ~Members() = default; |
1532 | | |
1533 | | private: |
1534 | | Members(QPDFObjectHandle& oh, bool for_begin); |
1535 | | Members() = delete; |
1536 | | Members(Members const&) = delete; |
1537 | | |
1538 | | QPDFObjectHandle& oh; |
1539 | | int item_number; |
1540 | | bool is_end; |
1541 | | }; |
1542 | | std::shared_ptr<Members> m; |
1543 | | value_type ivalue; |
1544 | | }; |
1545 | | |
1546 | | QPDF_DLL |
1547 | | iterator begin(); |
1548 | | QPDF_DLL |
1549 | | iterator end(); |
1550 | | |
1551 | | private: |
1552 | | QPDFObjectHandle oh; |
1553 | | }; |
1554 | | |
1555 | | namespace qpdf |
1556 | | { |
1557 | | inline BaseHandle:: |
1558 | | operator bool() const |
1559 | 7.25M | { |
1560 | 7.25M | return static_cast<bool>(obj); |
1561 | 7.25M | } |
1562 | | |
1563 | | inline BaseHandle:: |
1564 | | operator QPDFObjectHandle() const |
1565 | 3.36k | { |
1566 | 3.36k | return {obj}; |
1567 | 3.36k | } |
1568 | | |
1569 | | } // namespace qpdf |
1570 | | |
1571 | | inline bool |
1572 | | QPDFObjectHandle::isInitialized() const |
1573 | 0 | { |
1574 | 0 | return obj != nullptr; |
1575 | 0 | } |
1576 | | |
1577 | | #endif // QPDFOBJECTHANDLE_HH |