Commit 9685176ceae9049205783597752b09298631fbfd
Committed by
GitHub
Merge pull request #1372 from m-holger/object
Refactor QPDFObject / QPDFObjectHandle
Showing
61 changed files
with
2705 additions
and
2989 deletions
include/qpdf/Constants.h
| @@ -126,6 +126,7 @@ enum qpdf_object_type_e { | @@ -126,6 +126,7 @@ enum qpdf_object_type_e { | ||
| 126 | /* Object types internal to qpdf */ | 126 | /* Object types internal to qpdf */ |
| 127 | ot_unresolved, | 127 | ot_unresolved, |
| 128 | ot_destroyed, | 128 | ot_destroyed, |
| 129 | + ot_reference, | ||
| 129 | }; | 130 | }; |
| 130 | 131 | ||
| 131 | /* Write Parameters. See QPDFWriter.hh for details. */ | 132 | /* Write Parameters. See QPDFWriter.hh for details. */ |
include/qpdf/ObjectHandle.hh
0 → 100644
| 1 | +// Copyright (c) 2005-2021 Jay Berkenbilt | ||
| 2 | +// Copyright (c) 2022-2025 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"); you may not use this file except | ||
| 7 | +// in compliance with the License. You may obtain a copy of the License at | ||
| 8 | +// | ||
| 9 | +// http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | +// | ||
| 11 | +// Unless required by applicable law or agreed to in writing, software distributed under the License | ||
| 12 | +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express | ||
| 13 | +// or implied. See the License for the specific language governing permissions and limitations under | ||
| 14 | +// the License. | ||
| 15 | +// | ||
| 16 | +// Versions of qpdf prior to version 7 were released under the terms of version 2.0 of the Artistic | ||
| 17 | +// License. At your option, you may continue to consider qpdf to be licensed under those terms. | ||
| 18 | +// Please see the manual for additional information. | ||
| 19 | + | ||
| 20 | +#ifndef OBJECTHANDLE_HH | ||
| 21 | +#define OBJECTHANDLE_HH | ||
| 22 | + | ||
| 23 | +#include <qpdf/Constants.h> | ||
| 24 | +#include <qpdf/DLL.h> | ||
| 25 | +#include <qpdf/QPDFObjGen.hh> | ||
| 26 | +#include <qpdf/Types.h> | ||
| 27 | + | ||
| 28 | +#include <cstdint> | ||
| 29 | +#include <memory> | ||
| 30 | + | ||
| 31 | +class QPDF; | ||
| 32 | +class QPDF_Dictionary; | ||
| 33 | +class QPDFObject; | ||
| 34 | +class QPDFObjectHandle; | ||
| 35 | + | ||
| 36 | +namespace qpdf | ||
| 37 | +{ | ||
| 38 | + class Array; | ||
| 39 | + class BaseDictionary; | ||
| 40 | + class Dictionary; | ||
| 41 | + class Stream; | ||
| 42 | + | ||
| 43 | + enum typed : std::uint8_t { strict = 0, any_flag = 1, optional = 2, any = 3, error = 4 }; | ||
| 44 | + | ||
| 45 | + // Basehandle is only used as a base-class for QPDFObjectHandle like classes. Currently the only | ||
| 46 | + // methods exposed in public API are operators to convert derived objects to QPDFObjectHandle, | ||
| 47 | + // QPDFObjGen and bool. | ||
| 48 | + class BaseHandle | ||
| 49 | + { | ||
| 50 | + public: | ||
| 51 | + explicit inline operator bool() const; | ||
| 52 | + inline operator QPDFObjectHandle() const; | ||
| 53 | + operator QPDFObjGen() const; | ||
| 54 | + | ||
| 55 | + // The rest of the header file is for qpdf internal use only. | ||
| 56 | + | ||
| 57 | + inline QPDFObjGen id_gen() const; | ||
| 58 | + inline bool indirect() const; | ||
| 59 | + inline bool null() const; | ||
| 60 | + inline QPDF* qpdf() const; | ||
| 61 | + inline qpdf_object_type_e raw_type_code() const; | ||
| 62 | + inline qpdf_object_type_e type_code() const; | ||
| 63 | + | ||
| 64 | + protected: | ||
| 65 | + BaseHandle() = default; | ||
| 66 | + BaseHandle(std::shared_ptr<QPDFObject> const& obj) : | ||
| 67 | + obj(obj) {}; | ||
| 68 | + BaseHandle(std::shared_ptr<QPDFObject>&& obj) : | ||
| 69 | + obj(std::move(obj)) {}; | ||
| 70 | + BaseHandle(BaseHandle const&) = default; | ||
| 71 | + BaseHandle& operator=(BaseHandle const&) = default; | ||
| 72 | + BaseHandle(BaseHandle&&) = default; | ||
| 73 | + BaseHandle& operator=(BaseHandle&&) = default; | ||
| 74 | + ~BaseHandle() = default; | ||
| 75 | + | ||
| 76 | + template <typename T> | ||
| 77 | + T* as() const; | ||
| 78 | + | ||
| 79 | + std::shared_ptr<QPDFObject> obj; | ||
| 80 | + }; | ||
| 81 | + | ||
| 82 | +} // namespace qpdf | ||
| 83 | + | ||
| 84 | +#endif // QPDFOBJECTHANDLE_HH |
include/qpdf/QPDF.hh
| @@ -798,9 +798,10 @@ class QPDF | @@ -798,9 +798,10 @@ class QPDF | ||
| 798 | { | 798 | { |
| 799 | friend class QPDFObject; | 799 | friend class QPDFObject; |
| 800 | friend class QPDF_Unresolved; | 800 | friend class QPDF_Unresolved; |
| 801 | + friend class qpdf::BaseHandle; | ||
| 801 | 802 | ||
| 802 | private: | 803 | private: |
| 803 | - static QPDFObject* | 804 | + static std::shared_ptr<QPDFObject> const& |
| 804 | resolved(QPDF* qpdf, QPDFObjGen og) | 805 | resolved(QPDF* qpdf, QPDFObjGen og) |
| 805 | { | 806 | { |
| 806 | return qpdf->resolve(og); | 807 | return qpdf->resolve(og); |
| @@ -854,6 +855,7 @@ class QPDF | @@ -854,6 +855,7 @@ class QPDF | ||
| 854 | class Pipe | 855 | class Pipe |
| 855 | { | 856 | { |
| 856 | friend class QPDF_Stream; | 857 | friend class QPDF_Stream; |
| 858 | + friend class qpdf::Stream; | ||
| 857 | 859 | ||
| 858 | private: | 860 | private: |
| 859 | static bool | 861 | static bool |
| @@ -1071,7 +1073,7 @@ class QPDF | @@ -1071,7 +1073,7 @@ class QPDF | ||
| 1071 | QPDFObjGen exp_og, | 1073 | QPDFObjGen exp_og, |
| 1072 | QPDFObjGen& og, | 1074 | QPDFObjGen& og, |
| 1073 | bool skip_cache_if_in_xref); | 1075 | bool skip_cache_if_in_xref); |
| 1074 | - QPDFObject* resolve(QPDFObjGen og); | 1076 | + std::shared_ptr<QPDFObject> const& resolve(QPDFObjGen og); |
| 1075 | void resolveObjectsInStream(int obj_stream_number); | 1077 | void resolveObjectsInStream(int obj_stream_number); |
| 1076 | void stopOnError(std::string const& message); | 1078 | void stopOnError(std::string const& message); |
| 1077 | QPDFObjGen nextObjGen(); | 1079 | QPDFObjGen nextObjGen(); |
| @@ -1086,7 +1088,8 @@ class QPDF | @@ -1086,7 +1088,8 @@ class QPDF | ||
| 1086 | QPDFObjGen og, | 1088 | QPDFObjGen og, |
| 1087 | std::shared_ptr<QPDFObject> const& object, | 1089 | std::shared_ptr<QPDFObject> const& object, |
| 1088 | qpdf_offset_t end_before_space, | 1090 | qpdf_offset_t end_before_space, |
| 1089 | - qpdf_offset_t end_after_space); | 1091 | + qpdf_offset_t end_after_space, |
| 1092 | + bool destroy = true); | ||
| 1090 | static QPDFExc damagedPDF( | 1093 | static QPDFExc damagedPDF( |
| 1091 | InputSource& input, | 1094 | InputSource& input, |
| 1092 | std::string const& object, | 1095 | std::string const& object, |
include/qpdf/QPDFObjGen.hh
| @@ -130,12 +130,6 @@ class QPDFObjGen | @@ -130,12 +130,6 @@ class QPDFObjGen | ||
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | QPDF_DLL | 132 | QPDF_DLL |
| 133 | - bool add(QPDFObjectHandle const& oh); | ||
| 134 | - | ||
| 135 | - QPDF_DLL | ||
| 136 | - bool add(QPDFObjectHelper const& oh); | ||
| 137 | - | ||
| 138 | - QPDF_DLL | ||
| 139 | void | 133 | void |
| 140 | erase(QPDFObjGen og) | 134 | erase(QPDFObjGen og) |
| 141 | { | 135 | { |
| @@ -143,12 +137,6 @@ class QPDFObjGen | @@ -143,12 +137,6 @@ class QPDFObjGen | ||
| 143 | std::set<QPDFObjGen>::erase(og); | 137 | std::set<QPDFObjGen>::erase(og); |
| 144 | } | 138 | } |
| 145 | } | 139 | } |
| 146 | - | ||
| 147 | - QPDF_DLL | ||
| 148 | - void erase(QPDFObjectHandle const& oh); | ||
| 149 | - | ||
| 150 | - QPDF_DLL | ||
| 151 | - void erase(QPDFObjectHelper const& oh); | ||
| 152 | }; | 140 | }; |
| 153 | 141 | ||
| 154 | private: | 142 | private: |
include/qpdf/QPDFObjectHandle.hh
| @@ -37,6 +37,7 @@ | @@ -37,6 +37,7 @@ | ||
| 37 | #include <qpdf/Buffer.hh> | 37 | #include <qpdf/Buffer.hh> |
| 38 | #include <qpdf/InputSource.hh> | 38 | #include <qpdf/InputSource.hh> |
| 39 | #include <qpdf/JSON.hh> | 39 | #include <qpdf/JSON.hh> |
| 40 | +#include <qpdf/ObjectHandle.hh> | ||
| 40 | #include <qpdf/QPDFObjGen.hh> | 41 | #include <qpdf/QPDFObjGen.hh> |
| 41 | #include <qpdf/QPDFTokenizer.hh> | 42 | #include <qpdf/QPDFTokenizer.hh> |
| 42 | 43 | ||
| @@ -55,13 +56,14 @@ class QPDF_Reserved; | @@ -55,13 +56,14 @@ class QPDF_Reserved; | ||
| 55 | class QPDF_Stream; | 56 | class QPDF_Stream; |
| 56 | class QPDF_String; | 57 | class QPDF_String; |
| 57 | class QPDFObject; | 58 | class QPDFObject; |
| 59 | +class QPDFObjectHandle; | ||
| 58 | class QPDFTokenizer; | 60 | class QPDFTokenizer; |
| 59 | class QPDFExc; | 61 | class QPDFExc; |
| 60 | class Pl_QPDFTokenizer; | 62 | class Pl_QPDFTokenizer; |
| 61 | class QPDFMatrix; | 63 | class QPDFMatrix; |
| 62 | class QPDFParser; | 64 | class QPDFParser; |
| 63 | 65 | ||
| 64 | -class QPDFObjectHandle | 66 | +class QPDFObjectHandle final: public qpdf::BaseHandle |
| 65 | { | 67 | { |
| 66 | friend class QPDFParser; | 68 | friend class QPDFParser; |
| 67 | 69 | ||
| @@ -290,25 +292,19 @@ class QPDFObjectHandle | @@ -290,25 +292,19 @@ class QPDFObjectHandle | ||
| 290 | QPDFObjectHandle(QPDFObjectHandle const&) = default; | 292 | QPDFObjectHandle(QPDFObjectHandle const&) = default; |
| 291 | QPDF_DLL | 293 | QPDF_DLL |
| 292 | QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default; | 294 | QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default; |
| 293 | - | ||
| 294 | QPDF_DLL | 295 | QPDF_DLL |
| 295 | QPDFObjectHandle(QPDFObjectHandle&&) = default; | 296 | QPDFObjectHandle(QPDFObjectHandle&&) = default; |
| 296 | QPDF_DLL | 297 | QPDF_DLL |
| 297 | QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default; | 298 | QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default; |
| 298 | 299 | ||
| 299 | - // Return true if the QPDFObjectHandle is initialized. This allows object handles to be used in | ||
| 300 | - // if statements with initializer. | ||
| 301 | - QPDF_DLL | ||
| 302 | - explicit inline operator bool() const noexcept; | ||
| 303 | - | ||
| 304 | - [[deprecated("use operator bool()")]] QPDF_DLL inline bool isInitialized() const noexcept; | 300 | + [[deprecated("use operator bool()")]] QPDF_DLL inline bool isInitialized() const; |
| 305 | 301 | ||
| 306 | // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying | 302 | // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying |
| 307 | // object, meaning that changes to one are reflected in the other, or "if you paint one, the | 303 | // object, meaning that changes to one are reflected in the other, or "if you paint one, the |
| 308 | // other one changes color." This does not perform a structural comparison of the contents of | 304 | // other one changes color." This does not perform a structural comparison of the contents of |
| 309 | // the objects. | 305 | // the objects. |
| 310 | QPDF_DLL | 306 | QPDF_DLL |
| 311 | - bool isSameObjectAs(QPDFObjectHandle const&) const noexcept; | 307 | + bool isSameObjectAs(QPDFObjectHandle const&) const; |
| 312 | 308 | ||
| 313 | // Return type code and type name of underlying object. These are useful for doing rapid type | 309 | // Return type code and type name of underlying object. These are useful for doing rapid type |
| 314 | // tests (like switch statements) or for testing and debugging. | 310 | // tests (like switch statements) or for testing and debugging. |
| @@ -1258,8 +1254,7 @@ class QPDFObjectHandle | @@ -1258,8 +1254,7 @@ class QPDFObjectHandle | ||
| 1258 | // Provide access to specific classes for recursive disconnected(). | 1254 | // Provide access to specific classes for recursive disconnected(). |
| 1259 | class DisconnectAccess | 1255 | class DisconnectAccess |
| 1260 | { | 1256 | { |
| 1261 | - friend class QPDF_Dictionary; | ||
| 1262 | - friend class QPDF_Stream; | 1257 | + friend class QPDFObject; |
| 1263 | 1258 | ||
| 1264 | private: | 1259 | private: |
| 1265 | static void | 1260 | static void |
| @@ -1329,7 +1324,11 @@ class QPDFObjectHandle | @@ -1329,7 +1324,11 @@ class QPDFObjectHandle | ||
| 1329 | // The following methods do not form part of the public API and are for internal use only. | 1324 | // The following methods do not form part of the public API and are for internal use only. |
| 1330 | 1325 | ||
| 1331 | QPDFObjectHandle(std::shared_ptr<QPDFObject> const& obj) : | 1326 | QPDFObjectHandle(std::shared_ptr<QPDFObject> const& obj) : |
| 1332 | - obj(obj) | 1327 | + qpdf::BaseHandle(obj) |
| 1328 | + { | ||
| 1329 | + } | ||
| 1330 | + QPDFObjectHandle(std::shared_ptr<QPDFObject>&& obj) : | ||
| 1331 | + qpdf::BaseHandle(std::move(obj)) | ||
| 1333 | { | 1332 | { |
| 1334 | } | 1333 | } |
| 1335 | std::shared_ptr<QPDFObject> | 1334 | std::shared_ptr<QPDFObject> |
| @@ -1355,21 +1354,11 @@ class QPDFObjectHandle | @@ -1355,21 +1354,11 @@ class QPDFObjectHandle | ||
| 1355 | 1354 | ||
| 1356 | void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false) const; | 1355 | void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false) const; |
| 1357 | 1356 | ||
| 1358 | - private: | ||
| 1359 | - QPDF_Array* asArray() const; | ||
| 1360 | - QPDF_Bool* asBool() const; | ||
| 1361 | - QPDF_Dictionary* asDictionary() const; | ||
| 1362 | - QPDF_InlineImage* asInlineImage() const; | ||
| 1363 | - QPDF_Integer* asInteger() const; | ||
| 1364 | - QPDF_Name* asName() const; | ||
| 1365 | - QPDF_Null* asNull() const; | ||
| 1366 | - QPDF_Operator* asOperator() const; | ||
| 1367 | - QPDF_Real* asReal() const; | ||
| 1368 | - QPDF_Reserved* asReserved() const; | ||
| 1369 | - QPDF_Stream* asStream() const; | ||
| 1370 | - QPDF_Stream* asStreamWithAssert() const; | ||
| 1371 | - QPDF_String* asString() const; | 1357 | + inline qpdf::Array as_array(qpdf::typed options = qpdf::typed::any) const; |
| 1358 | + inline qpdf::Dictionary as_dictionary(qpdf::typed options = qpdf::typed::any) const; | ||
| 1359 | + inline qpdf::Stream as_stream(qpdf::typed options = qpdf::typed::strict) const; | ||
| 1372 | 1360 | ||
| 1361 | + private: | ||
| 1373 | void typeWarning(char const* expected_type, std::string const& warning) const; | 1362 | void typeWarning(char const* expected_type, std::string const& warning) const; |
| 1374 | void objectWarning(std::string const& warning) const; | 1363 | void objectWarning(std::string const& warning) const; |
| 1375 | void assertType(char const* type_name, bool istype) const; | 1364 | void assertType(char const* type_name, bool istype) const; |
| @@ -1386,10 +1375,6 @@ class QPDFObjectHandle | @@ -1386,10 +1375,6 @@ class QPDFObjectHandle | ||
| 1386 | arrayOrStreamToStreamArray(std::string const& description, std::string& all_description); | 1375 | arrayOrStreamToStreamArray(std::string const& description, std::string& all_description); |
| 1387 | static void warn(QPDF*, QPDFExc const&); | 1376 | static void warn(QPDF*, QPDFExc const&); |
| 1388 | void checkOwnership(QPDFObjectHandle const&) const; | 1377 | void checkOwnership(QPDFObjectHandle const&) const; |
| 1389 | - | ||
| 1390 | - // Moving members of QPDFObjectHandle into a smart pointer incurs a substantial performance | ||
| 1391 | - // penalty since QPDFObjectHandle objects are copied around so frequently. | ||
| 1392 | - std::shared_ptr<QPDFObject> obj; | ||
| 1393 | }; | 1378 | }; |
| 1394 | 1379 | ||
| 1395 | #ifndef QPDF_NO_QPDF_STRING | 1380 | #ifndef QPDF_NO_QPDF_STRING |
| @@ -1606,6 +1591,22 @@ class QPDFObjectHandle::QPDFArrayItems | @@ -1606,6 +1591,22 @@ class QPDFObjectHandle::QPDFArrayItems | ||
| 1606 | QPDFObjectHandle oh; | 1591 | QPDFObjectHandle oh; |
| 1607 | }; | 1592 | }; |
| 1608 | 1593 | ||
| 1594 | +namespace qpdf | ||
| 1595 | +{ | ||
| 1596 | + inline BaseHandle:: | ||
| 1597 | + operator bool() const | ||
| 1598 | + { | ||
| 1599 | + return static_cast<bool>(obj); | ||
| 1600 | + } | ||
| 1601 | + | ||
| 1602 | + inline BaseHandle:: | ||
| 1603 | + operator QPDFObjectHandle() const | ||
| 1604 | + { | ||
| 1605 | + return {obj}; | ||
| 1606 | + } | ||
| 1607 | + | ||
| 1608 | +} // namespace qpdf | ||
| 1609 | + | ||
| 1609 | inline int | 1610 | inline int |
| 1610 | QPDFObjectHandle::getObjectID() const | 1611 | QPDFObjectHandle::getObjectID() const |
| 1611 | { | 1612 | { |
| @@ -1625,15 +1626,9 @@ QPDFObjectHandle::isIndirect() const | @@ -1625,15 +1626,9 @@ QPDFObjectHandle::isIndirect() const | ||
| 1625 | } | 1626 | } |
| 1626 | 1627 | ||
| 1627 | inline bool | 1628 | inline bool |
| 1628 | -QPDFObjectHandle::isInitialized() const noexcept | 1629 | +QPDFObjectHandle::isInitialized() const |
| 1629 | { | 1630 | { |
| 1630 | return obj != nullptr; | 1631 | return obj != nullptr; |
| 1631 | } | 1632 | } |
| 1632 | 1633 | ||
| 1633 | -inline QPDFObjectHandle:: | ||
| 1634 | -operator bool() const noexcept | ||
| 1635 | -{ | ||
| 1636 | - return static_cast<bool>(obj); | ||
| 1637 | -} | ||
| 1638 | - | ||
| 1639 | #endif // QPDFOBJECTHANDLE_HH | 1634 | #endif // QPDFOBJECTHANDLE_HH |
include/qpdf/QPDFObjectHandle_future.hh deleted
include/qpdf/QPDFObjectHelper.hh
| @@ -31,13 +31,12 @@ | @@ -31,13 +31,12 @@ | ||
| 31 | // underlying QPDF objects unless there is a specific comment in a specific helper method that says | 31 | // underlying QPDF objects unless there is a specific comment in a specific helper method that says |
| 32 | // otherwise. The pattern of using helper objects was introduced to allow creation of higher level | 32 | // otherwise. The pattern of using helper objects was introduced to allow creation of higher level |
| 33 | // helper functions without polluting the public interface of QPDFObjectHandle. | 33 | // helper functions without polluting the public interface of QPDFObjectHandle. |
| 34 | - | ||
| 35 | -class QPDF_DLL_CLASS QPDFObjectHelper | 34 | +class QPDF_DLL_CLASS QPDFObjectHelper: public qpdf::BaseHandle |
| 36 | { | 35 | { |
| 37 | public: | 36 | public: |
| 38 | QPDF_DLL | 37 | QPDF_DLL |
| 39 | QPDFObjectHelper(QPDFObjectHandle oh) : | 38 | QPDFObjectHelper(QPDFObjectHandle oh) : |
| 40 | - oh(oh) | 39 | + qpdf::BaseHandle(oh.getObj()) |
| 41 | { | 40 | { |
| 42 | } | 41 | } |
| 43 | QPDF_DLL | 42 | QPDF_DLL |
| @@ -46,17 +45,29 @@ class QPDF_DLL_CLASS QPDFObjectHelper | @@ -46,17 +45,29 @@ class QPDF_DLL_CLASS QPDFObjectHelper | ||
| 46 | QPDFObjectHandle | 45 | QPDFObjectHandle |
| 47 | getObjectHandle() | 46 | getObjectHandle() |
| 48 | { | 47 | { |
| 49 | - return this->oh; | 48 | + return {obj}; |
| 50 | } | 49 | } |
| 51 | QPDF_DLL | 50 | QPDF_DLL |
| 52 | QPDFObjectHandle const | 51 | QPDFObjectHandle const |
| 53 | getObjectHandle() const | 52 | getObjectHandle() const |
| 54 | { | 53 | { |
| 55 | - return this->oh; | 54 | + return {obj}; |
| 56 | } | 55 | } |
| 57 | 56 | ||
| 58 | protected: | 57 | protected: |
| 59 | - QPDFObjectHandle oh; | 58 | + QPDF_DLL_PRIVATE |
| 59 | + QPDFObjectHandle | ||
| 60 | + oh() | ||
| 61 | + { | ||
| 62 | + return {obj}; | ||
| 63 | + } | ||
| 64 | + QPDF_DLL_PRIVATE | ||
| 65 | + QPDFObjectHandle const | ||
| 66 | + oh() const | ||
| 67 | + { | ||
| 68 | + return {obj}; | ||
| 69 | + } | ||
| 70 | + QPDFObjectHandle oh_; | ||
| 60 | }; | 71 | }; |
| 61 | 72 | ||
| 62 | #endif // QPDFOBJECTHELPER_HH | 73 | #endif // QPDFOBJECTHELPER_HH |
libqpdf/CMakeLists.txt
| @@ -76,7 +76,6 @@ set(libqpdf_SOURCES | @@ -76,7 +76,6 @@ set(libqpdf_SOURCES | ||
| 76 | QPDFObject.cc | 76 | QPDFObject.cc |
| 77 | QPDFObjectHandle.cc | 77 | QPDFObjectHandle.cc |
| 78 | QPDFObjectHelper.cc | 78 | QPDFObjectHelper.cc |
| 79 | - QPDFObjGen.cc | ||
| 80 | QPDFOutlineDocumentHelper.cc | 79 | QPDFOutlineDocumentHelper.cc |
| 81 | QPDFOutlineObjectHelper.cc | 80 | QPDFOutlineObjectHelper.cc |
| 82 | QPDFPageDocumentHelper.cc | 81 | QPDFPageDocumentHelper.cc |
| @@ -87,23 +86,12 @@ set(libqpdf_SOURCES | @@ -87,23 +86,12 @@ set(libqpdf_SOURCES | ||
| 87 | QPDFSystemError.cc | 86 | QPDFSystemError.cc |
| 88 | QPDFTokenizer.cc | 87 | QPDFTokenizer.cc |
| 89 | QPDFUsage.cc | 88 | QPDFUsage.cc |
| 90 | - QPDFValue.cc | ||
| 91 | QPDFWriter.cc | 89 | QPDFWriter.cc |
| 92 | QPDFXRefEntry.cc | 90 | QPDFXRefEntry.cc |
| 93 | QPDF_Array.cc | 91 | QPDF_Array.cc |
| 94 | - QPDF_Bool.cc | ||
| 95 | - QPDF_Destroyed.cc | ||
| 96 | QPDF_Dictionary.cc | 92 | QPDF_Dictionary.cc |
| 97 | - QPDF_InlineImage.cc | ||
| 98 | - QPDF_Integer.cc | ||
| 99 | - QPDF_Name.cc | ||
| 100 | - QPDF_Null.cc | ||
| 101 | - QPDF_Operator.cc | ||
| 102 | - QPDF_Real.cc | ||
| 103 | - QPDF_Reserved.cc | ||
| 104 | QPDF_Stream.cc | 93 | QPDF_Stream.cc |
| 105 | QPDF_String.cc | 94 | QPDF_String.cc |
| 106 | - QPDF_Unresolved.cc | ||
| 107 | QPDF_encryption.cc | 95 | QPDF_encryption.cc |
| 108 | QPDF_json.cc | 96 | QPDF_json.cc |
| 109 | QPDF_linearization.cc | 97 | QPDF_linearization.cc |
libqpdf/ContentNormalizer.cc
| 1 | #include <qpdf/ContentNormalizer.hh> | 1 | #include <qpdf/ContentNormalizer.hh> |
| 2 | 2 | ||
| 3 | -#include <qpdf/QPDF_Name.hh> | 3 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 4 | #include <qpdf/QUtil.hh> | 4 | #include <qpdf/QUtil.hh> |
| 5 | 5 | ||
| 6 | +using namespace qpdf; | ||
| 7 | + | ||
| 6 | ContentNormalizer::ContentNormalizer() : | 8 | ContentNormalizer::ContentNormalizer() : |
| 7 | any_bad_tokens(false), | 9 | any_bad_tokens(false), |
| 8 | last_token_was_bad(false) | 10 | last_token_was_bad(false) |
| @@ -55,7 +57,7 @@ ContentNormalizer::handleToken(QPDFTokenizer::Token const& token) | @@ -55,7 +57,7 @@ ContentNormalizer::handleToken(QPDFTokenizer::Token const& token) | ||
| 55 | break; | 57 | break; |
| 56 | 58 | ||
| 57 | case QPDFTokenizer::tt_name: | 59 | case QPDFTokenizer::tt_name: |
| 58 | - write(QPDF_Name::normalizeName(token.getValue())); | 60 | + write(Name::normalize(token.getValue())); |
| 59 | break; | 61 | break; |
| 60 | 62 | ||
| 61 | default: | 63 | default: |
libqpdf/QPDF.cc
| @@ -17,14 +17,9 @@ | @@ -17,14 +17,9 @@ | ||
| 17 | #include <qpdf/Pipeline.hh> | 17 | #include <qpdf/Pipeline.hh> |
| 18 | #include <qpdf/QPDFExc.hh> | 18 | #include <qpdf/QPDFExc.hh> |
| 19 | #include <qpdf/QPDFLogger.hh> | 19 | #include <qpdf/QPDFLogger.hh> |
| 20 | +#include <qpdf/QPDFObjectHandle_private.hh> | ||
| 20 | #include <qpdf/QPDFObject_private.hh> | 21 | #include <qpdf/QPDFObject_private.hh> |
| 21 | #include <qpdf/QPDFParser.hh> | 22 | #include <qpdf/QPDFParser.hh> |
| 22 | -#include <qpdf/QPDF_Array.hh> | ||
| 23 | -#include <qpdf/QPDF_Dictionary.hh> | ||
| 24 | -#include <qpdf/QPDF_Null.hh> | ||
| 25 | -#include <qpdf/QPDF_Reserved.hh> | ||
| 26 | -#include <qpdf/QPDF_Stream.hh> | ||
| 27 | -#include <qpdf/QPDF_Unresolved.hh> | ||
| 28 | #include <qpdf/QTC.hh> | 23 | #include <qpdf/QTC.hh> |
| 29 | #include <qpdf/QUtil.hh> | 24 | #include <qpdf/QUtil.hh> |
| 30 | 25 | ||
| @@ -298,7 +293,7 @@ void | @@ -298,7 +293,7 @@ void | ||
| 298 | QPDF::registerStreamFilter( | 293 | QPDF::registerStreamFilter( |
| 299 | std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory) | 294 | std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory) |
| 300 | { | 295 | { |
| 301 | - QPDF_Stream::registerStreamFilter(filter_name, factory); | 296 | + qpdf::Stream::registerStreamFilter(filter_name, factory); |
| 302 | } | 297 | } |
| 303 | 298 | ||
| 304 | void | 299 | void |
| @@ -1565,7 +1560,7 @@ QPDF::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) | @@ -1565,7 +1560,7 @@ QPDF::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) | ||
| 1565 | throw; | 1560 | throw; |
| 1566 | } | 1561 | } |
| 1567 | } | 1562 | } |
| 1568 | - object = {QPDF_Stream::create(this, og, object, stream_offset, length)}; | 1563 | + object = QPDFObjectHandle(qpdf::Stream(*this, og, object, stream_offset, length)); |
| 1569 | } | 1564 | } |
| 1570 | 1565 | ||
| 1571 | void | 1566 | void |
| @@ -1872,11 +1867,11 @@ QPDF::readObjectAtOffset( | @@ -1872,11 +1867,11 @@ QPDF::readObjectAtOffset( | ||
| 1872 | return oh; | 1867 | return oh; |
| 1873 | } | 1868 | } |
| 1874 | 1869 | ||
| 1875 | -QPDFObject* | 1870 | +std::shared_ptr<QPDFObject> const& |
| 1876 | QPDF::resolve(QPDFObjGen og) | 1871 | QPDF::resolve(QPDFObjGen og) |
| 1877 | { | 1872 | { |
| 1878 | if (!isUnresolved(og)) { | 1873 | if (!isUnresolved(og)) { |
| 1879 | - return m->obj_cache[og].object.get(); | 1874 | + return m->obj_cache[og].object; |
| 1880 | } | 1875 | } |
| 1881 | 1876 | ||
| 1882 | if (m->resolving.count(og)) { | 1877 | if (m->resolving.count(og)) { |
| @@ -1884,8 +1879,8 @@ QPDF::resolve(QPDFObjGen og) | @@ -1884,8 +1879,8 @@ QPDF::resolve(QPDFObjGen og) | ||
| 1884 | // has to be resolved during object parsing, such as stream length. | 1879 | // has to be resolved during object parsing, such as stream length. |
| 1885 | QTC::TC("qpdf", "QPDF recursion loop in resolve"); | 1880 | QTC::TC("qpdf", "QPDF recursion loop in resolve"); |
| 1886 | warn(damagedPDF("", "loop detected resolving object " + og.unparse(' '))); | 1881 | warn(damagedPDF("", "loop detected resolving object " + og.unparse(' '))); |
| 1887 | - updateCache(og, QPDF_Null::create(), -1, -1); | ||
| 1888 | - return m->obj_cache[og].object.get(); | 1882 | + updateCache(og, QPDFObject::create<QPDF_Null>(), -1, -1); |
| 1883 | + return m->obj_cache[og].object; | ||
| 1889 | } | 1884 | } |
| 1890 | ResolveRecorder rr(this, og); | 1885 | ResolveRecorder rr(this, og); |
| 1891 | 1886 | ||
| @@ -1921,12 +1916,12 @@ QPDF::resolve(QPDFObjGen og) | @@ -1921,12 +1916,12 @@ QPDF::resolve(QPDFObjGen og) | ||
| 1921 | if (isUnresolved(og)) { | 1916 | if (isUnresolved(og)) { |
| 1922 | // PDF spec says unknown objects resolve to the null object. | 1917 | // PDF spec says unknown objects resolve to the null object. |
| 1923 | QTC::TC("qpdf", "QPDF resolve failure to null"); | 1918 | QTC::TC("qpdf", "QPDF resolve failure to null"); |
| 1924 | - updateCache(og, QPDF_Null::create(), -1, -1); | 1919 | + updateCache(og, QPDFObject::create<QPDF_Null>(), -1, -1); |
| 1925 | } | 1920 | } |
| 1926 | 1921 | ||
| 1927 | - auto result(m->obj_cache[og].object); | 1922 | + auto& result(m->obj_cache[og].object); |
| 1928 | result->setDefaultDescription(this, og); | 1923 | result->setDefaultDescription(this, og); |
| 1929 | - return result.get(); | 1924 | + return result; |
| 1930 | } | 1925 | } |
| 1931 | 1926 | ||
| 1932 | void | 1927 | void |
| @@ -2034,12 +2029,13 @@ QPDF::updateCache( | @@ -2034,12 +2029,13 @@ QPDF::updateCache( | ||
| 2034 | QPDFObjGen og, | 2029 | QPDFObjGen og, |
| 2035 | std::shared_ptr<QPDFObject> const& object, | 2030 | std::shared_ptr<QPDFObject> const& object, |
| 2036 | qpdf_offset_t end_before_space, | 2031 | qpdf_offset_t end_before_space, |
| 2037 | - qpdf_offset_t end_after_space) | 2032 | + qpdf_offset_t end_after_space, |
| 2033 | + bool destroy) | ||
| 2038 | { | 2034 | { |
| 2039 | object->setObjGen(this, og); | 2035 | object->setObjGen(this, og); |
| 2040 | if (isCached(og)) { | 2036 | if (isCached(og)) { |
| 2041 | auto& cache = m->obj_cache[og]; | 2037 | auto& cache = m->obj_cache[og]; |
| 2042 | - cache.object->assign(object); | 2038 | + object->move_to(cache.object, destroy); |
| 2043 | cache.end_before_space = end_before_space; | 2039 | cache.end_before_space = end_before_space; |
| 2044 | cache.end_after_space = end_after_space; | 2040 | cache.end_after_space = end_after_space; |
| 2045 | } else { | 2041 | } else { |
| @@ -2089,20 +2085,20 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) | @@ -2089,20 +2085,20 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) | ||
| 2089 | QPDFObjectHandle | 2085 | QPDFObjectHandle |
| 2090 | QPDF::newReserved() | 2086 | QPDF::newReserved() |
| 2091 | { | 2087 | { |
| 2092 | - return makeIndirectFromQPDFObject(QPDF_Reserved::create()); | 2088 | + return makeIndirectFromQPDFObject(QPDFObject::create<QPDF_Reserved>()); |
| 2093 | } | 2089 | } |
| 2094 | 2090 | ||
| 2095 | QPDFObjectHandle | 2091 | QPDFObjectHandle |
| 2096 | QPDF::newIndirectNull() | 2092 | QPDF::newIndirectNull() |
| 2097 | { | 2093 | { |
| 2098 | - return makeIndirectFromQPDFObject(QPDF_Null::create()); | 2094 | + return makeIndirectFromQPDFObject(QPDFObject::create<QPDF_Null>()); |
| 2099 | } | 2095 | } |
| 2100 | 2096 | ||
| 2101 | QPDFObjectHandle | 2097 | QPDFObjectHandle |
| 2102 | QPDF::newStream() | 2098 | QPDF::newStream() |
| 2103 | { | 2099 | { |
| 2104 | - return makeIndirectFromQPDFObject( | ||
| 2105 | - QPDF_Stream::create(this, nextObjGen(), QPDFObjectHandle::newDictionary(), 0, 0)); | 2100 | + return makeIndirectObject( |
| 2101 | + qpdf::Stream(*this, nextObjGen(), QPDFObjectHandle::newDictionary(), 0, 0)); | ||
| 2106 | } | 2102 | } |
| 2107 | 2103 | ||
| 2108 | QPDFObjectHandle | 2104 | QPDFObjectHandle |
| @@ -2130,12 +2126,13 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf) | @@ -2130,12 +2126,13 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf) | ||
| 2130 | return iter->second.object; | 2126 | return iter->second.object; |
| 2131 | } | 2127 | } |
| 2132 | if (m->xref_table.count(og) || !m->parsed) { | 2128 | if (m->xref_table.count(og) || !m->parsed) { |
| 2133 | - return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object; | 2129 | + return m->obj_cache.insert({og, QPDFObject::create<QPDF_Unresolved>(this, og)}) |
| 2130 | + .first->second.object; | ||
| 2134 | } | 2131 | } |
| 2135 | if (parse_pdf) { | 2132 | if (parse_pdf) { |
| 2136 | - return QPDF_Null::create(); | 2133 | + return QPDFObject::create<QPDF_Null>(); |
| 2137 | } | 2134 | } |
| 2138 | - return m->obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object; | 2135 | + return m->obj_cache.insert({og, QPDFObject::create<QPDF_Null>(this, og)}).first->second.object; |
| 2139 | } | 2136 | } |
| 2140 | 2137 | ||
| 2141 | std::shared_ptr<QPDFObject> | 2138 | std::shared_ptr<QPDFObject> |
| @@ -2145,8 +2142,9 @@ QPDF::getObjectForJSON(int id, int gen) | @@ -2145,8 +2142,9 @@ QPDF::getObjectForJSON(int id, int gen) | ||
| 2145 | auto [it, inserted] = m->obj_cache.try_emplace(og); | 2142 | auto [it, inserted] = m->obj_cache.try_emplace(og); |
| 2146 | auto& obj = it->second.object; | 2143 | auto& obj = it->second.object; |
| 2147 | if (inserted) { | 2144 | if (inserted) { |
| 2148 | - obj = (m->parsed && !m->xref_table.count(og)) ? QPDF_Null::create(this, og) | ||
| 2149 | - : QPDF_Unresolved::create(this, og); | 2145 | + obj = (m->parsed && !m->xref_table.count(og)) |
| 2146 | + ? QPDFObject::create<QPDF_Null>(this, og) | ||
| 2147 | + : QPDFObject::create<QPDF_Unresolved>(this, og); | ||
| 2150 | } | 2148 | } |
| 2151 | return obj; | 2149 | return obj; |
| 2152 | } | 2150 | } |
| @@ -2157,9 +2155,10 @@ QPDF::getObject(QPDFObjGen og) | @@ -2157,9 +2155,10 @@ QPDF::getObject(QPDFObjGen og) | ||
| 2157 | if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) { | 2155 | if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) { |
| 2158 | return {it->second.object}; | 2156 | return {it->second.object}; |
| 2159 | } else if (m->parsed && !m->xref_table.count(og)) { | 2157 | } else if (m->parsed && !m->xref_table.count(og)) { |
| 2160 | - return QPDF_Null::create(); | 2158 | + return QPDFObject::create<QPDF_Null>(); |
| 2161 | } else { | 2159 | } else { |
| 2162 | - auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1); | 2160 | + auto result = |
| 2161 | + m->obj_cache.try_emplace(og, QPDFObject::create<QPDF_Unresolved>(this, og), -1, -1); | ||
| 2163 | return {result.first->second.object}; | 2162 | return {result.first->second.object}; |
| 2164 | } | 2163 | } |
| 2165 | } | 2164 | } |
| @@ -2195,7 +2194,7 @@ QPDF::replaceObject(QPDFObjGen og, QPDFObjectHandle oh) | @@ -2195,7 +2194,7 @@ QPDF::replaceObject(QPDFObjGen og, QPDFObjectHandle oh) | ||
| 2195 | QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); | 2194 | QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); |
| 2196 | throw std::logic_error("QPDF::replaceObject called with indirect object handle"); | 2195 | throw std::logic_error("QPDF::replaceObject called with indirect object handle"); |
| 2197 | } | 2196 | } |
| 2198 | - updateCache(og, oh.getObj(), -1, -1); | 2197 | + updateCache(og, oh.getObj(), -1, -1, false); |
| 2199 | } | 2198 | } |
| 2200 | 2199 | ||
| 2201 | void | 2200 | void |
| @@ -2204,7 +2203,7 @@ QPDF::removeObject(QPDFObjGen og) | @@ -2204,7 +2203,7 @@ QPDF::removeObject(QPDFObjGen og) | ||
| 2204 | m->xref_table.erase(og); | 2203 | m->xref_table.erase(og); |
| 2205 | if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) { | 2204 | if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) { |
| 2206 | // Take care of any object handles that may be floating around. | 2205 | // Take care of any object handles that may be floating around. |
| 2207 | - cached->second.object->assign(QPDF_Null::create()); | 2206 | + cached->second.object->assign_null(); |
| 2208 | cached->second.object->setObjGen(nullptr, QPDFObjGen()); | 2207 | cached->second.object->setObjGen(nullptr, QPDFObjGen()); |
| 2209 | m->obj_cache.erase(cached); | 2208 | m->obj_cache.erase(cached); |
| 2210 | } | 2209 | } |
| @@ -2347,14 +2346,15 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top) | @@ -2347,14 +2346,15 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top) | ||
| 2347 | 2346 | ||
| 2348 | if (foreign_tc == ::ot_array) { | 2347 | if (foreign_tc == ::ot_array) { |
| 2349 | QTC::TC("qpdf", "QPDF reserve array"); | 2348 | QTC::TC("qpdf", "QPDF reserve array"); |
| 2350 | - int n = foreign.getArrayNItems(); | ||
| 2351 | - for (int i = 0; i < n; ++i) { | ||
| 2352 | - reserveObjects(foreign.getArrayItem(i), obj_copier, false); | 2349 | + for (auto const& item: foreign.as_array()) { |
| 2350 | + reserveObjects(item, obj_copier, false); | ||
| 2353 | } | 2351 | } |
| 2354 | } else if (foreign_tc == ::ot_dictionary) { | 2352 | } else if (foreign_tc == ::ot_dictionary) { |
| 2355 | QTC::TC("qpdf", "QPDF reserve dictionary"); | 2353 | QTC::TC("qpdf", "QPDF reserve dictionary"); |
| 2356 | - for (auto const& key: foreign.getKeys()) { | ||
| 2357 | - reserveObjects(foreign.getKey(key), obj_copier, false); | 2354 | + for (auto const& item: foreign.as_dictionary()) { |
| 2355 | + if (!item.second.null()) { | ||
| 2356 | + reserveObjects(item.second, obj_copier, false); | ||
| 2357 | + } | ||
| 2358 | } | 2358 | } |
| 2359 | } else if (foreign_tc == ::ot_stream) { | 2359 | } else if (foreign_tc == ::ot_stream) { |
| 2360 | QTC::TC("qpdf", "QPDF reserve stream"); | 2360 | QTC::TC("qpdf", "QPDF reserve stream"); |
| @@ -2383,30 +2383,26 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_cop | @@ -2383,30 +2383,26 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_cop | ||
| 2383 | } else if (foreign_tc == ::ot_array) { | 2383 | } else if (foreign_tc == ::ot_array) { |
| 2384 | QTC::TC("qpdf", "QPDF replace array"); | 2384 | QTC::TC("qpdf", "QPDF replace array"); |
| 2385 | result = QPDFObjectHandle::newArray(); | 2385 | result = QPDFObjectHandle::newArray(); |
| 2386 | - int n = foreign.getArrayNItems(); | ||
| 2387 | - for (int i = 0; i < n; ++i) { | ||
| 2388 | - result.appendItem( | ||
| 2389 | - // line-break | ||
| 2390 | - replaceForeignIndirectObjects(foreign.getArrayItem(i), obj_copier, false)); | 2386 | + for (auto const& item: foreign.as_array()) { |
| 2387 | + result.appendItem(replaceForeignIndirectObjects(item, obj_copier, false)); | ||
| 2391 | } | 2388 | } |
| 2392 | } else if (foreign_tc == ::ot_dictionary) { | 2389 | } else if (foreign_tc == ::ot_dictionary) { |
| 2393 | QTC::TC("qpdf", "QPDF replace dictionary"); | 2390 | QTC::TC("qpdf", "QPDF replace dictionary"); |
| 2394 | result = QPDFObjectHandle::newDictionary(); | 2391 | result = QPDFObjectHandle::newDictionary(); |
| 2395 | - std::set<std::string> keys = foreign.getKeys(); | ||
| 2396 | - for (auto const& iter: keys) { | ||
| 2397 | - result.replaceKey( | ||
| 2398 | - iter, replaceForeignIndirectObjects(foreign.getKey(iter), obj_copier, false)); | 2392 | + for (auto const& [key, value]: foreign.as_dictionary()) { |
| 2393 | + if (!value.null()) { | ||
| 2394 | + result.replaceKey(key, replaceForeignIndirectObjects(value, obj_copier, false)); | ||
| 2395 | + } | ||
| 2399 | } | 2396 | } |
| 2400 | } else if (foreign_tc == ::ot_stream) { | 2397 | } else if (foreign_tc == ::ot_stream) { |
| 2401 | QTC::TC("qpdf", "QPDF replace stream"); | 2398 | QTC::TC("qpdf", "QPDF replace stream"); |
| 2402 | result = obj_copier.object_map[foreign.getObjGen()]; | 2399 | result = obj_copier.object_map[foreign.getObjGen()]; |
| 2403 | - result.assertStream(); | ||
| 2404 | QPDFObjectHandle dict = result.getDict(); | 2400 | QPDFObjectHandle dict = result.getDict(); |
| 2405 | QPDFObjectHandle old_dict = foreign.getDict(); | 2401 | QPDFObjectHandle old_dict = foreign.getDict(); |
| 2406 | - std::set<std::string> keys = old_dict.getKeys(); | ||
| 2407 | - for (auto const& iter: keys) { | ||
| 2408 | - dict.replaceKey( | ||
| 2409 | - iter, replaceForeignIndirectObjects(old_dict.getKey(iter), obj_copier, false)); | 2402 | + for (auto const& [key, value]: old_dict.as_dictionary()) { |
| 2403 | + if (!value.null()) { | ||
| 2404 | + dict.replaceKey(key, replaceForeignIndirectObjects(value, obj_copier, false)); | ||
| 2405 | + } | ||
| 2410 | } | 2406 | } |
| 2411 | copyStreamData(result, foreign); | 2407 | copyStreamData(result, foreign); |
| 2412 | } else { | 2408 | } else { |
| @@ -2442,13 +2438,11 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | @@ -2442,13 +2438,11 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | ||
| 2442 | QPDF& foreign_stream_qpdf = | 2438 | QPDF& foreign_stream_qpdf = |
| 2443 | foreign.getQPDF("unable to retrieve owning qpdf from foreign stream"); | 2439 | foreign.getQPDF("unable to retrieve owning qpdf from foreign stream"); |
| 2444 | 2440 | ||
| 2445 | - auto stream = foreign.getObjectPtr()->as<QPDF_Stream>(); | ||
| 2446 | - if (stream == nullptr) { | ||
| 2447 | - throw std::logic_error( | ||
| 2448 | - "unable to retrieve underlying" | ||
| 2449 | - " stream object from foreign stream"); | 2441 | + auto stream = foreign.as_stream(); |
| 2442 | + if (!stream) { | ||
| 2443 | + throw std::logic_error("unable to retrieve underlying stream object from foreign stream"); | ||
| 2450 | } | 2444 | } |
| 2451 | - std::shared_ptr<Buffer> stream_buffer = stream->getStreamDataBuffer(); | 2445 | + std::shared_ptr<Buffer> stream_buffer = stream.getStreamDataBuffer(); |
| 2452 | if ((foreign_stream_qpdf.m->immediate_copy_from) && (stream_buffer == nullptr)) { | 2446 | if ((foreign_stream_qpdf.m->immediate_copy_from) && (stream_buffer == nullptr)) { |
| 2453 | // Pull the stream data into a buffer before attempting the copy operation. Do it on the | 2447 | // Pull the stream data into a buffer before attempting the copy operation. Do it on the |
| 2454 | // source stream so that if the source stream is copied multiple times, we don't have to | 2448 | // source stream so that if the source stream is copied multiple times, we don't have to |
| @@ -2458,10 +2452,10 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | @@ -2458,10 +2452,10 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | ||
| 2458 | foreign.getRawStreamData(), | 2452 | foreign.getRawStreamData(), |
| 2459 | old_dict.getKey("/Filter"), | 2453 | old_dict.getKey("/Filter"), |
| 2460 | old_dict.getKey("/DecodeParms")); | 2454 | old_dict.getKey("/DecodeParms")); |
| 2461 | - stream_buffer = stream->getStreamDataBuffer(); | 2455 | + stream_buffer = stream.getStreamDataBuffer(); |
| 2462 | } | 2456 | } |
| 2463 | std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider = | 2457 | std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider = |
| 2464 | - stream->getStreamDataProvider(); | 2458 | + stream.getStreamDataProvider(); |
| 2465 | if (stream_buffer.get()) { | 2459 | if (stream_buffer.get()) { |
| 2466 | QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); | 2460 | QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); |
| 2467 | result.replaceStreamData( | 2461 | result.replaceStreamData( |
| @@ -2476,9 +2470,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | @@ -2476,9 +2470,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | ||
| 2476 | auto foreign_stream_data = std::make_shared<ForeignStreamData>( | 2470 | auto foreign_stream_data = std::make_shared<ForeignStreamData>( |
| 2477 | foreign_stream_qpdf.m->encp, | 2471 | foreign_stream_qpdf.m->encp, |
| 2478 | foreign_stream_qpdf.m->file, | 2472 | foreign_stream_qpdf.m->file, |
| 2479 | - foreign.getObjGen(), | ||
| 2480 | - stream->getParsedOffset(), | ||
| 2481 | - stream->getLength(), | 2473 | + foreign, |
| 2474 | + foreign.getParsedOffset(), | ||
| 2475 | + stream.getLength(), | ||
| 2482 | dict); | 2476 | dict); |
| 2483 | m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); | 2477 | m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); |
| 2484 | result.replaceStreamData( | 2478 | result.replaceStreamData( |
| @@ -2692,30 +2686,32 @@ QPDF::getCompressibleObjGens() | @@ -2692,30 +2686,32 @@ QPDF::getCompressibleObjGens() | ||
| 2692 | } | 2686 | } |
| 2693 | } | 2687 | } |
| 2694 | if (obj.isStream()) { | 2688 | if (obj.isStream()) { |
| 2695 | - QPDFObjectHandle dict = obj.getDict(); | ||
| 2696 | - std::set<std::string> keys = dict.getKeys(); | ||
| 2697 | - for (auto iter = keys.rbegin(); iter != keys.rend(); ++iter) { | ||
| 2698 | - std::string const& key = *iter; | ||
| 2699 | - QPDFObjectHandle value = dict.getKey(key); | ||
| 2700 | - if (key == "/Length") { | ||
| 2701 | - // omit stream lengths | ||
| 2702 | - if (value.isIndirect()) { | ||
| 2703 | - QTC::TC("qpdf", "QPDF exclude indirect length"); | 2689 | + auto dict = obj.getDict().as_dictionary(); |
| 2690 | + auto end = dict.crend(); | ||
| 2691 | + for (auto iter = dict.crbegin(); iter != end; ++iter) { | ||
| 2692 | + std::string const& key = iter->first; | ||
| 2693 | + QPDFObjectHandle const& value = iter->second; | ||
| 2694 | + if (!value.null()) { | ||
| 2695 | + if (key == "/Length") { | ||
| 2696 | + // omit stream lengths | ||
| 2697 | + if (value.isIndirect()) { | ||
| 2698 | + QTC::TC("qpdf", "QPDF exclude indirect length"); | ||
| 2699 | + } | ||
| 2700 | + } else { | ||
| 2701 | + queue.emplace_back(value); | ||
| 2704 | } | 2702 | } |
| 2705 | - } else { | ||
| 2706 | - queue.push_back(value); | ||
| 2707 | } | 2703 | } |
| 2708 | } | 2704 | } |
| 2709 | } else if (obj.isDictionary()) { | 2705 | } else if (obj.isDictionary()) { |
| 2710 | - std::set<std::string> keys = obj.getKeys(); | ||
| 2711 | - for (auto iter = keys.rbegin(); iter != keys.rend(); ++iter) { | ||
| 2712 | - queue.push_back(obj.getKey(*iter)); | ||
| 2713 | - } | ||
| 2714 | - } else if (obj.isArray()) { | ||
| 2715 | - int n = obj.getArrayNItems(); | ||
| 2716 | - for (int i = 1; i <= n; ++i) { | ||
| 2717 | - queue.push_back(obj.getArrayItem(n - i)); | 2706 | + auto dict = obj.as_dictionary(); |
| 2707 | + auto end = dict.crend(); | ||
| 2708 | + for (auto iter = dict.crbegin(); iter != end; ++iter) { | ||
| 2709 | + if (!iter->second.null()) { | ||
| 2710 | + queue.emplace_back(iter->second); | ||
| 2711 | + } | ||
| 2718 | } | 2712 | } |
| 2713 | + } else if (auto items = obj.as_array()) { | ||
| 2714 | + queue.insert(queue.end(), items.crbegin(), items.crend()); | ||
| 2719 | } | 2715 | } |
| 2720 | } | 2716 | } |
| 2721 | 2717 |
libqpdf/QPDFAcroFormDocumentHelper.cc
| 1 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> | 1 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> |
| 2 | 2 | ||
| 3 | #include <qpdf/Pl_Buffer.hh> | 3 | #include <qpdf/Pl_Buffer.hh> |
| 4 | +#include <qpdf/QPDFObjectHandle_private.hh> | ||
| 4 | #include <qpdf/QPDFPageDocumentHelper.hh> | 5 | #include <qpdf/QPDFPageDocumentHelper.hh> |
| 5 | #include <qpdf/QTC.hh> | 6 | #include <qpdf/QTC.hh> |
| 6 | #include <qpdf/QUtil.hh> | 7 | #include <qpdf/QUtil.hh> |
| 7 | #include <qpdf/ResourceFinder.hh> | 8 | #include <qpdf/ResourceFinder.hh> |
| 8 | 9 | ||
| 10 | +using namespace qpdf; | ||
| 11 | + | ||
| 9 | QPDFAcroFormDocumentHelper::Members::Members() : | 12 | QPDFAcroFormDocumentHelper::Members::Members() : |
| 10 | cache_valid(false) | 13 | cache_valid(false) |
| 11 | { | 14 | { |
| @@ -238,26 +241,25 @@ QPDFAcroFormDocumentHelper::analyze() | @@ -238,26 +241,25 @@ QPDFAcroFormDocumentHelper::analyze() | ||
| 238 | return; | 241 | return; |
| 239 | } | 242 | } |
| 240 | m->cache_valid = true; | 243 | m->cache_valid = true; |
| 241 | - QPDFObjectHandle acroform = this->qpdf.getRoot().getKey("/AcroForm"); | 244 | + QPDFObjectHandle acroform = qpdf.getRoot().getKey("/AcroForm"); |
| 242 | if (!(acroform.isDictionary() && acroform.hasKey("/Fields"))) { | 245 | if (!(acroform.isDictionary() && acroform.hasKey("/Fields"))) { |
| 243 | return; | 246 | return; |
| 244 | } | 247 | } |
| 245 | QPDFObjectHandle fields = acroform.getKey("/Fields"); | 248 | QPDFObjectHandle fields = acroform.getKey("/Fields"); |
| 246 | - if (!fields.isArray()) { | 249 | + if (auto fa = fields.as_array(strict)) { |
| 250 | + // Traverse /AcroForm to find annotations and map them bidirectionally to fields. | ||
| 251 | + | ||
| 252 | + QPDFObjGen::set visited; | ||
| 253 | + QPDFObjectHandle null(QPDFObjectHandle::newNull()); | ||
| 254 | + for (auto const& field: fa) { | ||
| 255 | + traverseField(field, null, 0, visited); | ||
| 256 | + } | ||
| 257 | + } else { | ||
| 247 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array"); | 258 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array"); |
| 248 | acroform.warnIfPossible("/Fields key of /AcroForm dictionary is not an array; ignoring"); | 259 | acroform.warnIfPossible("/Fields key of /AcroForm dictionary is not an array; ignoring"); |
| 249 | fields = QPDFObjectHandle::newArray(); | 260 | fields = QPDFObjectHandle::newArray(); |
| 250 | } | 261 | } |
| 251 | 262 | ||
| 252 | - // Traverse /AcroForm to find annotations and map them bidirectionally to fields. | ||
| 253 | - | ||
| 254 | - QPDFObjGen::set visited; | ||
| 255 | - int nfields = fields.getArrayNItems(); | ||
| 256 | - QPDFObjectHandle null(QPDFObjectHandle::newNull()); | ||
| 257 | - for (int i = 0; i < nfields; ++i) { | ||
| 258 | - traverseField(fields.getArrayItem(i), null, 0, visited); | ||
| 259 | - } | ||
| 260 | - | ||
| 261 | // All Widget annotations should have been encountered by traversing /AcroForm, but in case any | 263 | // All Widget annotations should have been encountered by traversing /AcroForm, but in case any |
| 262 | // weren't, find them by walking through pages, and treat any widget annotation that is not | 264 | // weren't, find them by walking through pages, and treat any widget annotation that is not |
| 263 | // associated with a field as its own field. This just ensures that requesting the field for any | 265 | // associated with a field as its own field. This just ensures that requesting the field for any |
| @@ -324,12 +326,10 @@ QPDFAcroFormDocumentHelper::traverseField( | @@ -324,12 +326,10 @@ QPDFAcroFormDocumentHelper::traverseField( | ||
| 324 | 326 | ||
| 325 | bool is_annotation = false; | 327 | bool is_annotation = false; |
| 326 | bool is_field = (0 == depth); | 328 | bool is_field = (0 == depth); |
| 327 | - QPDFObjectHandle kids = field.getKey("/Kids"); | ||
| 328 | - if (kids.isArray()) { | 329 | + if (auto a = field.getKey("/Kids").as_array(strict)) { |
| 329 | is_field = true; | 330 | is_field = true; |
| 330 | - int nkids = kids.getArrayNItems(); | ||
| 331 | - for (int k = 0; k < nkids; ++k) { | ||
| 332 | - traverseField(kids.getArrayItem(k), field, 1 + depth, visited); | 331 | + for (auto const& item: a) { |
| 332 | + traverseField(item, field, 1 + depth, visited); | ||
| 333 | } | 333 | } |
| 334 | } else { | 334 | } else { |
| 335 | if (field.hasKey("/Parent")) { | 335 | if (field.hasKey("/Parent")) { |
| @@ -975,17 +975,14 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | @@ -975,17 +975,14 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | ||
| 975 | auto replace_stream = [](auto& dict, auto& key, auto& old) { | 975 | auto replace_stream = [](auto& dict, auto& key, auto& old) { |
| 976 | return dict.replaceKeyAndGetNew(key, old.copyStream()); | 976 | return dict.replaceKeyAndGetNew(key, old.copyStream()); |
| 977 | }; | 977 | }; |
| 978 | - if (apdict.isDictionary()) { | ||
| 979 | - for (auto& ap: apdict.ditems()) { | ||
| 980 | - if (ap.second.isStream()) { | ||
| 981 | - streams.push_back(replace_stream(apdict, ap.first, ap.second)); | ||
| 982 | - } else if (ap.second.isDictionary()) { | ||
| 983 | - for (auto& ap2: ap.second.ditems()) { | ||
| 984 | - if (ap2.second.isStream()) { | ||
| 985 | - streams.push_back( | ||
| 986 | - // line-break | ||
| 987 | - replace_stream(ap.second, ap2.first, ap2.second)); | ||
| 988 | - } | 978 | + |
| 979 | + for (auto& [key1, value1]: apdict.as_dictionary()) { | ||
| 980 | + if (value1.isStream()) { | ||
| 981 | + streams.emplace_back(replace_stream(apdict, key1, value1)); | ||
| 982 | + } else { | ||
| 983 | + for (auto& [key2, value2]: value1.as_dictionary()) { | ||
| 984 | + if (value2.isStream()) { | ||
| 985 | + streams.emplace_back(replace_stream(value1, key2, value2)); | ||
| 989 | } | 986 | } |
| 990 | } | 987 | } |
| 991 | } | 988 | } |
libqpdf/QPDFAnnotationObjectHelper.cc
| @@ -13,27 +13,27 @@ QPDFAnnotationObjectHelper::QPDFAnnotationObjectHelper(QPDFObjectHandle oh) : | @@ -13,27 +13,27 @@ QPDFAnnotationObjectHelper::QPDFAnnotationObjectHelper(QPDFObjectHandle oh) : | ||
| 13 | std::string | 13 | std::string |
| 14 | QPDFAnnotationObjectHelper::getSubtype() | 14 | QPDFAnnotationObjectHelper::getSubtype() |
| 15 | { | 15 | { |
| 16 | - return this->oh.getKey("/Subtype").getName(); | 16 | + return oh().getKey("/Subtype").getName(); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | QPDFObjectHandle::Rectangle | 19 | QPDFObjectHandle::Rectangle |
| 20 | QPDFAnnotationObjectHelper::getRect() | 20 | QPDFAnnotationObjectHelper::getRect() |
| 21 | { | 21 | { |
| 22 | - return this->oh.getKey("/Rect").getArrayAsRectangle(); | 22 | + return oh().getKey("/Rect").getArrayAsRectangle(); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | QPDFObjectHandle | 25 | QPDFObjectHandle |
| 26 | QPDFAnnotationObjectHelper::getAppearanceDictionary() | 26 | QPDFAnnotationObjectHelper::getAppearanceDictionary() |
| 27 | { | 27 | { |
| 28 | - return this->oh.getKey("/AP"); | 28 | + return oh().getKey("/AP"); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | std::string | 31 | std::string |
| 32 | QPDFAnnotationObjectHelper::getAppearanceState() | 32 | QPDFAnnotationObjectHelper::getAppearanceState() |
| 33 | { | 33 | { |
| 34 | - if (this->oh.getKey("/AS").isName()) { | 34 | + if (oh().getKey("/AS").isName()) { |
| 35 | QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS present"); | 35 | QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS present"); |
| 36 | - return this->oh.getKey("/AS").getName(); | 36 | + return oh().getKey("/AS").getName(); |
| 37 | } | 37 | } |
| 38 | QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS absent"); | 38 | QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS absent"); |
| 39 | return ""; | 39 | return ""; |
| @@ -42,7 +42,7 @@ QPDFAnnotationObjectHelper::getAppearanceState() | @@ -42,7 +42,7 @@ QPDFAnnotationObjectHelper::getAppearanceState() | ||
| 42 | int | 42 | int |
| 43 | QPDFAnnotationObjectHelper::getFlags() | 43 | QPDFAnnotationObjectHelper::getFlags() |
| 44 | { | 44 | { |
| 45 | - QPDFObjectHandle flags_obj = this->oh.getKey("/F"); | 45 | + QPDFObjectHandle flags_obj = oh().getKey("/F"); |
| 46 | return flags_obj.isInteger() ? flags_obj.getIntValueAsInt() : 0; | 46 | return flags_obj.isInteger() ? flags_obj.getIntValueAsInt() : 0; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| @@ -143,7 +143,7 @@ QPDFAnnotationObjectHelper::getPageContentForAppearance( | @@ -143,7 +143,7 @@ QPDFAnnotationObjectHelper::getPageContentForAppearance( | ||
| 143 | 143 | ||
| 144 | // 3. Apply the rotation to A as computed above to get the final appearance matrix. | 144 | // 3. Apply the rotation to A as computed above to get the final appearance matrix. |
| 145 | 145 | ||
| 146 | - QPDFObjectHandle rect_obj = this->oh.getKey("/Rect"); | 146 | + QPDFObjectHandle rect_obj = oh().getKey("/Rect"); |
| 147 | QPDFObjectHandle as = getAppearanceStream("/N").getDict(); | 147 | QPDFObjectHandle as = getAppearanceStream("/N").getDict(); |
| 148 | QPDFObjectHandle bbox_obj = as.getKey("/BBox"); | 148 | QPDFObjectHandle bbox_obj = as.getKey("/BBox"); |
| 149 | QPDFObjectHandle matrix_obj = as.getKey("/Matrix"); | 149 | QPDFObjectHandle matrix_obj = as.getKey("/Matrix"); |
libqpdf/QPDFEFStreamObjectHelper.cc
| @@ -16,7 +16,7 @@ QPDFEFStreamObjectHelper::QPDFEFStreamObjectHelper(QPDFObjectHandle oh) : | @@ -16,7 +16,7 @@ QPDFEFStreamObjectHelper::QPDFEFStreamObjectHelper(QPDFObjectHandle oh) : | ||
| 16 | QPDFObjectHandle | 16 | QPDFObjectHandle |
| 17 | QPDFEFStreamObjectHelper::getParam(std::string const& pkey) | 17 | QPDFEFStreamObjectHelper::getParam(std::string const& pkey) |
| 18 | { | 18 | { |
| 19 | - auto params = this->oh.getDict().getKey("/Params"); | 19 | + auto params = oh().getDict().getKey("/Params"); |
| 20 | if (params.isDictionary()) { | 20 | if (params.isDictionary()) { |
| 21 | return params.getKey(pkey); | 21 | return params.getKey(pkey); |
| 22 | } | 22 | } |
| @@ -26,10 +26,9 @@ QPDFEFStreamObjectHelper::getParam(std::string const& pkey) | @@ -26,10 +26,9 @@ QPDFEFStreamObjectHelper::getParam(std::string const& pkey) | ||
| 26 | void | 26 | void |
| 27 | QPDFEFStreamObjectHelper::setParam(std::string const& pkey, QPDFObjectHandle const& pval) | 27 | QPDFEFStreamObjectHelper::setParam(std::string const& pkey, QPDFObjectHandle const& pval) |
| 28 | { | 28 | { |
| 29 | - auto params = this->oh.getDict().getKey("/Params"); | 29 | + auto params = oh().getDict().getKey("/Params"); |
| 30 | if (!params.isDictionary()) { | 30 | if (!params.isDictionary()) { |
| 31 | - params = | ||
| 32 | - this->oh.getDict().replaceKeyAndGetNew("/Params", QPDFObjectHandle::newDictionary()); | 31 | + params = oh().getDict().replaceKeyAndGetNew("/Params", QPDFObjectHandle::newDictionary()); |
| 33 | } | 32 | } |
| 34 | params.replaceKey(pkey, pval); | 33 | params.replaceKey(pkey, pval); |
| 35 | } | 34 | } |
| @@ -67,7 +66,7 @@ QPDFEFStreamObjectHelper::getSize() | @@ -67,7 +66,7 @@ QPDFEFStreamObjectHelper::getSize() | ||
| 67 | std::string | 66 | std::string |
| 68 | QPDFEFStreamObjectHelper::getSubtype() | 67 | QPDFEFStreamObjectHelper::getSubtype() |
| 69 | { | 68 | { |
| 70 | - auto val = this->oh.getDict().getKey("/Subtype"); | 69 | + auto val = oh().getDict().getKey("/Subtype"); |
| 71 | if (val.isName()) { | 70 | if (val.isName()) { |
| 72 | auto n = val.getName(); | 71 | auto n = val.getName(); |
| 73 | if (n.length() > 1) { | 72 | if (n.length() > 1) { |
| @@ -124,7 +123,7 @@ QPDFEFStreamObjectHelper::setModDate(std::string const& date) | @@ -124,7 +123,7 @@ QPDFEFStreamObjectHelper::setModDate(std::string const& date) | ||
| 124 | QPDFEFStreamObjectHelper& | 123 | QPDFEFStreamObjectHelper& |
| 125 | QPDFEFStreamObjectHelper::setSubtype(std::string const& subtype) | 124 | QPDFEFStreamObjectHelper::setSubtype(std::string const& subtype) |
| 126 | { | 125 | { |
| 127 | - this->oh.getDict().replaceKey("/Subtype", QPDFObjectHandle::newName("/" + subtype)); | 126 | + oh().getDict().replaceKey("/Subtype", QPDFObjectHandle::newName("/" + subtype)); |
| 128 | return *this; | 127 | return *this; |
| 129 | } | 128 | } |
| 130 | 129 |
libqpdf/QPDFFileSpecObjectHelper.cc
| @@ -25,7 +25,7 @@ std::string | @@ -25,7 +25,7 @@ std::string | ||
| 25 | QPDFFileSpecObjectHelper::getDescription() | 25 | QPDFFileSpecObjectHelper::getDescription() |
| 26 | { | 26 | { |
| 27 | std::string result; | 27 | std::string result; |
| 28 | - auto desc = this->oh.getKey("/Desc"); | 28 | + auto desc = oh().getKey("/Desc"); |
| 29 | if (desc.isString()) { | 29 | if (desc.isString()) { |
| 30 | result = desc.getUTF8Value(); | 30 | result = desc.getUTF8Value(); |
| 31 | } | 31 | } |
| @@ -36,7 +36,7 @@ std::string | @@ -36,7 +36,7 @@ std::string | ||
| 36 | QPDFFileSpecObjectHelper::getFilename() | 36 | QPDFFileSpecObjectHelper::getFilename() |
| 37 | { | 37 | { |
| 38 | for (auto const& i: name_keys) { | 38 | for (auto const& i: name_keys) { |
| 39 | - auto k = this->oh.getKey(i); | 39 | + auto k = oh().getKey(i); |
| 40 | if (k.isString()) { | 40 | if (k.isString()) { |
| 41 | return k.getUTF8Value(); | 41 | return k.getUTF8Value(); |
| 42 | } | 42 | } |
| @@ -49,7 +49,7 @@ QPDFFileSpecObjectHelper::getFilenames() | @@ -49,7 +49,7 @@ QPDFFileSpecObjectHelper::getFilenames() | ||
| 49 | { | 49 | { |
| 50 | std::map<std::string, std::string> result; | 50 | std::map<std::string, std::string> result; |
| 51 | for (auto const& i: name_keys) { | 51 | for (auto const& i: name_keys) { |
| 52 | - auto k = this->oh.getKey(i); | 52 | + auto k = oh().getKey(i); |
| 53 | if (k.isString()) { | 53 | if (k.isString()) { |
| 54 | result[i] = k.getUTF8Value(); | 54 | result[i] = k.getUTF8Value(); |
| 55 | } | 55 | } |
| @@ -60,7 +60,7 @@ QPDFFileSpecObjectHelper::getFilenames() | @@ -60,7 +60,7 @@ QPDFFileSpecObjectHelper::getFilenames() | ||
| 60 | QPDFObjectHandle | 60 | QPDFObjectHandle |
| 61 | QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key) | 61 | QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key) |
| 62 | { | 62 | { |
| 63 | - auto ef = this->oh.getKey("/EF"); | 63 | + auto ef = oh().getKey("/EF"); |
| 64 | if (!ef.isDictionary()) { | 64 | if (!ef.isDictionary()) { |
| 65 | return QPDFObjectHandle::newNull(); | 65 | return QPDFObjectHandle::newNull(); |
| 66 | } | 66 | } |
| @@ -79,7 +79,7 @@ QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key) | @@ -79,7 +79,7 @@ QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key) | ||
| 79 | QPDFObjectHandle | 79 | QPDFObjectHandle |
| 80 | QPDFFileSpecObjectHelper::getEmbeddedFileStreams() | 80 | QPDFFileSpecObjectHelper::getEmbeddedFileStreams() |
| 81 | { | 81 | { |
| 82 | - return this->oh.getKey("/EF"); | 82 | + return oh().getKey("/EF"); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | QPDFFileSpecObjectHelper | 85 | QPDFFileSpecObjectHelper |
| @@ -110,7 +110,7 @@ QPDFFileSpecObjectHelper::createFileSpec( | @@ -110,7 +110,7 @@ QPDFFileSpecObjectHelper::createFileSpec( | ||
| 110 | QPDFFileSpecObjectHelper& | 110 | QPDFFileSpecObjectHelper& |
| 111 | QPDFFileSpecObjectHelper::setDescription(std::string const& desc) | 111 | QPDFFileSpecObjectHelper::setDescription(std::string const& desc) |
| 112 | { | 112 | { |
| 113 | - this->oh.replaceKey("/Desc", QPDFObjectHandle::newUnicodeString(desc)); | 113 | + oh().replaceKey("/Desc", QPDFObjectHandle::newUnicodeString(desc)); |
| 114 | return *this; | 114 | return *this; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| @@ -119,13 +119,13 @@ QPDFFileSpecObjectHelper::setFilename( | @@ -119,13 +119,13 @@ QPDFFileSpecObjectHelper::setFilename( | ||
| 119 | std::string const& unicode_name, std::string const& compat_name) | 119 | std::string const& unicode_name, std::string const& compat_name) |
| 120 | { | 120 | { |
| 121 | auto uf = QPDFObjectHandle::newUnicodeString(unicode_name); | 121 | auto uf = QPDFObjectHandle::newUnicodeString(unicode_name); |
| 122 | - this->oh.replaceKey("/UF", uf); | 122 | + oh().replaceKey("/UF", uf); |
| 123 | if (compat_name.empty()) { | 123 | if (compat_name.empty()) { |
| 124 | QTC::TC("qpdf", "QPDFFileSpecObjectHelper empty compat_name"); | 124 | QTC::TC("qpdf", "QPDFFileSpecObjectHelper empty compat_name"); |
| 125 | - this->oh.replaceKey("/F", uf); | 125 | + oh().replaceKey("/F", uf); |
| 126 | } else { | 126 | } else { |
| 127 | QTC::TC("qpdf", "QPDFFileSpecObjectHelper non-empty compat_name"); | 127 | QTC::TC("qpdf", "QPDFFileSpecObjectHelper non-empty compat_name"); |
| 128 | - this->oh.replaceKey("/F", QPDFObjectHandle::newString(compat_name)); | 128 | + oh().replaceKey("/F", QPDFObjectHandle::newString(compat_name)); |
| 129 | } | 129 | } |
| 130 | return *this; | 130 | return *this; |
| 131 | } | 131 | } |
libqpdf/QPDFFormFieldObjectHelper.cc
| @@ -4,6 +4,7 @@ | @@ -4,6 +4,7 @@ | ||
| 4 | #include <qpdf/QIntC.hh> | 4 | #include <qpdf/QIntC.hh> |
| 5 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> | 5 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> |
| 6 | #include <qpdf/QPDFAnnotationObjectHelper.hh> | 6 | #include <qpdf/QPDFAnnotationObjectHelper.hh> |
| 7 | +#include <qpdf/QPDFObjectHandle_private.hh> | ||
| 7 | #include <qpdf/QTC.hh> | 8 | #include <qpdf/QTC.hh> |
| 8 | #include <qpdf/QUtil.hh> | 9 | #include <qpdf/QUtil.hh> |
| 9 | #include <cstdlib> | 10 | #include <cstdlib> |
| @@ -23,19 +24,19 @@ QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper() : | @@ -23,19 +24,19 @@ QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper() : | ||
| 23 | bool | 24 | bool |
| 24 | QPDFFormFieldObjectHelper::isNull() | 25 | QPDFFormFieldObjectHelper::isNull() |
| 25 | { | 26 | { |
| 26 | - return this->oh.isNull(); | 27 | + return oh().isNull(); |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | QPDFFormFieldObjectHelper | 30 | QPDFFormFieldObjectHelper |
| 30 | QPDFFormFieldObjectHelper::getParent() | 31 | QPDFFormFieldObjectHelper::getParent() |
| 31 | { | 32 | { |
| 32 | - return this->oh.getKey("/Parent"); // may be null | 33 | + return oh().getKey("/Parent"); // may be null |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | QPDFFormFieldObjectHelper | 36 | QPDFFormFieldObjectHelper |
| 36 | QPDFFormFieldObjectHelper::getTopLevelField(bool* is_different) | 37 | QPDFFormFieldObjectHelper::getTopLevelField(bool* is_different) |
| 37 | { | 38 | { |
| 38 | - auto top_field = this->oh; | 39 | + auto top_field = oh(); |
| 39 | QPDFObjGen::set seen; | 40 | QPDFObjGen::set seen; |
| 40 | while (seen.add(top_field) && !top_field.getKeyIfDict("/Parent").isNull()) { | 41 | while (seen.add(top_field) && !top_field.getKeyIfDict("/Parent").isNull()) { |
| 41 | top_field = top_field.getKey("/Parent"); | 42 | top_field = top_field.getKey("/Parent"); |
| @@ -51,7 +52,7 @@ QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const& name) | @@ -51,7 +52,7 @@ QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const& name) | ||
| 51 | { | 52 | { |
| 52 | QPDFObjectHandle result = QPDFObjectHandle::newNull(); | 53 | QPDFObjectHandle result = QPDFObjectHandle::newNull(); |
| 53 | // Fields are supposed to be indirect, so this should work. | 54 | // Fields are supposed to be indirect, so this should work. |
| 54 | - QPDF* q = this->oh.getOwningQPDF(); | 55 | + QPDF* q = oh().getOwningQPDF(); |
| 55 | if (!q) { | 56 | if (!q) { |
| 56 | return result; | 57 | return result; |
| 57 | } | 58 | } |
| @@ -65,7 +66,7 @@ QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const& name) | @@ -65,7 +66,7 @@ QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const& name) | ||
| 65 | QPDFObjectHandle | 66 | QPDFObjectHandle |
| 66 | QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name) | 67 | QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name) |
| 67 | { | 68 | { |
| 68 | - QPDFObjectHandle node = this->oh; | 69 | + QPDFObjectHandle node = oh(); |
| 69 | if (!node.isDictionary()) { | 70 | if (!node.isDictionary()) { |
| 70 | return QPDFObjectHandle::newNull(); | 71 | return QPDFObjectHandle::newNull(); |
| 71 | } | 72 | } |
| @@ -116,7 +117,7 @@ std::string | @@ -116,7 +117,7 @@ std::string | ||
| 116 | QPDFFormFieldObjectHelper::getFullyQualifiedName() | 117 | QPDFFormFieldObjectHelper::getFullyQualifiedName() |
| 117 | { | 118 | { |
| 118 | std::string result; | 119 | std::string result; |
| 119 | - QPDFObjectHandle node = this->oh; | 120 | + QPDFObjectHandle node = oh(); |
| 120 | QPDFObjGen::set seen; | 121 | QPDFObjGen::set seen; |
| 121 | while (!node.isNull() && seen.add(node)) { | 122 | while (!node.isNull() && seen.add(node)) { |
| 122 | if (node.getKey("/T").isString()) { | 123 | if (node.getKey("/T").isString()) { |
| @@ -135,8 +136,8 @@ std::string | @@ -135,8 +136,8 @@ std::string | ||
| 135 | QPDFFormFieldObjectHelper::getPartialName() | 136 | QPDFFormFieldObjectHelper::getPartialName() |
| 136 | { | 137 | { |
| 137 | std::string result; | 138 | std::string result; |
| 138 | - if (this->oh.getKey("/T").isString()) { | ||
| 139 | - result = this->oh.getKey("/T").getUTF8Value(); | 139 | + if (oh().getKey("/T").isString()) { |
| 140 | + result = oh().getKey("/T").getUTF8Value(); | ||
| 140 | } | 141 | } |
| 141 | return result; | 142 | return result; |
| 142 | } | 143 | } |
| @@ -144,9 +145,9 @@ QPDFFormFieldObjectHelper::getPartialName() | @@ -144,9 +145,9 @@ QPDFFormFieldObjectHelper::getPartialName() | ||
| 144 | std::string | 145 | std::string |
| 145 | QPDFFormFieldObjectHelper::getAlternativeName() | 146 | QPDFFormFieldObjectHelper::getAlternativeName() |
| 146 | { | 147 | { |
| 147 | - if (this->oh.getKey("/TU").isString()) { | 148 | + if (oh().getKey("/TU").isString()) { |
| 148 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU present"); | 149 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU present"); |
| 149 | - return this->oh.getKey("/TU").getUTF8Value(); | 150 | + return oh().getKey("/TU").getUTF8Value(); |
| 150 | } | 151 | } |
| 151 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU absent"); | 152 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU absent"); |
| 152 | return getFullyQualifiedName(); | 153 | return getFullyQualifiedName(); |
| @@ -155,9 +156,9 @@ QPDFFormFieldObjectHelper::getAlternativeName() | @@ -155,9 +156,9 @@ QPDFFormFieldObjectHelper::getAlternativeName() | ||
| 155 | std::string | 156 | std::string |
| 156 | QPDFFormFieldObjectHelper::getMappingName() | 157 | QPDFFormFieldObjectHelper::getMappingName() |
| 157 | { | 158 | { |
| 158 | - if (this->oh.getKey("/TM").isString()) { | 159 | + if (oh().getKey("/TM").isString()) { |
| 159 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM present"); | 160 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM present"); |
| 160 | - return this->oh.getKey("/TM").getUTF8Value(); | 161 | + return oh().getKey("/TM").getUTF8Value(); |
| 161 | } | 162 | } |
| 162 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM absent"); | 163 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM absent"); |
| 163 | return getAlternativeName(); | 164 | return getAlternativeName(); |
| @@ -271,14 +272,9 @@ QPDFFormFieldObjectHelper::getChoices() | @@ -271,14 +272,9 @@ QPDFFormFieldObjectHelper::getChoices() | ||
| 271 | if (!isChoice()) { | 272 | if (!isChoice()) { |
| 272 | return result; | 273 | return result; |
| 273 | } | 274 | } |
| 274 | - QPDFObjectHandle opt = getInheritableFieldValue("/Opt"); | ||
| 275 | - if (opt.isArray()) { | ||
| 276 | - int n = opt.getArrayNItems(); | ||
| 277 | - for (int i = 0; i < n; ++i) { | ||
| 278 | - QPDFObjectHandle item = opt.getArrayItem(i); | ||
| 279 | - if (item.isString()) { | ||
| 280 | - result.push_back(item.getUTF8Value()); | ||
| 281 | - } | 275 | + for (auto const& item: getInheritableFieldValue("/Opt").as_array()) { |
| 276 | + if (item.isString()) { | ||
| 277 | + result.emplace_back(item.getUTF8Value()); | ||
| 282 | } | 278 | } |
| 283 | } | 279 | } |
| 284 | return result; | 280 | return result; |
| @@ -287,13 +283,13 @@ QPDFFormFieldObjectHelper::getChoices() | @@ -287,13 +283,13 @@ QPDFFormFieldObjectHelper::getChoices() | ||
| 287 | void | 283 | void |
| 288 | QPDFFormFieldObjectHelper::setFieldAttribute(std::string const& key, QPDFObjectHandle value) | 284 | QPDFFormFieldObjectHelper::setFieldAttribute(std::string const& key, QPDFObjectHandle value) |
| 289 | { | 285 | { |
| 290 | - this->oh.replaceKey(key, value); | 286 | + oh().replaceKey(key, value); |
| 291 | } | 287 | } |
| 292 | 288 | ||
| 293 | void | 289 | void |
| 294 | QPDFFormFieldObjectHelper::setFieldAttribute(std::string const& key, std::string const& utf8_value) | 290 | QPDFFormFieldObjectHelper::setFieldAttribute(std::string const& key, std::string const& utf8_value) |
| 295 | { | 291 | { |
| 296 | - this->oh.replaceKey(key, QPDFObjectHandle::newUnicodeString(utf8_value)); | 292 | + oh().replaceKey(key, QPDFObjectHandle::newUnicodeString(utf8_value)); |
| 297 | } | 293 | } |
| 298 | 294 | ||
| 299 | void | 295 | void |
| @@ -310,18 +306,18 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) | @@ -310,18 +306,18 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) | ||
| 310 | setCheckBoxValue((name != "/Off")); | 306 | setCheckBoxValue((name != "/Off")); |
| 311 | } | 307 | } |
| 312 | if (!okay) { | 308 | if (!okay) { |
| 313 | - this->oh.warnIfPossible( | 309 | + oh().warnIfPossible( |
| 314 | "ignoring attempt to set a checkbox field to a value whose type is not name"); | 310 | "ignoring attempt to set a checkbox field to a value whose type is not name"); |
| 315 | } | 311 | } |
| 316 | } else if (isRadioButton()) { | 312 | } else if (isRadioButton()) { |
| 317 | if (value.isName()) { | 313 | if (value.isName()) { |
| 318 | setRadioButtonValue(value); | 314 | setRadioButtonValue(value); |
| 319 | } else { | 315 | } else { |
| 320 | - this->oh.warnIfPossible( | 316 | + oh().warnIfPossible( |
| 321 | "ignoring attempt to set a radio button field to an object that is not a name"); | 317 | "ignoring attempt to set a radio button field to an object that is not a name"); |
| 322 | } | 318 | } |
| 323 | } else if (isPushbutton()) { | 319 | } else if (isPushbutton()) { |
| 324 | - this->oh.warnIfPossible("ignoring attempt set the value of a pushbutton field"); | 320 | + oh().warnIfPossible("ignoring attempt set the value of a pushbutton field"); |
| 325 | } | 321 | } |
| 326 | return; | 322 | return; |
| 327 | } | 323 | } |
| @@ -331,7 +327,7 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) | @@ -331,7 +327,7 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) | ||
| 331 | setFieldAttribute("/V", value); | 327 | setFieldAttribute("/V", value); |
| 332 | } | 328 | } |
| 333 | if (need_appearances) { | 329 | if (need_appearances) { |
| 334 | - QPDF& qpdf = this->oh.getQPDF( | 330 | + QPDF& qpdf = oh().getQPDF( |
| 335 | "QPDFFormFieldObjectHelper::setV called with need_appearances = " | 331 | "QPDFFormFieldObjectHelper::setV called with need_appearances = " |
| 336 | "true on an object that is not associated with an owning QPDF"); | 332 | "true on an object that is not associated with an owning QPDF"); |
| 337 | QPDFAcroFormDocumentHelper(qpdf).setNeedAppearances(true); | 333 | QPDFAcroFormDocumentHelper(qpdf).setNeedAppearances(true); |
| @@ -355,7 +351,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | @@ -355,7 +351,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | ||
| 355 | // its /AP (i.e. its normal appearance stream dictionary), set /AS to name; otherwise, if /Off | 351 | // its /AP (i.e. its normal appearance stream dictionary), set /AS to name; otherwise, if /Off |
| 356 | // is a member, set /AS to /Off. | 352 | // is a member, set /AS to /Off. |
| 357 | // Note that we never turn on /NeedAppearances when setting a radio button field. | 353 | // Note that we never turn on /NeedAppearances when setting a radio button field. |
| 358 | - QPDFObjectHandle parent = this->oh.getKey("/Parent"); | 354 | + QPDFObjectHandle parent = oh().getKey("/Parent"); |
| 359 | if (parent.isDictionary() && parent.getKey("/Parent").isNull()) { | 355 | if (parent.isDictionary() && parent.getKey("/Parent").isNull()) { |
| 360 | QPDFFormFieldObjectHelper ph(parent); | 356 | QPDFFormFieldObjectHelper ph(parent); |
| 361 | if (ph.isRadioButton()) { | 357 | if (ph.isRadioButton()) { |
| @@ -366,32 +362,23 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | @@ -366,32 +362,23 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | ||
| 366 | } | 362 | } |
| 367 | } | 363 | } |
| 368 | 364 | ||
| 369 | - QPDFObjectHandle kids = this->oh.getKey("/Kids"); | 365 | + QPDFObjectHandle kids = oh().getKey("/Kids"); |
| 370 | if (!(isRadioButton() && parent.isNull() && kids.isArray())) { | 366 | if (!(isRadioButton() && parent.isNull() && kids.isArray())) { |
| 371 | - this->oh.warnIfPossible( | ||
| 372 | - "don't know how to set the value" | ||
| 373 | - " of this field as a radio button"); | 367 | + oh().warnIfPossible("don't know how to set the value of this field as a radio button"); |
| 374 | return; | 368 | return; |
| 375 | } | 369 | } |
| 376 | setFieldAttribute("/V", name); | 370 | setFieldAttribute("/V", name); |
| 377 | - int nkids = kids.getArrayNItems(); | ||
| 378 | - for (int i = 0; i < nkids; ++i) { | ||
| 379 | - QPDFObjectHandle kid = kids.getArrayItem(i); | 371 | + for (auto const& kid: kids.as_array()) { |
| 380 | QPDFObjectHandle AP = kid.getKey("/AP"); | 372 | QPDFObjectHandle AP = kid.getKey("/AP"); |
| 381 | QPDFObjectHandle annot; | 373 | QPDFObjectHandle annot; |
| 382 | - if (AP.isNull()) { | 374 | + if (AP.null()) { |
| 383 | // The widget may be below. If there is more than one, just find the first one. | 375 | // The widget may be below. If there is more than one, just find the first one. |
| 384 | - QPDFObjectHandle grandkids = kid.getKey("/Kids"); | ||
| 385 | - if (grandkids.isArray()) { | ||
| 386 | - int ngrandkids = grandkids.getArrayNItems(); | ||
| 387 | - for (int j = 0; j < ngrandkids; ++j) { | ||
| 388 | - QPDFObjectHandle grandkid = grandkids.getArrayItem(j); | ||
| 389 | - AP = grandkid.getKey("/AP"); | ||
| 390 | - if (!AP.isNull()) { | ||
| 391 | - QTC::TC("qpdf", "QPDFFormFieldObjectHelper radio button grandkid"); | ||
| 392 | - annot = grandkid; | ||
| 393 | - break; | ||
| 394 | - } | 376 | + for (auto const& grandkid: kid.getKey("/Kids").as_array()) { |
| 377 | + AP = grandkid.getKey("/AP"); | ||
| 378 | + if (!AP.null()) { | ||
| 379 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper radio button grandkid"); | ||
| 380 | + annot = grandkid; | ||
| 381 | + break; | ||
| 395 | } | 382 | } |
| 396 | } | 383 | } |
| 397 | } else { | 384 | } else { |
| @@ -399,7 +386,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | @@ -399,7 +386,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | ||
| 399 | } | 386 | } |
| 400 | if (!annot) { | 387 | if (!annot) { |
| 401 | QTC::TC("qpdf", "QPDFObjectHandle broken radio button"); | 388 | QTC::TC("qpdf", "QPDFObjectHandle broken radio button"); |
| 402 | - this->oh.warnIfPossible("unable to set the value of this radio button"); | 389 | + oh().warnIfPossible("unable to set the value of this radio button"); |
| 403 | continue; | 390 | continue; |
| 404 | } | 391 | } |
| 405 | if (AP.isDictionary() && AP.getKey("/N").isDictionary() && | 392 | if (AP.isDictionary() && AP.getKey("/N").isDictionary() && |
| @@ -416,39 +403,32 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | @@ -416,39 +403,32 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | ||
| 416 | void | 403 | void |
| 417 | QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) | 404 | QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) |
| 418 | { | 405 | { |
| 419 | - QPDFObjectHandle AP = this->oh.getKey("/AP"); | 406 | + QPDFObjectHandle AP = oh().getKey("/AP"); |
| 420 | QPDFObjectHandle annot; | 407 | QPDFObjectHandle annot; |
| 421 | - if (AP.isNull()) { | 408 | + if (AP.null()) { |
| 422 | // The widget may be below. If there is more than one, just | 409 | // The widget may be below. If there is more than one, just |
| 423 | // find the first one. | 410 | // find the first one. |
| 424 | - QPDFObjectHandle kids = this->oh.getKey("/Kids"); | ||
| 425 | - if (kids.isArray()) { | ||
| 426 | - int nkids = kids.getArrayNItems(); | ||
| 427 | - for (int i = 0; i < nkids; ++i) { | ||
| 428 | - QPDFObjectHandle kid = kids.getArrayItem(i); | ||
| 429 | - AP = kid.getKey("/AP"); | ||
| 430 | - if (!AP.isNull()) { | ||
| 431 | - QTC::TC("qpdf", "QPDFFormFieldObjectHelper checkbox kid widget"); | ||
| 432 | - annot = kid; | ||
| 433 | - break; | ||
| 434 | - } | 411 | + QPDFObjectHandle kids = oh().getKey("/Kids"); |
| 412 | + for (auto const& kid: oh().getKey("/Kids").as_array(qpdf::strict)) { | ||
| 413 | + AP = kid.getKey("/AP"); | ||
| 414 | + if (!AP.null()) { | ||
| 415 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper checkbox kid widget"); | ||
| 416 | + annot = kid; | ||
| 417 | + break; | ||
| 435 | } | 418 | } |
| 436 | } | 419 | } |
| 437 | } else { | 420 | } else { |
| 438 | - annot = this->oh; | 421 | + annot = oh(); |
| 439 | } | 422 | } |
| 440 | std::string on_value; | 423 | std::string on_value; |
| 441 | if (value) { | 424 | if (value) { |
| 442 | // Set the "on" value to the first value in the appearance stream's normal state dictionary | 425 | // Set the "on" value to the first value in the appearance stream's normal state dictionary |
| 443 | // that isn't /Off. If not found, fall back to /Yes. | 426 | // that isn't /Off. If not found, fall back to /Yes. |
| 444 | if (AP.isDictionary()) { | 427 | if (AP.isDictionary()) { |
| 445 | - auto N = AP.getKey("/N"); | ||
| 446 | - if (N.isDictionary()) { | ||
| 447 | - for (auto const& iter: N.ditems()) { | ||
| 448 | - if (iter.first != "/Off") { | ||
| 449 | - on_value = iter.first; | ||
| 450 | - break; | ||
| 451 | - } | 428 | + for (auto const& item: AP.getKey("/N").as_dictionary()) { |
| 429 | + if (item.first != "/Off") { | ||
| 430 | + on_value = item.first; | ||
| 431 | + break; | ||
| 452 | } | 432 | } |
| 453 | } | 433 | } |
| 454 | } | 434 | } |
| @@ -462,7 +442,7 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) | @@ -462,7 +442,7 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) | ||
| 462 | setFieldAttribute("/V", name); | 442 | setFieldAttribute("/V", name); |
| 463 | if (!annot) { | 443 | if (!annot) { |
| 464 | QTC::TC("qpdf", "QPDFObjectHandle broken checkbox"); | 444 | QTC::TC("qpdf", "QPDFObjectHandle broken checkbox"); |
| 465 | - this->oh.warnIfPossible("unable to set the value of this checkbox"); | 445 | + oh().warnIfPossible("unable to set the value of this checkbox"); |
| 466 | return; | 446 | return; |
| 467 | } | 447 | } |
| 468 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper set checkbox AS"); | 448 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper set checkbox AS"); |
| @@ -775,7 +755,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper& ao | @@ -775,7 +755,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper& ao | ||
| 775 | "<< /Resources << /ProcSet [ /PDF /Text ] >>" | 755 | "<< /Resources << /ProcSet [ /PDF /Text ] >>" |
| 776 | " /Type /XObject /Subtype /Form >>"); | 756 | " /Type /XObject /Subtype /Form >>"); |
| 777 | dict.replaceKey("/BBox", QPDFObjectHandle::newFromRectangle(bbox)); | 757 | dict.replaceKey("/BBox", QPDFObjectHandle::newFromRectangle(bbox)); |
| 778 | - AS = QPDFObjectHandle::newStream(this->oh.getOwningQPDF(), "/Tx BMC\nEMC\n"); | 758 | + AS = QPDFObjectHandle::newStream(oh().getOwningQPDF(), "/Tx BMC\nEMC\n"); |
| 779 | AS.replaceDict(dict); | 759 | AS.replaceDict(dict); |
| 780 | QPDFObjectHandle AP = aoh.getAppearanceDictionary(); | 760 | QPDFObjectHandle AP = aoh.getAppearanceDictionary(); |
| 781 | if (AP.isNull()) { | 761 | if (AP.isNull()) { |
libqpdf/QPDFJob.cc
| @@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
| 19 | #include <qpdf/QPDFEmbeddedFileDocumentHelper.hh> | 19 | #include <qpdf/QPDFEmbeddedFileDocumentHelper.hh> |
| 20 | #include <qpdf/QPDFExc.hh> | 20 | #include <qpdf/QPDFExc.hh> |
| 21 | #include <qpdf/QPDFLogger.hh> | 21 | #include <qpdf/QPDFLogger.hh> |
| 22 | +#include <qpdf/QPDFObjectHandle_private.hh> | ||
| 22 | #include <qpdf/QPDFOutlineDocumentHelper.hh> | 23 | #include <qpdf/QPDFOutlineDocumentHelper.hh> |
| 23 | #include <qpdf/QPDFPageDocumentHelper.hh> | 24 | #include <qpdf/QPDFPageDocumentHelper.hh> |
| 24 | #include <qpdf/QPDFPageLabelDocumentHelper.hh> | 25 | #include <qpdf/QPDFPageLabelDocumentHelper.hh> |
| @@ -916,10 +917,13 @@ QPDFJob::doListAttachments(QPDF& pdf) | @@ -916,10 +917,13 @@ QPDFJob::doListAttachments(QPDF& pdf) | ||
| 916 | v << " " << i2.first << " -> " << i2.second << "\n"; | 917 | v << " " << i2.first << " -> " << i2.second << "\n"; |
| 917 | } | 918 | } |
| 918 | v << " all data streams:\n"; | 919 | v << " all data streams:\n"; |
| 919 | - for (auto const& i2: efoh->getEmbeddedFileStreams().ditems()) { | ||
| 920 | - auto efs = QPDFEFStreamObjectHelper(i2.second); | ||
| 921 | - v << " " << i2.first << " -> " | ||
| 922 | - << efs.getObjectHandle().getObjGen().unparse(',') << "\n"; | 920 | + for (auto const& [key2, value2]: efoh->getEmbeddedFileStreams().as_dictionary()) { |
| 921 | + if (value2.null()) { | ||
| 922 | + continue; | ||
| 923 | + } | ||
| 924 | + auto efs = QPDFEFStreamObjectHelper(value2); | ||
| 925 | + v << " " << key2 << " -> " << efs.getObjectHandle().getObjGen().unparse(',') | ||
| 926 | + << "\n"; | ||
| 923 | v << " creation date: " << efs.getCreationDate() << "\n" | 927 | v << " creation date: " << efs.getCreationDate() << "\n" |
| 924 | << " modification date: " << efs.getModDate() << "\n" | 928 | << " modification date: " << efs.getModDate() << "\n" |
| 925 | << " mime type: " << efs.getSubtype() << "\n" | 929 | << " mime type: " << efs.getSubtype() << "\n" |
| @@ -1338,9 +1342,12 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf) | @@ -1338,9 +1342,12 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1338 | j_names.addDictionaryMember(i2.first, JSON::makeString(i2.second)); | 1342 | j_names.addDictionaryMember(i2.first, JSON::makeString(i2.second)); |
| 1339 | } | 1343 | } |
| 1340 | auto j_streams = j_details.addDictionaryMember("streams", JSON::makeDictionary()); | 1344 | auto j_streams = j_details.addDictionaryMember("streams", JSON::makeDictionary()); |
| 1341 | - for (auto const& i2: fsoh->getEmbeddedFileStreams().ditems()) { | ||
| 1342 | - auto efs = QPDFEFStreamObjectHelper(i2.second); | ||
| 1343 | - auto j_stream = j_streams.addDictionaryMember(i2.first, JSON::makeDictionary()); | 1345 | + for (auto const& [key2, value2]: fsoh->getEmbeddedFileStreams().as_dictionary()) { |
| 1346 | + if (value2.null()) { | ||
| 1347 | + continue; | ||
| 1348 | + } | ||
| 1349 | + auto efs = QPDFEFStreamObjectHelper(value2); | ||
| 1350 | + auto j_stream = j_streams.addDictionaryMember(key2, JSON::makeDictionary()); | ||
| 1344 | j_stream.addDictionaryMember( | 1351 | j_stream.addDictionaryMember( |
| 1345 | "creationdate", null_or_string(to_iso8601(efs.getCreationDate()))); | 1352 | "creationdate", null_or_string(to_iso8601(efs.getCreationDate()))); |
| 1346 | j_stream.addDictionaryMember( | 1353 | j_stream.addDictionaryMember( |
| @@ -2347,12 +2354,10 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) | @@ -2347,12 +2354,10 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) | ||
| 2347 | return true; | 2354 | return true; |
| 2348 | } | 2355 | } |
| 2349 | } | 2356 | } |
| 2350 | - if (xobject.isDictionary()) { | ||
| 2351 | - for (auto const& k: xobject.getKeys()) { | ||
| 2352 | - QPDFObjectHandle xobj = xobject.getKey(k); | ||
| 2353 | - if (xobj.isFormXObject()) { | ||
| 2354 | - queue.push_back(xobj); | ||
| 2355 | - } | 2357 | + |
| 2358 | + for (auto const& xobj: xobject.as_dictionary()) { | ||
| 2359 | + if (xobj.second.isFormXObject()) { | ||
| 2360 | + queue.emplace_back(xobj.second); | ||
| 2356 | } | 2361 | } |
| 2357 | } | 2362 | } |
| 2358 | } | 2363 | } |
libqpdf/QPDFObjGen.cc deleted
| 1 | -#include <qpdf/QPDFObjGen.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/QPDFObjectHandle.hh> | ||
| 4 | -#include <qpdf/QPDFObjectHelper.hh> | ||
| 5 | -#include <qpdf/QPDFObject_private.hh> | ||
| 6 | - | ||
| 7 | -#include <stdexcept> | ||
| 8 | - | ||
| 9 | -bool | ||
| 10 | -QPDFObjGen::set::add(QPDFObjectHandle const& oh) | ||
| 11 | -{ | ||
| 12 | - if (auto* ptr = oh.getObjectPtr()) { | ||
| 13 | - return add(ptr->getObjGen()); | ||
| 14 | - } else { | ||
| 15 | - throw std::logic_error( | ||
| 16 | - "attempt to retrieve QPDFObjGen from uninitialized QPDFObjectHandle"); | ||
| 17 | - return false; | ||
| 18 | - } | ||
| 19 | -} | ||
| 20 | - | ||
| 21 | -bool | ||
| 22 | -QPDFObjGen::set::add(QPDFObjectHelper const& helper) | ||
| 23 | -{ | ||
| 24 | - if (auto* ptr = helper.getObjectHandle().getObjectPtr()) { | ||
| 25 | - return add(ptr->getObjGen()); | ||
| 26 | - } else { | ||
| 27 | - throw std::logic_error( | ||
| 28 | - "attempt to retrieve QPDFObjGen from uninitialized QPDFObjectHandle"); | ||
| 29 | - return false; | ||
| 30 | - } | ||
| 31 | -} | ||
| 32 | - | ||
| 33 | -void | ||
| 34 | -QPDFObjGen::set::erase(QPDFObjectHandle const& oh) | ||
| 35 | -{ | ||
| 36 | - if (auto* ptr = oh.getObjectPtr()) { | ||
| 37 | - erase(ptr->getObjGen()); | ||
| 38 | - } else { | ||
| 39 | - throw std::logic_error( | ||
| 40 | - "attempt to retrieve QPDFObjGen from uninitialized QPDFObjectHandle"); | ||
| 41 | - } | ||
| 42 | -} | ||
| 43 | - | ||
| 44 | -void | ||
| 45 | -QPDFObjGen::set::erase(QPDFObjectHelper const& helper) | ||
| 46 | -{ | ||
| 47 | - if (auto* ptr = helper.getObjectHandle().getObjectPtr()) { | ||
| 48 | - erase(ptr->getObjGen()); | ||
| 49 | - } else { | ||
| 50 | - throw std::logic_error( | ||
| 51 | - "attempt to retrieve QPDFObjGen from uninitialized QPDFObjectHandle"); | ||
| 52 | - } | ||
| 53 | -} |
libqpdf/QPDFObject.cc
| 1 | #include <qpdf/QPDFObject_private.hh> | 1 | #include <qpdf/QPDFObject_private.hh> |
| 2 | 2 | ||
| 3 | -#include <qpdf/QPDF.hh> | ||
| 4 | -#include <qpdf/QPDF_Destroyed.hh> | ||
| 5 | - | ||
| 6 | -void | ||
| 7 | -QPDFObject::destroy() | 3 | +std::string |
| 4 | +QPDFObject::getDescription() | ||
| 8 | { | 5 | { |
| 9 | - value = QPDF_Destroyed::getInstance(); | 6 | + if (object_description) { |
| 7 | + switch (object_description->index()) { | ||
| 8 | + case 0: | ||
| 9 | + { | ||
| 10 | + // Simple template string | ||
| 11 | + auto description = std::get<0>(*object_description); | ||
| 12 | + | ||
| 13 | + if (auto pos = description.find("$OG"); pos != std::string::npos) { | ||
| 14 | + description.replace(pos, 3, og.unparse(' ')); | ||
| 15 | + } | ||
| 16 | + if (auto pos = description.find("$PO"); pos != std::string::npos) { | ||
| 17 | + qpdf_offset_t shift = (getTypeCode() == ::ot_dictionary) ? 2 | ||
| 18 | + : (getTypeCode() == ::ot_array) ? 1 | ||
| 19 | + : 0; | ||
| 20 | + | ||
| 21 | + description.replace(pos, 3, std::to_string(parsed_offset + shift)); | ||
| 22 | + } | ||
| 23 | + return description; | ||
| 24 | + } | ||
| 25 | + case 1: | ||
| 26 | + { | ||
| 27 | + // QPDF::JSONReactor generated description | ||
| 28 | + auto j_descr = std::get<1>(*object_description); | ||
| 29 | + return ( | ||
| 30 | + *j_descr.input + (j_descr.object.empty() ? "" : ", " + j_descr.object) + | ||
| 31 | + " at offset " + std::to_string(parsed_offset)); | ||
| 32 | + } | ||
| 33 | + case 2: | ||
| 34 | + { | ||
| 35 | + // Child object description | ||
| 36 | + auto j_descr = std::get<2>(*object_description); | ||
| 37 | + std::string result; | ||
| 38 | + if (auto p = j_descr.parent.lock()) { | ||
| 39 | + result = p->getDescription(); | ||
| 40 | + } | ||
| 41 | + result += j_descr.static_descr; | ||
| 42 | + if (auto pos = result.find("$VD"); pos != std::string::npos) { | ||
| 43 | + result.replace(pos, 3, j_descr.var_descr); | ||
| 44 | + } | ||
| 45 | + return result; | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + } else if (og.isIndirect()) { | ||
| 49 | + return "object " + og.unparse(' '); | ||
| 50 | + } | ||
| 51 | + return {}; | ||
| 10 | } | 52 | } |
libqpdf/QPDFObjectHandle.cc
| 1 | -#include <qpdf/QPDFObjectHandle.hh> | 1 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 2 | 2 | ||
| 3 | #include <qpdf/BufferInputSource.hh> | 3 | #include <qpdf/BufferInputSource.hh> |
| 4 | #include <qpdf/JSON_writer.hh> | 4 | #include <qpdf/JSON_writer.hh> |
| @@ -11,19 +11,6 @@ | @@ -11,19 +11,6 @@ | ||
| 11 | #include <qpdf/QPDFObject_private.hh> | 11 | #include <qpdf/QPDFObject_private.hh> |
| 12 | #include <qpdf/QPDFPageObjectHelper.hh> | 12 | #include <qpdf/QPDFPageObjectHelper.hh> |
| 13 | #include <qpdf/QPDFParser.hh> | 13 | #include <qpdf/QPDFParser.hh> |
| 14 | -#include <qpdf/QPDF_Array.hh> | ||
| 15 | -#include <qpdf/QPDF_Bool.hh> | ||
| 16 | -#include <qpdf/QPDF_Dictionary.hh> | ||
| 17 | -#include <qpdf/QPDF_InlineImage.hh> | ||
| 18 | -#include <qpdf/QPDF_Integer.hh> | ||
| 19 | -#include <qpdf/QPDF_Name.hh> | ||
| 20 | -#include <qpdf/QPDF_Null.hh> | ||
| 21 | -#include <qpdf/QPDF_Operator.hh> | ||
| 22 | -#include <qpdf/QPDF_Real.hh> | ||
| 23 | -#include <qpdf/QPDF_Reserved.hh> | ||
| 24 | -#include <qpdf/QPDF_Stream.hh> | ||
| 25 | -#include <qpdf/QPDF_String.hh> | ||
| 26 | -#include <qpdf/QPDF_Unresolved.hh> | ||
| 27 | 14 | ||
| 28 | #include <qpdf/QIntC.hh> | 15 | #include <qpdf/QIntC.hh> |
| 29 | #include <qpdf/QTC.hh> | 16 | #include <qpdf/QTC.hh> |
| @@ -38,6 +25,13 @@ | @@ -38,6 +25,13 @@ | ||
| 38 | #include <stdexcept> | 25 | #include <stdexcept> |
| 39 | 26 | ||
| 40 | using namespace std::literals; | 27 | using namespace std::literals; |
| 28 | +using namespace qpdf; | ||
| 29 | + | ||
| 30 | +BaseHandle:: | ||
| 31 | +operator QPDFObjGen() const | ||
| 32 | +{ | ||
| 33 | + return obj ? obj->getObjGen() : QPDFObjGen(); | ||
| 34 | +} | ||
| 41 | 35 | ||
| 42 | namespace | 36 | namespace |
| 43 | { | 37 | { |
| @@ -221,8 +215,441 @@ LastChar::getLastChar() | @@ -221,8 +215,441 @@ LastChar::getLastChar() | ||
| 221 | return this->last_char; | 215 | return this->last_char; |
| 222 | } | 216 | } |
| 223 | 217 | ||
| 218 | +std::pair<bool, bool> | ||
| 219 | +Name::analyzeJSONEncoding(const std::string& name) | ||
| 220 | +{ | ||
| 221 | + int tail = 0; // Number of continuation characters expected. | ||
| 222 | + bool tail2 = false; // Potential overlong 3 octet utf-8. | ||
| 223 | + bool tail3 = false; // potential overlong 4 octet | ||
| 224 | + bool needs_escaping = false; | ||
| 225 | + for (auto const& it: name) { | ||
| 226 | + auto c = static_cast<unsigned char>(it); | ||
| 227 | + if (tail) { | ||
| 228 | + if ((c & 0xc0) != 0x80) { | ||
| 229 | + return {false, false}; | ||
| 230 | + } | ||
| 231 | + if (tail2) { | ||
| 232 | + if ((c & 0xe0) == 0x80) { | ||
| 233 | + return {false, false}; | ||
| 234 | + } | ||
| 235 | + tail2 = false; | ||
| 236 | + } else if (tail3) { | ||
| 237 | + if ((c & 0xf0) == 0x80) { | ||
| 238 | + return {false, false}; | ||
| 239 | + } | ||
| 240 | + tail3 = false; | ||
| 241 | + } | ||
| 242 | + tail--; | ||
| 243 | + } else if (c < 0x80) { | ||
| 244 | + if (!needs_escaping) { | ||
| 245 | + needs_escaping = !((c > 34 && c != '\\') || c == ' ' || c == 33); | ||
| 246 | + } | ||
| 247 | + } else if ((c & 0xe0) == 0xc0) { | ||
| 248 | + if ((c & 0xfe) == 0xc0) { | ||
| 249 | + return {false, false}; | ||
| 250 | + } | ||
| 251 | + tail = 1; | ||
| 252 | + } else if ((c & 0xf0) == 0xe0) { | ||
| 253 | + tail2 = (c == 0xe0); | ||
| 254 | + tail = 2; | ||
| 255 | + } else if ((c & 0xf8) == 0xf0) { | ||
| 256 | + tail3 = (c == 0xf0); | ||
| 257 | + tail = 3; | ||
| 258 | + } else { | ||
| 259 | + return {false, false}; | ||
| 260 | + } | ||
| 261 | + } | ||
| 262 | + return {tail == 0, !needs_escaping}; | ||
| 263 | +} | ||
| 264 | + | ||
| 265 | +std::string | ||
| 266 | +Name::normalize(std::string const& name) | ||
| 267 | +{ | ||
| 268 | + if (name.empty()) { | ||
| 269 | + return name; | ||
| 270 | + } | ||
| 271 | + std::string result; | ||
| 272 | + result += name.at(0); | ||
| 273 | + for (size_t i = 1; i < name.length(); ++i) { | ||
| 274 | + char ch = name.at(i); | ||
| 275 | + // Don't use locale/ctype here; follow PDF spec guidelines. | ||
| 276 | + if (ch == '\0') { | ||
| 277 | + // QPDFTokenizer embeds a null character to encode an invalid #. | ||
| 278 | + result += "#"; | ||
| 279 | + } else if ( | ||
| 280 | + ch < 33 || ch == '#' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' || | ||
| 281 | + ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch > 126) { | ||
| 282 | + result += QUtil::hex_encode_char(ch); | ||
| 283 | + } else { | ||
| 284 | + result += ch; | ||
| 285 | + } | ||
| 286 | + } | ||
| 287 | + return result; | ||
| 288 | +} | ||
| 289 | + | ||
| 290 | +std::shared_ptr<QPDFObject> | ||
| 291 | +QPDFObject::copy(bool shallow) | ||
| 292 | +{ | ||
| 293 | + switch (getResolvedTypeCode()) { | ||
| 294 | + case ::ot_uninitialized: | ||
| 295 | + throw std::logic_error("QPDFObjectHandle: attempting to copy an uninitialized object"); | ||
| 296 | + return {}; // does not return | ||
| 297 | + case ::ot_reserved: | ||
| 298 | + return create<QPDF_Reserved>(); | ||
| 299 | + case ::ot_null: | ||
| 300 | + return create<QPDF_Null>(); | ||
| 301 | + case ::ot_boolean: | ||
| 302 | + return create<QPDF_Bool>(std::get<QPDF_Bool>(value).val); | ||
| 303 | + case ::ot_integer: | ||
| 304 | + return create<QPDF_Integer>(std::get<QPDF_Integer>(value).val); | ||
| 305 | + case ::ot_real: | ||
| 306 | + return create<QPDF_Real>(std::get<QPDF_Real>(value).val); | ||
| 307 | + case ::ot_string: | ||
| 308 | + return create<QPDF_String>(std::get<QPDF_String>(value).val); | ||
| 309 | + case ::ot_name: | ||
| 310 | + return create<QPDF_Name>(std::get<QPDF_Name>(value).name); | ||
| 311 | + case ::ot_array: | ||
| 312 | + { | ||
| 313 | + auto const& a = std::get<QPDF_Array>(value); | ||
| 314 | + if (shallow) { | ||
| 315 | + return QPDFObject::create<QPDF_Array>(a); | ||
| 316 | + } else { | ||
| 317 | + QTC::TC("qpdf", "QPDF_Array copy", a.sp ? 0 : 1); | ||
| 318 | + if (a.sp) { | ||
| 319 | + QPDF_Array result; | ||
| 320 | + result.sp = std::make_unique<QPDF_Array::Sparse>(); | ||
| 321 | + result.sp->size = a.sp->size; | ||
| 322 | + for (auto const& [idx, oh]: a.sp->elements) { | ||
| 323 | + result.sp->elements[idx] = oh.indirect() ? oh : oh.getObj()->copy(); | ||
| 324 | + } | ||
| 325 | + return QPDFObject::create<QPDF_Array>(std::move(result)); | ||
| 326 | + } else { | ||
| 327 | + std::vector<QPDFObjectHandle> result; | ||
| 328 | + result.reserve(a.elements.size()); | ||
| 329 | + for (auto const& element: a.elements) { | ||
| 330 | + result.emplace_back( | ||
| 331 | + element ? (element.indirect() ? element : element.getObj()->copy()) | ||
| 332 | + : element); | ||
| 333 | + } | ||
| 334 | + return QPDFObject::create<QPDF_Array>(std::move(result), false); | ||
| 335 | + } | ||
| 336 | + } | ||
| 337 | + } | ||
| 338 | + case ::ot_dictionary: | ||
| 339 | + { | ||
| 340 | + auto const& d = std::get<QPDF_Dictionary>(value); | ||
| 341 | + if (shallow) { | ||
| 342 | + return QPDFObject::create<QPDF_Dictionary>(d.items); | ||
| 343 | + } else { | ||
| 344 | + std::map<std::string, QPDFObjectHandle> new_items; | ||
| 345 | + for (auto const& [key, val]: d.items) { | ||
| 346 | + new_items[key] = val.indirect() ? val : val.getObj()->copy(); | ||
| 347 | + } | ||
| 348 | + return QPDFObject::create<QPDF_Dictionary>(new_items); | ||
| 349 | + } | ||
| 350 | + } | ||
| 351 | + case ::ot_stream: | ||
| 352 | + QTC::TC("qpdf", "QPDF_Stream ERR shallow copy stream"); | ||
| 353 | + throw std::runtime_error("stream objects cannot be cloned"); | ||
| 354 | + return {}; // does not return | ||
| 355 | + case ::ot_operator: | ||
| 356 | + return create<QPDF_Operator>(std::get<QPDF_Operator>(value).val); | ||
| 357 | + case ::ot_inlineimage: | ||
| 358 | + return create<QPDF_InlineImage>(std::get<QPDF_InlineImage>(value).val); | ||
| 359 | + case ::ot_unresolved: | ||
| 360 | + throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object"); | ||
| 361 | + return {}; // does not return | ||
| 362 | + case ::ot_destroyed: | ||
| 363 | + throw std::logic_error("attempted to shallow copy QPDFObjectHandle from destroyed QPDF"); | ||
| 364 | + return {}; // does not return | ||
| 365 | + case ::ot_reference: | ||
| 366 | + return qpdf->getObject(og).getObj(); | ||
| 367 | + } | ||
| 368 | + return {}; // unreachable | ||
| 369 | +} | ||
| 370 | + | ||
| 371 | +std::string | ||
| 372 | +QPDFObject::unparse() | ||
| 373 | +{ | ||
| 374 | + switch (getResolvedTypeCode()) { | ||
| 375 | + case ::ot_uninitialized: | ||
| 376 | + throw std::logic_error("QPDFObjectHandle: attempting to unparse an uninitialized object"); | ||
| 377 | + return ""; // does not return | ||
| 378 | + case ::ot_reserved: | ||
| 379 | + throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object"); | ||
| 380 | + return ""; // does not return | ||
| 381 | + case ::ot_null: | ||
| 382 | + return "null"; | ||
| 383 | + case ::ot_boolean: | ||
| 384 | + return std::get<QPDF_Bool>(value).val ? "true" : "false"; | ||
| 385 | + case ::ot_integer: | ||
| 386 | + return std::to_string(std::get<QPDF_Integer>(value).val); | ||
| 387 | + case ::ot_real: | ||
| 388 | + return std::get<QPDF_Real>(value).val; | ||
| 389 | + case ::ot_string: | ||
| 390 | + return std::get<QPDF_String>(value).unparse(false); | ||
| 391 | + case ::ot_name: | ||
| 392 | + return Name::normalize(std::get<QPDF_Name>(value).name); | ||
| 393 | + case ::ot_array: | ||
| 394 | + { | ||
| 395 | + auto const& a = std::get<QPDF_Array>(value); | ||
| 396 | + std::string result = "[ "; | ||
| 397 | + if (a.sp) { | ||
| 398 | + int next = 0; | ||
| 399 | + for (auto& item: a.sp->elements) { | ||
| 400 | + int key = item.first; | ||
| 401 | + for (int j = next; j < key; ++j) { | ||
| 402 | + result += "null "; | ||
| 403 | + } | ||
| 404 | + auto item_og = item.second.id_gen(); | ||
| 405 | + result += item_og.isIndirect() ? item_og.unparse(' ') + " R " | ||
| 406 | + : item.second.getObj()->unparse() + " "; | ||
| 407 | + next = ++key; | ||
| 408 | + } | ||
| 409 | + for (int j = next; j < a.sp->size; ++j) { | ||
| 410 | + result += "null "; | ||
| 411 | + } | ||
| 412 | + } else { | ||
| 413 | + for (auto const& item: a.elements) { | ||
| 414 | + auto item_og = item.id_gen(); | ||
| 415 | + result += item_og.isIndirect() ? item_og.unparse(' ') + " R " | ||
| 416 | + : item.getObj()->unparse() + " "; | ||
| 417 | + } | ||
| 418 | + } | ||
| 419 | + result += "]"; | ||
| 420 | + return result; | ||
| 421 | + } | ||
| 422 | + case ::ot_dictionary: | ||
| 423 | + { | ||
| 424 | + auto const& items = std::get<QPDF_Dictionary>(value).items; | ||
| 425 | + std::string result = "<< "; | ||
| 426 | + for (auto& iter: items) { | ||
| 427 | + if (!iter.second.null()) { | ||
| 428 | + result += Name::normalize(iter.first) + " " + iter.second.unparse() + " "; | ||
| 429 | + } | ||
| 430 | + } | ||
| 431 | + result += ">>"; | ||
| 432 | + return result; | ||
| 433 | + } | ||
| 434 | + case ::ot_stream: | ||
| 435 | + return og.unparse(' ') + " R"; | ||
| 436 | + case ::ot_operator: | ||
| 437 | + return std::get<QPDF_Operator>(value).val; | ||
| 438 | + case ::ot_inlineimage: | ||
| 439 | + return std::get<QPDF_InlineImage>(value).val; | ||
| 440 | + case ::ot_unresolved: | ||
| 441 | + throw std::logic_error("QPDFObjectHandle: attempting to unparse a unresolved object"); | ||
| 442 | + return ""; // does not return | ||
| 443 | + case ::ot_destroyed: | ||
| 444 | + throw std::logic_error("attempted to unparse a QPDFObjectHandle from a destroyed QPDF"); | ||
| 445 | + return ""; // does not return | ||
| 446 | + case ::ot_reference: | ||
| 447 | + return og.unparse(' ') + " R"; | ||
| 448 | + } | ||
| 449 | + return {}; // unreachable | ||
| 450 | +} | ||
| 451 | + | ||
| 452 | +void | ||
| 453 | +QPDFObject::write_json(int json_version, JSON::Writer& p) | ||
| 454 | +{ | ||
| 455 | + switch (getResolvedTypeCode()) { | ||
| 456 | + case ::ot_uninitialized: | ||
| 457 | + throw std::logic_error( | ||
| 458 | + "QPDFObjectHandle: attempting to get JSON from a uninitialized object"); | ||
| 459 | + break; // unreachable | ||
| 460 | + case ::ot_null: | ||
| 461 | + case ::ot_operator: | ||
| 462 | + case ::ot_inlineimage: | ||
| 463 | + p << "null"; | ||
| 464 | + break; | ||
| 465 | + case ::ot_boolean: | ||
| 466 | + p << std::get<QPDF_Bool>(value).val; | ||
| 467 | + break; | ||
| 468 | + case ::ot_integer: | ||
| 469 | + p << std::to_string(std::get<QPDF_Integer>(value).val); | ||
| 470 | + break; | ||
| 471 | + case ::ot_real: | ||
| 472 | + { | ||
| 473 | + auto const& val = std::get<QPDF_Real>(value).val; | ||
| 474 | + if (val.length() == 0) { | ||
| 475 | + // Can't really happen... | ||
| 476 | + p << "0"; | ||
| 477 | + } else if (val.at(0) == '.') { | ||
| 478 | + p << "0" << val; | ||
| 479 | + } else if (val.length() >= 2 && val.at(0) == '-' && val.at(1) == '.') { | ||
| 480 | + p << "-0." << val.substr(2); | ||
| 481 | + } else { | ||
| 482 | + p << val; | ||
| 483 | + } | ||
| 484 | + if (val.back() == '.') { | ||
| 485 | + p << "0"; | ||
| 486 | + } | ||
| 487 | + } | ||
| 488 | + break; | ||
| 489 | + case ::ot_string: | ||
| 490 | + std::get<QPDF_String>(value).writeJSON(json_version, p); | ||
| 491 | + break; | ||
| 492 | + case ::ot_name: | ||
| 493 | + { | ||
| 494 | + auto const& n = std::get<QPDF_Name>(value); | ||
| 495 | + // For performance reasons this code is duplicated in QPDF_Dictionary::writeJSON. When | ||
| 496 | + // updating this method make sure QPDF_Dictionary is also update. | ||
| 497 | + if (json_version == 1) { | ||
| 498 | + p << "\"" << JSON::Writer::encode_string(Name::normalize(n.name)) << "\""; | ||
| 499 | + } else { | ||
| 500 | + if (auto res = Name::analyzeJSONEncoding(n.name); res.first) { | ||
| 501 | + if (res.second) { | ||
| 502 | + p << "\"" << n.name << "\""; | ||
| 503 | + } else { | ||
| 504 | + p << "\"" << JSON::Writer::encode_string(n.name) << "\""; | ||
| 505 | + } | ||
| 506 | + } else { | ||
| 507 | + p << "\"n:" << JSON::Writer::encode_string(Name::normalize(n.name)) << "\""; | ||
| 508 | + } | ||
| 509 | + } | ||
| 510 | + } | ||
| 511 | + break; | ||
| 512 | + case ::ot_array: | ||
| 513 | + { | ||
| 514 | + auto const& a = std::get<QPDF_Array>(value); | ||
| 515 | + p.writeStart('['); | ||
| 516 | + if (a.sp) { | ||
| 517 | + int next = 0; | ||
| 518 | + for (auto& item: a.sp->elements) { | ||
| 519 | + int key = item.first; | ||
| 520 | + for (int j = next; j < key; ++j) { | ||
| 521 | + p.writeNext() << "null"; | ||
| 522 | + } | ||
| 523 | + p.writeNext(); | ||
| 524 | + auto item_og = item.second.getObj()->getObjGen(); | ||
| 525 | + if (item_og.isIndirect()) { | ||
| 526 | + p << "\"" << item_og.unparse(' ') << " R\""; | ||
| 527 | + } else { | ||
| 528 | + item.second.getObj()->write_json(json_version, p); | ||
| 529 | + } | ||
| 530 | + next = ++key; | ||
| 531 | + } | ||
| 532 | + for (int j = next; j < a.sp->size; ++j) { | ||
| 533 | + p.writeNext() << "null"; | ||
| 534 | + } | ||
| 535 | + } else { | ||
| 536 | + for (auto const& item: a.elements) { | ||
| 537 | + p.writeNext(); | ||
| 538 | + auto item_og = item.getObj()->getObjGen(); | ||
| 539 | + if (item_og.isIndirect()) { | ||
| 540 | + p << "\"" << item_og.unparse(' ') << " R\""; | ||
| 541 | + } else { | ||
| 542 | + item.getObj()->write_json(json_version, p); | ||
| 543 | + } | ||
| 544 | + } | ||
| 545 | + } | ||
| 546 | + p.writeEnd(']'); | ||
| 547 | + } | ||
| 548 | + break; | ||
| 549 | + case ::ot_dictionary: | ||
| 550 | + { | ||
| 551 | + auto const& d = std::get<QPDF_Dictionary>(value); | ||
| 552 | + p.writeStart('{'); | ||
| 553 | + for (auto& iter: d.items) { | ||
| 554 | + if (!iter.second.null()) { | ||
| 555 | + p.writeNext(); | ||
| 556 | + if (json_version == 1) { | ||
| 557 | + p << "\"" << JSON::Writer::encode_string(Name::normalize(iter.first)) | ||
| 558 | + << "\": "; | ||
| 559 | + } else if (auto res = Name::analyzeJSONEncoding(iter.first); res.first) { | ||
| 560 | + if (res.second) { | ||
| 561 | + p << "\"" << iter.first << "\": "; | ||
| 562 | + } else { | ||
| 563 | + p << "\"" << JSON::Writer::encode_string(iter.first) << "\": "; | ||
| 564 | + } | ||
| 565 | + } else { | ||
| 566 | + p << "\"n:" << JSON::Writer::encode_string(Name::normalize(iter.first)) | ||
| 567 | + << "\": "; | ||
| 568 | + } | ||
| 569 | + iter.second.writeJSON(json_version, p); | ||
| 570 | + } | ||
| 571 | + } | ||
| 572 | + p.writeEnd('}'); | ||
| 573 | + } | ||
| 574 | + break; | ||
| 575 | + case ::ot_stream: | ||
| 576 | + std::get<QPDF_Stream>(value).m->stream_dict.writeJSON(json_version, p); | ||
| 577 | + break; | ||
| 578 | + case ::ot_reference: | ||
| 579 | + p << "\"" << getObjGen().unparse(' ') << " R\""; | ||
| 580 | + break; | ||
| 581 | + default: | ||
| 582 | + throw std::logic_error("attempted to write an unsuitable object as JSON"); | ||
| 583 | + } | ||
| 584 | +} | ||
| 585 | + | ||
| 586 | +void | ||
| 587 | +QPDFObject::disconnect() | ||
| 588 | +{ | ||
| 589 | + // Disconnect an object from its owning QPDF. This is called by QPDF's destructor. | ||
| 590 | + | ||
| 591 | + switch (getTypeCode()) { | ||
| 592 | + case ::ot_array: | ||
| 593 | + { | ||
| 594 | + auto& a = std::get<QPDF_Array>(value); | ||
| 595 | + if (a.sp) { | ||
| 596 | + for (auto& item: a.sp->elements) { | ||
| 597 | + auto& obj = item.second; | ||
| 598 | + if (!obj.indirect()) { | ||
| 599 | + obj.getObj()->disconnect(); | ||
| 600 | + } | ||
| 601 | + } | ||
| 602 | + } else { | ||
| 603 | + for (auto& obj: a.elements) { | ||
| 604 | + if (!obj.indirect()) { | ||
| 605 | + obj.getObj()->disconnect(); | ||
| 606 | + } | ||
| 607 | + } | ||
| 608 | + } | ||
| 609 | + } | ||
| 610 | + break; | ||
| 611 | + case ::ot_dictionary: | ||
| 612 | + for (auto& iter: std::get<QPDF_Dictionary>(value).items) { | ||
| 613 | + QPDFObjectHandle::DisconnectAccess::disconnect(iter.second); | ||
| 614 | + } | ||
| 615 | + break; | ||
| 616 | + case ::ot_stream: | ||
| 617 | + { | ||
| 618 | + auto& s = std::get<QPDF_Stream>(value); | ||
| 619 | + s.m->stream_provider = nullptr; | ||
| 620 | + QPDFObjectHandle::DisconnectAccess::disconnect(s.m->stream_dict); | ||
| 621 | + } | ||
| 622 | + break; | ||
| 623 | + default: | ||
| 624 | + break; | ||
| 625 | + } | ||
| 626 | + qpdf = nullptr; | ||
| 627 | + og = QPDFObjGen(); | ||
| 628 | +} | ||
| 629 | +std::string | ||
| 630 | +QPDFObject::getStringValue() const | ||
| 631 | +{ | ||
| 632 | + switch (getResolvedTypeCode()) { | ||
| 633 | + case ::ot_real: | ||
| 634 | + return std::get<QPDF_Real>(value).val; | ||
| 635 | + case ::ot_string: | ||
| 636 | + return std::get<QPDF_String>(value).val; | ||
| 637 | + case ::ot_name: | ||
| 638 | + return std::get<QPDF_Name>(value).name; | ||
| 639 | + case ::ot_operator: | ||
| 640 | + return std::get<QPDF_Operator>(value).val; | ||
| 641 | + case ::ot_inlineimage: | ||
| 642 | + return std::get<QPDF_InlineImage>(value).val; | ||
| 643 | + case ::ot_reference: | ||
| 644 | + return std::get<QPDF_Reference>(value).obj->getStringValue(); | ||
| 645 | + default: | ||
| 646 | + throw std::logic_error("Internal error in QPDFObject::getStringValue"); | ||
| 647 | + } | ||
| 648 | + return ""; // unreachable | ||
| 649 | +} | ||
| 650 | + | ||
| 224 | bool | 651 | bool |
| 225 | -QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const noexcept | 652 | +QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const |
| 226 | { | 653 | { |
| 227 | return this->obj == rhs.obj; | 654 | return this->obj == rhs.obj; |
| 228 | } | 655 | } |
| @@ -246,7 +673,7 @@ QPDFObjectHandle::getTypeCode() const | @@ -246,7 +673,7 @@ QPDFObjectHandle::getTypeCode() const | ||
| 246 | char const* | 673 | char const* |
| 247 | QPDFObjectHandle::getTypeName() const | 674 | QPDFObjectHandle::getTypeName() const |
| 248 | { | 675 | { |
| 249 | - static constexpr std::array<char const*, 15> tn{ | 676 | + static constexpr std::array<char const*, 16> tn{ |
| 250 | "uninitialized", | 677 | "uninitialized", |
| 251 | "reserved", | 678 | "reserved", |
| 252 | "null", | 679 | "null", |
| @@ -261,100 +688,21 @@ QPDFObjectHandle::getTypeName() const | @@ -261,100 +688,21 @@ QPDFObjectHandle::getTypeName() const | ||
| 261 | "operator", | 688 | "operator", |
| 262 | "inline-image", | 689 | "inline-image", |
| 263 | "unresolved", | 690 | "unresolved", |
| 264 | - "destroyed"}; | 691 | + "destroyed", |
| 692 | + "reference"}; | ||
| 265 | return obj ? tn[getTypeCode()] : "uninitialized"; | 693 | return obj ? tn[getTypeCode()] : "uninitialized"; |
| 266 | } | 694 | } |
| 267 | 695 | ||
| 268 | -QPDF_Array* | ||
| 269 | -QPDFObjectHandle::asArray() const | ||
| 270 | -{ | ||
| 271 | - return obj ? obj->as<QPDF_Array>() : nullptr; | ||
| 272 | -} | ||
| 273 | - | ||
| 274 | -QPDF_Bool* | ||
| 275 | -QPDFObjectHandle::asBool() const | ||
| 276 | -{ | ||
| 277 | - return obj ? obj->as<QPDF_Bool>() : nullptr; | ||
| 278 | -} | ||
| 279 | - | ||
| 280 | -QPDF_Dictionary* | ||
| 281 | -QPDFObjectHandle::asDictionary() const | ||
| 282 | -{ | ||
| 283 | - return obj ? obj->as<QPDF_Dictionary>() : nullptr; | ||
| 284 | -} | ||
| 285 | - | ||
| 286 | -QPDF_InlineImage* | ||
| 287 | -QPDFObjectHandle::asInlineImage() const | ||
| 288 | -{ | ||
| 289 | - return obj ? obj->as<QPDF_InlineImage>() : nullptr; | ||
| 290 | -} | ||
| 291 | - | ||
| 292 | -QPDF_Integer* | ||
| 293 | -QPDFObjectHandle::asInteger() const | ||
| 294 | -{ | ||
| 295 | - return obj ? obj->as<QPDF_Integer>() : nullptr; | ||
| 296 | -} | ||
| 297 | - | ||
| 298 | -QPDF_Name* | ||
| 299 | -QPDFObjectHandle::asName() const | ||
| 300 | -{ | ||
| 301 | - return obj ? obj->as<QPDF_Name>() : nullptr; | ||
| 302 | -} | ||
| 303 | - | ||
| 304 | -QPDF_Null* | ||
| 305 | -QPDFObjectHandle::asNull() const | ||
| 306 | -{ | ||
| 307 | - return obj ? obj->as<QPDF_Null>() : nullptr; | ||
| 308 | -} | ||
| 309 | - | ||
| 310 | -QPDF_Operator* | ||
| 311 | -QPDFObjectHandle::asOperator() const | ||
| 312 | -{ | ||
| 313 | - return obj ? obj->as<QPDF_Operator>() : nullptr; | ||
| 314 | -} | ||
| 315 | - | ||
| 316 | -QPDF_Real* | ||
| 317 | -QPDFObjectHandle::asReal() const | ||
| 318 | -{ | ||
| 319 | - return obj ? obj->as<QPDF_Real>() : nullptr; | ||
| 320 | -} | ||
| 321 | - | ||
| 322 | -QPDF_Reserved* | ||
| 323 | -QPDFObjectHandle::asReserved() const | ||
| 324 | -{ | ||
| 325 | - return obj ? obj->as<QPDF_Reserved>() : nullptr; | ||
| 326 | -} | ||
| 327 | - | ||
| 328 | -QPDF_Stream* | ||
| 329 | -QPDFObjectHandle::asStream() const | ||
| 330 | -{ | ||
| 331 | - return obj ? obj->as<QPDF_Stream>() : nullptr; | ||
| 332 | -} | ||
| 333 | - | ||
| 334 | -QPDF_Stream* | ||
| 335 | -QPDFObjectHandle::asStreamWithAssert() const | ||
| 336 | -{ | ||
| 337 | - auto stream = asStream(); | ||
| 338 | - assertType("stream", stream); | ||
| 339 | - return stream; | ||
| 340 | -} | ||
| 341 | - | ||
| 342 | -QPDF_String* | ||
| 343 | -QPDFObjectHandle::asString() const | ||
| 344 | -{ | ||
| 345 | - return obj ? obj->as<QPDF_String>() : nullptr; | ||
| 346 | -} | ||
| 347 | - | ||
| 348 | bool | 696 | bool |
| 349 | QPDFObjectHandle::isDestroyed() const | 697 | QPDFObjectHandle::isDestroyed() const |
| 350 | { | 698 | { |
| 351 | - return obj && obj->getResolvedTypeCode() == ::ot_destroyed; | 699 | + return type_code() == ::ot_destroyed; |
| 352 | } | 700 | } |
| 353 | 701 | ||
| 354 | bool | 702 | bool |
| 355 | QPDFObjectHandle::isBool() const | 703 | QPDFObjectHandle::isBool() const |
| 356 | { | 704 | { |
| 357 | - return obj && obj->getResolvedTypeCode() == ::ot_boolean; | 705 | + return type_code() == ::ot_boolean; |
| 358 | } | 706 | } |
| 359 | 707 | ||
| 360 | bool | 708 | bool |
| @@ -362,25 +710,25 @@ QPDFObjectHandle::isDirectNull() const | @@ -362,25 +710,25 @@ QPDFObjectHandle::isDirectNull() const | ||
| 362 | { | 710 | { |
| 363 | // Don't call dereference() -- this is a const method, and we know | 711 | // Don't call dereference() -- this is a const method, and we know |
| 364 | // objid == 0, so there's nothing to resolve. | 712 | // objid == 0, so there's nothing to resolve. |
| 365 | - return (obj && getObjectID() == 0 && obj->getTypeCode() == ::ot_null); | 713 | + return !indirect() && raw_type_code() == ::ot_null; |
| 366 | } | 714 | } |
| 367 | 715 | ||
| 368 | bool | 716 | bool |
| 369 | QPDFObjectHandle::isNull() const | 717 | QPDFObjectHandle::isNull() const |
| 370 | { | 718 | { |
| 371 | - return obj && obj->getResolvedTypeCode() == ::ot_null; | 719 | + return type_code() == ::ot_null; |
| 372 | } | 720 | } |
| 373 | 721 | ||
| 374 | bool | 722 | bool |
| 375 | QPDFObjectHandle::isInteger() const | 723 | QPDFObjectHandle::isInteger() const |
| 376 | { | 724 | { |
| 377 | - return obj && obj->getResolvedTypeCode() == ::ot_integer; | 725 | + return type_code() == ::ot_integer; |
| 378 | } | 726 | } |
| 379 | 727 | ||
| 380 | bool | 728 | bool |
| 381 | QPDFObjectHandle::isReal() const | 729 | QPDFObjectHandle::isReal() const |
| 382 | { | 730 | { |
| 383 | - return obj && obj->getResolvedTypeCode() == ::ot_real; | 731 | + return type_code() == ::ot_real; |
| 384 | } | 732 | } |
| 385 | 733 | ||
| 386 | bool | 734 | bool |
| @@ -416,49 +764,49 @@ QPDFObjectHandle::getValueAsNumber(double& value) const | @@ -416,49 +764,49 @@ QPDFObjectHandle::getValueAsNumber(double& value) const | ||
| 416 | bool | 764 | bool |
| 417 | QPDFObjectHandle::isName() const | 765 | QPDFObjectHandle::isName() const |
| 418 | { | 766 | { |
| 419 | - return obj && obj->getResolvedTypeCode() == ::ot_name; | 767 | + return type_code() == ::ot_name; |
| 420 | } | 768 | } |
| 421 | 769 | ||
| 422 | bool | 770 | bool |
| 423 | QPDFObjectHandle::isString() const | 771 | QPDFObjectHandle::isString() const |
| 424 | { | 772 | { |
| 425 | - return obj && obj->getResolvedTypeCode() == ::ot_string; | 773 | + return type_code() == ::ot_string; |
| 426 | } | 774 | } |
| 427 | 775 | ||
| 428 | bool | 776 | bool |
| 429 | QPDFObjectHandle::isOperator() const | 777 | QPDFObjectHandle::isOperator() const |
| 430 | { | 778 | { |
| 431 | - return obj && obj->getResolvedTypeCode() == ::ot_operator; | 779 | + return type_code() == ::ot_operator; |
| 432 | } | 780 | } |
| 433 | 781 | ||
| 434 | bool | 782 | bool |
| 435 | QPDFObjectHandle::isInlineImage() const | 783 | QPDFObjectHandle::isInlineImage() const |
| 436 | { | 784 | { |
| 437 | - return obj && obj->getResolvedTypeCode() == ::ot_inlineimage; | 785 | + return type_code() == ::ot_inlineimage; |
| 438 | } | 786 | } |
| 439 | 787 | ||
| 440 | bool | 788 | bool |
| 441 | QPDFObjectHandle::isArray() const | 789 | QPDFObjectHandle::isArray() const |
| 442 | { | 790 | { |
| 443 | - return obj && obj->getResolvedTypeCode() == ::ot_array; | 791 | + return type_code() == ::ot_array; |
| 444 | } | 792 | } |
| 445 | 793 | ||
| 446 | bool | 794 | bool |
| 447 | QPDFObjectHandle::isDictionary() const | 795 | QPDFObjectHandle::isDictionary() const |
| 448 | { | 796 | { |
| 449 | - return obj && obj->getResolvedTypeCode() == ::ot_dictionary; | 797 | + return type_code() == ::ot_dictionary; |
| 450 | } | 798 | } |
| 451 | 799 | ||
| 452 | bool | 800 | bool |
| 453 | QPDFObjectHandle::isStream() const | 801 | QPDFObjectHandle::isStream() const |
| 454 | { | 802 | { |
| 455 | - return obj && obj->getResolvedTypeCode() == ::ot_stream; | 803 | + return type_code() == ::ot_stream; |
| 456 | } | 804 | } |
| 457 | 805 | ||
| 458 | bool | 806 | bool |
| 459 | QPDFObjectHandle::isReserved() const | 807 | QPDFObjectHandle::isReserved() const |
| 460 | { | 808 | { |
| 461 | - return obj && obj->getResolvedTypeCode() == ::ot_reserved; | 809 | + return type_code() == ::ot_reserved; |
| 462 | } | 810 | } |
| 463 | 811 | ||
| 464 | bool | 812 | bool |
| @@ -491,9 +839,8 @@ QPDFObjectHandle::isStreamOfType(std::string const& type, std::string const& sub | @@ -491,9 +839,8 @@ QPDFObjectHandle::isStreamOfType(std::string const& type, std::string const& sub | ||
| 491 | bool | 839 | bool |
| 492 | QPDFObjectHandle::getBoolValue() const | 840 | QPDFObjectHandle::getBoolValue() const |
| 493 | { | 841 | { |
| 494 | - auto boolean = asBool(); | ||
| 495 | - if (boolean) { | ||
| 496 | - return boolean->getVal(); | 842 | + if (auto boolean = as<QPDF_Bool>()) { |
| 843 | + return boolean->val; | ||
| 497 | } else { | 844 | } else { |
| 498 | typeWarning("boolean", "returning false"); | 845 | typeWarning("boolean", "returning false"); |
| 499 | QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); | 846 | QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); |
| @@ -504,12 +851,11 @@ QPDFObjectHandle::getBoolValue() const | @@ -504,12 +851,11 @@ QPDFObjectHandle::getBoolValue() const | ||
| 504 | bool | 851 | bool |
| 505 | QPDFObjectHandle::getValueAsBool(bool& value) const | 852 | QPDFObjectHandle::getValueAsBool(bool& value) const |
| 506 | { | 853 | { |
| 507 | - auto boolean = asBool(); | ||
| 508 | - if (boolean == nullptr) { | ||
| 509 | - return false; | 854 | + if (auto boolean = as<QPDF_Bool>()) { |
| 855 | + value = boolean->val; | ||
| 856 | + return true; | ||
| 510 | } | 857 | } |
| 511 | - value = boolean->getVal(); | ||
| 512 | - return true; | 858 | + return false; |
| 513 | } | 859 | } |
| 514 | 860 | ||
| 515 | // Integer accessors | 861 | // Integer accessors |
| @@ -517,9 +863,8 @@ QPDFObjectHandle::getValueAsBool(bool& value) const | @@ -517,9 +863,8 @@ QPDFObjectHandle::getValueAsBool(bool& value) const | ||
| 517 | long long | 863 | long long |
| 518 | QPDFObjectHandle::getIntValue() const | 864 | QPDFObjectHandle::getIntValue() const |
| 519 | { | 865 | { |
| 520 | - auto integer = asInteger(); | ||
| 521 | - if (integer) { | ||
| 522 | - return integer->getVal(); | 866 | + if (auto integer = as<QPDF_Integer>()) { |
| 867 | + return integer->val; | ||
| 523 | } else { | 868 | } else { |
| 524 | typeWarning("integer", "returning 0"); | 869 | typeWarning("integer", "returning 0"); |
| 525 | QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); | 870 | QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); |
| @@ -530,12 +875,11 @@ QPDFObjectHandle::getIntValue() const | @@ -530,12 +875,11 @@ QPDFObjectHandle::getIntValue() const | ||
| 530 | bool | 875 | bool |
| 531 | QPDFObjectHandle::getValueAsInt(long long& value) const | 876 | QPDFObjectHandle::getValueAsInt(long long& value) const |
| 532 | { | 877 | { |
| 533 | - auto integer = asInteger(); | ||
| 534 | - if (integer == nullptr) { | ||
| 535 | - return false; | 878 | + if (auto integer = as<QPDF_Integer>()) { |
| 879 | + value = integer->val; | ||
| 880 | + return true; | ||
| 536 | } | 881 | } |
| 537 | - value = integer->getVal(); | ||
| 538 | - return true; | 882 | + return false; |
| 539 | } | 883 | } |
| 540 | 884 | ||
| 541 | int | 885 | int |
| @@ -692,8 +1036,7 @@ QPDFObjectHandle::getValueAsString(std::string& value) const | @@ -692,8 +1036,7 @@ QPDFObjectHandle::getValueAsString(std::string& value) const | ||
| 692 | std::string | 1036 | std::string |
| 693 | QPDFObjectHandle::getUTF8Value() const | 1037 | QPDFObjectHandle::getUTF8Value() const |
| 694 | { | 1038 | { |
| 695 | - auto str = asString(); | ||
| 696 | - if (str) { | 1039 | + if (auto str = as<QPDF_String>()) { |
| 697 | return str->getUTF8Val(); | 1040 | return str->getUTF8Val(); |
| 698 | } else { | 1041 | } else { |
| 699 | typeWarning("string", "returning empty string"); | 1042 | typeWarning("string", "returning empty string"); |
| @@ -705,12 +1048,11 @@ QPDFObjectHandle::getUTF8Value() const | @@ -705,12 +1048,11 @@ QPDFObjectHandle::getUTF8Value() const | ||
| 705 | bool | 1048 | bool |
| 706 | QPDFObjectHandle::getValueAsUTF8(std::string& value) const | 1049 | QPDFObjectHandle::getValueAsUTF8(std::string& value) const |
| 707 | { | 1050 | { |
| 708 | - auto str = asString(); | ||
| 709 | - if (str == nullptr) { | ||
| 710 | - return false; | 1051 | + if (auto str = as<QPDF_String>()) { |
| 1052 | + value = str->getUTF8Val(); | ||
| 1053 | + return true; | ||
| 711 | } | 1054 | } |
| 712 | - value = str->getUTF8Val(); | ||
| 713 | - return true; | 1055 | + return false; |
| 714 | } | 1056 | } |
| 715 | 1057 | ||
| 716 | // Operator and Inline Image accessors | 1058 | // Operator and Inline Image accessors |
| @@ -759,7 +1101,7 @@ QPDFObjectHandle::getValueAsInlineImage(std::string& value) const | @@ -759,7 +1101,7 @@ QPDFObjectHandle::getValueAsInlineImage(std::string& value) const | ||
| 759 | return true; | 1101 | return true; |
| 760 | } | 1102 | } |
| 761 | 1103 | ||
| 762 | -// Array accessors | 1104 | +// Array accessors and mutators are in QPDF_Array.cc |
| 763 | 1105 | ||
| 764 | QPDFObjectHandle::QPDFArrayItems | 1106 | QPDFObjectHandle::QPDFArrayItems |
| 765 | QPDFObjectHandle::aitems() | 1107 | QPDFObjectHandle::aitems() |
| @@ -767,207 +1109,7 @@ QPDFObjectHandle::aitems() | @@ -767,207 +1109,7 @@ QPDFObjectHandle::aitems() | ||
| 767 | return *this; | 1109 | return *this; |
| 768 | } | 1110 | } |
| 769 | 1111 | ||
| 770 | -int | ||
| 771 | -QPDFObjectHandle::getArrayNItems() const | ||
| 772 | -{ | ||
| 773 | - if (auto array = asArray()) { | ||
| 774 | - return array->size(); | ||
| 775 | - } else { | ||
| 776 | - typeWarning("array", "treating as empty"); | ||
| 777 | - QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); | ||
| 778 | - return 0; | ||
| 779 | - } | ||
| 780 | -} | ||
| 781 | - | ||
| 782 | -QPDFObjectHandle | ||
| 783 | -QPDFObjectHandle::getArrayItem(int n) const | ||
| 784 | -{ | ||
| 785 | - if (auto array = asArray()) { | ||
| 786 | - auto result = array->at(n); | ||
| 787 | - if (result.first) { | ||
| 788 | - return result.second; | ||
| 789 | - } else { | ||
| 790 | - objectWarning("returning null for out of bounds array access"); | ||
| 791 | - QTC::TC("qpdf", "QPDFObjectHandle array bounds"); | ||
| 792 | - } | ||
| 793 | - } else { | ||
| 794 | - typeWarning("array", "returning null"); | ||
| 795 | - QTC::TC("qpdf", "QPDFObjectHandle array null for non-array"); | ||
| 796 | - } | ||
| 797 | - static auto constexpr msg = " -> null returned from invalid array access"sv; | ||
| 798 | - return QPDF_Null::create(obj, msg, ""); | ||
| 799 | -} | ||
| 800 | - | ||
| 801 | -bool | ||
| 802 | -QPDFObjectHandle::isRectangle() const | ||
| 803 | -{ | ||
| 804 | - if (auto array = asArray()) { | ||
| 805 | - for (int i = 0; i < 4; ++i) { | ||
| 806 | - if (auto item = array->at(i).second; !item.isNumber()) { | ||
| 807 | - return false; | ||
| 808 | - } | ||
| 809 | - } | ||
| 810 | - return array->size() == 4; | ||
| 811 | - } | ||
| 812 | - return false; | ||
| 813 | -} | ||
| 814 | - | ||
| 815 | -bool | ||
| 816 | -QPDFObjectHandle::isMatrix() const | ||
| 817 | -{ | ||
| 818 | - if (auto array = asArray()) { | ||
| 819 | - for (int i = 0; i < 6; ++i) { | ||
| 820 | - if (auto item = array->at(i).second; !item.isNumber()) { | ||
| 821 | - return false; | ||
| 822 | - } | ||
| 823 | - } | ||
| 824 | - return array->size() == 6; | ||
| 825 | - } | ||
| 826 | - return false; | ||
| 827 | -} | ||
| 828 | - | ||
| 829 | -QPDFObjectHandle::Rectangle | ||
| 830 | -QPDFObjectHandle::getArrayAsRectangle() const | ||
| 831 | -{ | ||
| 832 | - if (auto array = asArray()) { | ||
| 833 | - if (array->size() != 4) { | ||
| 834 | - return {}; | ||
| 835 | - } | ||
| 836 | - double items[4]; | ||
| 837 | - for (int i = 0; i < 4; ++i) { | ||
| 838 | - if (auto item = array->at(i).second; !item.getValueAsNumber(items[i])) { | ||
| 839 | - return {}; | ||
| 840 | - } | ||
| 841 | - } | ||
| 842 | - return { | ||
| 843 | - std::min(items[0], items[2]), | ||
| 844 | - std::min(items[1], items[3]), | ||
| 845 | - std::max(items[0], items[2]), | ||
| 846 | - std::max(items[1], items[3])}; | ||
| 847 | - } | ||
| 848 | - return {}; | ||
| 849 | -} | ||
| 850 | - | ||
| 851 | -QPDFObjectHandle::Matrix | ||
| 852 | -QPDFObjectHandle::getArrayAsMatrix() const | ||
| 853 | -{ | ||
| 854 | - if (auto array = asArray()) { | ||
| 855 | - if (array->size() != 6) { | ||
| 856 | - return {}; | ||
| 857 | - } | ||
| 858 | - double items[6]; | ||
| 859 | - for (int i = 0; i < 6; ++i) { | ||
| 860 | - if (auto item = array->at(i).second; !item.getValueAsNumber(items[i])) { | ||
| 861 | - return {}; | ||
| 862 | - } | ||
| 863 | - } | ||
| 864 | - return {items[0], items[1], items[2], items[3], items[4], items[5]}; | ||
| 865 | - } | ||
| 866 | - return {}; | ||
| 867 | -} | ||
| 868 | - | ||
| 869 | -std::vector<QPDFObjectHandle> | ||
| 870 | -QPDFObjectHandle::getArrayAsVector() const | ||
| 871 | -{ | ||
| 872 | - auto array = asArray(); | ||
| 873 | - if (array) { | ||
| 874 | - return array->getAsVector(); | ||
| 875 | - } else { | ||
| 876 | - typeWarning("array", "treating as empty"); | ||
| 877 | - QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector"); | ||
| 878 | - } | ||
| 879 | - return {}; | ||
| 880 | -} | ||
| 881 | - | ||
| 882 | -// Array mutators | ||
| 883 | - | ||
| 884 | -void | ||
| 885 | -QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item) | ||
| 886 | -{ | ||
| 887 | - if (auto array = asArray()) { | ||
| 888 | - if (!array->setAt(n, item)) { | ||
| 889 | - objectWarning("ignoring attempt to set out of bounds array item"); | ||
| 890 | - QTC::TC("qpdf", "QPDFObjectHandle set array bounds"); | ||
| 891 | - } | ||
| 892 | - } else { | ||
| 893 | - typeWarning("array", "ignoring attempt to set item"); | ||
| 894 | - QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item"); | ||
| 895 | - } | ||
| 896 | -} | ||
| 897 | -void | ||
| 898 | -QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items) | ||
| 899 | -{ | ||
| 900 | - if (auto array = asArray()) { | ||
| 901 | - array->setFromVector(items); | ||
| 902 | - } else { | ||
| 903 | - typeWarning("array", "ignoring attempt to replace items"); | ||
| 904 | - QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items"); | ||
| 905 | - } | ||
| 906 | -} | ||
| 907 | - | ||
| 908 | -void | ||
| 909 | -QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item) | ||
| 910 | -{ | ||
| 911 | - if (auto array = asArray()) { | ||
| 912 | - if (!array->insert(at, item)) { | ||
| 913 | - objectWarning("ignoring attempt to insert out of bounds array item"); | ||
| 914 | - QTC::TC("qpdf", "QPDFObjectHandle insert array bounds"); | ||
| 915 | - } | ||
| 916 | - } else { | ||
| 917 | - typeWarning("array", "ignoring attempt to insert item"); | ||
| 918 | - QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item"); | ||
| 919 | - } | ||
| 920 | -} | ||
| 921 | - | ||
| 922 | -QPDFObjectHandle | ||
| 923 | -QPDFObjectHandle::insertItemAndGetNew(int at, QPDFObjectHandle const& item) | ||
| 924 | -{ | ||
| 925 | - insertItem(at, item); | ||
| 926 | - return item; | ||
| 927 | -} | ||
| 928 | - | ||
| 929 | -void | ||
| 930 | -QPDFObjectHandle::appendItem(QPDFObjectHandle const& item) | ||
| 931 | -{ | ||
| 932 | - if (auto array = asArray()) { | ||
| 933 | - array->push_back(item); | ||
| 934 | - } else { | ||
| 935 | - typeWarning("array", "ignoring attempt to append item"); | ||
| 936 | - QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item"); | ||
| 937 | - } | ||
| 938 | -} | ||
| 939 | - | ||
| 940 | -QPDFObjectHandle | ||
| 941 | -QPDFObjectHandle::appendItemAndGetNew(QPDFObjectHandle const& item) | ||
| 942 | -{ | ||
| 943 | - appendItem(item); | ||
| 944 | - return item; | ||
| 945 | -} | ||
| 946 | - | ||
| 947 | -void | ||
| 948 | -QPDFObjectHandle::eraseItem(int at) | ||
| 949 | -{ | ||
| 950 | - if (auto array = asArray()) { | ||
| 951 | - if (!array->erase(at)) { | ||
| 952 | - objectWarning("ignoring attempt to erase out of bounds array item"); | ||
| 953 | - QTC::TC("qpdf", "QPDFObjectHandle erase array bounds"); | ||
| 954 | - } | ||
| 955 | - } else { | ||
| 956 | - typeWarning("array", "ignoring attempt to erase item"); | ||
| 957 | - QTC::TC("qpdf", "QPDFObjectHandle array ignoring erase item"); | ||
| 958 | - } | ||
| 959 | -} | ||
| 960 | - | ||
| 961 | -QPDFObjectHandle | ||
| 962 | -QPDFObjectHandle::eraseItemAndGetOld(int at) | ||
| 963 | -{ | ||
| 964 | - auto array = asArray(); | ||
| 965 | - auto result = (array && at < array->size() && at >= 0) ? array->at(at).second : newNull(); | ||
| 966 | - eraseItem(at); | ||
| 967 | - return result; | ||
| 968 | -} | ||
| 969 | - | ||
| 970 | -// Dictionary accessors | 1112 | +// Dictionary accessors are in QPDF_Dictionary.cc |
| 971 | 1113 | ||
| 972 | QPDFObjectHandle::QPDFDictItems | 1114 | QPDFObjectHandle::QPDFDictItems |
| 973 | QPDFObjectHandle::ditems() | 1115 | QPDFObjectHandle::ditems() |
| @@ -975,66 +1117,6 @@ QPDFObjectHandle::ditems() | @@ -975,66 +1117,6 @@ QPDFObjectHandle::ditems() | ||
| 975 | return {*this}; | 1117 | return {*this}; |
| 976 | } | 1118 | } |
| 977 | 1119 | ||
| 978 | -bool | ||
| 979 | -QPDFObjectHandle::hasKey(std::string const& key) const | ||
| 980 | -{ | ||
| 981 | - auto dict = asDictionary(); | ||
| 982 | - if (dict) { | ||
| 983 | - return dict->hasKey(key); | ||
| 984 | - } else { | ||
| 985 | - typeWarning("dictionary", "returning false for a key containment request"); | ||
| 986 | - QTC::TC("qpdf", "QPDFObjectHandle dictionary false for hasKey"); | ||
| 987 | - return false; | ||
| 988 | - } | ||
| 989 | -} | ||
| 990 | - | ||
| 991 | -QPDFObjectHandle | ||
| 992 | -QPDFObjectHandle::getKey(std::string const& key) const | ||
| 993 | -{ | ||
| 994 | - if (auto dict = asDictionary()) { | ||
| 995 | - return dict->getKey(key); | ||
| 996 | - } else { | ||
| 997 | - typeWarning("dictionary", "returning null for attempted key retrieval"); | ||
| 998 | - QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey"); | ||
| 999 | - static auto constexpr msg = " -> null returned from getting key $VD from non-Dictionary"sv; | ||
| 1000 | - return QPDF_Null::create(obj, msg, ""); | ||
| 1001 | - } | ||
| 1002 | -} | ||
| 1003 | - | ||
| 1004 | -QPDFObjectHandle | ||
| 1005 | -QPDFObjectHandle::getKeyIfDict(std::string const& key) const | ||
| 1006 | -{ | ||
| 1007 | - return isNull() ? newNull() : getKey(key); | ||
| 1008 | -} | ||
| 1009 | - | ||
| 1010 | -std::set<std::string> | ||
| 1011 | -QPDFObjectHandle::getKeys() const | ||
| 1012 | -{ | ||
| 1013 | - std::set<std::string> result; | ||
| 1014 | - auto dict = asDictionary(); | ||
| 1015 | - if (dict) { | ||
| 1016 | - result = dict->getKeys(); | ||
| 1017 | - } else { | ||
| 1018 | - typeWarning("dictionary", "treating as empty"); | ||
| 1019 | - QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys"); | ||
| 1020 | - } | ||
| 1021 | - return result; | ||
| 1022 | -} | ||
| 1023 | - | ||
| 1024 | -std::map<std::string, QPDFObjectHandle> | ||
| 1025 | -QPDFObjectHandle::getDictAsMap() const | ||
| 1026 | -{ | ||
| 1027 | - std::map<std::string, QPDFObjectHandle> result; | ||
| 1028 | - auto dict = asDictionary(); | ||
| 1029 | - if (dict) { | ||
| 1030 | - result = dict->getAsMap(); | ||
| 1031 | - } else { | ||
| 1032 | - typeWarning("dictionary", "treating as empty"); | ||
| 1033 | - QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap"); | ||
| 1034 | - } | ||
| 1035 | - return result; | ||
| 1036 | -} | ||
| 1037 | - | ||
| 1038 | // Array and Name accessors | 1120 | // Array and Name accessors |
| 1039 | 1121 | ||
| 1040 | bool | 1122 | bool |
| @@ -1055,19 +1137,10 @@ QPDFObjectHandle::isOrHasName(std::string const& value) const | @@ -1055,19 +1137,10 @@ QPDFObjectHandle::isOrHasName(std::string const& value) const | ||
| 1055 | void | 1137 | void |
| 1056 | QPDFObjectHandle::makeResourcesIndirect(QPDF& owning_qpdf) | 1138 | QPDFObjectHandle::makeResourcesIndirect(QPDF& owning_qpdf) |
| 1057 | { | 1139 | { |
| 1058 | - if (!isDictionary()) { | ||
| 1059 | - return; | ||
| 1060 | - } | ||
| 1061 | - for (auto const& i1: ditems()) { | ||
| 1062 | - QPDFObjectHandle sub = i1.second; | ||
| 1063 | - if (!sub.isDictionary()) { | ||
| 1064 | - continue; | ||
| 1065 | - } | ||
| 1066 | - for (auto const& i2: sub.ditems()) { | ||
| 1067 | - std::string const& key = i2.first; | ||
| 1068 | - QPDFObjectHandle val = i2.second; | ||
| 1069 | - if (!val.isIndirect()) { | ||
| 1070 | - sub.replaceKey(key, owning_qpdf.makeIndirectObject(val)); | 1140 | + for (auto const& i1: as_dictionary()) { |
| 1141 | + for (auto& i2: i1.second.as_dictionary()) { | ||
| 1142 | + if (!i2.second.null() && !i2.second.isIndirect()) { | ||
| 1143 | + i2.second = owning_qpdf.makeIndirectObject(i2.second); | ||
| 1071 | } | 1144 | } |
| 1072 | } | 1145 | } |
| 1073 | } | 1146 | } |
| @@ -1084,18 +1157,17 @@ QPDFObjectHandle::mergeResources( | @@ -1084,18 +1157,17 @@ QPDFObjectHandle::mergeResources( | ||
| 1084 | 1157 | ||
| 1085 | auto make_og_to_name = [](QPDFObjectHandle& dict, | 1158 | auto make_og_to_name = [](QPDFObjectHandle& dict, |
| 1086 | std::map<QPDFObjGen, std::string>& og_to_name) { | 1159 | std::map<QPDFObjGen, std::string>& og_to_name) { |
| 1087 | - for (auto const& i: dict.ditems()) { | ||
| 1088 | - if (i.second.isIndirect()) { | ||
| 1089 | - og_to_name[i.second.getObjGen()] = i.first; | 1160 | + for (auto const& [key, value]: dict.as_dictionary()) { |
| 1161 | + if (!value.null() && value.isIndirect()) { | ||
| 1162 | + og_to_name.insert_or_assign(value.getObjGen(), key); | ||
| 1090 | } | 1163 | } |
| 1091 | } | 1164 | } |
| 1092 | }; | 1165 | }; |
| 1093 | 1166 | ||
| 1094 | // This algorithm is described in comments in QPDFObjectHandle.hh | 1167 | // This algorithm is described in comments in QPDFObjectHandle.hh |
| 1095 | // above the declaration of mergeResources. | 1168 | // above the declaration of mergeResources. |
| 1096 | - for (auto const& o_top: other.ditems()) { | ||
| 1097 | - std::string const& rtype = o_top.first; | ||
| 1098 | - QPDFObjectHandle other_val = o_top.second; | 1169 | + for (auto const& [rtype, value1]: other.as_dictionary()) { |
| 1170 | + auto other_val = value1; | ||
| 1099 | if (hasKey(rtype)) { | 1171 | if (hasKey(rtype)) { |
| 1100 | QPDFObjectHandle this_val = getKey(rtype); | 1172 | QPDFObjectHandle this_val = getKey(rtype); |
| 1101 | if (this_val.isDictionary() && other_val.isDictionary()) { | 1173 | if (this_val.isDictionary() && other_val.isDictionary()) { |
| @@ -1110,9 +1182,8 @@ QPDFObjectHandle::mergeResources( | @@ -1110,9 +1182,8 @@ QPDFObjectHandle::mergeResources( | ||
| 1110 | std::set<std::string> rnames; | 1182 | std::set<std::string> rnames; |
| 1111 | int min_suffix = 1; | 1183 | int min_suffix = 1; |
| 1112 | bool initialized_maps = false; | 1184 | bool initialized_maps = false; |
| 1113 | - for (auto const& ov_iter: other_val.ditems()) { | ||
| 1114 | - std::string const& key = ov_iter.first; | ||
| 1115 | - QPDFObjectHandle rval = ov_iter.second; | 1185 | + for (auto const& [key, value2]: other_val.as_dictionary()) { |
| 1186 | + QPDFObjectHandle rval = value2; | ||
| 1116 | if (!this_val.hasKey(key)) { | 1187 | if (!this_val.hasKey(key)) { |
| 1117 | if (!rval.isIndirect()) { | 1188 | if (!rval.isIndirect()) { |
| 1118 | QTC::TC("qpdf", "QPDFObjectHandle merge shallow copy"); | 1189 | QTC::TC("qpdf", "QPDFObjectHandle merge shallow copy"); |
| @@ -1171,14 +1242,10 @@ QPDFObjectHandle::getResourceNames() const | @@ -1171,14 +1242,10 @@ QPDFObjectHandle::getResourceNames() const | ||
| 1171 | { | 1242 | { |
| 1172 | // Return second-level dictionary keys | 1243 | // Return second-level dictionary keys |
| 1173 | std::set<std::string> result; | 1244 | std::set<std::string> result; |
| 1174 | - if (!isDictionary()) { | ||
| 1175 | - return result; | ||
| 1176 | - } | ||
| 1177 | - for (auto const& key: getKeys()) { | ||
| 1178 | - QPDFObjectHandle val = getKey(key); | ||
| 1179 | - if (val.isDictionary()) { | ||
| 1180 | - for (auto const& val_key: val.getKeys()) { | ||
| 1181 | - result.insert(val_key); | 1245 | + for (auto const& item: as_dictionary(strict)) { |
| 1246 | + for (auto const& [key2, val2]: item.second.as_dictionary(strict)) { | ||
| 1247 | + if (!val2.null()) { | ||
| 1248 | + result.insert(key2); | ||
| 1182 | } | 1249 | } |
| 1183 | } | 1250 | } |
| 1184 | } | 1251 | } |
| @@ -1208,234 +1275,9 @@ QPDFObjectHandle::getUniqueResourceName( | @@ -1208,234 +1275,9 @@ QPDFObjectHandle::getUniqueResourceName( | ||
| 1208 | " QPDFObjectHandle::getUniqueResourceName"); | 1275 | " QPDFObjectHandle::getUniqueResourceName"); |
| 1209 | } | 1276 | } |
| 1210 | 1277 | ||
| 1211 | -// Dictionary mutators | ||
| 1212 | - | ||
| 1213 | -void | ||
| 1214 | -QPDFObjectHandle::replaceKey(std::string const& key, QPDFObjectHandle const& value) | ||
| 1215 | -{ | ||
| 1216 | - auto dict = asDictionary(); | ||
| 1217 | - if (dict) { | ||
| 1218 | - checkOwnership(value); | ||
| 1219 | - dict->replaceKey(key, value); | ||
| 1220 | - } else { | ||
| 1221 | - typeWarning("dictionary", "ignoring key replacement request"); | ||
| 1222 | - QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey"); | ||
| 1223 | - } | ||
| 1224 | -} | ||
| 1225 | - | ||
| 1226 | -QPDFObjectHandle | ||
| 1227 | -QPDFObjectHandle::replaceKeyAndGetNew(std::string const& key, QPDFObjectHandle const& value) | ||
| 1228 | -{ | ||
| 1229 | - replaceKey(key, value); | ||
| 1230 | - return value; | ||
| 1231 | -} | ||
| 1232 | - | ||
| 1233 | -QPDFObjectHandle | ||
| 1234 | -QPDFObjectHandle::replaceKeyAndGetOld(std::string const& key, QPDFObjectHandle const& value) | ||
| 1235 | -{ | ||
| 1236 | - QPDFObjectHandle old = removeKeyAndGetOld(key); | ||
| 1237 | - replaceKey(key, value); | ||
| 1238 | - return old; | ||
| 1239 | -} | ||
| 1240 | - | ||
| 1241 | -void | ||
| 1242 | -QPDFObjectHandle::removeKey(std::string const& key) | ||
| 1243 | -{ | ||
| 1244 | - auto dict = asDictionary(); | ||
| 1245 | - if (dict) { | ||
| 1246 | - dict->removeKey(key); | ||
| 1247 | - } else { | ||
| 1248 | - typeWarning("dictionary", "ignoring key removal request"); | ||
| 1249 | - QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey"); | ||
| 1250 | - } | ||
| 1251 | -} | ||
| 1252 | - | ||
| 1253 | -QPDFObjectHandle | ||
| 1254 | -QPDFObjectHandle::removeKeyAndGetOld(std::string const& key) | ||
| 1255 | -{ | ||
| 1256 | - auto result = QPDFObjectHandle::newNull(); | ||
| 1257 | - auto dict = asDictionary(); | ||
| 1258 | - if (dict) { | ||
| 1259 | - result = dict->getKey(key); | ||
| 1260 | - } | ||
| 1261 | - removeKey(key); | ||
| 1262 | - return result; | ||
| 1263 | -} | ||
| 1264 | - | ||
| 1265 | -// Stream accessors | ||
| 1266 | - | ||
| 1267 | -QPDFObjectHandle | ||
| 1268 | -QPDFObjectHandle::getDict() const | ||
| 1269 | -{ | ||
| 1270 | - return asStreamWithAssert()->getDict(); | ||
| 1271 | -} | ||
| 1272 | - | ||
| 1273 | -void | ||
| 1274 | -QPDFObjectHandle::setFilterOnWrite(bool val) | ||
| 1275 | -{ | ||
| 1276 | - asStreamWithAssert()->setFilterOnWrite(val); | ||
| 1277 | -} | ||
| 1278 | - | ||
| 1279 | -bool | ||
| 1280 | -QPDFObjectHandle::getFilterOnWrite() | ||
| 1281 | -{ | ||
| 1282 | - return asStreamWithAssert()->getFilterOnWrite(); | ||
| 1283 | -} | ||
| 1284 | - | ||
| 1285 | -bool | ||
| 1286 | -QPDFObjectHandle::isDataModified() | ||
| 1287 | -{ | ||
| 1288 | - return asStreamWithAssert()->isDataModified(); | ||
| 1289 | -} | ||
| 1290 | - | ||
| 1291 | -void | ||
| 1292 | -QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict) | ||
| 1293 | -{ | ||
| 1294 | - asStreamWithAssert()->replaceDict(new_dict); | ||
| 1295 | -} | ||
| 1296 | - | ||
| 1297 | -std::shared_ptr<Buffer> | ||
| 1298 | -QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level) | ||
| 1299 | -{ | ||
| 1300 | - return asStreamWithAssert()->getStreamData(level); | ||
| 1301 | -} | ||
| 1302 | - | ||
| 1303 | -std::shared_ptr<Buffer> | ||
| 1304 | -QPDFObjectHandle::getRawStreamData() | ||
| 1305 | -{ | ||
| 1306 | - return asStreamWithAssert()->getRawStreamData(); | ||
| 1307 | -} | ||
| 1308 | - | ||
| 1309 | -bool | ||
| 1310 | -QPDFObjectHandle::pipeStreamData( | ||
| 1311 | - Pipeline* p, | ||
| 1312 | - bool* filtering_attempted, | ||
| 1313 | - int encode_flags, | ||
| 1314 | - qpdf_stream_decode_level_e decode_level, | ||
| 1315 | - bool suppress_warnings, | ||
| 1316 | - bool will_retry) | ||
| 1317 | -{ | ||
| 1318 | - return asStreamWithAssert()->pipeStreamData( | ||
| 1319 | - p, filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry); | ||
| 1320 | -} | ||
| 1321 | - | ||
| 1322 | -bool | ||
| 1323 | -QPDFObjectHandle::pipeStreamData( | ||
| 1324 | - Pipeline* p, | ||
| 1325 | - int encode_flags, | ||
| 1326 | - qpdf_stream_decode_level_e decode_level, | ||
| 1327 | - bool suppress_warnings, | ||
| 1328 | - bool will_retry) | ||
| 1329 | -{ | ||
| 1330 | - bool filtering_attempted; | ||
| 1331 | - asStreamWithAssert()->pipeStreamData( | ||
| 1332 | - p, &filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry); | ||
| 1333 | - return filtering_attempted; | ||
| 1334 | -} | ||
| 1335 | - | ||
| 1336 | -bool | ||
| 1337 | -QPDFObjectHandle::pipeStreamData(Pipeline* p, bool filter, bool normalize, bool compress) | ||
| 1338 | -{ | ||
| 1339 | - int encode_flags = 0; | ||
| 1340 | - qpdf_stream_decode_level_e decode_level = qpdf_dl_none; | ||
| 1341 | - if (filter) { | ||
| 1342 | - decode_level = qpdf_dl_generalized; | ||
| 1343 | - if (normalize) { | ||
| 1344 | - encode_flags |= qpdf_ef_normalize; | ||
| 1345 | - } | ||
| 1346 | - if (compress) { | ||
| 1347 | - encode_flags |= qpdf_ef_compress; | ||
| 1348 | - } | ||
| 1349 | - } | ||
| 1350 | - return pipeStreamData(p, encode_flags, decode_level, false); | ||
| 1351 | -} | ||
| 1352 | - | ||
| 1353 | -void | ||
| 1354 | -QPDFObjectHandle::replaceStreamData( | ||
| 1355 | - std::shared_ptr<Buffer> data, | ||
| 1356 | - QPDFObjectHandle const& filter, | ||
| 1357 | - QPDFObjectHandle const& decode_parms) | ||
| 1358 | -{ | ||
| 1359 | - asStreamWithAssert()->replaceStreamData(data, filter, decode_parms); | ||
| 1360 | -} | ||
| 1361 | - | ||
| 1362 | -void | ||
| 1363 | -QPDFObjectHandle::replaceStreamData( | ||
| 1364 | - std::string const& data, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) | ||
| 1365 | -{ | ||
| 1366 | - auto b = std::make_shared<Buffer>(data.length()); | ||
| 1367 | - unsigned char* bp = b->getBuffer(); | ||
| 1368 | - if (bp) { | ||
| 1369 | - memcpy(bp, data.c_str(), data.length()); | ||
| 1370 | - } | ||
| 1371 | - asStreamWithAssert()->replaceStreamData(b, filter, decode_parms); | ||
| 1372 | -} | ||
| 1373 | - | ||
| 1374 | -void | ||
| 1375 | -QPDFObjectHandle::replaceStreamData( | ||
| 1376 | - std::shared_ptr<StreamDataProvider> provider, | ||
| 1377 | - QPDFObjectHandle const& filter, | ||
| 1378 | - QPDFObjectHandle const& decode_parms) | ||
| 1379 | -{ | ||
| 1380 | - asStreamWithAssert()->replaceStreamData(provider, filter, decode_parms); | ||
| 1381 | -} | ||
| 1382 | - | ||
| 1383 | -namespace | ||
| 1384 | -{ | ||
| 1385 | - class FunctionProvider: public QPDFObjectHandle::StreamDataProvider | ||
| 1386 | - { | ||
| 1387 | - public: | ||
| 1388 | - FunctionProvider(std::function<void(Pipeline*)> provider) : | ||
| 1389 | - StreamDataProvider(false), | ||
| 1390 | - p1(provider), | ||
| 1391 | - p2(nullptr) | ||
| 1392 | - { | ||
| 1393 | - } | ||
| 1394 | - FunctionProvider(std::function<bool(Pipeline*, bool, bool)> provider) : | ||
| 1395 | - StreamDataProvider(true), | ||
| 1396 | - p1(nullptr), | ||
| 1397 | - p2(provider) | ||
| 1398 | - { | ||
| 1399 | - } | 1278 | +// Dictionary mutators are in QPDF_Dictionary.cc |
| 1400 | 1279 | ||
| 1401 | - void | ||
| 1402 | - provideStreamData(QPDFObjGen const&, Pipeline* pipeline) override | ||
| 1403 | - { | ||
| 1404 | - p1(pipeline); | ||
| 1405 | - } | ||
| 1406 | - | ||
| 1407 | - bool | ||
| 1408 | - provideStreamData( | ||
| 1409 | - QPDFObjGen const&, Pipeline* pipeline, bool suppress_warnings, bool will_retry) override | ||
| 1410 | - { | ||
| 1411 | - return p2(pipeline, suppress_warnings, will_retry); | ||
| 1412 | - } | ||
| 1413 | - | ||
| 1414 | - private: | ||
| 1415 | - std::function<void(Pipeline*)> p1; | ||
| 1416 | - std::function<bool(Pipeline*, bool, bool)> p2; | ||
| 1417 | - }; | ||
| 1418 | -} // namespace | ||
| 1419 | - | ||
| 1420 | -void | ||
| 1421 | -QPDFObjectHandle::replaceStreamData( | ||
| 1422 | - std::function<void(Pipeline*)> provider, | ||
| 1423 | - QPDFObjectHandle const& filter, | ||
| 1424 | - QPDFObjectHandle const& decode_parms) | ||
| 1425 | -{ | ||
| 1426 | - auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); | ||
| 1427 | - asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms); | ||
| 1428 | -} | ||
| 1429 | - | ||
| 1430 | -void | ||
| 1431 | -QPDFObjectHandle::replaceStreamData( | ||
| 1432 | - std::function<bool(Pipeline*, bool, bool)> provider, | ||
| 1433 | - QPDFObjectHandle const& filter, | ||
| 1434 | - QPDFObjectHandle const& decode_parms) | ||
| 1435 | -{ | ||
| 1436 | - auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); | ||
| 1437 | - asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms); | ||
| 1438 | -} | 1280 | +// Stream accessors are in QPDF_Stream.cc |
| 1439 | 1281 | ||
| 1440 | std::map<std::string, QPDFObjectHandle> | 1282 | std::map<std::string, QPDFObjectHandle> |
| 1441 | QPDFObjectHandle::getPageImages() | 1283 | QPDFObjectHandle::getPageImages() |
| @@ -1449,12 +1291,12 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( | @@ -1449,12 +1291,12 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( | ||
| 1449 | { | 1291 | { |
| 1450 | all_description = description; | 1292 | all_description = description; |
| 1451 | std::vector<QPDFObjectHandle> result; | 1293 | std::vector<QPDFObjectHandle> result; |
| 1452 | - if (auto array = asArray()) { | ||
| 1453 | - int n_items = array->size(); | 1294 | + if (auto array = as_array(strict)) { |
| 1295 | + int n_items = array.size(); | ||
| 1454 | for (int i = 0; i < n_items; ++i) { | 1296 | for (int i = 0; i < n_items; ++i) { |
| 1455 | - QPDFObjectHandle item = array->at(i).second; | 1297 | + QPDFObjectHandle item = array.at(i).second; |
| 1456 | if (item.isStream()) { | 1298 | if (item.isStream()) { |
| 1457 | - result.push_back(item); | 1299 | + result.emplace_back(item); |
| 1458 | } else { | 1300 | } else { |
| 1459 | QTC::TC("qpdf", "QPDFObjectHandle non-stream in stream array"); | 1301 | QTC::TC("qpdf", "QPDFObjectHandle non-stream in stream array"); |
| 1460 | warn( | 1302 | warn( |
| @@ -1468,7 +1310,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( | @@ -1468,7 +1310,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( | ||
| 1468 | } | 1310 | } |
| 1469 | } | 1311 | } |
| 1470 | } else if (isStream()) { | 1312 | } else if (isStream()) { |
| 1471 | - result.push_back(*this); | 1313 | + result.emplace_back(*this); |
| 1472 | } else if (!isNull()) { | 1314 | } else if (!isNull()) { |
| 1473 | warn( | 1315 | warn( |
| 1474 | getOwningQPDF(), | 1316 | getOwningQPDF(), |
| @@ -1602,7 +1444,7 @@ QPDFObjectHandle::unparseResolved() const | @@ -1602,7 +1444,7 @@ QPDFObjectHandle::unparseResolved() const | ||
| 1602 | std::string | 1444 | std::string |
| 1603 | QPDFObjectHandle::unparseBinary() const | 1445 | QPDFObjectHandle::unparseBinary() const |
| 1604 | { | 1446 | { |
| 1605 | - if (auto str = asString()) { | 1447 | + if (auto str = as<QPDF_String>()) { |
| 1606 | return str->unparse(true); | 1448 | return str->unparse(true); |
| 1607 | } else { | 1449 | } else { |
| 1608 | return unparse(); | 1450 | return unparse(); |
| @@ -1633,7 +1475,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_ | @@ -1633,7 +1475,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_ | ||
| 1633 | } else if (!obj) { | 1475 | } else if (!obj) { |
| 1634 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); | 1476 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); |
| 1635 | } else { | 1477 | } else { |
| 1636 | - obj->writeJSON(json_version, p); | 1478 | + obj->write_json(json_version, p); |
| 1637 | } | 1479 | } |
| 1638 | } | 1480 | } |
| 1639 | 1481 | ||
| @@ -1645,18 +1487,6 @@ QPDFObjectHandle::writeJSON( | @@ -1645,18 +1487,6 @@ QPDFObjectHandle::writeJSON( | ||
| 1645 | writeJSON(json_version, jw, dereference_indirect); | 1487 | writeJSON(json_version, jw, dereference_indirect); |
| 1646 | } | 1488 | } |
| 1647 | 1489 | ||
| 1648 | -JSON | ||
| 1649 | -QPDFObjectHandle::getStreamJSON( | ||
| 1650 | - int json_version, | ||
| 1651 | - qpdf_json_stream_data_e json_data, | ||
| 1652 | - qpdf_stream_decode_level_e decode_level, | ||
| 1653 | - Pipeline* p, | ||
| 1654 | - std::string const& data_filename) | ||
| 1655 | -{ | ||
| 1656 | - return asStreamWithAssert()->getStreamJSON( | ||
| 1657 | - json_version, json_data, decode_level, p, data_filename); | ||
| 1658 | -} | ||
| 1659 | - | ||
| 1660 | QPDFObjectHandle | 1490 | QPDFObjectHandle |
| 1661 | QPDFObjectHandle::wrapInArray() | 1491 | QPDFObjectHandle::wrapInArray() |
| 1662 | { | 1492 | { |
| @@ -1857,7 +1687,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr<TokenFilter> filter) | @@ -1857,7 +1687,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr<TokenFilter> filter) | ||
| 1857 | void | 1687 | void |
| 1858 | QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter) | 1688 | QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter) |
| 1859 | { | 1689 | { |
| 1860 | - return asStreamWithAssert()->addTokenFilter(filter); | 1690 | + return as_stream(error).addTokenFilter(filter); |
| 1861 | } | 1691 | } |
| 1862 | 1692 | ||
| 1863 | QPDFObjectHandle | 1693 | QPDFObjectHandle |
| @@ -1882,43 +1712,43 @@ QPDFObjectHandle::getParsedOffset() const | @@ -1882,43 +1712,43 @@ QPDFObjectHandle::getParsedOffset() const | ||
| 1882 | QPDFObjectHandle | 1712 | QPDFObjectHandle |
| 1883 | QPDFObjectHandle::newBool(bool value) | 1713 | QPDFObjectHandle::newBool(bool value) |
| 1884 | { | 1714 | { |
| 1885 | - return {QPDF_Bool::create(value)}; | 1715 | + return {QPDFObject::create<QPDF_Bool>(value)}; |
| 1886 | } | 1716 | } |
| 1887 | 1717 | ||
| 1888 | QPDFObjectHandle | 1718 | QPDFObjectHandle |
| 1889 | QPDFObjectHandle::newNull() | 1719 | QPDFObjectHandle::newNull() |
| 1890 | { | 1720 | { |
| 1891 | - return {QPDF_Null::create()}; | 1721 | + return {QPDFObject::create<QPDF_Null>()}; |
| 1892 | } | 1722 | } |
| 1893 | 1723 | ||
| 1894 | QPDFObjectHandle | 1724 | QPDFObjectHandle |
| 1895 | QPDFObjectHandle::newInteger(long long value) | 1725 | QPDFObjectHandle::newInteger(long long value) |
| 1896 | { | 1726 | { |
| 1897 | - return {QPDF_Integer::create(value)}; | 1727 | + return {QPDFObject::create<QPDF_Integer>(value)}; |
| 1898 | } | 1728 | } |
| 1899 | 1729 | ||
| 1900 | QPDFObjectHandle | 1730 | QPDFObjectHandle |
| 1901 | QPDFObjectHandle::newReal(std::string const& value) | 1731 | QPDFObjectHandle::newReal(std::string const& value) |
| 1902 | { | 1732 | { |
| 1903 | - return {QPDF_Real::create(value)}; | 1733 | + return {QPDFObject::create<QPDF_Real>(value)}; |
| 1904 | } | 1734 | } |
| 1905 | 1735 | ||
| 1906 | QPDFObjectHandle | 1736 | QPDFObjectHandle |
| 1907 | QPDFObjectHandle::newReal(double value, int decimal_places, bool trim_trailing_zeroes) | 1737 | QPDFObjectHandle::newReal(double value, int decimal_places, bool trim_trailing_zeroes) |
| 1908 | { | 1738 | { |
| 1909 | - return {QPDF_Real::create(value, decimal_places, trim_trailing_zeroes)}; | 1739 | + return {QPDFObject::create<QPDF_Real>(value, decimal_places, trim_trailing_zeroes)}; |
| 1910 | } | 1740 | } |
| 1911 | 1741 | ||
| 1912 | QPDFObjectHandle | 1742 | QPDFObjectHandle |
| 1913 | QPDFObjectHandle::newName(std::string const& name) | 1743 | QPDFObjectHandle::newName(std::string const& name) |
| 1914 | { | 1744 | { |
| 1915 | - return {QPDF_Name::create(name)}; | 1745 | + return {QPDFObject::create<QPDF_Name>(name)}; |
| 1916 | } | 1746 | } |
| 1917 | 1747 | ||
| 1918 | QPDFObjectHandle | 1748 | QPDFObjectHandle |
| 1919 | QPDFObjectHandle::newString(std::string const& str) | 1749 | QPDFObjectHandle::newString(std::string const& str) |
| 1920 | { | 1750 | { |
| 1921 | - return {QPDF_String::create(str)}; | 1751 | + return {QPDFObject::create<QPDF_String>(str)}; |
| 1922 | } | 1752 | } |
| 1923 | 1753 | ||
| 1924 | QPDFObjectHandle | 1754 | QPDFObjectHandle |
| @@ -1930,13 +1760,13 @@ QPDFObjectHandle::newUnicodeString(std::string const& utf8_str) | @@ -1930,13 +1760,13 @@ QPDFObjectHandle::newUnicodeString(std::string const& utf8_str) | ||
| 1930 | QPDFObjectHandle | 1760 | QPDFObjectHandle |
| 1931 | QPDFObjectHandle::newOperator(std::string const& value) | 1761 | QPDFObjectHandle::newOperator(std::string const& value) |
| 1932 | { | 1762 | { |
| 1933 | - return {QPDF_Operator::create(value)}; | 1763 | + return {QPDFObject::create<QPDF_Operator>(value)}; |
| 1934 | } | 1764 | } |
| 1935 | 1765 | ||
| 1936 | QPDFObjectHandle | 1766 | QPDFObjectHandle |
| 1937 | QPDFObjectHandle::newInlineImage(std::string const& value) | 1767 | QPDFObjectHandle::newInlineImage(std::string const& value) |
| 1938 | { | 1768 | { |
| 1939 | - return {QPDF_InlineImage::create(value)}; | 1769 | + return {QPDFObject::create<QPDF_InlineImage>(value)}; |
| 1940 | } | 1770 | } |
| 1941 | 1771 | ||
| 1942 | QPDFObjectHandle | 1772 | QPDFObjectHandle |
| @@ -1948,7 +1778,7 @@ QPDFObjectHandle::newArray() | @@ -1948,7 +1778,7 @@ QPDFObjectHandle::newArray() | ||
| 1948 | QPDFObjectHandle | 1778 | QPDFObjectHandle |
| 1949 | QPDFObjectHandle::newArray(std::vector<QPDFObjectHandle> const& items) | 1779 | QPDFObjectHandle::newArray(std::vector<QPDFObjectHandle> const& items) |
| 1950 | { | 1780 | { |
| 1951 | - return {QPDF_Array::create(items)}; | 1781 | + return {QPDFObject::create<QPDF_Array>(items)}; |
| 1952 | } | 1782 | } |
| 1953 | 1783 | ||
| 1954 | QPDFObjectHandle | 1784 | QPDFObjectHandle |
| @@ -2008,7 +1838,7 @@ QPDFObjectHandle::newDictionary() | @@ -2008,7 +1838,7 @@ QPDFObjectHandle::newDictionary() | ||
| 2008 | QPDFObjectHandle | 1838 | QPDFObjectHandle |
| 2009 | QPDFObjectHandle::newDictionary(std::map<std::string, QPDFObjectHandle> const& items) | 1839 | QPDFObjectHandle::newDictionary(std::map<std::string, QPDFObjectHandle> const& items) |
| 2010 | { | 1840 | { |
| 2011 | - return {QPDF_Dictionary::create(items)}; | 1841 | + return {QPDFObject::create<QPDF_Dictionary>(items)}; |
| 2012 | } | 1842 | } |
| 2013 | 1843 | ||
| 2014 | QPDFObjectHandle | 1844 | QPDFObjectHandle |
| @@ -2054,7 +1884,7 @@ void | @@ -2054,7 +1884,7 @@ void | ||
| 2054 | QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) | 1884 | QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) |
| 2055 | { | 1885 | { |
| 2056 | if (obj) { | 1886 | if (obj) { |
| 2057 | - auto descr = std::make_shared<QPDFValue::Description>(object_description); | 1887 | + auto descr = std::make_shared<QPDFObject::Description>(object_description); |
| 2058 | obj->setDescription(owning_qpdf, descr); | 1888 | obj->setDescription(owning_qpdf, descr); |
| 2059 | } | 1889 | } |
| 2060 | } | 1890 | } |
| @@ -2096,23 +1926,22 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set& visited, bool stop_at_streams) | @@ -2096,23 +1926,22 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set& visited, bool stop_at_streams) | ||
| 2096 | 1926 | ||
| 2097 | if (isBool() || isInteger() || isName() || isNull() || isReal() || isString()) { | 1927 | if (isBool() || isInteger() || isName() || isNull() || isReal() || isString()) { |
| 2098 | this->obj = obj->copy(true); | 1928 | this->obj = obj->copy(true); |
| 2099 | - } else if (isArray()) { | 1929 | + } else if (auto a = as_array(strict)) { |
| 2100 | std::vector<QPDFObjectHandle> items; | 1930 | std::vector<QPDFObjectHandle> items; |
| 2101 | - auto array = asArray(); | ||
| 2102 | - int n = array->size(); | ||
| 2103 | - for (int i = 0; i < n; ++i) { | ||
| 2104 | - items.push_back(array->at(i).second); | 1931 | + for (auto const& item: a) { |
| 1932 | + items.emplace_back(item); | ||
| 2105 | items.back().makeDirect(visited, stop_at_streams); | 1933 | items.back().makeDirect(visited, stop_at_streams); |
| 2106 | } | 1934 | } |
| 2107 | - this->obj = QPDF_Array::create(items); | 1935 | + this->obj = QPDFObject::create<QPDF_Array>(items); |
| 2108 | } else if (isDictionary()) { | 1936 | } else if (isDictionary()) { |
| 2109 | std::map<std::string, QPDFObjectHandle> items; | 1937 | std::map<std::string, QPDFObjectHandle> items; |
| 2110 | - auto dict = asDictionary(); | ||
| 2111 | - for (auto const& key: getKeys()) { | ||
| 2112 | - items[key] = dict->getKey(key); | ||
| 2113 | - items[key].makeDirect(visited, stop_at_streams); | 1938 | + for (auto const& [key, value]: as_dictionary(strict)) { |
| 1939 | + if (!value.null()) { | ||
| 1940 | + items.insert({key, value}); | ||
| 1941 | + items[key].makeDirect(visited, stop_at_streams); | ||
| 1942 | + } | ||
| 2114 | } | 1943 | } |
| 2115 | - this->obj = QPDF_Dictionary::create(items); | 1944 | + this->obj = QPDFObject::create<QPDF_Dictionary>(items); |
| 2116 | } else if (isStream()) { | 1945 | } else if (isStream()) { |
| 2117 | QTC::TC("qpdf", "QPDFObjectHandle copy stream", stop_at_streams ? 0 : 1); | 1946 | QTC::TC("qpdf", "QPDFObjectHandle copy stream", stop_at_streams ? 0 : 1); |
| 2118 | if (!stop_at_streams) { | 1947 | if (!stop_at_streams) { |
| @@ -2349,19 +2178,6 @@ QPDFObjectHandle::isImage(bool exclude_imagemask) const | @@ -2349,19 +2178,6 @@ QPDFObjectHandle::isImage(bool exclude_imagemask) const | ||
| 2349 | } | 2178 | } |
| 2350 | 2179 | ||
| 2351 | void | 2180 | void |
| 2352 | -QPDFObjectHandle::checkOwnership(QPDFObjectHandle const& item) const | ||
| 2353 | -{ | ||
| 2354 | - auto qpdf = getOwningQPDF(); | ||
| 2355 | - auto item_qpdf = item.getOwningQPDF(); | ||
| 2356 | - if ((qpdf != nullptr) && (item_qpdf != nullptr) && (qpdf != item_qpdf)) { | ||
| 2357 | - QTC::TC("qpdf", "QPDFObjectHandle check ownership"); | ||
| 2358 | - throw std::logic_error( | ||
| 2359 | - "Attempting to add an object from a different QPDF. Use " | ||
| 2360 | - "QPDF::copyForeignObject to add objects from another file."); | ||
| 2361 | - } | ||
| 2362 | -} | ||
| 2363 | - | ||
| 2364 | -void | ||
| 2365 | QPDFObjectHandle::assertPageObject() const | 2181 | QPDFObjectHandle::assertPageObject() const |
| 2366 | { | 2182 | { |
| 2367 | if (!isPageObject()) { | 2183 | if (!isPageObject()) { |
libqpdf/QPDFOutlineObjectHelper.cc
| @@ -9,8 +9,8 @@ QPDFOutlineObjectHelper::Members::Members(QPDFOutlineDocumentHelper& dh) : | @@ -9,8 +9,8 @@ QPDFOutlineObjectHelper::Members::Members(QPDFOutlineDocumentHelper& dh) : | ||
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | QPDFOutlineObjectHelper::QPDFOutlineObjectHelper( | 11 | QPDFOutlineObjectHelper::QPDFOutlineObjectHelper( |
| 12 | - QPDFObjectHandle oh, QPDFOutlineDocumentHelper& dh, int depth) : | ||
| 13 | - QPDFObjectHelper(oh), | 12 | + QPDFObjectHandle a_oh, QPDFOutlineDocumentHelper& dh, int depth) : |
| 13 | + QPDFObjectHelper(a_oh), | ||
| 14 | m(new Members(dh)) | 14 | m(new Members(dh)) |
| 15 | { | 15 | { |
| 16 | if (depth > 50) { | 16 | if (depth > 50) { |
| @@ -18,13 +18,13 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper( | @@ -18,13 +18,13 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper( | ||
| 18 | // to 1. | 18 | // to 1. |
| 19 | return; | 19 | return; |
| 20 | } | 20 | } |
| 21 | - if (QPDFOutlineDocumentHelper::Accessor::checkSeen(m->dh, this->oh.getObjGen())) { | 21 | + if (QPDFOutlineDocumentHelper::Accessor::checkSeen(m->dh, a_oh.getObjGen())) { |
| 22 | QTC::TC("qpdf", "QPDFOutlineObjectHelper loop"); | 22 | QTC::TC("qpdf", "QPDFOutlineObjectHelper loop"); |
| 23 | return; | 23 | return; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | QPDFObjGen::set children; | 26 | QPDFObjGen::set children; |
| 27 | - QPDFObjectHandle cur = oh.getKey("/First"); | 27 | + QPDFObjectHandle cur = a_oh.getKey("/First"); |
| 28 | while (!cur.isNull() && cur.isIndirect() && children.add(cur)) { | 28 | while (!cur.isNull() && cur.isIndirect() && children.add(cur)) { |
| 29 | QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth); | 29 | QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth); |
| 30 | new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this); | 30 | new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this); |
| @@ -50,11 +50,11 @@ QPDFOutlineObjectHelper::getDest() | @@ -50,11 +50,11 @@ QPDFOutlineObjectHelper::getDest() | ||
| 50 | { | 50 | { |
| 51 | QPDFObjectHandle dest; | 51 | QPDFObjectHandle dest; |
| 52 | QPDFObjectHandle A; | 52 | QPDFObjectHandle A; |
| 53 | - if (this->oh.hasKey("/Dest")) { | 53 | + if (oh().hasKey("/Dest")) { |
| 54 | QTC::TC("qpdf", "QPDFOutlineObjectHelper direct dest"); | 54 | QTC::TC("qpdf", "QPDFOutlineObjectHelper direct dest"); |
| 55 | - dest = this->oh.getKey("/Dest"); | 55 | + dest = oh().getKey("/Dest"); |
| 56 | } else if ( | 56 | } else if ( |
| 57 | - (A = this->oh.getKey("/A")).isDictionary() && A.getKey("/S").isName() && | 57 | + (A = oh().getKey("/A")).isDictionary() && A.getKey("/S").isName() && |
| 58 | (A.getKey("/S").getName() == "/GoTo") && A.hasKey("/D")) { | 58 | (A.getKey("/S").getName() == "/GoTo") && A.hasKey("/D")) { |
| 59 | QTC::TC("qpdf", "QPDFOutlineObjectHelper action dest"); | 59 | QTC::TC("qpdf", "QPDFOutlineObjectHelper action dest"); |
| 60 | dest = A.getKey("/D"); | 60 | dest = A.getKey("/D"); |
| @@ -85,8 +85,8 @@ int | @@ -85,8 +85,8 @@ int | ||
| 85 | QPDFOutlineObjectHelper::getCount() | 85 | QPDFOutlineObjectHelper::getCount() |
| 86 | { | 86 | { |
| 87 | int count = 0; | 87 | int count = 0; |
| 88 | - if (this->oh.hasKey("/Count")) { | ||
| 89 | - count = this->oh.getKey("/Count").getIntValueAsInt(); | 88 | + if (oh().hasKey("/Count")) { |
| 89 | + count = oh().getKey("/Count").getIntValueAsInt(); | ||
| 90 | } | 90 | } |
| 91 | return count; | 91 | return count; |
| 92 | } | 92 | } |
| @@ -95,8 +95,8 @@ std::string | @@ -95,8 +95,8 @@ std::string | ||
| 95 | QPDFOutlineObjectHelper::getTitle() | 95 | QPDFOutlineObjectHelper::getTitle() |
| 96 | { | 96 | { |
| 97 | std::string result; | 97 | std::string result; |
| 98 | - if (this->oh.hasKey("/Title")) { | ||
| 99 | - result = this->oh.getKey("/Title").getUTF8Value(); | 98 | + if (oh().hasKey("/Title")) { |
| 99 | + result = oh().getKey("/Title").getUTF8Value(); | ||
| 100 | } | 100 | } |
| 101 | return result; | 101 | return result; |
| 102 | } | 102 | } |
libqpdf/QPDFPageObjectHelper.cc
| @@ -7,6 +7,7 @@ | @@ -7,6 +7,7 @@ | ||
| 7 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> | 7 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> |
| 8 | #include <qpdf/QPDFExc.hh> | 8 | #include <qpdf/QPDFExc.hh> |
| 9 | #include <qpdf/QPDFMatrix.hh> | 9 | #include <qpdf/QPDFMatrix.hh> |
| 10 | +#include <qpdf/QPDFObjectHandle_private.hh> | ||
| 10 | #include <qpdf/QTC.hh> | 11 | #include <qpdf/QTC.hh> |
| 11 | #include <qpdf/QUtil.hh> | 12 | #include <qpdf/QUtil.hh> |
| 12 | #include <qpdf/ResourceFinder.hh> | 13 | #include <qpdf/ResourceFinder.hh> |
| @@ -72,9 +73,12 @@ InlineImageTracker::convertIIDict(QPDFObjectHandle odict) | @@ -72,9 +73,12 @@ InlineImageTracker::convertIIDict(QPDFObjectHandle odict) | ||
| 72 | QPDFObjectHandle dict = QPDFObjectHandle::newDictionary(); | 73 | QPDFObjectHandle dict = QPDFObjectHandle::newDictionary(); |
| 73 | dict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); | 74 | dict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); |
| 74 | dict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Image")); | 75 | dict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Image")); |
| 75 | - std::set<std::string> keys = odict.getKeys(); | ||
| 76 | - for (auto key: keys) { | ||
| 77 | - QPDFObjectHandle value = odict.getKey(key); | 76 | + for (auto const& [k, v]: odict.as_dictionary()) { |
| 77 | + if (v.null()) { | ||
| 78 | + continue; | ||
| 79 | + } | ||
| 80 | + auto key = k; | ||
| 81 | + auto value = v; | ||
| 78 | if (key == "/BPC") { | 82 | if (key == "/BPC") { |
| 79 | key = "/BitsPerComponent"; | 83 | key = "/BitsPerComponent"; |
| 80 | } else if (key == "/CS") { | 84 | } else if (key == "/CS") { |
| @@ -227,9 +231,9 @@ QPDFPageObjectHelper::getAttribute( | @@ -227,9 +231,9 @@ QPDFPageObjectHelper::getAttribute( | ||
| 227 | std::function<QPDFObjectHandle()> get_fallback, | 231 | std::function<QPDFObjectHandle()> get_fallback, |
| 228 | bool copy_if_fallback) | 232 | bool copy_if_fallback) |
| 229 | { | 233 | { |
| 230 | - const bool is_form_xobject = this->oh.isFormXObject(); | 234 | + const bool is_form_xobject = oh().isFormXObject(); |
| 231 | bool inherited = false; | 235 | bool inherited = false; |
| 232 | - auto dict = is_form_xobject ? oh.getDict() : oh; | 236 | + auto dict = is_form_xobject ? oh().getDict() : oh(); |
| 233 | auto result = dict.getKey(name); | 237 | auto result = dict.getKey(name); |
| 234 | 238 | ||
| 235 | if (!is_form_xobject && result.isNull() && | 239 | if (!is_form_xobject && result.isNull() && |
| @@ -324,23 +328,24 @@ QPDFPageObjectHelper::forEachXObject( | @@ -324,23 +328,24 @@ QPDFPageObjectHelper::forEachXObject( | ||
| 324 | QTC::TC( | 328 | QTC::TC( |
| 325 | "qpdf", | 329 | "qpdf", |
| 326 | "QPDFPageObjectHelper::forEachXObject", | 330 | "QPDFPageObjectHelper::forEachXObject", |
| 327 | - recursive ? (this->oh.isFormXObject() ? 0 : 1) : (this->oh.isFormXObject() ? 2 : 3)); | 331 | + recursive ? (oh().isFormXObject() ? 0 : 1) : (oh().isFormXObject() ? 2 : 3)); |
| 328 | QPDFObjGen::set seen; | 332 | QPDFObjGen::set seen; |
| 329 | std::list<QPDFPageObjectHelper> queue; | 333 | std::list<QPDFPageObjectHelper> queue; |
| 330 | - queue.push_back(*this); | 334 | + queue.emplace_back(*this); |
| 331 | while (!queue.empty()) { | 335 | while (!queue.empty()) { |
| 332 | auto& ph = queue.front(); | 336 | auto& ph = queue.front(); |
| 333 | if (seen.add(ph)) { | 337 | if (seen.add(ph)) { |
| 334 | auto xobj_dict = ph.getAttribute("/Resources", false).getKeyIfDict("/XObject"); | 338 | auto xobj_dict = ph.getAttribute("/Resources", false).getKeyIfDict("/XObject"); |
| 335 | - if (xobj_dict.isDictionary()) { | ||
| 336 | - for (auto const& key: xobj_dict.getKeys()) { | ||
| 337 | - QPDFObjectHandle obj = xobj_dict.getKey(key); | ||
| 338 | - if ((!selector) || selector(obj)) { | ||
| 339 | - action(obj, xobj_dict, key); | ||
| 340 | - } | ||
| 341 | - if (recursive && obj.isFormXObject()) { | ||
| 342 | - queue.emplace_back(obj); | ||
| 343 | - } | 339 | + for (auto const& [key, value]: xobj_dict.as_dictionary()) { |
| 340 | + if (value.null()) { | ||
| 341 | + continue; | ||
| 342 | + } | ||
| 343 | + auto obj = value; | ||
| 344 | + if ((!selector) || selector(obj)) { | ||
| 345 | + action(obj, xobj_dict, key); | ||
| 346 | + } | ||
| 347 | + if (recursive && obj.isFormXObject()) { | ||
| 348 | + queue.emplace_back(obj); | ||
| 344 | } | 349 | } |
| 345 | } | 350 | } |
| 346 | } | 351 | } |
| @@ -402,28 +407,27 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) | @@ -402,28 +407,27 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) | ||
| 402 | // Calling mergeResources also ensures that /XObject becomes direct and is not shared with | 407 | // Calling mergeResources also ensures that /XObject becomes direct and is not shared with |
| 403 | // other pages. | 408 | // other pages. |
| 404 | resources.mergeResources("<< /XObject << >> >>"_qpdf); | 409 | resources.mergeResources("<< /XObject << >> >>"_qpdf); |
| 405 | - InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources); | 410 | + InlineImageTracker iit(oh().getOwningQPDF(), min_size, resources); |
| 406 | Pl_Buffer b("new page content"); | 411 | Pl_Buffer b("new page content"); |
| 407 | bool filtered = false; | 412 | bool filtered = false; |
| 408 | try { | 413 | try { |
| 409 | filterContents(&iit, &b); | 414 | filterContents(&iit, &b); |
| 410 | filtered = true; | 415 | filtered = true; |
| 411 | } catch (std::exception& e) { | 416 | } catch (std::exception& e) { |
| 412 | - this->oh.warnIfPossible( | 417 | + oh().warnIfPossible( |
| 413 | std::string("Unable to filter content stream: ") + e.what() + | 418 | std::string("Unable to filter content stream: ") + e.what() + |
| 414 | - "; not attempting to externalize inline images" | ||
| 415 | - " from this stream"); | 419 | + "; not attempting to externalize inline images from this stream"); |
| 416 | } | 420 | } |
| 417 | if (filtered && iit.any_images) { | 421 | if (filtered && iit.any_images) { |
| 418 | - if (this->oh.isFormXObject()) { | ||
| 419 | - this->oh.replaceStreamData( | 422 | + if (oh().isFormXObject()) { |
| 423 | + oh().replaceStreamData( | ||
| 420 | b.getBufferSharedPointer(), | 424 | b.getBufferSharedPointer(), |
| 421 | QPDFObjectHandle::newNull(), | 425 | QPDFObjectHandle::newNull(), |
| 422 | QPDFObjectHandle::newNull()); | 426 | QPDFObjectHandle::newNull()); |
| 423 | } else { | 427 | } else { |
| 424 | - this->oh.replaceKey( | 428 | + oh().replaceKey( |
| 425 | "/Contents", | 429 | "/Contents", |
| 426 | - QPDFObjectHandle::newStream(&this->oh.getQPDF(), b.getBufferSharedPointer())); | 430 | + QPDFObjectHandle::newStream(&oh().getQPDF(), b.getBufferSharedPointer())); |
| 427 | } | 431 | } |
| 428 | } | 432 | } |
| 429 | } else { | 433 | } else { |
| @@ -439,7 +443,7 @@ std::vector<QPDFAnnotationObjectHelper> | @@ -439,7 +443,7 @@ std::vector<QPDFAnnotationObjectHelper> | ||
| 439 | QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) | 443 | QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) |
| 440 | { | 444 | { |
| 441 | std::vector<QPDFAnnotationObjectHelper> result; | 445 | std::vector<QPDFAnnotationObjectHelper> result; |
| 442 | - QPDFObjectHandle annots = this->oh.getKey("/Annots"); | 446 | + QPDFObjectHandle annots = oh().getKey("/Annots"); |
| 443 | if (annots.isArray()) { | 447 | if (annots.isArray()) { |
| 444 | int nannots = annots.getArrayNItems(); | 448 | int nannots = annots.getArrayNItems(); |
| 445 | for (int i = 0; i < nannots; ++i) { | 449 | for (int i = 0; i < nannots; ++i) { |
| @@ -455,25 +459,25 @@ QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) | @@ -455,25 +459,25 @@ QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) | ||
| 455 | std::vector<QPDFObjectHandle> | 459 | std::vector<QPDFObjectHandle> |
| 456 | QPDFPageObjectHelper::getPageContents() | 460 | QPDFPageObjectHelper::getPageContents() |
| 457 | { | 461 | { |
| 458 | - return this->oh.getPageContents(); | 462 | + return oh().getPageContents(); |
| 459 | } | 463 | } |
| 460 | 464 | ||
| 461 | void | 465 | void |
| 462 | QPDFPageObjectHelper::addPageContents(QPDFObjectHandle contents, bool first) | 466 | QPDFPageObjectHelper::addPageContents(QPDFObjectHandle contents, bool first) |
| 463 | { | 467 | { |
| 464 | - this->oh.addPageContents(contents, first); | 468 | + oh().addPageContents(contents, first); |
| 465 | } | 469 | } |
| 466 | 470 | ||
| 467 | void | 471 | void |
| 468 | QPDFPageObjectHelper::rotatePage(int angle, bool relative) | 472 | QPDFPageObjectHelper::rotatePage(int angle, bool relative) |
| 469 | { | 473 | { |
| 470 | - this->oh.rotatePage(angle, relative); | 474 | + oh().rotatePage(angle, relative); |
| 471 | } | 475 | } |
| 472 | 476 | ||
| 473 | void | 477 | void |
| 474 | QPDFPageObjectHelper::coalesceContentStreams() | 478 | QPDFPageObjectHelper::coalesceContentStreams() |
| 475 | { | 479 | { |
| 476 | - this->oh.coalesceContentStreams(); | 480 | + oh().coalesceContentStreams(); |
| 477 | } | 481 | } |
| 478 | 482 | ||
| 479 | void | 483 | void |
| @@ -485,10 +489,10 @@ QPDFPageObjectHelper::parsePageContents(QPDFObjectHandle::ParserCallbacks* callb | @@ -485,10 +489,10 @@ QPDFPageObjectHelper::parsePageContents(QPDFObjectHandle::ParserCallbacks* callb | ||
| 485 | void | 489 | void |
| 486 | QPDFPageObjectHelper::parseContents(QPDFObjectHandle::ParserCallbacks* callbacks) | 490 | QPDFPageObjectHelper::parseContents(QPDFObjectHandle::ParserCallbacks* callbacks) |
| 487 | { | 491 | { |
| 488 | - if (this->oh.isFormXObject()) { | ||
| 489 | - this->oh.parseAsContents(callbacks); | 492 | + if (oh().isFormXObject()) { |
| 493 | + oh().parseAsContents(callbacks); | ||
| 490 | } else { | 494 | } else { |
| 491 | - this->oh.parsePageContents(callbacks); | 495 | + oh().parsePageContents(callbacks); |
| 492 | } | 496 | } |
| 493 | } | 497 | } |
| 494 | 498 | ||
| @@ -501,10 +505,10 @@ QPDFPageObjectHelper::filterPageContents(QPDFObjectHandle::TokenFilter* filter, | @@ -501,10 +505,10 @@ QPDFPageObjectHelper::filterPageContents(QPDFObjectHandle::TokenFilter* filter, | ||
| 501 | void | 505 | void |
| 502 | QPDFPageObjectHelper::filterContents(QPDFObjectHandle::TokenFilter* filter, Pipeline* next) | 506 | QPDFPageObjectHelper::filterContents(QPDFObjectHandle::TokenFilter* filter, Pipeline* next) |
| 503 | { | 507 | { |
| 504 | - if (this->oh.isFormXObject()) { | ||
| 505 | - this->oh.filterAsContents(filter, next); | 508 | + if (oh().isFormXObject()) { |
| 509 | + oh().filterAsContents(filter, next); | ||
| 506 | } else { | 510 | } else { |
| 507 | - this->oh.filterPageContents(filter, next); | 511 | + oh().filterPageContents(filter, next); |
| 508 | } | 512 | } |
| 509 | } | 513 | } |
| 510 | 514 | ||
| @@ -517,10 +521,10 @@ QPDFPageObjectHelper::pipePageContents(Pipeline* p) | @@ -517,10 +521,10 @@ QPDFPageObjectHelper::pipePageContents(Pipeline* p) | ||
| 517 | void | 521 | void |
| 518 | QPDFPageObjectHelper::pipeContents(Pipeline* p) | 522 | QPDFPageObjectHelper::pipeContents(Pipeline* p) |
| 519 | { | 523 | { |
| 520 | - if (this->oh.isFormXObject()) { | ||
| 521 | - this->oh.pipeStreamData(p, 0, qpdf_dl_specialized); | 524 | + if (oh().isFormXObject()) { |
| 525 | + oh().pipeStreamData(p, 0, qpdf_dl_specialized); | ||
| 522 | } else { | 526 | } else { |
| 523 | - this->oh.pipePageContents(p); | 527 | + oh().pipePageContents(p); |
| 524 | } | 528 | } |
| 525 | } | 529 | } |
| 526 | 530 | ||
| @@ -528,10 +532,10 @@ void | @@ -528,10 +532,10 @@ void | ||
| 528 | QPDFPageObjectHelper::addContentTokenFilter( | 532 | QPDFPageObjectHelper::addContentTokenFilter( |
| 529 | std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter) | 533 | std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter) |
| 530 | { | 534 | { |
| 531 | - if (this->oh.isFormXObject()) { | ||
| 532 | - this->oh.addTokenFilter(token_filter); | 535 | + if (oh().isFormXObject()) { |
| 536 | + oh().addTokenFilter(token_filter); | ||
| 533 | } else { | 537 | } else { |
| 534 | - this->oh.addContentTokenFilter(token_filter); | 538 | + oh().addContentTokenFilter(token_filter); |
| 535 | } | 539 | } |
| 536 | } | 540 | } |
| 537 | 541 | ||
| @@ -539,30 +543,28 @@ bool | @@ -539,30 +543,28 @@ bool | ||
| 539 | QPDFPageObjectHelper::removeUnreferencedResourcesHelper( | 543 | QPDFPageObjectHelper::removeUnreferencedResourcesHelper( |
| 540 | QPDFPageObjectHelper ph, std::set<std::string>& unresolved) | 544 | QPDFPageObjectHelper ph, std::set<std::string>& unresolved) |
| 541 | { | 545 | { |
| 542 | - bool is_page = (!ph.oh.isFormXObject()); | 546 | + bool is_page = (!ph.oh().isFormXObject()); |
| 543 | if (!is_page) { | 547 | if (!is_page) { |
| 544 | QTC::TC("qpdf", "QPDFPageObjectHelper filter form xobject"); | 548 | QTC::TC("qpdf", "QPDFPageObjectHelper filter form xobject"); |
| 545 | } | 549 | } |
| 546 | 550 | ||
| 547 | ResourceFinder rf; | 551 | ResourceFinder rf; |
| 548 | try { | 552 | try { |
| 549 | - auto q = ph.oh.getOwningQPDF(); | 553 | + auto q = ph.oh().getOwningQPDF(); |
| 550 | size_t before_nw = (q ? q->numWarnings() : 0); | 554 | size_t before_nw = (q ? q->numWarnings() : 0); |
| 551 | ph.parseContents(&rf); | 555 | ph.parseContents(&rf); |
| 552 | size_t after_nw = (q ? q->numWarnings() : 0); | 556 | size_t after_nw = (q ? q->numWarnings() : 0); |
| 553 | if (after_nw > before_nw) { | 557 | if (after_nw > before_nw) { |
| 554 | - ph.oh.warnIfPossible( | 558 | + ph.oh().warnIfPossible( |
| 555 | "Bad token found while scanning content stream; " | 559 | "Bad token found while scanning content stream; " |
| 556 | - "not attempting to remove unreferenced objects from" | ||
| 557 | - " this object"); | 560 | + "not attempting to remove unreferenced objects from this object"); |
| 558 | return false; | 561 | return false; |
| 559 | } | 562 | } |
| 560 | } catch (std::exception& e) { | 563 | } catch (std::exception& e) { |
| 561 | QTC::TC("qpdf", "QPDFPageObjectHelper bad token finding names"); | 564 | QTC::TC("qpdf", "QPDFPageObjectHelper bad token finding names"); |
| 562 | - ph.oh.warnIfPossible( | 565 | + ph.oh().warnIfPossible( |
| 563 | std::string("Unable to parse content stream: ") + e.what() + | 566 | std::string("Unable to parse content stream: ") + e.what() + |
| 564 | - "; not attempting to remove unreferenced objects" | ||
| 565 | - " from this object"); | 567 | + "; not attempting to remove unreferenced objects from this object"); |
| 566 | return false; | 568 | return false; |
| 567 | } | 569 | } |
| 568 | 570 | ||
| @@ -646,7 +648,7 @@ QPDFPageObjectHelper::removeUnreferencedResources() | @@ -646,7 +648,7 @@ QPDFPageObjectHelper::removeUnreferencedResources() | ||
| 646 | any_failures = true; | 648 | any_failures = true; |
| 647 | } | 649 | } |
| 648 | }); | 650 | }); |
| 649 | - if (this->oh.isFormXObject() || (!any_failures)) { | 651 | + if (oh().isFormXObject() || (!any_failures)) { |
| 650 | removeUnreferencedResourcesHelper(*this, unresolved); | 652 | removeUnreferencedResourcesHelper(*this, unresolved); |
| 651 | } | 653 | } |
| 652 | } | 654 | } |
| @@ -654,9 +656,8 @@ QPDFPageObjectHelper::removeUnreferencedResources() | @@ -654,9 +656,8 @@ QPDFPageObjectHelper::removeUnreferencedResources() | ||
| 654 | QPDFPageObjectHelper | 656 | QPDFPageObjectHelper |
| 655 | QPDFPageObjectHelper::shallowCopyPage() | 657 | QPDFPageObjectHelper::shallowCopyPage() |
| 656 | { | 658 | { |
| 657 | - QPDF& qpdf = | ||
| 658 | - this->oh.getQPDF("QPDFPageObjectHelper::shallowCopyPage called with a direct object"); | ||
| 659 | - QPDFObjectHandle new_page = this->oh.shallowCopy(); | 659 | + QPDF& qpdf = oh().getQPDF("QPDFPageObjectHelper::shallowCopyPage called with a direct object"); |
| 660 | + QPDFObjectHandle new_page = oh().shallowCopy(); | ||
| 660 | return {qpdf.makeIndirectObject(new_page)}; | 661 | return {qpdf.makeIndirectObject(new_page)}; |
| 661 | } | 662 | } |
| 662 | 663 | ||
| @@ -707,7 +708,7 @@ QPDFObjectHandle | @@ -707,7 +708,7 @@ QPDFObjectHandle | ||
| 707 | QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) | 708 | QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) |
| 708 | { | 709 | { |
| 709 | auto result = | 710 | auto result = |
| 710 | - this->oh.getQPDF("QPDFPageObjectHelper::getFormXObjectForPage called with a direct object") | 711 | + oh().getQPDF("QPDFPageObjectHelper::getFormXObjectForPage called with a direct object") |
| 711 | .newStream(); | 712 | .newStream(); |
| 712 | QPDFObjectHandle newdict = result.getDict(); | 713 | QPDFObjectHandle newdict = result.getDict(); |
| 713 | newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); | 714 | newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); |
| @@ -716,13 +717,13 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) | @@ -716,13 +717,13 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) | ||
| 716 | newdict.replaceKey("/Group", getAttribute("/Group", false).shallowCopy()); | 717 | newdict.replaceKey("/Group", getAttribute("/Group", false).shallowCopy()); |
| 717 | QPDFObjectHandle bbox = getTrimBox(false).shallowCopy(); | 718 | QPDFObjectHandle bbox = getTrimBox(false).shallowCopy(); |
| 718 | if (!bbox.isRectangle()) { | 719 | if (!bbox.isRectangle()) { |
| 719 | - this->oh.warnIfPossible( | 720 | + oh().warnIfPossible( |
| 720 | "bounding box is invalid; form" | 721 | "bounding box is invalid; form" |
| 721 | " XObject created from page will not work"); | 722 | " XObject created from page will not work"); |
| 722 | } | 723 | } |
| 723 | newdict.replaceKey("/BBox", bbox); | 724 | newdict.replaceKey("/BBox", bbox); |
| 724 | auto provider = | 725 | auto provider = |
| 725 | - std::shared_ptr<QPDFObjectHandle::StreamDataProvider>(new ContentProvider(this->oh)); | 726 | + std::shared_ptr<QPDFObjectHandle::StreamDataProvider>(new ContentProvider(oh())); |
| 726 | result.replaceStreamData(provider, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull()); | 727 | result.replaceStreamData(provider, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull()); |
| 727 | QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); | 728 | QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); |
| 728 | QPDFObjectHandle scale_obj = getAttribute("/UserUnit", false); | 729 | QPDFObjectHandle scale_obj = getAttribute("/UserUnit", false); |
| @@ -863,9 +864,8 @@ QPDFPageObjectHelper::placeFormXObject( | @@ -863,9 +864,8 @@ QPDFPageObjectHelper::placeFormXObject( | ||
| 863 | void | 864 | void |
| 864 | QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | 865 | QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) |
| 865 | { | 866 | { |
| 866 | - QPDF& qpdf = | ||
| 867 | - this->oh.getQPDF("QPDFPageObjectHelper::flattenRotation called with a direct object"); | ||
| 868 | - auto rotate_oh = this->oh.getKey("/Rotate"); | 867 | + QPDF& qpdf = oh().getQPDF("QPDFPageObjectHelper::flattenRotation called with a direct object"); |
| 868 | + auto rotate_oh = oh().getKey("/Rotate"); | ||
| 869 | int rotate = 0; | 869 | int rotate = 0; |
| 870 | if (rotate_oh.isInteger()) { | 870 | if (rotate_oh.isInteger()) { |
| 871 | rotate = rotate_oh.getIntValueAsInt(); | 871 | rotate = rotate_oh.getIntValueAsInt(); |
| @@ -873,7 +873,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | @@ -873,7 +873,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | ||
| 873 | if (!((rotate == 90) || (rotate == 180) || (rotate == 270))) { | 873 | if (!((rotate == 90) || (rotate == 180) || (rotate == 270))) { |
| 874 | return; | 874 | return; |
| 875 | } | 875 | } |
| 876 | - auto mediabox = this->oh.getKey("/MediaBox"); | 876 | + auto mediabox = oh().getKey("/MediaBox"); |
| 877 | if (!mediabox.isRectangle()) { | 877 | if (!mediabox.isRectangle()) { |
| 878 | return; | 878 | return; |
| 879 | } | 879 | } |
| @@ -887,7 +887,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | @@ -887,7 +887,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | ||
| 887 | "/ArtBox", | 887 | "/ArtBox", |
| 888 | }; | 888 | }; |
| 889 | for (auto const& boxkey: boxes) { | 889 | for (auto const& boxkey: boxes) { |
| 890 | - auto box = this->oh.getKey(boxkey); | 890 | + auto box = oh().getKey(boxkey); |
| 891 | if (!box.isRectangle()) { | 891 | if (!box.isRectangle()) { |
| 892 | continue; | 892 | continue; |
| 893 | } | 893 | } |
| @@ -930,7 +930,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | @@ -930,7 +930,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | ||
| 930 | break; | 930 | break; |
| 931 | } | 931 | } |
| 932 | 932 | ||
| 933 | - this->oh.replaceKey(boxkey, QPDFObjectHandle::newFromRectangle(new_rect)); | 933 | + oh().replaceKey(boxkey, QPDFObjectHandle::newFromRectangle(new_rect)); |
| 934 | } | 934 | } |
| 935 | 935 | ||
| 936 | // When we rotate the page, pivot about the point 0, 0 and then translate so the page is visible | 936 | // When we rotate the page, pivot about the point 0, 0 and then translate so the page is visible |
| @@ -962,16 +962,16 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | @@ -962,16 +962,16 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | ||
| 962 | break; | 962 | break; |
| 963 | } | 963 | } |
| 964 | std::string cm_str = std::string("q\n") + cm.unparse() + " cm\n"; | 964 | std::string cm_str = std::string("q\n") + cm.unparse() + " cm\n"; |
| 965 | - this->oh.addPageContents(QPDFObjectHandle::newStream(&qpdf, cm_str), true); | ||
| 966 | - this->oh.addPageContents(qpdf.newStream("\nQ\n"), false); | ||
| 967 | - this->oh.removeKey("/Rotate"); | 965 | + oh().addPageContents(QPDFObjectHandle::newStream(&qpdf, cm_str), true); |
| 966 | + oh().addPageContents(qpdf.newStream("\nQ\n"), false); | ||
| 967 | + oh().removeKey("/Rotate"); | ||
| 968 | QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); | 968 | QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); |
| 969 | if (!rotate_obj.isNull()) { | 969 | if (!rotate_obj.isNull()) { |
| 970 | QTC::TC("qpdf", "QPDFPageObjectHelper flatten inherit rotate"); | 970 | QTC::TC("qpdf", "QPDFPageObjectHelper flatten inherit rotate"); |
| 971 | - this->oh.replaceKey("/Rotate", QPDFObjectHandle::newInteger(0)); | 971 | + oh().replaceKey("/Rotate", QPDFObjectHandle::newInteger(0)); |
| 972 | } | 972 | } |
| 973 | 973 | ||
| 974 | - QPDFObjectHandle annots = this->oh.getKey("/Annots"); | 974 | + QPDFObjectHandle annots = oh().getKey("/Annots"); |
| 975 | if (annots.isArray()) { | 975 | if (annots.isArray()) { |
| 976 | std::vector<QPDFObjectHandle> new_annots; | 976 | std::vector<QPDFObjectHandle> new_annots; |
| 977 | std::vector<QPDFObjectHandle> new_fields; | 977 | std::vector<QPDFObjectHandle> new_fields; |
| @@ -986,7 +986,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | @@ -986,7 +986,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | ||
| 986 | for (auto const& f: new_fields) { | 986 | for (auto const& f: new_fields) { |
| 987 | afdh->addFormField(QPDFFormFieldObjectHelper(f)); | 987 | afdh->addFormField(QPDFFormFieldObjectHelper(f)); |
| 988 | } | 988 | } |
| 989 | - this->oh.replaceKey("/Annots", QPDFObjectHandle::newArray(new_annots)); | 989 | + oh().replaceKey("/Annots", QPDFObjectHandle::newArray(new_annots)); |
| 990 | } | 990 | } |
| 991 | } | 991 | } |
| 992 | 992 | ||
| @@ -1005,7 +1005,7 @@ QPDFPageObjectHelper::copyAnnotations( | @@ -1005,7 +1005,7 @@ QPDFPageObjectHelper::copyAnnotations( | ||
| 1005 | QPDF& from_qpdf = from_page.getObjectHandle().getQPDF( | 1005 | QPDF& from_qpdf = from_page.getObjectHandle().getQPDF( |
| 1006 | "QPDFPageObjectHelper::copyAnnotations: from page is a direct object"); | 1006 | "QPDFPageObjectHelper::copyAnnotations: from page is a direct object"); |
| 1007 | QPDF& this_qpdf = | 1007 | QPDF& this_qpdf = |
| 1008 | - this->oh.getQPDF("QPDFPageObjectHelper::copyAnnotations: this page is a direct object"); | 1008 | + oh().getQPDF("QPDFPageObjectHelper::copyAnnotations: this page is a direct object"); |
| 1009 | 1009 | ||
| 1010 | std::vector<QPDFObjectHandle> new_annots; | 1010 | std::vector<QPDFObjectHandle> new_annots; |
| 1011 | std::vector<QPDFObjectHandle> new_fields; | 1011 | std::vector<QPDFObjectHandle> new_fields; |
| @@ -1032,9 +1032,9 @@ QPDFPageObjectHelper::copyAnnotations( | @@ -1032,9 +1032,9 @@ QPDFPageObjectHelper::copyAnnotations( | ||
| 1032 | afdh->transformAnnotations( | 1032 | afdh->transformAnnotations( |
| 1033 | old_annots, new_annots, new_fields, old_fields, cm, &from_qpdf, from_afdh); | 1033 | old_annots, new_annots, new_fields, old_fields, cm, &from_qpdf, from_afdh); |
| 1034 | afdh->addAndRenameFormFields(new_fields); | 1034 | afdh->addAndRenameFormFields(new_fields); |
| 1035 | - auto annots = this->oh.getKey("/Annots"); | 1035 | + auto annots = oh().getKey("/Annots"); |
| 1036 | if (!annots.isArray()) { | 1036 | if (!annots.isArray()) { |
| 1037 | - annots = this->oh.replaceKeyAndGetNew("/Annots", QPDFObjectHandle::newArray()); | 1037 | + annots = oh().replaceKeyAndGetNew("/Annots", QPDFObjectHandle::newArray()); |
| 1038 | } | 1038 | } |
| 1039 | for (auto const& annot: new_annots) { | 1039 | for (auto const& annot: new_annots) { |
| 1040 | annots.appendItem(annot); | 1040 | annots.appendItem(annot); |
libqpdf/QPDFParser.cc
| @@ -4,18 +4,6 @@ | @@ -4,18 +4,6 @@ | ||
| 4 | #include <qpdf/QPDFObjGen.hh> | 4 | #include <qpdf/QPDFObjGen.hh> |
| 5 | #include <qpdf/QPDFObjectHandle.hh> | 5 | #include <qpdf/QPDFObjectHandle.hh> |
| 6 | #include <qpdf/QPDFObject_private.hh> | 6 | #include <qpdf/QPDFObject_private.hh> |
| 7 | -#include <qpdf/QPDF_Array.hh> | ||
| 8 | -#include <qpdf/QPDF_Bool.hh> | ||
| 9 | -#include <qpdf/QPDF_Dictionary.hh> | ||
| 10 | -#include <qpdf/QPDF_InlineImage.hh> | ||
| 11 | -#include <qpdf/QPDF_Integer.hh> | ||
| 12 | -#include <qpdf/QPDF_Name.hh> | ||
| 13 | -#include <qpdf/QPDF_Null.hh> | ||
| 14 | -#include <qpdf/QPDF_Operator.hh> | ||
| 15 | -#include <qpdf/QPDF_Real.hh> | ||
| 16 | -#include <qpdf/QPDF_Reserved.hh> | ||
| 17 | -#include <qpdf/QPDF_Stream.hh> | ||
| 18 | -#include <qpdf/QPDF_String.hh> | ||
| 19 | #include <qpdf/QTC.hh> | 7 | #include <qpdf/QTC.hh> |
| 20 | #include <qpdf/QUtil.hh> | 8 | #include <qpdf/QUtil.hh> |
| 21 | 9 | ||
| @@ -47,27 +35,27 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -47,27 +35,27 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 47 | } | 35 | } |
| 48 | QTC::TC("qpdf", "QPDFParser eof in parse"); | 36 | QTC::TC("qpdf", "QPDFParser eof in parse"); |
| 49 | warn("unexpected EOF"); | 37 | warn("unexpected EOF"); |
| 50 | - return {QPDF_Null::create()}; | 38 | + return {QPDFObject::create<QPDF_Null>()}; |
| 51 | 39 | ||
| 52 | case QPDFTokenizer::tt_bad: | 40 | case QPDFTokenizer::tt_bad: |
| 53 | QTC::TC("qpdf", "QPDFParser bad token in parse"); | 41 | QTC::TC("qpdf", "QPDFParser bad token in parse"); |
| 54 | - return {QPDF_Null::create()}; | 42 | + return {QPDFObject::create<QPDF_Null>()}; |
| 55 | 43 | ||
| 56 | case QPDFTokenizer::tt_brace_open: | 44 | case QPDFTokenizer::tt_brace_open: |
| 57 | case QPDFTokenizer::tt_brace_close: | 45 | case QPDFTokenizer::tt_brace_close: |
| 58 | QTC::TC("qpdf", "QPDFParser bad brace"); | 46 | QTC::TC("qpdf", "QPDFParser bad brace"); |
| 59 | warn("treating unexpected brace token as null"); | 47 | warn("treating unexpected brace token as null"); |
| 60 | - return {QPDF_Null::create()}; | 48 | + return {QPDFObject::create<QPDF_Null>()}; |
| 61 | 49 | ||
| 62 | case QPDFTokenizer::tt_array_close: | 50 | case QPDFTokenizer::tt_array_close: |
| 63 | QTC::TC("qpdf", "QPDFParser bad array close"); | 51 | QTC::TC("qpdf", "QPDFParser bad array close"); |
| 64 | warn("treating unexpected array close token as null"); | 52 | warn("treating unexpected array close token as null"); |
| 65 | - return {QPDF_Null::create()}; | 53 | + return {QPDFObject::create<QPDF_Null>()}; |
| 66 | 54 | ||
| 67 | case QPDFTokenizer::tt_dict_close: | 55 | case QPDFTokenizer::tt_dict_close: |
| 68 | QTC::TC("qpdf", "QPDFParser bad dictionary close"); | 56 | QTC::TC("qpdf", "QPDFParser bad dictionary close"); |
| 69 | warn("unexpected dictionary close token"); | 57 | warn("unexpected dictionary close token"); |
| 70 | - return {QPDF_Null::create()}; | 58 | + return {QPDFObject::create<QPDF_Null>()}; |
| 71 | 59 | ||
| 72 | case QPDFTokenizer::tt_array_open: | 60 | case QPDFTokenizer::tt_array_open: |
| 73 | case QPDFTokenizer::tt_dict_open: | 61 | case QPDFTokenizer::tt_dict_open: |
| @@ -82,7 +70,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -82,7 +70,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 82 | return withDescription<QPDF_Bool>(tokenizer.getValue() == "true"); | 70 | return withDescription<QPDF_Bool>(tokenizer.getValue() == "true"); |
| 83 | 71 | ||
| 84 | case QPDFTokenizer::tt_null: | 72 | case QPDFTokenizer::tt_null: |
| 85 | - return {QPDF_Null::create()}; | 73 | + return {QPDFObject::create<QPDF_Null>()}; |
| 86 | 74 | ||
| 87 | case QPDFTokenizer::tt_integer: | 75 | case QPDFTokenizer::tt_integer: |
| 88 | return withDescription<QPDF_Integer>(QUtil::string_to_ll(tokenizer.getValue().c_str())); | 76 | return withDescription<QPDF_Integer>(QUtil::string_to_ll(tokenizer.getValue().c_str())); |
| @@ -103,7 +91,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -103,7 +91,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 103 | // not move the input source's offset. | 91 | // not move the input source's offset. |
| 104 | input.seek(input.getLastOffset(), SEEK_SET); | 92 | input.seek(input.getLastOffset(), SEEK_SET); |
| 105 | empty = true; | 93 | empty = true; |
| 106 | - return {QPDF_Null::create()}; | 94 | + return {QPDFObject::create<QPDF_Null>()}; |
| 107 | } else { | 95 | } else { |
| 108 | QTC::TC("qpdf", "QPDFParser treat word as string"); | 96 | QTC::TC("qpdf", "QPDFParser treat word as string"); |
| 109 | warn("unknown token while reading object; treating as string"); | 97 | warn("unknown token while reading object; treating as string"); |
| @@ -122,7 +110,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -122,7 +110,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 122 | 110 | ||
| 123 | default: | 111 | default: |
| 124 | warn("treating unknown token type as null while reading object"); | 112 | warn("treating unknown token type as null while reading object"); |
| 125 | - return {QPDF_Null::create()}; | 113 | + return {QPDFObject::create<QPDF_Null>()}; |
| 126 | } | 114 | } |
| 127 | } | 115 | } |
| 128 | 116 | ||
| @@ -194,12 +182,12 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -194,12 +182,12 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 194 | } | 182 | } |
| 195 | QTC::TC("qpdf", "QPDFParser eof in parseRemainder"); | 183 | QTC::TC("qpdf", "QPDFParser eof in parseRemainder"); |
| 196 | warn("unexpected EOF"); | 184 | warn("unexpected EOF"); |
| 197 | - return {QPDF_Null::create()}; | 185 | + return {QPDFObject::create<QPDF_Null>()}; |
| 198 | 186 | ||
| 199 | case QPDFTokenizer::tt_bad: | 187 | case QPDFTokenizer::tt_bad: |
| 200 | QTC::TC("qpdf", "QPDFParser bad token in parseRemainder"); | 188 | QTC::TC("qpdf", "QPDFParser bad token in parseRemainder"); |
| 201 | if (tooManyBadTokens()) { | 189 | if (tooManyBadTokens()) { |
| 202 | - return {QPDF_Null::create()}; | 190 | + return {QPDFObject::create<QPDF_Null>()}; |
| 203 | } | 191 | } |
| 204 | addNull(); | 192 | addNull(); |
| 205 | continue; | 193 | continue; |
| @@ -209,7 +197,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -209,7 +197,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 209 | QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder"); | 197 | QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder"); |
| 210 | warn("treating unexpected brace token as null"); | 198 | warn("treating unexpected brace token as null"); |
| 211 | if (tooManyBadTokens()) { | 199 | if (tooManyBadTokens()) { |
| 212 | - return {QPDF_Null::create()}; | 200 | + return {QPDFObject::create<QPDF_Null>()}; |
| 213 | } | 201 | } |
| 214 | addNull(); | 202 | addNull(); |
| 215 | continue; | 203 | continue; |
| @@ -218,10 +206,12 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -218,10 +206,12 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 218 | if (bad_count && !max_bad_count) { | 206 | if (bad_count && !max_bad_count) { |
| 219 | // Trigger warning. | 207 | // Trigger warning. |
| 220 | (void)tooManyBadTokens(); | 208 | (void)tooManyBadTokens(); |
| 221 | - return {QPDF_Null::create()}; | 209 | + return {QPDFObject::create<QPDF_Null>()}; |
| 222 | } | 210 | } |
| 223 | if (frame->state == st_array) { | 211 | if (frame->state == st_array) { |
| 224 | - auto object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100); | 212 | + auto object = frame->null_count > 100 |
| 213 | + ? QPDFObject::create<QPDF_Array>(std::move(frame->olist), true) | ||
| 214 | + : QPDFObject::create<QPDF_Array>(std::move(frame->olist)); | ||
| 225 | setDescription(object, frame->offset - 1); | 215 | setDescription(object, frame->offset - 1); |
| 226 | // The `offset` points to the next of "[". Set the rewind offset to point to the | 216 | // The `offset` points to the next of "[". Set the rewind offset to point to the |
| 227 | // beginning of "[". This has been explicitly tested with whitespace surrounding the | 217 | // beginning of "[". This has been explicitly tested with whitespace surrounding the |
| @@ -237,7 +227,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -237,7 +227,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 237 | QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); | 227 | QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); |
| 238 | warn("treating unexpected array close token as null"); | 228 | warn("treating unexpected array close token as null"); |
| 239 | if (tooManyBadTokens()) { | 229 | if (tooManyBadTokens()) { |
| 240 | - return {QPDF_Null::create()}; | 230 | + return {QPDFObject::create<QPDF_Null>()}; |
| 241 | } | 231 | } |
| 242 | addNull(); | 232 | addNull(); |
| 243 | } | 233 | } |
| @@ -247,7 +237,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -247,7 +237,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 247 | if (bad_count && !max_bad_count) { | 237 | if (bad_count && !max_bad_count) { |
| 248 | // Trigger warning. | 238 | // Trigger warning. |
| 249 | (void)tooManyBadTokens(); | 239 | (void)tooManyBadTokens(); |
| 250 | - return {QPDF_Null::create()}; | 240 | + return {QPDFObject::create<QPDF_Null>()}; |
| 251 | } | 241 | } |
| 252 | if (frame->state <= st_dictionary_value) { | 242 | if (frame->state <= st_dictionary_value) { |
| 253 | // Attempt to recover more or less gracefully from invalid dictionaries. | 243 | // Attempt to recover more or less gracefully from invalid dictionaries. |
| @@ -258,7 +248,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -258,7 +248,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 258 | warn( | 248 | warn( |
| 259 | frame->offset, | 249 | frame->offset, |
| 260 | "dictionary ended prematurely; using null as value for last key"); | 250 | "dictionary ended prematurely; using null as value for last key"); |
| 261 | - dict[frame->key] = QPDF_Null::create(); | 251 | + dict[frame->key] = QPDFObject::create<QPDF_Null>(); |
| 262 | } | 252 | } |
| 263 | 253 | ||
| 264 | if (!frame->olist.empty()) { | 254 | if (!frame->olist.empty()) { |
| @@ -271,7 +261,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -271,7 +261,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 271 | dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string); | 261 | dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string); |
| 272 | dict["/Contents"].setParsedOffset(frame->contents_offset); | 262 | dict["/Contents"].setParsedOffset(frame->contents_offset); |
| 273 | } | 263 | } |
| 274 | - auto object = QPDF_Dictionary::create(std::move(dict)); | 264 | + auto object = QPDFObject::create<QPDF_Dictionary>(std::move(dict)); |
| 275 | setDescription(object, frame->offset - 2); | 265 | setDescription(object, frame->offset - 2); |
| 276 | // The `offset` points to the next of "<<". Set the rewind offset to point to the | 266 | // The `offset` points to the next of "<<". Set the rewind offset to point to the |
| 277 | // beginning of "<<". This has been explicitly tested with whitespace surrounding | 267 | // beginning of "<<". This has been explicitly tested with whitespace surrounding |
| @@ -287,7 +277,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -287,7 +277,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 287 | QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder"); | 277 | QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder"); |
| 288 | warn("unexpected dictionary close token"); | 278 | warn("unexpected dictionary close token"); |
| 289 | if (tooManyBadTokens()) { | 279 | if (tooManyBadTokens()) { |
| 290 | - return {QPDF_Null::create()}; | 280 | + return {QPDFObject::create<QPDF_Null>()}; |
| 291 | } | 281 | } |
| 292 | addNull(); | 282 | addNull(); |
| 293 | } | 283 | } |
| @@ -298,7 +288,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -298,7 +288,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 298 | if (stack.size() > 499) { | 288 | if (stack.size() > 499) { |
| 299 | QTC::TC("qpdf", "QPDFParser too deep"); | 289 | QTC::TC("qpdf", "QPDFParser too deep"); |
| 300 | warn("ignoring excessively deeply nested data structure"); | 290 | warn("ignoring excessively deeply nested data structure"); |
| 301 | - return {QPDF_Null::create()}; | 291 | + return {QPDFObject::create<QPDF_Null>()}; |
| 302 | } else { | 292 | } else { |
| 303 | b_contents = false; | 293 | b_contents = false; |
| 304 | stack.emplace_back( | 294 | stack.emplace_back( |
| @@ -350,7 +340,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -350,7 +340,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 350 | QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); | 340 | QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); |
| 351 | warn("unknown token while reading object; treating as string"); | 341 | warn("unknown token while reading object; treating as string"); |
| 352 | if (tooManyBadTokens()) { | 342 | if (tooManyBadTokens()) { |
| 353 | - return {QPDF_Null::create()}; | 343 | + return {QPDFObject::create<QPDF_Null>()}; |
| 354 | } | 344 | } |
| 355 | addScalar<QPDF_String>(tokenizer.getValue()); | 345 | addScalar<QPDF_String>(tokenizer.getValue()); |
| 356 | } | 346 | } |
| @@ -377,7 +367,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -377,7 +367,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 377 | default: | 367 | default: |
| 378 | warn("treating unknown token type as null while reading object"); | 368 | warn("treating unknown token type as null while reading object"); |
| 379 | if (tooManyBadTokens()) { | 369 | if (tooManyBadTokens()) { |
| 380 | - return {QPDF_Null::create()}; | 370 | + return {QPDFObject::create<QPDF_Null>()}; |
| 381 | } | 371 | } |
| 382 | addNull(); | 372 | addNull(); |
| 383 | } | 373 | } |
| @@ -402,7 +392,7 @@ QPDFParser::add(std::shared_ptr<QPDFObject>&& obj) | @@ -402,7 +392,7 @@ QPDFParser::add(std::shared_ptr<QPDFObject>&& obj) | ||
| 402 | void | 392 | void |
| 403 | QPDFParser::addNull() | 393 | QPDFParser::addNull() |
| 404 | { | 394 | { |
| 405 | - const static ObjectPtr null_obj = QPDF_Null::create(); | 395 | + const static ObjectPtr null_obj = QPDFObject::create<QPDF_Null>(); |
| 406 | 396 | ||
| 407 | if (frame->state != st_dictionary_value) { | 397 | if (frame->state != st_dictionary_value) { |
| 408 | // If state is st_dictionary_key then there is a missing key. Push onto olist for | 398 | // If state is st_dictionary_key then there is a missing key. Push onto olist for |
| @@ -420,7 +410,7 @@ QPDFParser::addNull() | @@ -420,7 +410,7 @@ QPDFParser::addNull() | ||
| 420 | void | 410 | void |
| 421 | QPDFParser::addInt(int count) | 411 | QPDFParser::addInt(int count) |
| 422 | { | 412 | { |
| 423 | - auto obj = QPDF_Integer::create(int_buffer[count % 2]); | 413 | + auto obj = QPDFObject::create<QPDF_Integer>(int_buffer[count % 2]); |
| 424 | obj->setDescription(context, description, last_offset_buffer[count % 2]); | 414 | obj->setDescription(context, description, last_offset_buffer[count % 2]); |
| 425 | add(std::move(obj)); | 415 | add(std::move(obj)); |
| 426 | } | 416 | } |
| @@ -435,7 +425,7 @@ QPDFParser::addScalar(Args&&... args) | @@ -435,7 +425,7 @@ QPDFParser::addScalar(Args&&... args) | ||
| 435 | max_bad_count = 0; | 425 | max_bad_count = 0; |
| 436 | return; | 426 | return; |
| 437 | } | 427 | } |
| 438 | - auto obj = T::create(args...); | 428 | + auto obj = QPDFObject::create<T>(std::forward<Args>(args)...); |
| 439 | obj->setDescription(context, description, input.getLastOffset()); | 429 | obj->setDescription(context, description, input.getLastOffset()); |
| 440 | add(std::move(obj)); | 430 | add(std::move(obj)); |
| 441 | } | 431 | } |
| @@ -444,7 +434,7 @@ template <typename T, typename... Args> | @@ -444,7 +434,7 @@ template <typename T, typename... Args> | ||
| 444 | QPDFObjectHandle | 434 | QPDFObjectHandle |
| 445 | QPDFParser::withDescription(Args&&... args) | 435 | QPDFParser::withDescription(Args&&... args) |
| 446 | { | 436 | { |
| 447 | - auto obj = T::create(args...); | 437 | + auto obj = QPDFObject::create<T>(std::forward<Args>(args)...); |
| 448 | obj->setDescription(context, description, start); | 438 | obj->setDescription(context, description, start); |
| 449 | return {obj}; | 439 | return {obj}; |
| 450 | } | 440 | } |
| @@ -462,8 +452,8 @@ QPDFParser::fixMissingKeys() | @@ -462,8 +452,8 @@ QPDFParser::fixMissingKeys() | ||
| 462 | { | 452 | { |
| 463 | std::set<std::string> names; | 453 | std::set<std::string> names; |
| 464 | for (auto& obj: frame->olist) { | 454 | for (auto& obj: frame->olist) { |
| 465 | - if (obj->getTypeCode() == ::ot_name) { | ||
| 466 | - names.insert(obj->getStringValue()); | 455 | + if (obj.getObj()->getTypeCode() == ::ot_name) { |
| 456 | + names.insert(obj.getObj()->getStringValue()); | ||
| 467 | } | 457 | } |
| 468 | } | 458 | } |
| 469 | int next_fake_key = 1; | 459 | int next_fake_key = 1; |
libqpdf/QPDFValue.cc deleted
| 1 | -#include <qpdf/QPDFValue.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/QPDFObject_private.hh> | ||
| 4 | - | ||
| 5 | -std::shared_ptr<QPDFObject> | ||
| 6 | -QPDFValue::do_create(QPDFValue* object) | ||
| 7 | -{ | ||
| 8 | - std::shared_ptr<QPDFObject> obj(new QPDFObject()); | ||
| 9 | - obj->value = std::shared_ptr<QPDFValue>(object); | ||
| 10 | - return obj; | ||
| 11 | -} | ||
| 12 | - | ||
| 13 | -std::string | ||
| 14 | -QPDFValue::getDescription() | ||
| 15 | -{ | ||
| 16 | - if (object_description) { | ||
| 17 | - switch (object_description->index()) { | ||
| 18 | - case 0: | ||
| 19 | - { | ||
| 20 | - // Simple template string | ||
| 21 | - auto description = std::get<0>(*object_description); | ||
| 22 | - | ||
| 23 | - if (auto pos = description.find("$OG"); pos != std::string::npos) { | ||
| 24 | - description.replace(pos, 3, og.unparse(' ')); | ||
| 25 | - } | ||
| 26 | - if (auto pos = description.find("$PO"); pos != std::string::npos) { | ||
| 27 | - qpdf_offset_t shift = (type_code == ::ot_dictionary) ? 2 | ||
| 28 | - : (type_code == ::ot_array) ? 1 | ||
| 29 | - : 0; | ||
| 30 | - | ||
| 31 | - description.replace(pos, 3, std::to_string(parsed_offset + shift)); | ||
| 32 | - } | ||
| 33 | - return description; | ||
| 34 | - } | ||
| 35 | - case 1: | ||
| 36 | - { | ||
| 37 | - // QPDF::JSONReactor generated description | ||
| 38 | - auto j_descr = std::get<1>(*object_description); | ||
| 39 | - return ( | ||
| 40 | - *j_descr.input + (j_descr.object.empty() ? "" : ", " + j_descr.object) + | ||
| 41 | - " at offset " + std::to_string(parsed_offset)); | ||
| 42 | - } | ||
| 43 | - case 2: | ||
| 44 | - { | ||
| 45 | - // Child object description | ||
| 46 | - auto j_descr = std::get<2>(*object_description); | ||
| 47 | - std::string result; | ||
| 48 | - if (auto p = j_descr.parent.lock()) { | ||
| 49 | - result = p->getDescription(); | ||
| 50 | - } | ||
| 51 | - result += j_descr.static_descr; | ||
| 52 | - if (auto pos = result.find("$VD"); pos != std::string::npos) { | ||
| 53 | - result.replace(pos, 3, j_descr.var_descr); | ||
| 54 | - } | ||
| 55 | - return result; | ||
| 56 | - } | ||
| 57 | - } | ||
| 58 | - } else if (og.isIndirect()) { | ||
| 59 | - return "object " + og.unparse(' '); | ||
| 60 | - } | ||
| 61 | - return {}; | ||
| 62 | -} |
libqpdf/QPDFWriter.cc
| @@ -15,9 +15,8 @@ | @@ -15,9 +15,8 @@ | ||
| 15 | #include <qpdf/Pl_StdioFile.hh> | 15 | #include <qpdf/Pl_StdioFile.hh> |
| 16 | #include <qpdf/QIntC.hh> | 16 | #include <qpdf/QIntC.hh> |
| 17 | #include <qpdf/QPDF.hh> | 17 | #include <qpdf/QPDF.hh> |
| 18 | -#include <qpdf/QPDFObjectHandle.hh> | ||
| 19 | -#include <qpdf/QPDF_Name.hh> | ||
| 20 | -#include <qpdf/QPDF_String.hh> | 18 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 19 | +#include <qpdf/QPDFObject_private.hh> | ||
| 21 | #include <qpdf/QTC.hh> | 20 | #include <qpdf/QTC.hh> |
| 22 | #include <qpdf/QUtil.hh> | 21 | #include <qpdf/QUtil.hh> |
| 23 | #include <qpdf/RC4.hh> | 22 | #include <qpdf/RC4.hh> |
| @@ -27,6 +26,7 @@ | @@ -27,6 +26,7 @@ | ||
| 27 | #include <stdexcept> | 26 | #include <stdexcept> |
| 28 | 27 | ||
| 29 | using namespace std::literals; | 28 | using namespace std::literals; |
| 29 | +using namespace qpdf; | ||
| 30 | 30 | ||
| 31 | QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) | 31 | QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) |
| 32 | { | 32 | { |
| @@ -1129,12 +1129,12 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) | @@ -1129,12 +1129,12 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) | ||
| 1129 | return; | 1129 | return; |
| 1130 | } else if (!m->linearized) { | 1130 | } else if (!m->linearized) { |
| 1131 | if (object.isArray()) { | 1131 | if (object.isArray()) { |
| 1132 | - for (auto& item: object.getArrayAsVector()) { | 1132 | + for (auto& item: object.as_array()) { |
| 1133 | enqueueObject(item); | 1133 | enqueueObject(item); |
| 1134 | } | 1134 | } |
| 1135 | - } else if (object.isDictionary()) { | ||
| 1136 | - for (auto& item: object.getDictAsMap()) { | ||
| 1137 | - if (!item.second.isNull()) { | 1135 | + } else if (auto d = object.as_dictionary()) { |
| 1136 | + for (auto const& item: d) { | ||
| 1137 | + if (!item.second.null()) { | ||
| 1138 | enqueueObject(item.second); | 1138 | enqueueObject(item.second); |
| 1139 | } | 1139 | } |
| 1140 | } | 1140 | } |
| @@ -1173,10 +1173,13 @@ QPDFWriter::writeTrailer( | @@ -1173,10 +1173,13 @@ QPDFWriter::writeTrailer( | ||
| 1173 | writeString(" /Size "); | 1173 | writeString(" /Size "); |
| 1174 | writeString(std::to_string(size)); | 1174 | writeString(std::to_string(size)); |
| 1175 | } else { | 1175 | } else { |
| 1176 | - for (auto const& key: trailer.getKeys()) { | 1176 | + for (auto const& [key, value]: trailer.as_dictionary()) { |
| 1177 | + if (value.null()) { | ||
| 1178 | + continue; | ||
| 1179 | + } | ||
| 1177 | writeStringQDF(" "); | 1180 | writeStringQDF(" "); |
| 1178 | writeStringNoQDF(" "); | 1181 | writeStringNoQDF(" "); |
| 1179 | - writeString(QPDF_Name::normalizeName(key)); | 1182 | + writeString(Name::normalize(key)); |
| 1180 | writeString(" "); | 1183 | writeString(" "); |
| 1181 | if (key == "/Size") { | 1184 | if (key == "/Size") { |
| 1182 | writeString(std::to_string(size)); | 1185 | writeString(std::to_string(size)); |
| @@ -1187,7 +1190,7 @@ QPDFWriter::writeTrailer( | @@ -1187,7 +1190,7 @@ QPDFWriter::writeTrailer( | ||
| 1187 | writePad(QIntC::to_size(pos - m->pipeline->getCount() + 21)); | 1190 | writePad(QIntC::to_size(pos - m->pipeline->getCount() + 21)); |
| 1188 | } | 1191 | } |
| 1189 | } else { | 1192 | } else { |
| 1190 | - unparseChild(trailer.getKey(key), 1, 0); | 1193 | + unparseChild(value, 1, 0); |
| 1191 | } | 1194 | } |
| 1192 | writeStringQDF("\n"); | 1195 | writeStringQDF("\n"); |
| 1193 | } | 1196 | } |
| @@ -1347,7 +1350,7 @@ QPDFWriter::unparseObject( | @@ -1347,7 +1350,7 @@ QPDFWriter::unparseObject( | ||
| 1347 | // [ in the /H key of the linearization parameter dictionary. We'll do this unconditionally | 1350 | // [ in the /H key of the linearization parameter dictionary. We'll do this unconditionally |
| 1348 | // for all arrays because it looks nicer and doesn't make the files that much bigger. | 1351 | // for all arrays because it looks nicer and doesn't make the files that much bigger. |
| 1349 | writeString("["); | 1352 | writeString("["); |
| 1350 | - for (auto const& item: object.getArrayAsVector()) { | 1353 | + for (auto const& item: object.as_array()) { |
| 1351 | writeString(indent); | 1354 | writeString(indent); |
| 1352 | writeStringQDF(" "); | 1355 | writeStringQDF(" "); |
| 1353 | unparseChild(item, level + 1, child_flags); | 1356 | unparseChild(item, level + 1, child_flags); |
| @@ -1498,20 +1501,18 @@ QPDFWriter::unparseObject( | @@ -1498,20 +1501,18 @@ QPDFWriter::unparseObject( | ||
| 1498 | 1501 | ||
| 1499 | writeString("<<"); | 1502 | writeString("<<"); |
| 1500 | 1503 | ||
| 1501 | - for (auto& item: object.getDictAsMap()) { | ||
| 1502 | - if (!item.second.isNull()) { | ||
| 1503 | - auto const& key = item.first; | 1504 | + for (auto const& [key, value]: object.as_dictionary()) { |
| 1505 | + if (!value.null()) { | ||
| 1504 | writeString(indent); | 1506 | writeString(indent); |
| 1505 | writeStringQDF(" "); | 1507 | writeStringQDF(" "); |
| 1506 | - writeString(QPDF_Name::normalizeName(key)); | 1508 | + writeString(Name::normalize(key)); |
| 1507 | writeString(" "); | 1509 | writeString(" "); |
| 1508 | if (key == "/Contents" && object.isDictionaryOfType("/Sig") && | 1510 | if (key == "/Contents" && object.isDictionaryOfType("/Sig") && |
| 1509 | object.hasKey("/ByteRange")) { | 1511 | object.hasKey("/ByteRange")) { |
| 1510 | QTC::TC("qpdf", "QPDFWriter no encryption sig contents"); | 1512 | QTC::TC("qpdf", "QPDFWriter no encryption sig contents"); |
| 1511 | - unparseChild( | ||
| 1512 | - item.second, level + 1, child_flags | f_hex_string | f_no_encryption); | 1513 | + unparseChild(value, level + 1, child_flags | f_hex_string | f_no_encryption); |
| 1513 | } else { | 1514 | } else { |
| 1514 | - unparseChild(item.second, level + 1, child_flags); | 1515 | + unparseChild(value, level + 1, child_flags); |
| 1515 | } | 1516 | } |
| 1516 | } | 1517 | } |
| 1517 | } | 1518 | } |
| @@ -1891,12 +1892,10 @@ QPDFWriter::generateID() | @@ -1891,12 +1892,10 @@ QPDFWriter::generateID() | ||
| 1891 | } | 1892 | } |
| 1892 | seed += " QPDF "; | 1893 | seed += " QPDF "; |
| 1893 | if (trailer.hasKey("/Info")) { | 1894 | if (trailer.hasKey("/Info")) { |
| 1894 | - QPDFObjectHandle info = trailer.getKey("/Info"); | ||
| 1895 | - for (auto const& key: info.getKeys()) { | ||
| 1896 | - QPDFObjectHandle obj = info.getKey(key); | ||
| 1897 | - if (obj.isString()) { | 1895 | + for (auto const& item: trailer.getKey("/Info").as_dictionary()) { |
| 1896 | + if (item.second.isString()) { | ||
| 1898 | seed += " "; | 1897 | seed += " "; |
| 1899 | - seed += obj.getStringValue(); | 1898 | + seed += item.second.getStringValue(); |
| 1900 | } | 1899 | } |
| 1901 | } | 1900 | } |
| 1902 | } | 1901 | } |
| @@ -1922,8 +1921,7 @@ QPDFWriter::generateID() | @@ -1922,8 +1921,7 @@ QPDFWriter::generateID() | ||
| 1922 | void | 1921 | void |
| 1923 | QPDFWriter::initializeSpecialStreams() | 1922 | QPDFWriter::initializeSpecialStreams() |
| 1924 | { | 1923 | { |
| 1925 | - // Mark all page content streams in case we are filtering or | ||
| 1926 | - // normalizing. | 1924 | + // Mark all page content streams in case we are filtering or normalizing. |
| 1927 | std::vector<QPDFObjectHandle> pages = m->pdf.getAllPages(); | 1925 | std::vector<QPDFObjectHandle> pages = m->pdf.getAllPages(); |
| 1928 | int num = 0; | 1926 | int num = 0; |
| 1929 | for (auto& page: pages) { | 1927 | for (auto& page: pages) { |
| @@ -2939,8 +2937,10 @@ QPDFWriter::enqueueObjectsStandard() | @@ -2939,8 +2937,10 @@ QPDFWriter::enqueueObjectsStandard() | ||
| 2939 | 2937 | ||
| 2940 | // Next place any other objects referenced from the trailer dictionary into the queue, handling | 2938 | // Next place any other objects referenced from the trailer dictionary into the queue, handling |
| 2941 | // direct objects recursively. Root is already there, so enqueuing it a second time is a no-op. | 2939 | // direct objects recursively. Root is already there, so enqueuing it a second time is a no-op. |
| 2942 | - for (auto const& key: trailer.getKeys()) { | ||
| 2943 | - enqueueObject(trailer.getKey(key)); | 2940 | + for (auto& item: trailer.as_dictionary()) { |
| 2941 | + if (!item.second.null()) { | ||
| 2942 | + enqueueObject(item.second); | ||
| 2943 | + } | ||
| 2944 | } | 2944 | } |
| 2945 | } | 2945 | } |
| 2946 | 2946 | ||
| @@ -2962,9 +2962,11 @@ QPDFWriter::enqueueObjectsPCLm() | @@ -2962,9 +2962,11 @@ QPDFWriter::enqueueObjectsPCLm() | ||
| 2962 | 2962 | ||
| 2963 | // enqueue all the strips for each page | 2963 | // enqueue all the strips for each page |
| 2964 | QPDFObjectHandle strips = page.getKey("/Resources").getKey("/XObject"); | 2964 | QPDFObjectHandle strips = page.getKey("/Resources").getKey("/XObject"); |
| 2965 | - for (auto const& image: strips.getKeys()) { | ||
| 2966 | - enqueueObject(strips.getKey(image)); | ||
| 2967 | - enqueueObject(QPDFObjectHandle::newStream(&m->pdf, image_transform_content)); | 2965 | + for (auto& image: strips.as_dictionary()) { |
| 2966 | + if (!image.second.null()) { | ||
| 2967 | + enqueueObject(image.second); | ||
| 2968 | + enqueueObject(QPDFObjectHandle::newStream(&m->pdf, image_transform_content)); | ||
| 2969 | + } | ||
| 2968 | } | 2970 | } |
| 2969 | } | 2971 | } |
| 2970 | 2972 |
libqpdf/QPDF_Array.cc
| 1 | -#include <qpdf/QPDF_Array.hh> | 1 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 2 | 2 | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | -#include <qpdf/QPDFObjectHandle.hh> | ||
| 5 | -#include <qpdf/QPDFObject_private.hh> | ||
| 6 | #include <qpdf/QTC.hh> | 3 | #include <qpdf/QTC.hh> |
| 7 | 4 | ||
| 5 | +using namespace std::literals; | ||
| 6 | +using namespace qpdf; | ||
| 7 | + | ||
| 8 | static const QPDFObjectHandle null_oh = QPDFObjectHandle::newNull(); | 8 | static const QPDFObjectHandle null_oh = QPDFObjectHandle::newNull(); |
| 9 | 9 | ||
| 10 | inline void | 10 | inline void |
| 11 | -QPDF_Array::checkOwnership(QPDFObjectHandle const& item) const | ||
| 12 | -{ | ||
| 13 | - if (auto obj = item.getObjectPtr()) { | ||
| 14 | - if (qpdf) { | ||
| 15 | - if (auto item_qpdf = obj->getQPDF()) { | ||
| 16 | - if (qpdf != item_qpdf) { | ||
| 17 | - throw std::logic_error( | ||
| 18 | - "Attempting to add an object from a different QPDF. Use " | ||
| 19 | - "QPDF::copyForeignObject to add objects from another file."); | ||
| 20 | - } | ||
| 21 | - } | ||
| 22 | - } | ||
| 23 | - } else { | 11 | +Array::checkOwnership(QPDFObjectHandle const& item) const |
| 12 | +{ | ||
| 13 | + if (!item) { | ||
| 24 | throw std::logic_error("Attempting to add an uninitialized object to a QPDF_Array."); | 14 | throw std::logic_error("Attempting to add an uninitialized object to a QPDF_Array."); |
| 25 | } | 15 | } |
| 16 | + if (qpdf() && item.qpdf() && qpdf() != item.qpdf()) { | ||
| 17 | + throw std::logic_error( | ||
| 18 | + "Attempting to add an object from a different QPDF. Use " | ||
| 19 | + "QPDF::copyForeignObject to add objects from another file."); | ||
| 20 | + } | ||
| 26 | } | 21 | } |
| 27 | 22 | ||
| 28 | -QPDF_Array::QPDF_Array() : | ||
| 29 | - QPDFValue(::ot_array) | ||
| 30 | -{ | ||
| 31 | -} | ||
| 32 | - | ||
| 33 | -QPDF_Array::QPDF_Array(QPDF_Array const& other) : | ||
| 34 | - QPDFValue(::ot_array), | ||
| 35 | - sp(other.sp ? std::make_unique<Sparse>(*other.sp) : nullptr) | ||
| 36 | -{ | ||
| 37 | -} | ||
| 38 | - | ||
| 39 | -QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v) : | ||
| 40 | - QPDFValue(::ot_array) | ||
| 41 | -{ | ||
| 42 | - setFromVector(v); | ||
| 43 | -} | ||
| 44 | - | ||
| 45 | -QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse) : | ||
| 46 | - QPDFValue(::ot_array) | 23 | +QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle>&& v, bool sparse) |
| 47 | { | 24 | { |
| 48 | if (sparse) { | 25 | if (sparse) { |
| 49 | sp = std::make_unique<Sparse>(); | 26 | sp = std::make_unique<Sparse>(); |
| 50 | - for (auto&& item: v) { | ||
| 51 | - if (item->getTypeCode() != ::ot_null || item->getObjGen().isIndirect()) { | 27 | + for (auto& item: v) { |
| 28 | + if (item.raw_type_code() != ::ot_null || item.indirect()) { | ||
| 52 | sp->elements[sp->size] = std::move(item); | 29 | sp->elements[sp->size] = std::move(item); |
| 53 | } | 30 | } |
| 54 | ++sp->size; | 31 | ++sp->size; |
| @@ -58,191 +35,184 @@ QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse | @@ -58,191 +35,184 @@ QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse | ||
| 58 | } | 35 | } |
| 59 | } | 36 | } |
| 60 | 37 | ||
| 61 | -std::shared_ptr<QPDFObject> | ||
| 62 | -QPDF_Array::create(std::vector<QPDFObjectHandle> const& items) | 38 | +QPDF_Array* |
| 39 | +Array::array() const | ||
| 63 | { | 40 | { |
| 64 | - return do_create(new QPDF_Array(items)); | 41 | + if (auto a = as<QPDF_Array>()) { |
| 42 | + return a; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + throw std::runtime_error("Expected an array but found a non-array object"); | ||
| 46 | + return nullptr; // unreachable | ||
| 65 | } | 47 | } |
| 66 | 48 | ||
| 67 | -std::shared_ptr<QPDFObject> | ||
| 68 | -QPDF_Array::create(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse) | 49 | +Array::iterator |
| 50 | +Array::begin() | ||
| 69 | { | 51 | { |
| 70 | - return do_create(new QPDF_Array(std::move(items), sparse)); | 52 | + if (auto a = as<QPDF_Array>()) { |
| 53 | + if (!a->sp) { | ||
| 54 | + return a->elements.begin(); | ||
| 55 | + } | ||
| 56 | + if (!sp_elements) { | ||
| 57 | + sp_elements = std::make_unique<std::vector<QPDFObjectHandle>>(getAsVector()); | ||
| 58 | + } | ||
| 59 | + return sp_elements->begin(); | ||
| 60 | + } | ||
| 61 | + return {}; | ||
| 71 | } | 62 | } |
| 72 | 63 | ||
| 73 | -std::shared_ptr<QPDFObject> | ||
| 74 | -QPDF_Array::copy(bool shallow) | 64 | +Array::iterator |
| 65 | +Array::end() | ||
| 75 | { | 66 | { |
| 76 | - if (shallow) { | ||
| 77 | - return do_create(new QPDF_Array(*this)); | ||
| 78 | - } else { | ||
| 79 | - QTC::TC("qpdf", "QPDF_Array copy", sp ? 0 : 1); | ||
| 80 | - if (sp) { | ||
| 81 | - auto* result = new QPDF_Array(); | ||
| 82 | - result->sp = std::make_unique<Sparse>(); | ||
| 83 | - result->sp->size = sp->size; | ||
| 84 | - for (auto const& element: sp->elements) { | ||
| 85 | - auto const& obj = element.second; | ||
| 86 | - result->sp->elements[element.first] = | ||
| 87 | - obj->getObjGen().isIndirect() ? obj : obj->copy(); | ||
| 88 | - } | ||
| 89 | - return do_create(result); | ||
| 90 | - } else { | ||
| 91 | - std::vector<std::shared_ptr<QPDFObject>> result; | ||
| 92 | - result.reserve(elements.size()); | ||
| 93 | - for (auto const& element: elements) { | ||
| 94 | - result.push_back( | ||
| 95 | - element ? (element->getObjGen().isIndirect() ? element : element->copy()) | ||
| 96 | - : element); | ||
| 97 | - } | ||
| 98 | - return create(std::move(result), false); | 67 | + if (auto a = as<QPDF_Array>()) { |
| 68 | + if (!a->sp) { | ||
| 69 | + return a->elements.end(); | ||
| 99 | } | 70 | } |
| 71 | + if (!sp_elements) { | ||
| 72 | + sp_elements = std::make_unique<std::vector<QPDFObjectHandle>>(getAsVector()); | ||
| 73 | + } | ||
| 74 | + return sp_elements->end(); | ||
| 100 | } | 75 | } |
| 76 | + return {}; | ||
| 101 | } | 77 | } |
| 102 | 78 | ||
| 103 | -void | ||
| 104 | -QPDF_Array::disconnect() | 79 | +Array::const_iterator |
| 80 | +Array::cbegin() | ||
| 105 | { | 81 | { |
| 106 | - if (sp) { | ||
| 107 | - for (auto& item: sp->elements) { | ||
| 108 | - auto& obj = item.second; | ||
| 109 | - if (!obj->getObjGen().isIndirect()) { | ||
| 110 | - obj->disconnect(); | ||
| 111 | - } | 82 | + if (auto a = as<QPDF_Array>()) { |
| 83 | + if (!a->sp) { | ||
| 84 | + return a->elements.cbegin(); | ||
| 112 | } | 85 | } |
| 113 | - } else { | ||
| 114 | - for (auto& obj: elements) { | ||
| 115 | - if (!obj->getObjGen().isIndirect()) { | ||
| 116 | - obj->disconnect(); | ||
| 117 | - } | 86 | + if (!sp_elements) { |
| 87 | + sp_elements = std::make_unique<std::vector<QPDFObjectHandle>>(getAsVector()); | ||
| 118 | } | 88 | } |
| 89 | + return sp_elements->cbegin(); | ||
| 119 | } | 90 | } |
| 91 | + return {}; | ||
| 120 | } | 92 | } |
| 121 | 93 | ||
| 122 | -std::string | ||
| 123 | -QPDF_Array::unparse() | 94 | +Array::const_iterator |
| 95 | +Array::cend() | ||
| 124 | { | 96 | { |
| 125 | - std::string result = "[ "; | ||
| 126 | - if (sp) { | ||
| 127 | - int next = 0; | ||
| 128 | - for (auto& item: sp->elements) { | ||
| 129 | - int key = item.first; | ||
| 130 | - for (int j = next; j < key; ++j) { | ||
| 131 | - result += "null "; | ||
| 132 | - } | ||
| 133 | - auto og = item.second->resolved_object()->getObjGen(); | ||
| 134 | - result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " "; | ||
| 135 | - next = ++key; | 97 | + if (auto a = as<QPDF_Array>()) { |
| 98 | + if (!a->sp) { | ||
| 99 | + return a->elements.cend(); | ||
| 136 | } | 100 | } |
| 137 | - for (int j = next; j < sp->size; ++j) { | ||
| 138 | - result += "null "; | ||
| 139 | - } | ||
| 140 | - } else { | ||
| 141 | - for (auto const& item: elements) { | ||
| 142 | - auto og = item->resolved_object()->getObjGen(); | ||
| 143 | - result += og.isIndirect() ? og.unparse(' ') + " R " : item->unparse() + " "; | 101 | + if (!sp_elements) { |
| 102 | + sp_elements = std::make_unique<std::vector<QPDFObjectHandle>>(getAsVector()); | ||
| 144 | } | 103 | } |
| 104 | + return sp_elements->cend(); | ||
| 145 | } | 105 | } |
| 146 | - result += "]"; | ||
| 147 | - return result; | 106 | + return {}; |
| 148 | } | 107 | } |
| 149 | 108 | ||
| 150 | -void | ||
| 151 | -QPDF_Array::writeJSON(int json_version, JSON::Writer& p) | ||
| 152 | -{ | ||
| 153 | - p.writeStart('['); | ||
| 154 | - if (sp) { | ||
| 155 | - int next = 0; | ||
| 156 | - for (auto& item: sp->elements) { | ||
| 157 | - int key = item.first; | ||
| 158 | - for (int j = next; j < key; ++j) { | ||
| 159 | - p.writeNext() << "null"; | ||
| 160 | - } | ||
| 161 | - p.writeNext(); | ||
| 162 | - auto og = item.second->getObjGen(); | ||
| 163 | - if (og.isIndirect()) { | ||
| 164 | - p << "\"" << og.unparse(' ') << " R\""; | ||
| 165 | - } else { | ||
| 166 | - item.second->writeJSON(json_version, p); | ||
| 167 | - } | ||
| 168 | - next = ++key; | 109 | +Array::const_reverse_iterator |
| 110 | +Array::crbegin() | ||
| 111 | +{ | ||
| 112 | + if (auto a = as<QPDF_Array>()) { | ||
| 113 | + if (!a->sp) { | ||
| 114 | + return a->elements.crbegin(); | ||
| 169 | } | 115 | } |
| 170 | - for (int j = next; j < sp->size; ++j) { | ||
| 171 | - p.writeNext() << "null"; | 116 | + if (!sp_elements) { |
| 117 | + sp_elements = std::make_unique<std::vector<QPDFObjectHandle>>(getAsVector()); | ||
| 172 | } | 118 | } |
| 173 | - } else { | ||
| 174 | - for (auto const& item: elements) { | ||
| 175 | - p.writeNext(); | ||
| 176 | - auto og = item->getObjGen(); | ||
| 177 | - if (og.isIndirect()) { | ||
| 178 | - p << "\"" << og.unparse(' ') << " R\""; | ||
| 179 | - } else { | ||
| 180 | - item->writeJSON(json_version, p); | ||
| 181 | - } | 119 | + return sp_elements->crbegin(); |
| 120 | + } | ||
| 121 | + return {}; | ||
| 122 | +} | ||
| 123 | + | ||
| 124 | +Array::const_reverse_iterator | ||
| 125 | +Array::crend() | ||
| 126 | +{ | ||
| 127 | + if (auto a = as<QPDF_Array>()) { | ||
| 128 | + if (!a->sp) { | ||
| 129 | + return a->elements.crend(); | ||
| 182 | } | 130 | } |
| 131 | + if (!sp_elements) { | ||
| 132 | + sp_elements = std::make_unique<std::vector<QPDFObjectHandle>>(getAsVector()); | ||
| 133 | + } | ||
| 134 | + return sp_elements->crend(); | ||
| 183 | } | 135 | } |
| 184 | - p.writeEnd(']'); | 136 | + return {}; |
| 137 | +} | ||
| 138 | + | ||
| 139 | +QPDFObjectHandle | ||
| 140 | +Array::null() const | ||
| 141 | +{ | ||
| 142 | + return null_oh; | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +int | ||
| 146 | +Array::size() const | ||
| 147 | +{ | ||
| 148 | + auto a = array(); | ||
| 149 | + return a->sp ? a->sp->size : int(a->elements.size()); | ||
| 185 | } | 150 | } |
| 186 | 151 | ||
| 187 | std::pair<bool, QPDFObjectHandle> | 152 | std::pair<bool, QPDFObjectHandle> |
| 188 | -QPDF_Array::at(int n) const noexcept | 153 | +Array::at(int n) const |
| 189 | { | 154 | { |
| 155 | + auto a = array(); | ||
| 190 | if (n < 0 || n >= size()) { | 156 | if (n < 0 || n >= size()) { |
| 191 | return {false, {}}; | 157 | return {false, {}}; |
| 192 | - } else if (sp) { | ||
| 193 | - auto const& iter = sp->elements.find(n); | ||
| 194 | - return {true, iter == sp->elements.end() ? null_oh : (*iter).second}; | ||
| 195 | - } else { | ||
| 196 | - return {true, elements[size_t(n)]}; | ||
| 197 | } | 158 | } |
| 159 | + if (!a->sp) { | ||
| 160 | + return {true, a->elements[size_t(n)]}; | ||
| 161 | + } | ||
| 162 | + auto const& iter = a->sp->elements.find(n); | ||
| 163 | + return {true, iter == a->sp->elements.end() ? null() : iter->second}; | ||
| 198 | } | 164 | } |
| 199 | 165 | ||
| 200 | std::vector<QPDFObjectHandle> | 166 | std::vector<QPDFObjectHandle> |
| 201 | -QPDF_Array::getAsVector() const | 167 | +Array::getAsVector() const |
| 202 | { | 168 | { |
| 203 | - if (sp) { | 169 | + auto a = array(); |
| 170 | + if (a->sp) { | ||
| 204 | std::vector<QPDFObjectHandle> v; | 171 | std::vector<QPDFObjectHandle> v; |
| 205 | v.reserve(size_t(size())); | 172 | v.reserve(size_t(size())); |
| 206 | - for (auto const& item: sp->elements) { | 173 | + for (auto const& item: a->sp->elements) { |
| 207 | v.resize(size_t(item.first), null_oh); | 174 | v.resize(size_t(item.first), null_oh); |
| 208 | v.emplace_back(item.second); | 175 | v.emplace_back(item.second); |
| 209 | } | 176 | } |
| 210 | v.resize(size_t(size()), null_oh); | 177 | v.resize(size_t(size()), null_oh); |
| 211 | return v; | 178 | return v; |
| 212 | } else { | 179 | } else { |
| 213 | - return {elements.cbegin(), elements.cend()}; | 180 | + return a->elements; |
| 214 | } | 181 | } |
| 215 | } | 182 | } |
| 216 | 183 | ||
| 217 | bool | 184 | bool |
| 218 | -QPDF_Array::setAt(int at, QPDFObjectHandle const& oh) | 185 | +Array::setAt(int at, QPDFObjectHandle const& oh) |
| 219 | { | 186 | { |
| 220 | if (at < 0 || at >= size()) { | 187 | if (at < 0 || at >= size()) { |
| 221 | return false; | 188 | return false; |
| 222 | } | 189 | } |
| 190 | + auto a = array(); | ||
| 223 | checkOwnership(oh); | 191 | checkOwnership(oh); |
| 224 | - if (sp) { | ||
| 225 | - sp->elements[at] = oh.getObj(); | 192 | + if (a->sp) { |
| 193 | + a->sp->elements[at] = oh; | ||
| 226 | } else { | 194 | } else { |
| 227 | - elements[size_t(at)] = oh.getObj(); | 195 | + a->elements[size_t(at)] = oh; |
| 228 | } | 196 | } |
| 229 | return true; | 197 | return true; |
| 230 | } | 198 | } |
| 231 | 199 | ||
| 232 | void | 200 | void |
| 233 | -QPDF_Array::setFromVector(std::vector<QPDFObjectHandle> const& v) | 201 | +Array::setFromVector(std::vector<QPDFObjectHandle> const& v) |
| 234 | { | 202 | { |
| 235 | - elements.resize(0); | ||
| 236 | - elements.reserve(v.size()); | 203 | + auto a = array(); |
| 204 | + a->elements.resize(0); | ||
| 205 | + a->elements.reserve(v.size()); | ||
| 237 | for (auto const& item: v) { | 206 | for (auto const& item: v) { |
| 238 | checkOwnership(item); | 207 | checkOwnership(item); |
| 239 | - elements.push_back(item.getObj()); | 208 | + a->elements.emplace_back(item); |
| 240 | } | 209 | } |
| 241 | } | 210 | } |
| 242 | 211 | ||
| 243 | bool | 212 | bool |
| 244 | -QPDF_Array::insert(int at, QPDFObjectHandle const& item) | 213 | +Array::insert(int at, QPDFObjectHandle const& item) |
| 245 | { | 214 | { |
| 215 | + auto a = array(); | ||
| 246 | int sz = size(); | 216 | int sz = size(); |
| 247 | if (at < 0 || at > sz) { | 217 | if (at < 0 || at > sz) { |
| 248 | // As special case, also allow insert beyond the end | 218 | // As special case, also allow insert beyond the end |
| @@ -251,61 +221,257 @@ QPDF_Array::insert(int at, QPDFObjectHandle const& item) | @@ -251,61 +221,257 @@ QPDF_Array::insert(int at, QPDFObjectHandle const& item) | ||
| 251 | push_back(item); | 221 | push_back(item); |
| 252 | } else { | 222 | } else { |
| 253 | checkOwnership(item); | 223 | checkOwnership(item); |
| 254 | - if (sp) { | ||
| 255 | - auto iter = sp->elements.crbegin(); | ||
| 256 | - while (iter != sp->elements.crend()) { | 224 | + if (a->sp) { |
| 225 | + auto iter = a->sp->elements.crbegin(); | ||
| 226 | + while (iter != a->sp->elements.crend()) { | ||
| 257 | auto key = (iter++)->first; | 227 | auto key = (iter++)->first; |
| 258 | if (key >= at) { | 228 | if (key >= at) { |
| 259 | - auto nh = sp->elements.extract(key); | 229 | + auto nh = a->sp->elements.extract(key); |
| 260 | ++nh.key(); | 230 | ++nh.key(); |
| 261 | - sp->elements.insert(std::move(nh)); | 231 | + a->sp->elements.insert(std::move(nh)); |
| 262 | } else { | 232 | } else { |
| 263 | break; | 233 | break; |
| 264 | } | 234 | } |
| 265 | } | 235 | } |
| 266 | - sp->elements[at] = item.getObj(); | ||
| 267 | - ++sp->size; | 236 | + a->sp->elements[at] = item.getObj(); |
| 237 | + ++a->sp->size; | ||
| 268 | } else { | 238 | } else { |
| 269 | - elements.insert(elements.cbegin() + at, item.getObj()); | 239 | + a->elements.insert(a->elements.cbegin() + at, item.getObj()); |
| 270 | } | 240 | } |
| 271 | } | 241 | } |
| 272 | return true; | 242 | return true; |
| 273 | } | 243 | } |
| 274 | 244 | ||
| 275 | void | 245 | void |
| 276 | -QPDF_Array::push_back(QPDFObjectHandle const& item) | 246 | +Array::push_back(QPDFObjectHandle const& item) |
| 277 | { | 247 | { |
| 248 | + auto a = array(); | ||
| 278 | checkOwnership(item); | 249 | checkOwnership(item); |
| 279 | - if (sp) { | ||
| 280 | - sp->elements[(sp->size)++] = item.getObj(); | 250 | + if (a->sp) { |
| 251 | + a->sp->elements[(a->sp->size)++] = item; | ||
| 281 | } else { | 252 | } else { |
| 282 | - elements.push_back(item.getObj()); | 253 | + a->elements.emplace_back(item); |
| 283 | } | 254 | } |
| 284 | } | 255 | } |
| 285 | 256 | ||
| 286 | bool | 257 | bool |
| 287 | -QPDF_Array::erase(int at) | 258 | +Array::erase(int at) |
| 288 | { | 259 | { |
| 260 | + auto a = array(); | ||
| 289 | if (at < 0 || at >= size()) { | 261 | if (at < 0 || at >= size()) { |
| 290 | return false; | 262 | return false; |
| 291 | } | 263 | } |
| 292 | - if (sp) { | ||
| 293 | - auto end = sp->elements.end(); | ||
| 294 | - if (auto iter = sp->elements.lower_bound(at); iter != end) { | 264 | + if (a->sp) { |
| 265 | + auto end = a->sp->elements.end(); | ||
| 266 | + if (auto iter = a->sp->elements.lower_bound(at); iter != end) { | ||
| 295 | if (iter->first == at) { | 267 | if (iter->first == at) { |
| 296 | iter++; | 268 | iter++; |
| 297 | - sp->elements.erase(at); | 269 | + a->sp->elements.erase(at); |
| 298 | } | 270 | } |
| 299 | 271 | ||
| 300 | while (iter != end) { | 272 | while (iter != end) { |
| 301 | - auto nh = sp->elements.extract(iter++); | 273 | + auto nh = a->sp->elements.extract(iter++); |
| 302 | --nh.key(); | 274 | --nh.key(); |
| 303 | - sp->elements.insert(std::move(nh)); | 275 | + a->sp->elements.insert(std::move(nh)); |
| 304 | } | 276 | } |
| 305 | } | 277 | } |
| 306 | - --(sp->size); | 278 | + --(a->sp->size); |
| 307 | } else { | 279 | } else { |
| 308 | - elements.erase(elements.cbegin() + at); | 280 | + a->elements.erase(a->elements.cbegin() + at); |
| 309 | } | 281 | } |
| 310 | return true; | 282 | return true; |
| 311 | } | 283 | } |
| 284 | + | ||
| 285 | +int | ||
| 286 | +QPDFObjectHandle::getArrayNItems() const | ||
| 287 | +{ | ||
| 288 | + if (auto array = as_array(strict)) { | ||
| 289 | + return array.size(); | ||
| 290 | + } | ||
| 291 | + typeWarning("array", "treating as empty"); | ||
| 292 | + QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); | ||
| 293 | + return 0; | ||
| 294 | +} | ||
| 295 | + | ||
| 296 | +QPDFObjectHandle | ||
| 297 | +QPDFObjectHandle::getArrayItem(int n) const | ||
| 298 | +{ | ||
| 299 | + if (auto array = as_array(strict)) { | ||
| 300 | + if (auto const [success, oh] = array.at(n); success) { | ||
| 301 | + return oh; | ||
| 302 | + } else { | ||
| 303 | + objectWarning("returning null for out of bounds array access"); | ||
| 304 | + QTC::TC("qpdf", "QPDFObjectHandle array bounds"); | ||
| 305 | + } | ||
| 306 | + } else { | ||
| 307 | + typeWarning("array", "returning null"); | ||
| 308 | + QTC::TC("qpdf", "QPDFObjectHandle array null for non-array"); | ||
| 309 | + } | ||
| 310 | + static auto constexpr msg = " -> null returned from invalid array access"sv; | ||
| 311 | + return QPDF_Null::create(obj, msg, ""); | ||
| 312 | +} | ||
| 313 | + | ||
| 314 | +bool | ||
| 315 | +QPDFObjectHandle::isRectangle() const | ||
| 316 | +{ | ||
| 317 | + if (auto array = as_array(strict)) { | ||
| 318 | + for (int i = 0; i < 4; ++i) { | ||
| 319 | + if (auto item = array.at(i).second; !item.isNumber()) { | ||
| 320 | + return false; | ||
| 321 | + } | ||
| 322 | + } | ||
| 323 | + return array.size() == 4; | ||
| 324 | + } | ||
| 325 | + return false; | ||
| 326 | +} | ||
| 327 | + | ||
| 328 | +bool | ||
| 329 | +QPDFObjectHandle::isMatrix() const | ||
| 330 | +{ | ||
| 331 | + if (auto array = as_array(strict)) { | ||
| 332 | + for (int i = 0; i < 6; ++i) { | ||
| 333 | + if (auto item = array.at(i).second; !item.isNumber()) { | ||
| 334 | + return false; | ||
| 335 | + } | ||
| 336 | + } | ||
| 337 | + return array.size() == 6; | ||
| 338 | + } | ||
| 339 | + return false; | ||
| 340 | +} | ||
| 341 | + | ||
| 342 | +QPDFObjectHandle::Rectangle | ||
| 343 | +QPDFObjectHandle::getArrayAsRectangle() const | ||
| 344 | +{ | ||
| 345 | + if (auto array = as_array(strict)) { | ||
| 346 | + if (array.size() != 4) { | ||
| 347 | + return {}; | ||
| 348 | + } | ||
| 349 | + double items[4]; | ||
| 350 | + for (int i = 0; i < 4; ++i) { | ||
| 351 | + if (auto item = array.at(i).second; !item.getValueAsNumber(items[i])) { | ||
| 352 | + return {}; | ||
| 353 | + } | ||
| 354 | + } | ||
| 355 | + return { | ||
| 356 | + std::min(items[0], items[2]), | ||
| 357 | + std::min(items[1], items[3]), | ||
| 358 | + std::max(items[0], items[2]), | ||
| 359 | + std::max(items[1], items[3])}; | ||
| 360 | + } | ||
| 361 | + return {}; | ||
| 362 | +} | ||
| 363 | + | ||
| 364 | +QPDFObjectHandle::Matrix | ||
| 365 | +QPDFObjectHandle::getArrayAsMatrix() const | ||
| 366 | +{ | ||
| 367 | + if (auto array = as_array(strict)) { | ||
| 368 | + if (array.size() != 6) { | ||
| 369 | + return {}; | ||
| 370 | + } | ||
| 371 | + double items[6]; | ||
| 372 | + for (int i = 0; i < 6; ++i) { | ||
| 373 | + if (auto item = array.at(i).second; !item.getValueAsNumber(items[i])) { | ||
| 374 | + return {}; | ||
| 375 | + } | ||
| 376 | + } | ||
| 377 | + return {items[0], items[1], items[2], items[3], items[4], items[5]}; | ||
| 378 | + } | ||
| 379 | + return {}; | ||
| 380 | +} | ||
| 381 | + | ||
| 382 | +std::vector<QPDFObjectHandle> | ||
| 383 | +QPDFObjectHandle::getArrayAsVector() const | ||
| 384 | +{ | ||
| 385 | + if (auto array = as_array(strict)) { | ||
| 386 | + return array.getAsVector(); | ||
| 387 | + } | ||
| 388 | + typeWarning("array", "treating as empty"); | ||
| 389 | + QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector"); | ||
| 390 | + return {}; | ||
| 391 | +} | ||
| 392 | + | ||
| 393 | +void | ||
| 394 | +QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item) | ||
| 395 | +{ | ||
| 396 | + if (auto array = as_array(strict)) { | ||
| 397 | + if (!array.setAt(n, item)) { | ||
| 398 | + objectWarning("ignoring attempt to set out of bounds array item"); | ||
| 399 | + QTC::TC("qpdf", "QPDFObjectHandle set array bounds"); | ||
| 400 | + } | ||
| 401 | + } else { | ||
| 402 | + typeWarning("array", "ignoring attempt to set item"); | ||
| 403 | + QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item"); | ||
| 404 | + } | ||
| 405 | +} | ||
| 406 | +void | ||
| 407 | +QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items) | ||
| 408 | +{ | ||
| 409 | + if (auto array = as_array(strict)) { | ||
| 410 | + array.setFromVector(items); | ||
| 411 | + } else { | ||
| 412 | + typeWarning("array", "ignoring attempt to replace items"); | ||
| 413 | + QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items"); | ||
| 414 | + } | ||
| 415 | +} | ||
| 416 | + | ||
| 417 | +void | ||
| 418 | +QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item) | ||
| 419 | +{ | ||
| 420 | + if (auto array = as_array(strict)) { | ||
| 421 | + if (!array.insert(at, item)) { | ||
| 422 | + objectWarning("ignoring attempt to insert out of bounds array item"); | ||
| 423 | + QTC::TC("qpdf", "QPDFObjectHandle insert array bounds"); | ||
| 424 | + } | ||
| 425 | + } else { | ||
| 426 | + typeWarning("array", "ignoring attempt to insert item"); | ||
| 427 | + QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item"); | ||
| 428 | + } | ||
| 429 | +} | ||
| 430 | + | ||
| 431 | +QPDFObjectHandle | ||
| 432 | +QPDFObjectHandle::insertItemAndGetNew(int at, QPDFObjectHandle const& item) | ||
| 433 | +{ | ||
| 434 | + insertItem(at, item); | ||
| 435 | + return item; | ||
| 436 | +} | ||
| 437 | + | ||
| 438 | +void | ||
| 439 | +QPDFObjectHandle::appendItem(QPDFObjectHandle const& item) | ||
| 440 | +{ | ||
| 441 | + if (auto array = as_array(strict)) { | ||
| 442 | + array.push_back(item); | ||
| 443 | + } else { | ||
| 444 | + typeWarning("array", "ignoring attempt to append item"); | ||
| 445 | + QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item"); | ||
| 446 | + } | ||
| 447 | +} | ||
| 448 | + | ||
| 449 | +QPDFObjectHandle | ||
| 450 | +QPDFObjectHandle::appendItemAndGetNew(QPDFObjectHandle const& item) | ||
| 451 | +{ | ||
| 452 | + appendItem(item); | ||
| 453 | + return item; | ||
| 454 | +} | ||
| 455 | + | ||
| 456 | +void | ||
| 457 | +QPDFObjectHandle::eraseItem(int at) | ||
| 458 | +{ | ||
| 459 | + if (auto array = as_array(strict)) { | ||
| 460 | + if (!array.erase(at)) { | ||
| 461 | + objectWarning("ignoring attempt to erase out of bounds array item"); | ||
| 462 | + QTC::TC("qpdf", "QPDFObjectHandle erase array bounds"); | ||
| 463 | + } | ||
| 464 | + } else { | ||
| 465 | + typeWarning("array", "ignoring attempt to erase item"); | ||
| 466 | + QTC::TC("qpdf", "QPDFObjectHandle array ignoring erase item"); | ||
| 467 | + } | ||
| 468 | +} | ||
| 469 | + | ||
| 470 | +QPDFObjectHandle | ||
| 471 | +QPDFObjectHandle::eraseItemAndGetOld(int at) | ||
| 472 | +{ | ||
| 473 | + auto array = as_array(strict); | ||
| 474 | + auto result = (array && at < array.size() && at >= 0) ? array.at(at).second : newNull(); | ||
| 475 | + eraseItem(at); | ||
| 476 | + return result; | ||
| 477 | +} |
libqpdf/QPDF_Bool.cc deleted
| 1 | -#include <qpdf/QPDF_Bool.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | - | ||
| 5 | -QPDF_Bool::QPDF_Bool(bool val) : | ||
| 6 | - QPDFValue(::ot_boolean), | ||
| 7 | - val(val) | ||
| 8 | -{ | ||
| 9 | -} | ||
| 10 | - | ||
| 11 | -std::shared_ptr<QPDFObject> | ||
| 12 | -QPDF_Bool::create(bool value) | ||
| 13 | -{ | ||
| 14 | - return do_create(new QPDF_Bool(value)); | ||
| 15 | -} | ||
| 16 | - | ||
| 17 | -std::shared_ptr<QPDFObject> | ||
| 18 | -QPDF_Bool::copy(bool shallow) | ||
| 19 | -{ | ||
| 20 | - return create(val); | ||
| 21 | -} | ||
| 22 | - | ||
| 23 | -std::string | ||
| 24 | -QPDF_Bool::unparse() | ||
| 25 | -{ | ||
| 26 | - return (val ? "true" : "false"); | ||
| 27 | -} | ||
| 28 | - | ||
| 29 | -void | ||
| 30 | -QPDF_Bool::writeJSON(int json_version, JSON::Writer& p) | ||
| 31 | -{ | ||
| 32 | - p << val; | ||
| 33 | -} | ||
| 34 | - | ||
| 35 | -bool | ||
| 36 | -QPDF_Bool::getVal() const | ||
| 37 | -{ | ||
| 38 | - return this->val; | ||
| 39 | -} |
libqpdf/QPDF_Destroyed.cc deleted
| 1 | -#include <qpdf/QPDF_Destroyed.hh> | ||
| 2 | - | ||
| 3 | -#include <stdexcept> | ||
| 4 | - | ||
| 5 | -QPDF_Destroyed::QPDF_Destroyed() : | ||
| 6 | - QPDFValue(::ot_destroyed) | ||
| 7 | -{ | ||
| 8 | -} | ||
| 9 | - | ||
| 10 | -std::shared_ptr<QPDFValue> | ||
| 11 | -QPDF_Destroyed::getInstance() | ||
| 12 | -{ | ||
| 13 | - static std::shared_ptr<QPDFValue> instance(new QPDF_Destroyed()); | ||
| 14 | - return instance; | ||
| 15 | -} | ||
| 16 | - | ||
| 17 | -std::shared_ptr<QPDFObject> | ||
| 18 | -QPDF_Destroyed::copy(bool shallow) | ||
| 19 | -{ | ||
| 20 | - throw std::logic_error("attempted to shallow copy QPDFObjectHandle from destroyed QPDF"); | ||
| 21 | - return nullptr; | ||
| 22 | -} | ||
| 23 | - | ||
| 24 | -std::string | ||
| 25 | -QPDF_Destroyed::unparse() | ||
| 26 | -{ | ||
| 27 | - throw std::logic_error("attempted to unparse a QPDFObjectHandle from a destroyed QPDF"); | ||
| 28 | - return ""; | ||
| 29 | -} | ||
| 30 | - | ||
| 31 | -void | ||
| 32 | -QPDF_Destroyed::writeJSON(int json_version, JSON::Writer& p) | ||
| 33 | -{ | ||
| 34 | - throw std::logic_error("attempted to get JSON from a QPDFObjectHandle from a destroyed QPDF"); | ||
| 35 | -} | ||
| 36 | \ No newline at end of file | 0 | \ No newline at end of file |
libqpdf/QPDF_Dictionary.cc
| 1 | -#include <qpdf/QPDF_Dictionary.hh> | 1 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 2 | 2 | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | #include <qpdf/QPDFObject_private.hh> | 3 | #include <qpdf/QPDFObject_private.hh> |
| 5 | -#include <qpdf/QPDF_Name.hh> | ||
| 6 | -#include <qpdf/QPDF_Null.hh> | ||
| 7 | -#include <qpdf/QUtil.hh> | 4 | +#include <qpdf/QTC.hh> |
| 8 | 5 | ||
| 9 | using namespace std::literals; | 6 | using namespace std::literals; |
| 7 | +using namespace qpdf; | ||
| 10 | 8 | ||
| 11 | -QPDF_Dictionary::QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items) : | ||
| 12 | - QPDFValue(::ot_dictionary), | ||
| 13 | - items(items) | 9 | +QPDF_Dictionary* |
| 10 | +BaseDictionary::dict() const | ||
| 14 | { | 11 | { |
| 12 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 13 | + return d; | ||
| 14 | + } | ||
| 15 | + throw std::runtime_error("Expected a dictionary but found a non-dictionary object"); | ||
| 16 | + return nullptr; // unreachable | ||
| 15 | } | 17 | } |
| 16 | 18 | ||
| 17 | -QPDF_Dictionary::QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items) : | ||
| 18 | - QPDFValue(::ot_dictionary), | ||
| 19 | - items(items) | 19 | +bool |
| 20 | +BaseDictionary::hasKey(std::string const& key) const | ||
| 20 | { | 21 | { |
| 22 | + auto d = dict(); | ||
| 23 | + return d->items.count(key) > 0 && !d->items[key].isNull(); | ||
| 21 | } | 24 | } |
| 22 | 25 | ||
| 23 | -std::shared_ptr<QPDFObject> | ||
| 24 | -QPDF_Dictionary::create(std::map<std::string, QPDFObjectHandle> const& items) | 26 | +QPDFObjectHandle |
| 27 | +BaseDictionary::getKey(std::string const& key) const | ||
| 25 | { | 28 | { |
| 26 | - return do_create(new QPDF_Dictionary(items)); | ||
| 27 | -} | 29 | + auto d = dict(); |
| 28 | 30 | ||
| 29 | -std::shared_ptr<QPDFObject> | ||
| 30 | -QPDF_Dictionary::create(std::map<std::string, QPDFObjectHandle>&& items) | ||
| 31 | -{ | ||
| 32 | - return do_create(new QPDF_Dictionary(items)); | 31 | + // PDF spec says fetching a non-existent key from a dictionary returns the null object. |
| 32 | + auto item = d->items.find(key); | ||
| 33 | + if (item != d->items.end()) { | ||
| 34 | + // May be a null object | ||
| 35 | + return item->second; | ||
| 36 | + } | ||
| 37 | + static auto constexpr msg = " -> dictionary key $VD"sv; | ||
| 38 | + return QPDF_Null::create(obj, msg, key); | ||
| 33 | } | 39 | } |
| 34 | 40 | ||
| 35 | -std::shared_ptr<QPDFObject> | ||
| 36 | -QPDF_Dictionary::copy(bool shallow) | 41 | +std::set<std::string> |
| 42 | +BaseDictionary::getKeys() | ||
| 37 | { | 43 | { |
| 38 | - if (shallow) { | ||
| 39 | - return create(items); | ||
| 40 | - } else { | ||
| 41 | - std::map<std::string, QPDFObjectHandle> new_items; | ||
| 42 | - for (auto const& item: this->items) { | ||
| 43 | - auto value = item.second; | ||
| 44 | - new_items[item.first] = value.isIndirect() ? value : value.shallowCopy(); | 44 | + std::set<std::string> result; |
| 45 | + for (auto& iter: dict()->items) { | ||
| 46 | + if (!iter.second.isNull()) { | ||
| 47 | + result.insert(iter.first); | ||
| 45 | } | 48 | } |
| 46 | - return create(new_items); | ||
| 47 | } | 49 | } |
| 50 | + return result; | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +std::map<std::string, QPDFObjectHandle> const& | ||
| 54 | +BaseDictionary::getAsMap() const | ||
| 55 | +{ | ||
| 56 | + return dict()->items; | ||
| 48 | } | 57 | } |
| 49 | 58 | ||
| 50 | void | 59 | void |
| 51 | -QPDF_Dictionary::disconnect() | 60 | +BaseDictionary::removeKey(std::string const& key) |
| 52 | { | 61 | { |
| 53 | - for (auto& iter: this->items) { | ||
| 54 | - QPDFObjectHandle::DisconnectAccess::disconnect(iter.second); | ||
| 55 | - } | 62 | + // no-op if key does not exist |
| 63 | + dict()->items.erase(key); | ||
| 56 | } | 64 | } |
| 57 | 65 | ||
| 58 | -std::string | ||
| 59 | -QPDF_Dictionary::unparse() | 66 | +void |
| 67 | +BaseDictionary::replaceKey(std::string const& key, QPDFObjectHandle value) | ||
| 60 | { | 68 | { |
| 61 | - std::string result = "<< "; | ||
| 62 | - for (auto& iter: this->items) { | ||
| 63 | - if (!iter.second.isNull()) { | ||
| 64 | - result += QPDF_Name::normalizeName(iter.first) + " " + iter.second.unparse() + " "; | ||
| 65 | - } | 69 | + auto d = dict(); |
| 70 | + if (value.isNull() && !value.isIndirect()) { | ||
| 71 | + // The PDF spec doesn't distinguish between keys with null values and missing keys. | ||
| 72 | + // Allow indirect nulls which are equivalent to a dangling reference, which is | ||
| 73 | + // permitted by the spec. | ||
| 74 | + d->items.erase(key); | ||
| 75 | + } else { | ||
| 76 | + // add or replace value | ||
| 77 | + d->items[key] = value; | ||
| 66 | } | 78 | } |
| 67 | - result += ">>"; | ||
| 68 | - return result; | ||
| 69 | } | 79 | } |
| 70 | 80 | ||
| 71 | void | 81 | void |
| 72 | -QPDF_Dictionary::writeJSON(int json_version, JSON::Writer& p) | 82 | +QPDFObjectHandle::checkOwnership(QPDFObjectHandle const& item) const |
| 73 | { | 83 | { |
| 74 | - p.writeStart('{'); | ||
| 75 | - for (auto& iter: this->items) { | ||
| 76 | - if (!iter.second.isNull()) { | ||
| 77 | - p.writeNext(); | ||
| 78 | - if (json_version == 1) { | ||
| 79 | - p << "\"" << JSON::Writer::encode_string(QPDF_Name::normalizeName(iter.first)) | ||
| 80 | - << "\": "; | ||
| 81 | - } else if (auto res = QPDF_Name::analyzeJSONEncoding(iter.first); res.first) { | ||
| 82 | - if (res.second) { | ||
| 83 | - p << "\"" << iter.first << "\": "; | ||
| 84 | - } else { | ||
| 85 | - p << "\"" << JSON::Writer::encode_string(iter.first) << "\": "; | ||
| 86 | - } | ||
| 87 | - } else { | ||
| 88 | - p << "\"n:" << JSON::Writer::encode_string(QPDF_Name::normalizeName(iter.first)) | ||
| 89 | - << "\": "; | ||
| 90 | - } | ||
| 91 | - iter.second.writeJSON(json_version, p); | ||
| 92 | - } | 84 | + auto qpdf = getOwningQPDF(); |
| 85 | + auto item_qpdf = item.getOwningQPDF(); | ||
| 86 | + if (qpdf && item_qpdf && qpdf != item_qpdf) { | ||
| 87 | + QTC::TC("qpdf", "QPDFObjectHandle check ownership"); | ||
| 88 | + throw std::logic_error( | ||
| 89 | + "Attempting to add an object from a different QPDF. Use " | ||
| 90 | + "QPDF::copyForeignObject to add objects from another file."); | ||
| 93 | } | 91 | } |
| 94 | - p.writeEnd('}'); | ||
| 95 | } | 92 | } |
| 96 | 93 | ||
| 97 | bool | 94 | bool |
| 98 | -QPDF_Dictionary::hasKey(std::string const& key) | 95 | +QPDFObjectHandle::hasKey(std::string const& key) const |
| 99 | { | 96 | { |
| 100 | - return ((this->items.count(key) > 0) && (!this->items[key].isNull())); | 97 | + auto dict = as_dictionary(strict); |
| 98 | + if (dict) { | ||
| 99 | + return dict.hasKey(key); | ||
| 100 | + } else { | ||
| 101 | + typeWarning("dictionary", "returning false for a key containment request"); | ||
| 102 | + QTC::TC("qpdf", "QPDFObjectHandle dictionary false for hasKey"); | ||
| 103 | + return false; | ||
| 104 | + } | ||
| 101 | } | 105 | } |
| 102 | 106 | ||
| 103 | QPDFObjectHandle | 107 | QPDFObjectHandle |
| 104 | -QPDF_Dictionary::getKey(std::string const& key) | 108 | +QPDFObjectHandle::getKey(std::string const& key) const |
| 105 | { | 109 | { |
| 106 | - // PDF spec says fetching a non-existent key from a dictionary returns the null object. | ||
| 107 | - auto item = this->items.find(key); | ||
| 108 | - if (item != this->items.end()) { | ||
| 109 | - // May be a null object | ||
| 110 | - return item->second; | ||
| 111 | - } else { | ||
| 112 | - static auto constexpr msg = " -> dictionary key $VD"sv; | ||
| 113 | - return QPDF_Null::create(shared_from_this(), msg, key); | 110 | + if (auto dict = as_dictionary(strict)) { |
| 111 | + return dict.getKey(key); | ||
| 114 | } | 112 | } |
| 113 | + typeWarning("dictionary", "returning null for attempted key retrieval"); | ||
| 114 | + QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey"); | ||
| 115 | + static auto constexpr msg = " -> null returned from getting key $VD from non-Dictionary"sv; | ||
| 116 | + return QPDF_Null::create(obj, msg, ""); | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +QPDFObjectHandle | ||
| 120 | +QPDFObjectHandle::getKeyIfDict(std::string const& key) const | ||
| 121 | +{ | ||
| 122 | + return isNull() ? newNull() : getKey(key); | ||
| 115 | } | 123 | } |
| 116 | 124 | ||
| 117 | std::set<std::string> | 125 | std::set<std::string> |
| 118 | -QPDF_Dictionary::getKeys() | 126 | +QPDFObjectHandle::getKeys() const |
| 119 | { | 127 | { |
| 120 | - std::set<std::string> result; | ||
| 121 | - for (auto& iter: this->items) { | ||
| 122 | - if (!iter.second.isNull()) { | ||
| 123 | - result.insert(iter.first); | ||
| 124 | - } | 128 | + if (auto dict = as_dictionary(strict)) { |
| 129 | + return dict.getKeys(); | ||
| 125 | } | 130 | } |
| 126 | - return result; | 131 | + typeWarning("dictionary", "treating as empty"); |
| 132 | + QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys"); | ||
| 133 | + return {}; | ||
| 127 | } | 134 | } |
| 128 | 135 | ||
| 129 | -std::map<std::string, QPDFObjectHandle> const& | ||
| 130 | -QPDF_Dictionary::getAsMap() const | 136 | +std::map<std::string, QPDFObjectHandle> |
| 137 | +QPDFObjectHandle::getDictAsMap() const | ||
| 131 | { | 138 | { |
| 132 | - return this->items; | 139 | + if (auto dict = as_dictionary(strict)) { |
| 140 | + return dict.getAsMap(); | ||
| 141 | + } | ||
| 142 | + typeWarning("dictionary", "treating as empty"); | ||
| 143 | + QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap"); | ||
| 144 | + return {}; | ||
| 133 | } | 145 | } |
| 134 | 146 | ||
| 135 | void | 147 | void |
| 136 | -QPDF_Dictionary::replaceKey(std::string const& key, QPDFObjectHandle value) | 148 | +QPDFObjectHandle::replaceKey(std::string const& key, QPDFObjectHandle const& value) |
| 137 | { | 149 | { |
| 138 | - if (value.isNull() && !value.isIndirect()) { | ||
| 139 | - // The PDF spec doesn't distinguish between keys with null values and missing keys. Allow | ||
| 140 | - // indirect nulls which are equivalent to a dangling reference, which is permitted by the | ||
| 141 | - // spec. | ||
| 142 | - removeKey(key); | ||
| 143 | - } else { | ||
| 144 | - // add or replace value | ||
| 145 | - this->items[key] = value; | 150 | + if (auto dict = as_dictionary(strict)) { |
| 151 | + checkOwnership(value); | ||
| 152 | + dict.replaceKey(key, value); | ||
| 153 | + return; | ||
| 146 | } | 154 | } |
| 155 | + typeWarning("dictionary", "ignoring key replacement request"); | ||
| 156 | + QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey"); | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | +QPDFObjectHandle | ||
| 160 | +QPDFObjectHandle::replaceKeyAndGetNew(std::string const& key, QPDFObjectHandle const& value) | ||
| 161 | +{ | ||
| 162 | + replaceKey(key, value); | ||
| 163 | + return value; | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | +QPDFObjectHandle | ||
| 167 | +QPDFObjectHandle::replaceKeyAndGetOld(std::string const& key, QPDFObjectHandle const& value) | ||
| 168 | +{ | ||
| 169 | + QPDFObjectHandle old = removeKeyAndGetOld(key); | ||
| 170 | + replaceKey(key, value); | ||
| 171 | + return old; | ||
| 147 | } | 172 | } |
| 148 | 173 | ||
| 149 | void | 174 | void |
| 150 | -QPDF_Dictionary::removeKey(std::string const& key) | 175 | +QPDFObjectHandle::removeKey(std::string const& key) |
| 151 | { | 176 | { |
| 152 | - // no-op if key does not exist | ||
| 153 | - this->items.erase(key); | 177 | + if (auto dict = as_dictionary(strict)) { |
| 178 | + dict.removeKey(key); | ||
| 179 | + return; | ||
| 180 | + } | ||
| 181 | + typeWarning("dictionary", "ignoring key removal request"); | ||
| 182 | + QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey"); | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +QPDFObjectHandle | ||
| 186 | +QPDFObjectHandle::removeKeyAndGetOld(std::string const& key) | ||
| 187 | +{ | ||
| 188 | + auto result = QPDFObjectHandle::newNull(); | ||
| 189 | + if (auto dict = as_dictionary(strict)) { | ||
| 190 | + result = dict.getKey(key); | ||
| 191 | + } | ||
| 192 | + removeKey(key); | ||
| 193 | + return result; | ||
| 154 | } | 194 | } |
libqpdf/QPDF_InlineImage.cc deleted
| 1 | -#include <qpdf/QPDF_InlineImage.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | - | ||
| 5 | -QPDF_InlineImage::QPDF_InlineImage(std::string const& val) : | ||
| 6 | - QPDFValue(::ot_inlineimage), | ||
| 7 | - val(val) | ||
| 8 | -{ | ||
| 9 | -} | ||
| 10 | - | ||
| 11 | -std::shared_ptr<QPDFObject> | ||
| 12 | -QPDF_InlineImage::create(std::string const& val) | ||
| 13 | -{ | ||
| 14 | - return do_create(new QPDF_InlineImage(val)); | ||
| 15 | -} | ||
| 16 | - | ||
| 17 | -std::shared_ptr<QPDFObject> | ||
| 18 | -QPDF_InlineImage::copy(bool shallow) | ||
| 19 | -{ | ||
| 20 | - return create(val); | ||
| 21 | -} | ||
| 22 | - | ||
| 23 | -std::string | ||
| 24 | -QPDF_InlineImage::unparse() | ||
| 25 | -{ | ||
| 26 | - return this->val; | ||
| 27 | -} | ||
| 28 | - | ||
| 29 | -void | ||
| 30 | -QPDF_InlineImage::writeJSON(int json_version, JSON::Writer& p) | ||
| 31 | -{ | ||
| 32 | - p << "null"; | ||
| 33 | -} |
libqpdf/QPDF_Integer.cc deleted
| 1 | -#include <qpdf/QPDF_Integer.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | -#include <qpdf/QUtil.hh> | ||
| 5 | - | ||
| 6 | -QPDF_Integer::QPDF_Integer(long long val) : | ||
| 7 | - QPDFValue(::ot_integer), | ||
| 8 | - val(val) | ||
| 9 | -{ | ||
| 10 | -} | ||
| 11 | - | ||
| 12 | -std::shared_ptr<QPDFObject> | ||
| 13 | -QPDF_Integer::create(long long value) | ||
| 14 | -{ | ||
| 15 | - return do_create(new QPDF_Integer(value)); | ||
| 16 | -} | ||
| 17 | - | ||
| 18 | -std::shared_ptr<QPDFObject> | ||
| 19 | -QPDF_Integer::copy(bool shallow) | ||
| 20 | -{ | ||
| 21 | - return create(val); | ||
| 22 | -} | ||
| 23 | - | ||
| 24 | -std::string | ||
| 25 | -QPDF_Integer::unparse() | ||
| 26 | -{ | ||
| 27 | - return std::to_string(this->val); | ||
| 28 | -} | ||
| 29 | - | ||
| 30 | -void | ||
| 31 | -QPDF_Integer::writeJSON(int json_version, JSON::Writer& p) | ||
| 32 | -{ | ||
| 33 | - p << std::to_string(this->val); | ||
| 34 | -} | ||
| 35 | - | ||
| 36 | -long long | ||
| 37 | -QPDF_Integer::getVal() const | ||
| 38 | -{ | ||
| 39 | - return this->val; | ||
| 40 | -} |
libqpdf/QPDF_Name.cc
| 1 | -#include <qpdf/QPDF_Name.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | -#include <qpdf/QUtil.hh> | ||
| 5 | - | ||
| 6 | -QPDF_Name::QPDF_Name(std::string const& name) : | ||
| 7 | - QPDFValue(::ot_name), | ||
| 8 | - name(name) | ||
| 9 | -{ | ||
| 10 | -} | ||
| 11 | - | ||
| 12 | -std::shared_ptr<QPDFObject> | ||
| 13 | -QPDF_Name::create(std::string const& name) | ||
| 14 | -{ | ||
| 15 | - return do_create(new QPDF_Name(name)); | ||
| 16 | -} | ||
| 17 | - | ||
| 18 | -std::shared_ptr<QPDFObject> | ||
| 19 | -QPDF_Name::copy(bool shallow) | ||
| 20 | -{ | ||
| 21 | - return create(name); | ||
| 22 | -} | ||
| 23 | - | ||
| 24 | -std::string | ||
| 25 | -QPDF_Name::normalizeName(std::string const& name) | ||
| 26 | -{ | ||
| 27 | - if (name.empty()) { | ||
| 28 | - return name; | ||
| 29 | - } | ||
| 30 | - std::string result; | ||
| 31 | - result += name.at(0); | ||
| 32 | - for (size_t i = 1; i < name.length(); ++i) { | ||
| 33 | - char ch = name.at(i); | ||
| 34 | - // Don't use locale/ctype here; follow PDF spec guidelines. | ||
| 35 | - if (ch == '\0') { | ||
| 36 | - // QPDFTokenizer embeds a null character to encode an invalid #. | ||
| 37 | - result += "#"; | ||
| 38 | - } else if ( | ||
| 39 | - ch < 33 || ch == '#' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' || | ||
| 40 | - ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch > 126) { | ||
| 41 | - result += QUtil::hex_encode_char(ch); | ||
| 42 | - } else { | ||
| 43 | - result += ch; | ||
| 44 | - } | ||
| 45 | - } | ||
| 46 | - return result; | ||
| 47 | -} | ||
| 48 | - | ||
| 49 | -std::string | ||
| 50 | -QPDF_Name::unparse() | ||
| 51 | -{ | ||
| 52 | - return normalizeName(this->name); | ||
| 53 | -} | ||
| 54 | - | ||
| 55 | -std::pair<bool, bool> | ||
| 56 | -QPDF_Name::analyzeJSONEncoding(const std::string& name) | ||
| 57 | -{ | ||
| 58 | - int tail = 0; // Number of continuation characters expected. | ||
| 59 | - bool tail2 = false; // Potential overlong 3 octet utf-8. | ||
| 60 | - bool tail3 = false; // potential overlong 4 octet | ||
| 61 | - bool needs_escaping = false; | ||
| 62 | - for (auto const& it: name) { | ||
| 63 | - auto c = static_cast<unsigned char>(it); | ||
| 64 | - if (tail) { | ||
| 65 | - if ((c & 0xc0) != 0x80) { | ||
| 66 | - return {false, false}; | ||
| 67 | - } | ||
| 68 | - if (tail2) { | ||
| 69 | - if ((c & 0xe0) == 0x80) { | ||
| 70 | - return {false, false}; | ||
| 71 | - } | ||
| 72 | - tail2 = false; | ||
| 73 | - } else if (tail3) { | ||
| 74 | - if ((c & 0xf0) == 0x80) { | ||
| 75 | - return {false, false}; | ||
| 76 | - } | ||
| 77 | - tail3 = false; | ||
| 78 | - } | ||
| 79 | - tail--; | ||
| 80 | - } else if (c < 0x80) { | ||
| 81 | - if (!needs_escaping) { | ||
| 82 | - needs_escaping = !((c > 34 && c != '\\') || c == ' ' || c == 33); | ||
| 83 | - } | ||
| 84 | - } else if ((c & 0xe0) == 0xc0) { | ||
| 85 | - if ((c & 0xfe) == 0xc0) { | ||
| 86 | - return {false, false}; | ||
| 87 | - } | ||
| 88 | - tail = 1; | ||
| 89 | - } else if ((c & 0xf0) == 0xe0) { | ||
| 90 | - tail2 = (c == 0xe0); | ||
| 91 | - tail = 2; | ||
| 92 | - } else if ((c & 0xf8) == 0xf0) { | ||
| 93 | - tail3 = (c == 0xf0); | ||
| 94 | - tail = 3; | ||
| 95 | - } else { | ||
| 96 | - return {false, false}; | ||
| 97 | - } | ||
| 98 | - } | ||
| 99 | - return {tail == 0, !needs_escaping}; | ||
| 100 | -} | ||
| 101 | - | ||
| 102 | -void | ||
| 103 | -QPDF_Name::writeJSON(int json_version, JSON::Writer& p) | ||
| 104 | -{ | ||
| 105 | - // For performance reasons this code is duplicated in QPDF_Dictionary::writeJSON. When updating | ||
| 106 | - // this method make sure QPDF_Dictionary is also update. | ||
| 107 | - if (json_version == 1) { | ||
| 108 | - p << "\"" << JSON::Writer::encode_string(normalizeName(name)) << "\""; | ||
| 109 | - } else { | ||
| 110 | - if (auto res = analyzeJSONEncoding(name); res.first) { | ||
| 111 | - if (res.second) { | ||
| 112 | - p << "\"" << name << "\""; | ||
| 113 | - } else { | ||
| 114 | - p << "\"" << JSON::Writer::encode_string(name) << "\""; | ||
| 115 | - } | ||
| 116 | - } else { | ||
| 117 | - p << "\"n:" << JSON::Writer::encode_string(normalizeName(name)) << "\""; | ||
| 118 | - } | ||
| 119 | - } | ||
| 120 | -} |
libqpdf/QPDF_Null.cc deleted
| 1 | -#include <qpdf/QPDF_Null.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | -#include <qpdf/QPDFObject_private.hh> | ||
| 5 | - | ||
| 6 | -QPDF_Null::QPDF_Null(QPDF* qpdf, QPDFObjGen og) : | ||
| 7 | - QPDFValue(::ot_null, qpdf, og) | ||
| 8 | -{ | ||
| 9 | -} | ||
| 10 | - | ||
| 11 | -std::shared_ptr<QPDFObject> | ||
| 12 | -QPDF_Null::create(QPDF* qpdf, QPDFObjGen og) | ||
| 13 | -{ | ||
| 14 | - return do_create(new QPDF_Null(qpdf, og)); | ||
| 15 | -} | ||
| 16 | - | ||
| 17 | -std::shared_ptr<QPDFObject> | ||
| 18 | -QPDF_Null::create( | ||
| 19 | - std::shared_ptr<QPDFObject> parent, std::string_view const& static_descr, std::string var_descr) | ||
| 20 | -{ | ||
| 21 | - auto n = do_create(new QPDF_Null()); | ||
| 22 | - n->setChildDescription(parent, static_descr, var_descr); | ||
| 23 | - return n; | ||
| 24 | -} | ||
| 25 | - | ||
| 26 | -std::shared_ptr<QPDFObject> | ||
| 27 | -QPDF_Null::create( | ||
| 28 | - std::shared_ptr<QPDFValue> parent, std::string_view const& static_descr, std::string var_descr) | ||
| 29 | -{ | ||
| 30 | - auto n = do_create(new QPDF_Null()); | ||
| 31 | - n->setChildDescription(parent, static_descr, var_descr); | ||
| 32 | - return n; | ||
| 33 | -} | ||
| 34 | - | ||
| 35 | -std::shared_ptr<QPDFObject> | ||
| 36 | -QPDF_Null::copy(bool shallow) | ||
| 37 | -{ | ||
| 38 | - return create(); | ||
| 39 | -} | ||
| 40 | - | ||
| 41 | -std::string | ||
| 42 | -QPDF_Null::unparse() | ||
| 43 | -{ | ||
| 44 | - return "null"; | ||
| 45 | -} | ||
| 46 | - | ||
| 47 | -void | ||
| 48 | -QPDF_Null::writeJSON(int json_version, JSON::Writer& p) | ||
| 49 | -{ | ||
| 50 | - p << "null"; | ||
| 51 | -} |
libqpdf/QPDF_Operator.cc deleted
| 1 | -#include <qpdf/QPDF_Operator.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | - | ||
| 5 | -QPDF_Operator::QPDF_Operator(std::string const& val) : | ||
| 6 | - QPDFValue(::ot_operator), | ||
| 7 | - val(val) | ||
| 8 | -{ | ||
| 9 | -} | ||
| 10 | - | ||
| 11 | -std::shared_ptr<QPDFObject> | ||
| 12 | -QPDF_Operator::create(std::string const& val) | ||
| 13 | -{ | ||
| 14 | - return do_create(new QPDF_Operator(val)); | ||
| 15 | -} | ||
| 16 | - | ||
| 17 | -std::shared_ptr<QPDFObject> | ||
| 18 | -QPDF_Operator::copy(bool shallow) | ||
| 19 | -{ | ||
| 20 | - return create(val); | ||
| 21 | -} | ||
| 22 | - | ||
| 23 | -std::string | ||
| 24 | -QPDF_Operator::unparse() | ||
| 25 | -{ | ||
| 26 | - return val; | ||
| 27 | -} | ||
| 28 | - | ||
| 29 | -void | ||
| 30 | -QPDF_Operator::writeJSON(int json_version, JSON::Writer& p) | ||
| 31 | -{ | ||
| 32 | - p << "null"; | ||
| 33 | -} |
libqpdf/QPDF_Real.cc deleted
| 1 | -#include <qpdf/QPDF_Real.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/JSON_writer.hh> | ||
| 4 | -#include <qpdf/QUtil.hh> | ||
| 5 | - | ||
| 6 | -QPDF_Real::QPDF_Real(std::string const& val) : | ||
| 7 | - QPDFValue(::ot_real), | ||
| 8 | - val(val) | ||
| 9 | -{ | ||
| 10 | -} | ||
| 11 | - | ||
| 12 | -QPDF_Real::QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes) : | ||
| 13 | - QPDFValue(::ot_real), | ||
| 14 | - val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes)) | ||
| 15 | -{ | ||
| 16 | -} | ||
| 17 | - | ||
| 18 | -std::shared_ptr<QPDFObject> | ||
| 19 | -QPDF_Real::create(std::string const& val) | ||
| 20 | -{ | ||
| 21 | - return do_create(new QPDF_Real(val)); | ||
| 22 | -} | ||
| 23 | - | ||
| 24 | -std::shared_ptr<QPDFObject> | ||
| 25 | -QPDF_Real::create(double value, int decimal_places, bool trim_trailing_zeroes) | ||
| 26 | -{ | ||
| 27 | - return do_create(new QPDF_Real(value, decimal_places, trim_trailing_zeroes)); | ||
| 28 | -} | ||
| 29 | - | ||
| 30 | -std::shared_ptr<QPDFObject> | ||
| 31 | -QPDF_Real::copy(bool shallow) | ||
| 32 | -{ | ||
| 33 | - return create(val); | ||
| 34 | -} | ||
| 35 | - | ||
| 36 | -std::string | ||
| 37 | -QPDF_Real::unparse() | ||
| 38 | -{ | ||
| 39 | - return this->val; | ||
| 40 | -} | ||
| 41 | - | ||
| 42 | -void | ||
| 43 | -QPDF_Real::writeJSON(int json_version, JSON::Writer& p) | ||
| 44 | -{ | ||
| 45 | - if (this->val.length() == 0) { | ||
| 46 | - // Can't really happen... | ||
| 47 | - p << "0"; | ||
| 48 | - } else if (this->val.at(0) == '.') { | ||
| 49 | - p << "0" << this->val; | ||
| 50 | - } else if (this->val.length() >= 2 && this->val.at(0) == '-' && this->val.at(1) == '.') { | ||
| 51 | - p << "-0." << this->val.substr(2); | ||
| 52 | - } else { | ||
| 53 | - p << this->val; | ||
| 54 | - } | ||
| 55 | - if (val.back() == '.') { | ||
| 56 | - p << "0"; | ||
| 57 | - } | ||
| 58 | -} |
libqpdf/QPDF_Reserved.cc deleted
| 1 | -#include <qpdf/QPDF_Reserved.hh> | ||
| 2 | - | ||
| 3 | -#include <stdexcept> | ||
| 4 | - | ||
| 5 | -QPDF_Reserved::QPDF_Reserved() : | ||
| 6 | - QPDFValue(::ot_reserved) | ||
| 7 | -{ | ||
| 8 | -} | ||
| 9 | - | ||
| 10 | -std::shared_ptr<QPDFObject> | ||
| 11 | -QPDF_Reserved::create() | ||
| 12 | -{ | ||
| 13 | - return do_create(new QPDF_Reserved()); | ||
| 14 | -} | ||
| 15 | - | ||
| 16 | -std::shared_ptr<QPDFObject> | ||
| 17 | -QPDF_Reserved::copy(bool shallow) | ||
| 18 | -{ | ||
| 19 | - return create(); | ||
| 20 | -} | ||
| 21 | - | ||
| 22 | -std::string | ||
| 23 | -QPDF_Reserved::unparse() | ||
| 24 | -{ | ||
| 25 | - throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object"); | ||
| 26 | - return ""; | ||
| 27 | -} | ||
| 28 | - | ||
| 29 | -void | ||
| 30 | -QPDF_Reserved::writeJSON(int json_version, JSON::Writer& p) | ||
| 31 | -{ | ||
| 32 | - throw std::logic_error("QPDFObjectHandle: attempting to get JSON from a reserved object"); | ||
| 33 | -} |
libqpdf/QPDF_Stream.cc
| 1 | -#include <qpdf/QPDF_Stream.hh> | 1 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 2 | 2 | ||
| 3 | #include <qpdf/ContentNormalizer.hh> | 3 | #include <qpdf/ContentNormalizer.hh> |
| 4 | #include <qpdf/JSON_writer.hh> | 4 | #include <qpdf/JSON_writer.hh> |
| @@ -22,6 +22,9 @@ | @@ -22,6 +22,9 @@ | ||
| 22 | 22 | ||
| 23 | #include <stdexcept> | 23 | #include <stdexcept> |
| 24 | 24 | ||
| 25 | +using namespace std::literals; | ||
| 26 | +using namespace qpdf; | ||
| 27 | + | ||
| 25 | namespace | 28 | namespace |
| 26 | { | 29 | { |
| 27 | class SF_Crypt: public QPDFStreamFilter | 30 | class SF_Crypt: public QPDFStreamFilter |
| @@ -60,16 +63,24 @@ namespace | @@ -60,16 +63,24 @@ namespace | ||
| 60 | class StreamBlobProvider | 63 | class StreamBlobProvider |
| 61 | { | 64 | { |
| 62 | public: | 65 | public: |
| 63 | - StreamBlobProvider(QPDF_Stream* stream, qpdf_stream_decode_level_e decode_level); | ||
| 64 | - void operator()(Pipeline*); | 66 | + StreamBlobProvider(Stream stream, qpdf_stream_decode_level_e decode_level) : |
| 67 | + stream(stream), | ||
| 68 | + decode_level(decode_level) | ||
| 69 | + { | ||
| 70 | + } | ||
| 71 | + void | ||
| 72 | + operator()(Pipeline* p) | ||
| 73 | + { | ||
| 74 | + stream.pipeStreamData(p, nullptr, 0, decode_level, false, false); | ||
| 75 | + } | ||
| 65 | 76 | ||
| 66 | private: | 77 | private: |
| 67 | - QPDF_Stream* stream; | 78 | + Stream stream; |
| 68 | qpdf_stream_decode_level_e decode_level; | 79 | qpdf_stream_decode_level_e decode_level; |
| 69 | }; | 80 | }; |
| 70 | } // namespace | 81 | } // namespace |
| 71 | 82 | ||
| 72 | -std::map<std::string, std::string> QPDF_Stream::filter_abbreviations = { | 83 | +std::map<std::string, std::string> Stream::filter_abbreviations = { |
| 73 | // The PDF specification provides these filter abbreviations for use in inline images, but | 84 | // The PDF specification provides these filter abbreviations for use in inline images, but |
| 74 | // according to table H.1 in the pre-ISO versions of the PDF specification, Adobe Reader also | 85 | // according to table H.1 in the pre-ISO versions of the PDF specification, Adobe Reader also |
| 75 | // accepts them for stream filters. | 86 | // accepts them for stream filters. |
| @@ -82,8 +93,8 @@ std::map<std::string, std::string> QPDF_Stream::filter_abbreviations = { | @@ -82,8 +93,8 @@ std::map<std::string, std::string> QPDF_Stream::filter_abbreviations = { | ||
| 82 | {"/DCT", "/DCTDecode"}, | 93 | {"/DCT", "/DCTDecode"}, |
| 83 | }; | 94 | }; |
| 84 | 95 | ||
| 85 | -std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>> | ||
| 86 | - QPDF_Stream::filter_factories = { | 96 | +std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>> Stream::filter_factories = |
| 97 | + { | ||
| 87 | {"/Crypt", []() { return std::make_shared<SF_Crypt>(); }}, | 98 | {"/Crypt", []() { return std::make_shared<SF_Crypt>(); }}, |
| 88 | {"/FlateDecode", SF_FlateLzwDecode::flate_factory}, | 99 | {"/FlateDecode", SF_FlateLzwDecode::flate_factory}, |
| 89 | {"/LZWDecode", SF_FlateLzwDecode::lzw_factory}, | 100 | {"/LZWDecode", SF_FlateLzwDecode::lzw_factory}, |
| @@ -93,90 +104,25 @@ std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>> | @@ -93,90 +104,25 @@ std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>> | ||
| 93 | {"/ASCIIHexDecode", SF_ASCIIHexDecode::factory}, | 104 | {"/ASCIIHexDecode", SF_ASCIIHexDecode::factory}, |
| 94 | }; | 105 | }; |
| 95 | 106 | ||
| 96 | -StreamBlobProvider::StreamBlobProvider( | ||
| 97 | - QPDF_Stream* stream, qpdf_stream_decode_level_e decode_level) : | ||
| 98 | - stream(stream), | ||
| 99 | - decode_level(decode_level) | 107 | +Stream::Stream( |
| 108 | + QPDF& qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) : | ||
| 109 | + BaseHandle(QPDFObject::create<QPDF_Stream>(&qpdf, og, std::move(stream_dict), length)) | ||
| 100 | { | 110 | { |
| 111 | + auto descr = std::make_shared<QPDFObject::Description>( | ||
| 112 | + qpdf.getFilename() + ", stream object " + og.unparse(' ')); | ||
| 113 | + obj->setDescription(&qpdf, descr, offset); | ||
| 114 | + setDictDescription(); | ||
| 101 | } | 115 | } |
| 102 | 116 | ||
| 103 | void | 117 | void |
| 104 | -StreamBlobProvider::operator()(Pipeline* p) | ||
| 105 | -{ | ||
| 106 | - this->stream->pipeStreamData(p, nullptr, 0, decode_level, false, false); | ||
| 107 | -} | ||
| 108 | - | ||
| 109 | -QPDF_Stream::QPDF_Stream( | ||
| 110 | - QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) : | ||
| 111 | - QPDFValue(::ot_stream, qpdf, og), | ||
| 112 | - filter_on_write(true), | ||
| 113 | - stream_dict(stream_dict), | ||
| 114 | - length(length) | ||
| 115 | -{ | ||
| 116 | - if (!stream_dict.isDictionary()) { | ||
| 117 | - throw std::logic_error( | ||
| 118 | - "stream object instantiated with non-dictionary object for dictionary"); | ||
| 119 | - } | ||
| 120 | - auto descr = std::make_shared<QPDFValue::Description>( | ||
| 121 | - qpdf->getFilename() + ", stream object " + og.unparse(' ')); | ||
| 122 | - setDescription(qpdf, descr, offset); | ||
| 123 | -} | ||
| 124 | - | ||
| 125 | -std::shared_ptr<QPDFObject> | ||
| 126 | -QPDF_Stream::create( | ||
| 127 | - QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) | ||
| 128 | -{ | ||
| 129 | - return do_create(new QPDF_Stream(qpdf, og, stream_dict, offset, length)); | ||
| 130 | -} | ||
| 131 | - | ||
| 132 | -std::shared_ptr<QPDFObject> | ||
| 133 | -QPDF_Stream::copy(bool shallow) | ||
| 134 | -{ | ||
| 135 | - QTC::TC("qpdf", "QPDF_Stream ERR shallow copy stream"); | ||
| 136 | - throw std::runtime_error("stream objects cannot be cloned"); | ||
| 137 | -} | ||
| 138 | - | ||
| 139 | -void | ||
| 140 | -QPDF_Stream::registerStreamFilter( | 118 | +Stream::registerStreamFilter( |
| 141 | std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory) | 119 | std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory) |
| 142 | { | 120 | { |
| 143 | filter_factories[filter_name] = factory; | 121 | filter_factories[filter_name] = factory; |
| 144 | } | 122 | } |
| 145 | 123 | ||
| 146 | -void | ||
| 147 | -QPDF_Stream::setFilterOnWrite(bool val) | ||
| 148 | -{ | ||
| 149 | - this->filter_on_write = val; | ||
| 150 | -} | ||
| 151 | - | ||
| 152 | -bool | ||
| 153 | -QPDF_Stream::getFilterOnWrite() const | ||
| 154 | -{ | ||
| 155 | - return this->filter_on_write; | ||
| 156 | -} | ||
| 157 | - | ||
| 158 | -void | ||
| 159 | -QPDF_Stream::disconnect() | ||
| 160 | -{ | ||
| 161 | - this->stream_provider = nullptr; | ||
| 162 | - QPDFObjectHandle::DisconnectAccess::disconnect(this->stream_dict); | ||
| 163 | -} | ||
| 164 | - | ||
| 165 | -std::string | ||
| 166 | -QPDF_Stream::unparse() | ||
| 167 | -{ | ||
| 168 | - // Unparse stream objects as indirect references | ||
| 169 | - return og.unparse(' ') + " R"; | ||
| 170 | -} | ||
| 171 | - | ||
| 172 | -void | ||
| 173 | -QPDF_Stream::writeJSON(int json_version, JSON::Writer& jw) | ||
| 174 | -{ | ||
| 175 | - stream_dict.writeJSON(json_version, jw); | ||
| 176 | -} | ||
| 177 | - | ||
| 178 | JSON | 124 | JSON |
| 179 | -QPDF_Stream::getStreamJSON( | 125 | +Stream::getStreamJSON( |
| 180 | int json_version, | 126 | int json_version, |
| 181 | qpdf_json_stream_data_e json_data, | 127 | qpdf_json_stream_data_e json_data, |
| 182 | qpdf_stream_decode_level_e decode_level, | 128 | qpdf_stream_decode_level_e decode_level, |
| @@ -190,13 +136,13 @@ QPDF_Stream::getStreamJSON( | @@ -190,13 +136,13 @@ QPDF_Stream::getStreamJSON( | ||
| 190 | pb.finish(); | 136 | pb.finish(); |
| 191 | auto result = JSON::parse(pb.getString()); | 137 | auto result = JSON::parse(pb.getString()); |
| 192 | if (json_data == qpdf_sj_inline) { | 138 | if (json_data == qpdf_sj_inline) { |
| 193 | - result.addDictionaryMember("data", JSON::makeBlob(StreamBlobProvider(this, decode_level))); | 139 | + result.addDictionaryMember("data", JSON::makeBlob(StreamBlobProvider(*this, decode_level))); |
| 194 | } | 140 | } |
| 195 | return result; | 141 | return result; |
| 196 | } | 142 | } |
| 197 | 143 | ||
| 198 | qpdf_stream_decode_level_e | 144 | qpdf_stream_decode_level_e |
| 199 | -QPDF_Stream::writeStreamJSON( | 145 | +Stream::writeStreamJSON( |
| 200 | int json_version, | 146 | int json_version, |
| 201 | JSON::Writer& jw, | 147 | JSON::Writer& jw, |
| 202 | qpdf_json_stream_data_e json_data, | 148 | qpdf_json_stream_data_e json_data, |
| @@ -205,6 +151,7 @@ QPDF_Stream::writeStreamJSON( | @@ -205,6 +151,7 @@ QPDF_Stream::writeStreamJSON( | ||
| 205 | std::string const& data_filename, | 151 | std::string const& data_filename, |
| 206 | bool no_data_key) | 152 | bool no_data_key) |
| 207 | { | 153 | { |
| 154 | + auto s = stream(); | ||
| 208 | switch (json_data) { | 155 | switch (json_data) { |
| 209 | case qpdf_sj_none: | 156 | case qpdf_sj_none: |
| 210 | case qpdf_sj_inline: | 157 | case qpdf_sj_inline: |
| @@ -232,7 +179,7 @@ QPDF_Stream::writeStreamJSON( | @@ -232,7 +179,7 @@ QPDF_Stream::writeStreamJSON( | ||
| 232 | if (json_data == qpdf_sj_none) { | 179 | if (json_data == qpdf_sj_none) { |
| 233 | jw.writeNext(); | 180 | jw.writeNext(); |
| 234 | jw << R"("dict": )"; | 181 | jw << R"("dict": )"; |
| 235 | - stream_dict.writeJSON(json_version, jw); | 182 | + s->stream_dict.writeJSON(json_version, jw); |
| 236 | jw.writeEnd('}'); | 183 | jw.writeEnd('}'); |
| 237 | return decode_level; | 184 | return decode_level; |
| 238 | } | 185 | } |
| @@ -264,7 +211,7 @@ QPDF_Stream::writeStreamJSON( | @@ -264,7 +211,7 @@ QPDF_Stream::writeStreamJSON( | ||
| 264 | throw std::logic_error("QPDF_Stream: failed to get stream data"); | 211 | throw std::logic_error("QPDF_Stream: failed to get stream data"); |
| 265 | } | 212 | } |
| 266 | // We can use unsafeShallowCopy because we are only touching top-level keys. | 213 | // We can use unsafeShallowCopy because we are only touching top-level keys. |
| 267 | - auto dict = stream_dict.unsafeShallowCopy(); | 214 | + auto dict = s->stream_dict.unsafeShallowCopy(); |
| 268 | dict.removeKey("/Length"); | 215 | dict.removeKey("/Length"); |
| 269 | if (filter && filtered) { | 216 | if (filter && filtered) { |
| 270 | dict.removeKey("/Filter"); | 217 | dict.removeKey("/Filter"); |
| @@ -290,53 +237,17 @@ QPDF_Stream::writeStreamJSON( | @@ -290,53 +237,17 @@ QPDF_Stream::writeStreamJSON( | ||
| 290 | } | 237 | } |
| 291 | 238 | ||
| 292 | void | 239 | void |
| 293 | -QPDF_Stream::setDescription( | ||
| 294 | - QPDF* qpdf, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset) | ||
| 295 | -{ | ||
| 296 | - this->QPDFValue::setDescription(qpdf, description, offset); | ||
| 297 | - setDictDescription(); | ||
| 298 | -} | ||
| 299 | - | ||
| 300 | -void | ||
| 301 | -QPDF_Stream::setDictDescription() | 240 | +qpdf::Stream::setDictDescription() |
| 302 | { | 241 | { |
| 303 | - if (!this->stream_dict.hasObjectDescription()) { | ||
| 304 | - this->stream_dict.setObjectDescription(qpdf, getDescription() + " -> stream dictionary"); | 242 | + auto s = stream(); |
| 243 | + if (!s->stream_dict.hasObjectDescription()) { | ||
| 244 | + s->stream_dict.setObjectDescription( | ||
| 245 | + obj->getQPDF(), obj->getDescription() + " -> stream dictionary"); | ||
| 305 | } | 246 | } |
| 306 | } | 247 | } |
| 307 | 248 | ||
| 308 | -QPDFObjectHandle | ||
| 309 | -QPDF_Stream::getDict() const | ||
| 310 | -{ | ||
| 311 | - return this->stream_dict; | ||
| 312 | -} | ||
| 313 | - | ||
| 314 | -bool | ||
| 315 | -QPDF_Stream::isDataModified() const | ||
| 316 | -{ | ||
| 317 | - return (!this->token_filters.empty()); | ||
| 318 | -} | ||
| 319 | - | ||
| 320 | -size_t | ||
| 321 | -QPDF_Stream::getLength() const | ||
| 322 | -{ | ||
| 323 | - return this->length; | ||
| 324 | -} | ||
| 325 | - | ||
| 326 | std::shared_ptr<Buffer> | 249 | std::shared_ptr<Buffer> |
| 327 | -QPDF_Stream::getStreamDataBuffer() const | ||
| 328 | -{ | ||
| 329 | - return this->stream_data; | ||
| 330 | -} | ||
| 331 | - | ||
| 332 | -std::shared_ptr<QPDFObjectHandle::StreamDataProvider> | ||
| 333 | -QPDF_Stream::getStreamDataProvider() const | ||
| 334 | -{ | ||
| 335 | - return this->stream_provider; | ||
| 336 | -} | ||
| 337 | - | ||
| 338 | -std::shared_ptr<Buffer> | ||
| 339 | -QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) | 250 | +Stream::getStreamData(qpdf_stream_decode_level_e decode_level) |
| 340 | { | 251 | { |
| 341 | Pl_Buffer buf("stream data buffer"); | 252 | Pl_Buffer buf("stream data buffer"); |
| 342 | bool filtered; | 253 | bool filtered; |
| @@ -344,9 +255,9 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) | @@ -344,9 +255,9 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) | ||
| 344 | if (!filtered) { | 255 | if (!filtered) { |
| 345 | throw QPDFExc( | 256 | throw QPDFExc( |
| 346 | qpdf_e_unsupported, | 257 | qpdf_e_unsupported, |
| 347 | - qpdf->getFilename(), | 258 | + obj->getQPDF()->getFilename(), |
| 348 | "", | 259 | "", |
| 349 | - this->parsed_offset, | 260 | + obj->getParsedOffset(), |
| 350 | "getStreamData called on unfilterable stream"); | 261 | "getStreamData called on unfilterable stream"); |
| 351 | } | 262 | } |
| 352 | QTC::TC("qpdf", "QPDF_Stream getStreamData"); | 263 | QTC::TC("qpdf", "QPDF_Stream getStreamData"); |
| @@ -354,15 +265,15 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) | @@ -354,15 +265,15 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) | ||
| 354 | } | 265 | } |
| 355 | 266 | ||
| 356 | std::shared_ptr<Buffer> | 267 | std::shared_ptr<Buffer> |
| 357 | -QPDF_Stream::getRawStreamData() | 268 | +Stream::getRawStreamData() |
| 358 | { | 269 | { |
| 359 | Pl_Buffer buf("stream data buffer"); | 270 | Pl_Buffer buf("stream data buffer"); |
| 360 | if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) { | 271 | if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) { |
| 361 | throw QPDFExc( | 272 | throw QPDFExc( |
| 362 | qpdf_e_unsupported, | 273 | qpdf_e_unsupported, |
| 363 | - qpdf->getFilename(), | 274 | + obj->getQPDF()->getFilename(), |
| 364 | "", | 275 | "", |
| 365 | - this->parsed_offset, | 276 | + obj->getParsedOffset(), |
| 366 | "error getting raw stream data"); | 277 | "error getting raw stream data"); |
| 367 | } | 278 | } |
| 368 | QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); | 279 | QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); |
| @@ -370,14 +281,15 @@ QPDF_Stream::getRawStreamData() | @@ -370,14 +281,15 @@ QPDF_Stream::getRawStreamData() | ||
| 370 | } | 281 | } |
| 371 | 282 | ||
| 372 | bool | 283 | bool |
| 373 | -QPDF_Stream::filterable( | 284 | +Stream::filterable( |
| 374 | std::vector<std::shared_ptr<QPDFStreamFilter>>& filters, | 285 | std::vector<std::shared_ptr<QPDFStreamFilter>>& filters, |
| 375 | bool& specialized_compression, | 286 | bool& specialized_compression, |
| 376 | bool& lossy_compression) | 287 | bool& lossy_compression) |
| 377 | { | 288 | { |
| 289 | + auto s = stream(); | ||
| 378 | // Check filters | 290 | // Check filters |
| 379 | 291 | ||
| 380 | - QPDFObjectHandle filter_obj = this->stream_dict.getKey("/Filter"); | 292 | + QPDFObjectHandle filter_obj = s->stream_dict.getKey("/Filter"); |
| 381 | bool filters_okay = true; | 293 | bool filters_okay = true; |
| 382 | 294 | ||
| 383 | std::vector<std::string> filter_names; | 295 | std::vector<std::string> filter_names; |
| @@ -432,7 +344,7 @@ QPDF_Stream::filterable( | @@ -432,7 +344,7 @@ QPDF_Stream::filterable( | ||
| 432 | 344 | ||
| 433 | // See if we can support any decode parameters that are specified. | 345 | // See if we can support any decode parameters that are specified. |
| 434 | 346 | ||
| 435 | - QPDFObjectHandle decode_obj = this->stream_dict.getKey("/DecodeParms"); | 347 | + QPDFObjectHandle decode_obj = s->stream_dict.getKey("/DecodeParms"); |
| 436 | std::vector<QPDFObjectHandle> decode_parms; | 348 | std::vector<QPDFObjectHandle> decode_parms; |
| 437 | if (decode_obj.isArray() && (decode_obj.getArrayNItems() == 0)) { | 349 | if (decode_obj.isArray() && (decode_obj.getArrayNItems() == 0)) { |
| 438 | decode_obj = QPDFObjectHandle::newNull(); | 350 | decode_obj = QPDFObjectHandle::newNull(); |
| @@ -479,7 +391,7 @@ QPDF_Stream::filterable( | @@ -479,7 +391,7 @@ QPDF_Stream::filterable( | ||
| 479 | } | 391 | } |
| 480 | 392 | ||
| 481 | bool | 393 | bool |
| 482 | -QPDF_Stream::pipeStreamData( | 394 | +Stream::pipeStreamData( |
| 483 | Pipeline* pipeline, | 395 | Pipeline* pipeline, |
| 484 | bool* filterp, | 396 | bool* filterp, |
| 485 | int encode_flags, | 397 | int encode_flags, |
| @@ -487,6 +399,7 @@ QPDF_Stream::pipeStreamData( | @@ -487,6 +399,7 @@ QPDF_Stream::pipeStreamData( | ||
| 487 | bool suppress_warnings, | 399 | bool suppress_warnings, |
| 488 | bool will_retry) | 400 | bool will_retry) |
| 489 | { | 401 | { |
| 402 | + auto s = stream(); | ||
| 490 | std::vector<std::shared_ptr<QPDFStreamFilter>> filters; | 403 | std::vector<std::shared_ptr<QPDFStreamFilter>> filters; |
| 491 | bool specialized_compression = false; | 404 | bool specialized_compression = false; |
| 492 | bool lossy_compression = false; | 405 | bool lossy_compression = false; |
| @@ -543,7 +456,7 @@ QPDF_Stream::pipeStreamData( | @@ -543,7 +456,7 @@ QPDF_Stream::pipeStreamData( | ||
| 543 | pipeline = new_pipeline.get(); | 456 | pipeline = new_pipeline.get(); |
| 544 | } | 457 | } |
| 545 | 458 | ||
| 546 | - for (auto iter = this->token_filters.rbegin(); iter != this->token_filters.rend(); ++iter) { | 459 | + for (auto iter = s->token_filters.rbegin(); iter != s->token_filters.rend(); ++iter) { |
| 547 | new_pipeline = | 460 | new_pipeline = |
| 548 | std::make_shared<Pl_QPDFTokenizer>("token filter", (*iter).get(), pipeline); | 461 | std::make_shared<Pl_QPDFTokenizer>("token filter", (*iter).get(), pipeline); |
| 549 | to_delete.push_back(new_pipeline); | 462 | to_delete.push_back(new_pipeline); |
| @@ -562,25 +475,25 @@ QPDF_Stream::pipeStreamData( | @@ -562,25 +475,25 @@ QPDF_Stream::pipeStreamData( | ||
| 562 | } | 475 | } |
| 563 | } | 476 | } |
| 564 | 477 | ||
| 565 | - if (this->stream_data.get()) { | 478 | + if (s->stream_data.get()) { |
| 566 | QTC::TC("qpdf", "QPDF_Stream pipe replaced stream data"); | 479 | QTC::TC("qpdf", "QPDF_Stream pipe replaced stream data"); |
| 567 | - pipeline->write(this->stream_data->getBuffer(), this->stream_data->getSize()); | 480 | + pipeline->write(s->stream_data->getBuffer(), s->stream_data->getSize()); |
| 568 | pipeline->finish(); | 481 | pipeline->finish(); |
| 569 | - } else if (this->stream_provider.get()) { | 482 | + } else if (s->stream_provider.get()) { |
| 570 | Pl_Count count("stream provider count", pipeline); | 483 | Pl_Count count("stream provider count", pipeline); |
| 571 | - if (this->stream_provider->supportsRetry()) { | ||
| 572 | - if (!this->stream_provider->provideStreamData( | ||
| 573 | - og, &count, suppress_warnings, will_retry)) { | 484 | + if (s->stream_provider->supportsRetry()) { |
| 485 | + if (!s->stream_provider->provideStreamData( | ||
| 486 | + obj->getObjGen(), &count, suppress_warnings, will_retry)) { | ||
| 574 | filter = false; | 487 | filter = false; |
| 575 | success = false; | 488 | success = false; |
| 576 | } | 489 | } |
| 577 | } else { | 490 | } else { |
| 578 | - this->stream_provider->provideStreamData(og, &count); | 491 | + s->stream_provider->provideStreamData(obj->getObjGen(), &count); |
| 579 | } | 492 | } |
| 580 | qpdf_offset_t actual_length = count.getCount(); | 493 | qpdf_offset_t actual_length = count.getCount(); |
| 581 | qpdf_offset_t desired_length = 0; | 494 | qpdf_offset_t desired_length = 0; |
| 582 | - if (success && this->stream_dict.hasKey("/Length")) { | ||
| 583 | - desired_length = this->stream_dict.getKey("/Length").getIntValue(); | 495 | + if (success && s->stream_dict.hasKey("/Length")) { |
| 496 | + desired_length = s->stream_dict.getKey("/Length").getIntValue(); | ||
| 584 | if (actual_length == desired_length) { | 497 | if (actual_length == desired_length) { |
| 585 | QTC::TC("qpdf", "QPDF_Stream pipe use stream provider"); | 498 | QTC::TC("qpdf", "QPDF_Stream pipe use stream provider"); |
| 586 | } else { | 499 | } else { |
| @@ -588,25 +501,25 @@ QPDF_Stream::pipeStreamData( | @@ -588,25 +501,25 @@ QPDF_Stream::pipeStreamData( | ||
| 588 | // This would be caused by programmer error on the part of a library user, not by | 501 | // This would be caused by programmer error on the part of a library user, not by |
| 589 | // invalid input data. | 502 | // invalid input data. |
| 590 | throw std::runtime_error( | 503 | throw std::runtime_error( |
| 591 | - "stream data provider for " + og.unparse(' ') + " provided " + | 504 | + "stream data provider for " + obj->getObjGen().unparse(' ') + " provided " + |
| 592 | std::to_string(actual_length) + " bytes instead of expected " + | 505 | std::to_string(actual_length) + " bytes instead of expected " + |
| 593 | std::to_string(desired_length) + " bytes"); | 506 | std::to_string(desired_length) + " bytes"); |
| 594 | } | 507 | } |
| 595 | } else if (success) { | 508 | } else if (success) { |
| 596 | QTC::TC("qpdf", "QPDF_Stream provider length not provided"); | 509 | QTC::TC("qpdf", "QPDF_Stream provider length not provided"); |
| 597 | - this->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length)); | 510 | + s->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length)); |
| 598 | } | 511 | } |
| 599 | - } else if (this->parsed_offset == 0) { | 512 | + } else if (obj->getParsedOffset() == 0) { |
| 600 | QTC::TC("qpdf", "QPDF_Stream pipe no stream data"); | 513 | QTC::TC("qpdf", "QPDF_Stream pipe no stream data"); |
| 601 | throw std::logic_error("pipeStreamData called for stream with no data"); | 514 | throw std::logic_error("pipeStreamData called for stream with no data"); |
| 602 | } else { | 515 | } else { |
| 603 | QTC::TC("qpdf", "QPDF_Stream pipe original stream data"); | 516 | QTC::TC("qpdf", "QPDF_Stream pipe original stream data"); |
| 604 | if (!QPDF::Pipe::pipeStreamData( | 517 | if (!QPDF::Pipe::pipeStreamData( |
| 605 | - this->qpdf, | ||
| 606 | - og, | ||
| 607 | - this->parsed_offset, | ||
| 608 | - this->length, | ||
| 609 | - this->stream_dict, | 518 | + obj->getQPDF(), |
| 519 | + obj->getObjGen(), | ||
| 520 | + obj->getParsedOffset(), | ||
| 521 | + s->length, | ||
| 522 | + s->stream_dict, | ||
| 610 | pipeline, | 523 | pipeline, |
| 611 | suppress_warnings, | 524 | suppress_warnings, |
| 612 | will_retry)) { | 525 | will_retry)) { |
| @@ -634,60 +547,235 @@ QPDF_Stream::pipeStreamData( | @@ -634,60 +547,235 @@ QPDF_Stream::pipeStreamData( | ||
| 634 | } | 547 | } |
| 635 | 548 | ||
| 636 | void | 549 | void |
| 637 | -QPDF_Stream::replaceStreamData( | 550 | +Stream::replaceStreamData( |
| 638 | std::shared_ptr<Buffer> data, | 551 | std::shared_ptr<Buffer> data, |
| 639 | QPDFObjectHandle const& filter, | 552 | QPDFObjectHandle const& filter, |
| 640 | QPDFObjectHandle const& decode_parms) | 553 | QPDFObjectHandle const& decode_parms) |
| 641 | { | 554 | { |
| 642 | - this->stream_data = data; | ||
| 643 | - this->stream_provider = nullptr; | 555 | + auto s = stream(); |
| 556 | + s->stream_data = data; | ||
| 557 | + s->stream_provider = nullptr; | ||
| 644 | replaceFilterData(filter, decode_parms, data->getSize()); | 558 | replaceFilterData(filter, decode_parms, data->getSize()); |
| 645 | } | 559 | } |
| 646 | 560 | ||
| 647 | void | 561 | void |
| 648 | -QPDF_Stream::replaceStreamData( | 562 | +Stream::replaceStreamData( |
| 649 | std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider, | 563 | std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider, |
| 650 | QPDFObjectHandle const& filter, | 564 | QPDFObjectHandle const& filter, |
| 651 | QPDFObjectHandle const& decode_parms) | 565 | QPDFObjectHandle const& decode_parms) |
| 652 | { | 566 | { |
| 653 | - this->stream_provider = provider; | ||
| 654 | - this->stream_data = nullptr; | 567 | + auto s = stream(); |
| 568 | + s->stream_provider = provider; | ||
| 569 | + s->stream_data = nullptr; | ||
| 655 | replaceFilterData(filter, decode_parms, 0); | 570 | replaceFilterData(filter, decode_parms, 0); |
| 656 | } | 571 | } |
| 657 | 572 | ||
| 658 | void | 573 | void |
| 659 | -QPDF_Stream::addTokenFilter(std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter) | ||
| 660 | -{ | ||
| 661 | - this->token_filters.push_back(token_filter); | ||
| 662 | -} | ||
| 663 | - | ||
| 664 | -void | ||
| 665 | -QPDF_Stream::replaceFilterData( | 574 | +Stream::replaceFilterData( |
| 666 | QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length) | 575 | QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length) |
| 667 | { | 576 | { |
| 577 | + auto s = stream(); | ||
| 668 | if (filter) { | 578 | if (filter) { |
| 669 | - stream_dict.replaceKey("/Filter", filter); | 579 | + s->stream_dict.replaceKey("/Filter", filter); |
| 670 | } | 580 | } |
| 671 | if (decode_parms) { | 581 | if (decode_parms) { |
| 672 | - stream_dict.replaceKey("/DecodeParms", decode_parms); | 582 | + s->stream_dict.replaceKey("/DecodeParms", decode_parms); |
| 673 | } | 583 | } |
| 674 | if (length == 0) { | 584 | if (length == 0) { |
| 675 | QTC::TC("qpdf", "QPDF_Stream unknown stream length"); | 585 | QTC::TC("qpdf", "QPDF_Stream unknown stream length"); |
| 676 | - stream_dict.removeKey("/Length"); | 586 | + s->stream_dict.removeKey("/Length"); |
| 677 | } else { | 587 | } else { |
| 678 | - stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length))); | 588 | + s->stream_dict.replaceKey( |
| 589 | + "/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length))); | ||
| 679 | } | 590 | } |
| 680 | } | 591 | } |
| 681 | 592 | ||
| 682 | void | 593 | void |
| 683 | -QPDF_Stream::replaceDict(QPDFObjectHandle const& new_dict) | 594 | +Stream::warn(std::string const& message) |
| 684 | { | 595 | { |
| 685 | - this->stream_dict = new_dict; | ||
| 686 | - setDictDescription(); | 596 | + obj->getQPDF()->warn(qpdf_e_damaged_pdf, "", obj->getParsedOffset(), message); |
| 597 | +} | ||
| 598 | + | ||
| 599 | +QPDFObjectHandle | ||
| 600 | +QPDFObjectHandle::getDict() const | ||
| 601 | +{ | ||
| 602 | + return as_stream(error).getDict(); | ||
| 603 | +} | ||
| 604 | + | ||
| 605 | +void | ||
| 606 | +QPDFObjectHandle::setFilterOnWrite(bool val) | ||
| 607 | +{ | ||
| 608 | + as_stream(error).setFilterOnWrite(val); | ||
| 609 | +} | ||
| 610 | + | ||
| 611 | +bool | ||
| 612 | +QPDFObjectHandle::getFilterOnWrite() | ||
| 613 | +{ | ||
| 614 | + return as_stream(error).getFilterOnWrite(); | ||
| 615 | +} | ||
| 616 | + | ||
| 617 | +bool | ||
| 618 | +QPDFObjectHandle::isDataModified() | ||
| 619 | +{ | ||
| 620 | + return as_stream(error).isDataModified(); | ||
| 687 | } | 621 | } |
| 688 | 622 | ||
| 689 | void | 623 | void |
| 690 | -QPDF_Stream::warn(std::string const& message) | 624 | +QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict) |
| 625 | +{ | ||
| 626 | + as_stream(error).replaceDict(new_dict); | ||
| 627 | +} | ||
| 628 | + | ||
| 629 | +std::shared_ptr<Buffer> | ||
| 630 | +QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level) | ||
| 631 | +{ | ||
| 632 | + return as_stream(error).getStreamData(level); | ||
| 633 | +} | ||
| 634 | + | ||
| 635 | +std::shared_ptr<Buffer> | ||
| 636 | +QPDFObjectHandle::getRawStreamData() | ||
| 637 | +{ | ||
| 638 | + return as_stream(error).getRawStreamData(); | ||
| 639 | +} | ||
| 640 | + | ||
| 641 | +bool | ||
| 642 | +QPDFObjectHandle::pipeStreamData( | ||
| 643 | + Pipeline* p, | ||
| 644 | + bool* filtering_attempted, | ||
| 645 | + int encode_flags, | ||
| 646 | + qpdf_stream_decode_level_e decode_level, | ||
| 647 | + bool suppress_warnings, | ||
| 648 | + bool will_retry) | ||
| 649 | +{ | ||
| 650 | + return as_stream(error).pipeStreamData( | ||
| 651 | + p, filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry); | ||
| 652 | +} | ||
| 653 | + | ||
| 654 | +bool | ||
| 655 | +QPDFObjectHandle::pipeStreamData( | ||
| 656 | + Pipeline* p, | ||
| 657 | + int encode_flags, | ||
| 658 | + qpdf_stream_decode_level_e decode_level, | ||
| 659 | + bool suppress_warnings, | ||
| 660 | + bool will_retry) | ||
| 661 | +{ | ||
| 662 | + bool filtering_attempted; | ||
| 663 | + as_stream(error).pipeStreamData( | ||
| 664 | + p, &filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry); | ||
| 665 | + return filtering_attempted; | ||
| 666 | +} | ||
| 667 | + | ||
| 668 | +bool | ||
| 669 | +QPDFObjectHandle::pipeStreamData(Pipeline* p, bool filter, bool normalize, bool compress) | ||
| 670 | +{ | ||
| 671 | + int encode_flags = 0; | ||
| 672 | + qpdf_stream_decode_level_e decode_level = qpdf_dl_none; | ||
| 673 | + if (filter) { | ||
| 674 | + decode_level = qpdf_dl_generalized; | ||
| 675 | + if (normalize) { | ||
| 676 | + encode_flags |= qpdf_ef_normalize; | ||
| 677 | + } | ||
| 678 | + if (compress) { | ||
| 679 | + encode_flags |= qpdf_ef_compress; | ||
| 680 | + } | ||
| 681 | + } | ||
| 682 | + return pipeStreamData(p, encode_flags, decode_level, false); | ||
| 683 | +} | ||
| 684 | + | ||
| 685 | +void | ||
| 686 | +QPDFObjectHandle::replaceStreamData( | ||
| 687 | + std::shared_ptr<Buffer> data, | ||
| 688 | + QPDFObjectHandle const& filter, | ||
| 689 | + QPDFObjectHandle const& decode_parms) | ||
| 690 | +{ | ||
| 691 | + as_stream(error).replaceStreamData(data, filter, decode_parms); | ||
| 692 | +} | ||
| 693 | + | ||
| 694 | +void | ||
| 695 | +QPDFObjectHandle::replaceStreamData( | ||
| 696 | + std::string const& data, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) | ||
| 697 | +{ | ||
| 698 | + auto b = std::make_shared<Buffer>(data.length()); | ||
| 699 | + unsigned char* bp = b->getBuffer(); | ||
| 700 | + if (bp) { | ||
| 701 | + memcpy(bp, data.c_str(), data.length()); | ||
| 702 | + } | ||
| 703 | + as_stream(error).replaceStreamData(b, filter, decode_parms); | ||
| 704 | +} | ||
| 705 | + | ||
| 706 | +void | ||
| 707 | +QPDFObjectHandle::replaceStreamData( | ||
| 708 | + std::shared_ptr<StreamDataProvider> provider, | ||
| 709 | + QPDFObjectHandle const& filter, | ||
| 710 | + QPDFObjectHandle const& decode_parms) | ||
| 711 | +{ | ||
| 712 | + as_stream(error).replaceStreamData(provider, filter, decode_parms); | ||
| 713 | +} | ||
| 714 | + | ||
| 715 | +namespace | ||
| 716 | +{ | ||
| 717 | + class FunctionProvider: public QPDFObjectHandle::StreamDataProvider | ||
| 718 | + { | ||
| 719 | + public: | ||
| 720 | + FunctionProvider(std::function<void(Pipeline*)> provider) : | ||
| 721 | + StreamDataProvider(false), | ||
| 722 | + p1(provider), | ||
| 723 | + p2(nullptr) | ||
| 724 | + { | ||
| 725 | + } | ||
| 726 | + FunctionProvider(std::function<bool(Pipeline*, bool, bool)> provider) : | ||
| 727 | + StreamDataProvider(true), | ||
| 728 | + p1(nullptr), | ||
| 729 | + p2(provider) | ||
| 730 | + { | ||
| 731 | + } | ||
| 732 | + | ||
| 733 | + void | ||
| 734 | + provideStreamData(QPDFObjGen const&, Pipeline* pipeline) override | ||
| 735 | + { | ||
| 736 | + p1(pipeline); | ||
| 737 | + } | ||
| 738 | + | ||
| 739 | + bool | ||
| 740 | + provideStreamData( | ||
| 741 | + QPDFObjGen const&, Pipeline* pipeline, bool suppress_warnings, bool will_retry) override | ||
| 742 | + { | ||
| 743 | + return p2(pipeline, suppress_warnings, will_retry); | ||
| 744 | + } | ||
| 745 | + | ||
| 746 | + private: | ||
| 747 | + std::function<void(Pipeline*)> p1; | ||
| 748 | + std::function<bool(Pipeline*, bool, bool)> p2; | ||
| 749 | + }; | ||
| 750 | +} // namespace | ||
| 751 | + | ||
| 752 | +void | ||
| 753 | +QPDFObjectHandle::replaceStreamData( | ||
| 754 | + std::function<void(Pipeline*)> provider, | ||
| 755 | + QPDFObjectHandle const& filter, | ||
| 756 | + QPDFObjectHandle const& decode_parms) | ||
| 757 | +{ | ||
| 758 | + auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); | ||
| 759 | + as_stream(error).replaceStreamData(sdp, filter, decode_parms); | ||
| 760 | +} | ||
| 761 | + | ||
| 762 | +void | ||
| 763 | +QPDFObjectHandle::replaceStreamData( | ||
| 764 | + std::function<bool(Pipeline*, bool, bool)> provider, | ||
| 765 | + QPDFObjectHandle const& filter, | ||
| 766 | + QPDFObjectHandle const& decode_parms) | ||
| 767 | +{ | ||
| 768 | + auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); | ||
| 769 | + as_stream(error).replaceStreamData(sdp, filter, decode_parms); | ||
| 770 | +} | ||
| 771 | + | ||
| 772 | +JSON | ||
| 773 | +QPDFObjectHandle::getStreamJSON( | ||
| 774 | + int json_version, | ||
| 775 | + qpdf_json_stream_data_e json_data, | ||
| 776 | + qpdf_stream_decode_level_e decode_level, | ||
| 777 | + Pipeline* p, | ||
| 778 | + std::string const& data_filename) | ||
| 691 | { | 779 | { |
| 692 | - this->qpdf->warn(qpdf_e_damaged_pdf, "", this->parsed_offset, message); | 780 | + return as_stream(error).getStreamJSON(json_version, json_data, decode_level, p, data_filename); |
| 693 | } | 781 | } |
libqpdf/QPDF_String.cc
| 1 | -#include <qpdf/QPDF_String.hh> | 1 | +#include <qpdf/QPDFObject_private.hh> |
| 2 | 2 | ||
| 3 | -#include <qpdf/JSON_writer.hh> | 3 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 4 | #include <qpdf/QUtil.hh> | 4 | #include <qpdf/QUtil.hh> |
| 5 | 5 | ||
| 6 | // DO NOT USE ctype -- it is locale dependent for some things, and it's not worth the risk of | 6 | // DO NOT USE ctype -- it is locale dependent for some things, and it's not worth the risk of |
| @@ -12,18 +12,6 @@ is_iso_latin1_printable(char ch) | @@ -12,18 +12,6 @@ is_iso_latin1_printable(char ch) | ||
| 12 | return (((ch >= 32) && (ch <= 126)) || (static_cast<unsigned char>(ch) >= 160)); | 12 | return (((ch >= 32) && (ch <= 126)) || (static_cast<unsigned char>(ch) >= 160)); |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | -QPDF_String::QPDF_String(std::string const& val) : | ||
| 16 | - QPDFValue(::ot_string), | ||
| 17 | - val(val) | ||
| 18 | -{ | ||
| 19 | -} | ||
| 20 | - | ||
| 21 | -std::shared_ptr<QPDFObject> | ||
| 22 | -QPDF_String::create(std::string const& val) | ||
| 23 | -{ | ||
| 24 | - return do_create(new QPDF_String(val)); | ||
| 25 | -} | ||
| 26 | - | ||
| 27 | std::shared_ptr<QPDFObject> | 15 | std::shared_ptr<QPDFObject> |
| 28 | QPDF_String::create_utf16(std::string const& utf8_val) | 16 | QPDF_String::create_utf16(std::string const& utf8_val) |
| 29 | { | 17 | { |
| @@ -31,19 +19,7 @@ QPDF_String::create_utf16(std::string const& utf8_val) | @@ -31,19 +19,7 @@ QPDF_String::create_utf16(std::string const& utf8_val) | ||
| 31 | if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) { | 19 | if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) { |
| 32 | result = QUtil::utf8_to_utf16(utf8_val); | 20 | result = QUtil::utf8_to_utf16(utf8_val); |
| 33 | } | 21 | } |
| 34 | - return do_create(new QPDF_String(result)); | ||
| 35 | -} | ||
| 36 | - | ||
| 37 | -std::shared_ptr<QPDFObject> | ||
| 38 | -QPDF_String::copy(bool shallow) | ||
| 39 | -{ | ||
| 40 | - return create(val); | ||
| 41 | -} | ||
| 42 | - | ||
| 43 | -std::string | ||
| 44 | -QPDF_String::unparse() | ||
| 45 | -{ | ||
| 46 | - return unparse(false); | 22 | + return QPDFObject::create<QPDF_String>(result); |
| 47 | } | 23 | } |
| 48 | 24 | ||
| 49 | void | 25 | void |
libqpdf/QPDF_Unresolved.cc deleted
| 1 | -#include <qpdf/QPDF_Unresolved.hh> | ||
| 2 | - | ||
| 3 | -#include <qpdf/QPDF.hh> | ||
| 4 | -#include <qpdf/QPDFObject_private.hh> | ||
| 5 | - | ||
| 6 | -QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen og) : | ||
| 7 | - QPDFValue(::ot_unresolved, qpdf, og) | ||
| 8 | -{ | ||
| 9 | -} | ||
| 10 | - | ||
| 11 | -std::shared_ptr<QPDFObject> | ||
| 12 | -QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen og) | ||
| 13 | -{ | ||
| 14 | - return do_create(new QPDF_Unresolved(qpdf, og)); | ||
| 15 | -} | ||
| 16 | - | ||
| 17 | -std::shared_ptr<QPDFObject> | ||
| 18 | -QPDF_Unresolved::copy(bool shallow) | ||
| 19 | -{ | ||
| 20 | - return QPDF::Resolver::resolved(qpdf, og)->copy(shallow); | ||
| 21 | -} | ||
| 22 | - | ||
| 23 | -std::string | ||
| 24 | -QPDF_Unresolved::unparse() | ||
| 25 | -{ | ||
| 26 | - return QPDF::Resolver::resolved(qpdf, og)->unparse(); | ||
| 27 | -} | ||
| 28 | - | ||
| 29 | -void | ||
| 30 | -QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p) | ||
| 31 | -{ | ||
| 32 | - QPDF::Resolver::resolved(qpdf, og)->writeJSON(json_version, p); | ||
| 33 | -} | ||
| 34 | - | ||
| 35 | -std::string | ||
| 36 | -QPDF_Unresolved::getStringValue() const | ||
| 37 | -{ | ||
| 38 | - return QPDF::Resolver::resolved(qpdf, og)->getStringValue(); | ||
| 39 | -} |
libqpdf/QPDF_json.cc
| @@ -5,10 +5,8 @@ | @@ -5,10 +5,8 @@ | ||
| 5 | #include <qpdf/Pl_Base64.hh> | 5 | #include <qpdf/Pl_Base64.hh> |
| 6 | #include <qpdf/Pl_StdioFile.hh> | 6 | #include <qpdf/Pl_StdioFile.hh> |
| 7 | #include <qpdf/QIntC.hh> | 7 | #include <qpdf/QIntC.hh> |
| 8 | +#include <qpdf/QPDFObjectHandle_private.hh> | ||
| 8 | #include <qpdf/QPDFObject_private.hh> | 9 | #include <qpdf/QPDFObject_private.hh> |
| 9 | -#include <qpdf/QPDFValue.hh> | ||
| 10 | -#include <qpdf/QPDF_Null.hh> | ||
| 11 | -#include <qpdf/QPDF_Stream.hh> | ||
| 12 | #include <qpdf/QTC.hh> | 10 | #include <qpdf/QTC.hh> |
| 13 | #include <qpdf/QUtil.hh> | 11 | #include <qpdf/QUtil.hh> |
| 14 | #include <algorithm> | 12 | #include <algorithm> |
| @@ -238,8 +236,8 @@ class QPDF::JSONReactor: public JSON::Reactor | @@ -238,8 +236,8 @@ class QPDF::JSONReactor: public JSON::Reactor | ||
| 238 | is(is), | 236 | is(is), |
| 239 | must_be_complete(must_be_complete), | 237 | must_be_complete(must_be_complete), |
| 240 | descr( | 238 | descr( |
| 241 | - std::make_shared<QPDFValue::Description>( | ||
| 242 | - QPDFValue::JSON_Descr(std::make_shared<std::string>(is->getName()), ""))) | 239 | + std::make_shared<QPDFObject::Description>( |
| 240 | + QPDFObject::JSON_Descr(std::make_shared<std::string>(is->getName()), ""))) | ||
| 243 | { | 241 | { |
| 244 | } | 242 | } |
| 245 | ~JSONReactor() override = default; | 243 | ~JSONReactor() override = default; |
| @@ -286,7 +284,7 @@ class QPDF::JSONReactor: public JSON::Reactor | @@ -286,7 +284,7 @@ class QPDF::JSONReactor: public JSON::Reactor | ||
| 286 | QPDF& pdf; | 284 | QPDF& pdf; |
| 287 | std::shared_ptr<InputSource> is; | 285 | std::shared_ptr<InputSource> is; |
| 288 | bool must_be_complete{true}; | 286 | bool must_be_complete{true}; |
| 289 | - std::shared_ptr<QPDFValue::Description> descr; | 287 | + std::shared_ptr<QPDFObject::Description> descr; |
| 290 | bool errors{false}; | 288 | bool errors{false}; |
| 291 | bool saw_qpdf{false}; | 289 | bool saw_qpdf{false}; |
| 292 | bool saw_qpdf_meta{false}; | 290 | bool saw_qpdf_meta{false}; |
| @@ -576,8 +574,8 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | @@ -576,8 +574,8 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | ||
| 576 | } else { | 574 | } else { |
| 577 | this_stream_needs_data = true; | 575 | this_stream_needs_data = true; |
| 578 | replaceObject( | 576 | replaceObject( |
| 579 | - QPDF_Stream::create( | ||
| 580 | - &pdf, tos.object.getObjGen(), QPDFObjectHandle::newDictionary(), 0, 0), | 577 | + qpdf::Stream( |
| 578 | + pdf, tos.object.getObjGen(), QPDFObjectHandle::newDictionary(), 0, 0), | ||
| 581 | value); | 579 | value); |
| 582 | } | 580 | } |
| 583 | next_obj = tos.object; | 581 | next_obj = tos.object; |
| @@ -706,10 +704,10 @@ QPDF::JSONReactor::arrayItem(JSON const& value) | @@ -706,10 +704,10 @@ QPDF::JSONReactor::arrayItem(JSON const& value) | ||
| 706 | void | 704 | void |
| 707 | QPDF::JSONReactor::setObjectDescription(QPDFObjectHandle& oh, JSON const& value) | 705 | QPDF::JSONReactor::setObjectDescription(QPDFObjectHandle& oh, JSON const& value) |
| 708 | { | 706 | { |
| 709 | - auto j_descr = std::get<QPDFValue::JSON_Descr>(*descr); | 707 | + auto j_descr = std::get<QPDFObject::JSON_Descr>(*descr); |
| 710 | if (j_descr.object != cur_object) { | 708 | if (j_descr.object != cur_object) { |
| 711 | - descr = std::make_shared<QPDFValue::Description>( | ||
| 712 | - QPDFValue::JSON_Descr(j_descr.input, cur_object)); | 709 | + descr = std::make_shared<QPDFObject::Description>( |
| 710 | + QPDFObject::JSON_Descr(j_descr.input, cur_object)); | ||
| 713 | } | 711 | } |
| 714 | 712 | ||
| 715 | oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart()); | 713 | oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart()); |
| @@ -821,7 +819,7 @@ void | @@ -821,7 +819,7 @@ void | ||
| 821 | writeJSONStreamFile( | 819 | writeJSONStreamFile( |
| 822 | int version, | 820 | int version, |
| 823 | JSON::Writer& jw, | 821 | JSON::Writer& jw, |
| 824 | - QPDF_Stream& stream, | 822 | + qpdf::Stream& stream, |
| 825 | int id, | 823 | int id, |
| 826 | qpdf_stream_decode_level_e decode_level, | 824 | qpdf_stream_decode_level_e decode_level, |
| 827 | std::string const& file_prefix) | 825 | std::string const& file_prefix) |
| @@ -894,13 +892,13 @@ QPDF::writeJSON( | @@ -894,13 +892,13 @@ QPDF::writeJSON( | ||
| 894 | } else { | 892 | } else { |
| 895 | jw << "\n },\n \"" << key; | 893 | jw << "\n },\n \"" << key; |
| 896 | } | 894 | } |
| 897 | - if (auto* stream = obj.getObjectPtr()->as<QPDF_Stream>()) { | 895 | + if (auto stream = obj.as_stream()) { |
| 898 | jw << "\": {\n \"stream\": "; | 896 | jw << "\": {\n \"stream\": "; |
| 899 | if (json_stream_data == qpdf_sj_file) { | 897 | if (json_stream_data == qpdf_sj_file) { |
| 900 | writeJSONStreamFile( | 898 | writeJSONStreamFile( |
| 901 | - version, jw, *stream, og.getObj(), decode_level, file_prefix); | 899 | + version, jw, stream, og.getObj(), decode_level, file_prefix); |
| 902 | } else { | 900 | } else { |
| 903 | - stream->writeStreamJSON( | 901 | + stream.writeStreamJSON( |
| 904 | version, jw, json_stream_data, decode_level, nullptr, ""); | 902 | version, jw, json_stream_data, decode_level, nullptr, ""); |
| 905 | } | 903 | } |
| 906 | } else { | 904 | } else { |
libqpdf/QPDF_optimization.cc
| @@ -5,9 +5,8 @@ | @@ -5,9 +5,8 @@ | ||
| 5 | #include <qpdf/QPDF.hh> | 5 | #include <qpdf/QPDF.hh> |
| 6 | 6 | ||
| 7 | #include <qpdf/QPDFExc.hh> | 7 | #include <qpdf/QPDFExc.hh> |
| 8 | +#include <qpdf/QPDFObjectHandle_private.hh> | ||
| 8 | #include <qpdf/QPDFWriter_private.hh> | 9 | #include <qpdf/QPDFWriter_private.hh> |
| 9 | -#include <qpdf/QPDF_Array.hh> | ||
| 10 | -#include <qpdf/QPDF_Dictionary.hh> | ||
| 11 | #include <qpdf/QTC.hh> | 10 | #include <qpdf/QTC.hh> |
| 12 | 11 | ||
| 13 | QPDF::ObjUser::ObjUser() : | 12 | QPDF::ObjUser::ObjUser() : |
| @@ -115,24 +114,25 @@ QPDF::optimize_internal( | @@ -115,24 +114,25 @@ QPDF::optimize_internal( | ||
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | // Traverse document-level items | 116 | // Traverse document-level items |
| 118 | - for (auto const& key: m->trailer.getKeys()) { | 117 | + for (auto const& [key, value]: m->trailer.as_dictionary()) { |
| 119 | if (key == "/Root") { | 118 | if (key == "/Root") { |
| 120 | // handled separately | 119 | // handled separately |
| 121 | } else { | 120 | } else { |
| 122 | - updateObjectMaps( | ||
| 123 | - ObjUser(ObjUser::ou_trailer_key, key), | ||
| 124 | - m->trailer.getKey(key), | ||
| 125 | - skip_stream_parameters); | 121 | + if (!value.null()) { |
| 122 | + updateObjectMaps( | ||
| 123 | + ObjUser(ObjUser::ou_trailer_key, key), value, skip_stream_parameters); | ||
| 124 | + } | ||
| 126 | } | 125 | } |
| 127 | } | 126 | } |
| 128 | 127 | ||
| 129 | - for (auto const& key: root.getKeys()) { | 128 | + for (auto const& [key, value]: root.as_dictionary()) { |
| 130 | // Technically, /I keys from /Thread dictionaries are supposed to be handled separately, but | 129 | // Technically, /I keys from /Thread dictionaries are supposed to be handled separately, but |
| 131 | // we are going to disregard that specification for now. There is loads of evidence that | 130 | // we are going to disregard that specification for now. There is loads of evidence that |
| 132 | // pdlin and Acrobat both disregard things like this from time to time, so this is almost | 131 | // pdlin and Acrobat both disregard things like this from time to time, so this is almost |
| 133 | // certain not to cause any problems. | 132 | // certain not to cause any problems. |
| 134 | - updateObjectMaps( | ||
| 135 | - ObjUser(ObjUser::ou_root_key, key), root.getKey(key), skip_stream_parameters); | 133 | + if (!value.null()) { |
| 134 | + updateObjectMaps(ObjUser(ObjUser::ou_root_key, key), value, skip_stream_parameters); | ||
| 135 | + } | ||
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | ObjUser root_ou = ObjUser(ObjUser::ou_root); | 138 | ObjUser root_ou = ObjUser(ObjUser::ou_root); |
| @@ -319,9 +319,8 @@ QPDF::updateObjectMaps( | @@ -319,9 +319,8 @@ QPDF::updateObjectMaps( | ||
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | if (cur.oh.isArray()) { | 321 | if (cur.oh.isArray()) { |
| 322 | - int n = cur.oh.getArrayNItems(); | ||
| 323 | - for (int i = 0; i < n; ++i) { | ||
| 324 | - pending.emplace_back(cur.ou, cur.oh.getArrayItem(i), false); | 322 | + for (auto const& item: cur.oh.as_array()) { |
| 323 | + pending.emplace_back(cur.ou, item, false); | ||
| 325 | } | 324 | } |
| 326 | } else if (cur.oh.isDictionary() || cur.oh.isStream()) { | 325 | } else if (cur.oh.isDictionary() || cur.oh.isStream()) { |
| 327 | QPDFObjectHandle dict = cur.oh; | 326 | QPDFObjectHandle dict = cur.oh; |
| @@ -334,7 +333,11 @@ QPDF::updateObjectMaps( | @@ -334,7 +333,11 @@ QPDF::updateObjectMaps( | ||
| 334 | } | 333 | } |
| 335 | } | 334 | } |
| 336 | 335 | ||
| 337 | - for (auto const& key: dict.getKeys()) { | 336 | + for (auto& [key, value]: dict.as_dictionary()) { |
| 337 | + if (value.null()) { | ||
| 338 | + continue; | ||
| 339 | + } | ||
| 340 | + | ||
| 338 | if (is_page_node && (key == "/Thumb")) { | 341 | if (is_page_node && (key == "/Thumb")) { |
| 339 | // Traverse page thumbnail dictionaries as a special case. There can only ever | 342 | // Traverse page thumbnail dictionaries as a special case. There can only ever |
| 340 | // be one /Thumb key on a page, and we see at most one page node per call. | 343 | // be one /Thumb key on a page, and we see at most one page node per call. |
| @@ -347,7 +350,7 @@ QPDF::updateObjectMaps( | @@ -347,7 +350,7 @@ QPDF::updateObjectMaps( | ||
| 347 | ((ssp >= 2) && ((key == "/Filter") || (key == "/DecodeParms")))) { | 350 | ((ssp >= 2) && ((key == "/Filter") || (key == "/DecodeParms")))) { |
| 348 | // Don't traverse into stream parameters that we are not going to write. | 351 | // Don't traverse into stream parameters that we are not going to write. |
| 349 | } else { | 352 | } else { |
| 350 | - pending.emplace_back(cur.ou, dict.getKey(key), false); | 353 | + pending.emplace_back(cur.ou, value, false); |
| 351 | } | 354 | } |
| 352 | } | 355 | } |
| 353 | } | 356 | } |
libqpdf/QPDF_pages.cc
| 1 | #include <qpdf/QPDF.hh> | 1 | #include <qpdf/QPDF.hh> |
| 2 | 2 | ||
| 3 | #include <qpdf/QPDFExc.hh> | 3 | #include <qpdf/QPDFExc.hh> |
| 4 | +#include <qpdf/QPDFObjectHandle_private.hh> | ||
| 4 | #include <qpdf/QTC.hh> | 5 | #include <qpdf/QTC.hh> |
| 5 | #include <qpdf/QUtil.hh> | 6 | #include <qpdf/QUtil.hh> |
| 6 | 7 | ||
| @@ -108,9 +109,9 @@ QPDF::getAllPagesInternal( | @@ -108,9 +109,9 @@ QPDF::getAllPagesInternal( | ||
| 108 | QTC::TC("qpdf", "QPDF inherit mediabox", media_box ? 0 : 1); | 109 | QTC::TC("qpdf", "QPDF inherit mediabox", media_box ? 0 : 1); |
| 109 | } | 110 | } |
| 110 | auto kids = cur_node.getKey("/Kids"); | 111 | auto kids = cur_node.getKey("/Kids"); |
| 111 | - int n = kids.getArrayNItems(); | ||
| 112 | - for (int i = 0; i < n; ++i) { | ||
| 113 | - auto kid = kids.getArrayItem(i); | 112 | + int i = -1; |
| 113 | + for (auto& kid: kids.as_array()) { | ||
| 114 | + ++i; | ||
| 114 | if (!kid.isDictionary()) { | 115 | if (!kid.isDictionary()) { |
| 115 | kid.warnIfPossible("Pages tree includes non-dictionary object; ignoring"); | 116 | kid.warnIfPossible("Pages tree includes non-dictionary object; ignoring"); |
| 116 | m->invalid_page_found = true; | 117 | m->invalid_page_found = true; |
| @@ -133,7 +134,6 @@ QPDF::getAllPagesInternal( | @@ -133,7 +134,6 @@ QPDF::getAllPagesInternal( | ||
| 133 | cur_node.warnIfPossible( | 134 | cur_node.warnIfPossible( |
| 134 | "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect"); | 135 | "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect"); |
| 135 | kid = makeIndirectObject(kid); | 136 | kid = makeIndirectObject(kid); |
| 136 | - kids.setArrayItem(i, kid); | ||
| 137 | } else if (!seen.add(kid)) { | 137 | } else if (!seen.add(kid)) { |
| 138 | // Make a copy of the page. This does the same as shallowCopyPage in | 138 | // Make a copy of the page. This does the same as shallowCopyPage in |
| 139 | // QPDFPageObjectHelper. | 139 | // QPDFPageObjectHelper. |
| @@ -144,7 +144,6 @@ QPDF::getAllPagesInternal( | @@ -144,7 +144,6 @@ QPDF::getAllPagesInternal( | ||
| 144 | " creating a new page object as a copy"); | 144 | " creating a new page object as a copy"); |
| 145 | kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy()); | 145 | kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy()); |
| 146 | seen.add(kid); | 146 | seen.add(kid); |
| 147 | - kids.setArrayItem(i, kid); | ||
| 148 | } | 147 | } |
| 149 | if (!kid.isDictionaryOfType("/Page")) { | 148 | if (!kid.isDictionaryOfType("/Page")) { |
| 150 | kid.warnIfPossible("/Type key should be /Page but is not; overriding"); | 149 | kid.warnIfPossible("/Type key should be /Page but is not; overriding"); |
libqpdf/qpdf/QPDFObjectHandle_private.hh
0 → 100644
| 1 | +#ifndef OBJECTHANDLE_PRIVATE_HH | ||
| 2 | +#define OBJECTHANDLE_PRIVATE_HH | ||
| 3 | + | ||
| 4 | +#include <qpdf/QPDFObjectHandle.hh> | ||
| 5 | + | ||
| 6 | +#include <qpdf/QPDFObject_private.hh> | ||
| 7 | +#include <qpdf/QUtil.hh> | ||
| 8 | + | ||
| 9 | +namespace qpdf | ||
| 10 | +{ | ||
| 11 | + class Array final: public BaseHandle | ||
| 12 | + { | ||
| 13 | + public: | ||
| 14 | + explicit Array(std::shared_ptr<QPDFObject> const& obj) : | ||
| 15 | + BaseHandle(obj) | ||
| 16 | + { | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + explicit Array(std::shared_ptr<QPDFObject>&& obj) : | ||
| 20 | + BaseHandle(std::move(obj)) | ||
| 21 | + { | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + using iterator = std::vector<QPDFObjectHandle>::iterator; | ||
| 25 | + using const_iterator = std::vector<QPDFObjectHandle>::const_iterator; | ||
| 26 | + using const_reverse_iterator = std::vector<QPDFObjectHandle>::const_reverse_iterator; | ||
| 27 | + | ||
| 28 | + iterator begin(); | ||
| 29 | + | ||
| 30 | + iterator end(); | ||
| 31 | + | ||
| 32 | + const_iterator cbegin(); | ||
| 33 | + | ||
| 34 | + const_iterator cend(); | ||
| 35 | + | ||
| 36 | + const_reverse_iterator crbegin(); | ||
| 37 | + | ||
| 38 | + const_reverse_iterator crend(); | ||
| 39 | + | ||
| 40 | + int size() const; | ||
| 41 | + std::pair<bool, QPDFObjectHandle> at(int n) const; | ||
| 42 | + bool setAt(int at, QPDFObjectHandle const& oh); | ||
| 43 | + bool insert(int at, QPDFObjectHandle const& item); | ||
| 44 | + void push_back(QPDFObjectHandle const& item); | ||
| 45 | + bool erase(int at); | ||
| 46 | + | ||
| 47 | + std::vector<QPDFObjectHandle> getAsVector() const; | ||
| 48 | + void setFromVector(std::vector<QPDFObjectHandle> const& items); | ||
| 49 | + | ||
| 50 | + private: | ||
| 51 | + QPDF_Array* array() const; | ||
| 52 | + void checkOwnership(QPDFObjectHandle const& item) const; | ||
| 53 | + QPDFObjectHandle null() const; | ||
| 54 | + | ||
| 55 | + std::unique_ptr<std::vector<QPDFObjectHandle>> sp_elements{}; | ||
| 56 | + }; | ||
| 57 | + | ||
| 58 | + // BaseDictionary is only used as a base class. It does not contain any methods exposed in the | ||
| 59 | + // public API. | ||
| 60 | + class BaseDictionary: public BaseHandle | ||
| 61 | + { | ||
| 62 | + public: | ||
| 63 | + using iterator = std::map<std::string, QPDFObjectHandle>::iterator; | ||
| 64 | + using const_iterator = std::map<std::string, QPDFObjectHandle>::const_iterator; | ||
| 65 | + using reverse_iterator = std::map<std::string, QPDFObjectHandle>::reverse_iterator; | ||
| 66 | + using const_reverse_iterator = | ||
| 67 | + std::map<std::string, QPDFObjectHandle>::const_reverse_iterator; | ||
| 68 | + | ||
| 69 | + iterator | ||
| 70 | + begin() | ||
| 71 | + { | ||
| 72 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 73 | + return d->items.begin(); | ||
| 74 | + } | ||
| 75 | + return {}; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + iterator | ||
| 79 | + end() | ||
| 80 | + { | ||
| 81 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 82 | + return d->items.end(); | ||
| 83 | + } | ||
| 84 | + return {}; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + const_iterator | ||
| 88 | + cbegin() | ||
| 89 | + { | ||
| 90 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 91 | + return d->items.cbegin(); | ||
| 92 | + } | ||
| 93 | + return {}; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + const_iterator | ||
| 97 | + cend() | ||
| 98 | + { | ||
| 99 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 100 | + return d->items.cend(); | ||
| 101 | + } | ||
| 102 | + return {}; | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + reverse_iterator | ||
| 106 | + rbegin() | ||
| 107 | + { | ||
| 108 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 109 | + return d->items.rbegin(); | ||
| 110 | + } | ||
| 111 | + return {}; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + reverse_iterator | ||
| 115 | + rend() | ||
| 116 | + { | ||
| 117 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 118 | + return d->items.rend(); | ||
| 119 | + } | ||
| 120 | + return {}; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + const_reverse_iterator | ||
| 124 | + crbegin() | ||
| 125 | + { | ||
| 126 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 127 | + return d->items.crbegin(); | ||
| 128 | + } | ||
| 129 | + return {}; | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + const_reverse_iterator | ||
| 133 | + crend() | ||
| 134 | + { | ||
| 135 | + if (auto d = as<QPDF_Dictionary>()) { | ||
| 136 | + return d->items.crend(); | ||
| 137 | + } | ||
| 138 | + return {}; | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + // The following methods are not part of the public API. | ||
| 142 | + bool hasKey(std::string const& key) const; | ||
| 143 | + QPDFObjectHandle getKey(std::string const& key) const; | ||
| 144 | + std::set<std::string> getKeys(); | ||
| 145 | + std::map<std::string, QPDFObjectHandle> const& getAsMap() const; | ||
| 146 | + void removeKey(std::string const& key); | ||
| 147 | + void replaceKey(std::string const& key, QPDFObjectHandle value); | ||
| 148 | + | ||
| 149 | + protected: | ||
| 150 | + BaseDictionary() = default; | ||
| 151 | + BaseDictionary(std::shared_ptr<QPDFObject> const& obj) : | ||
| 152 | + BaseHandle(obj) {}; | ||
| 153 | + BaseDictionary(std::shared_ptr<QPDFObject>&& obj) : | ||
| 154 | + BaseHandle(std::move(obj)) {}; | ||
| 155 | + BaseDictionary(BaseDictionary const&) = default; | ||
| 156 | + BaseDictionary& operator=(BaseDictionary const&) = default; | ||
| 157 | + BaseDictionary(BaseDictionary&&) = default; | ||
| 158 | + BaseDictionary& operator=(BaseDictionary&&) = default; | ||
| 159 | + ~BaseDictionary() = default; | ||
| 160 | + | ||
| 161 | + QPDF_Dictionary* dict() const; | ||
| 162 | + }; | ||
| 163 | + | ||
| 164 | + class Dictionary final: public BaseDictionary | ||
| 165 | + { | ||
| 166 | + public: | ||
| 167 | + explicit Dictionary(std::shared_ptr<QPDFObject> const& obj) : | ||
| 168 | + BaseDictionary(obj) | ||
| 169 | + { | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + explicit Dictionary(std::shared_ptr<QPDFObject>&& obj) : | ||
| 173 | + BaseDictionary(std::move(obj)) | ||
| 174 | + { | ||
| 175 | + } | ||
| 176 | + }; | ||
| 177 | + | ||
| 178 | + class Name final: public BaseHandle | ||
| 179 | + { | ||
| 180 | + public: | ||
| 181 | + // Put # into strings with characters unsuitable for name token | ||
| 182 | + static std::string normalize(std::string const& name); | ||
| 183 | + | ||
| 184 | + // Check whether name is valid utf-8 and whether it contains characters that require | ||
| 185 | + // escaping. Return {false, false} if the name is not valid utf-8, otherwise return {true, | ||
| 186 | + // true} if no characters require or {true, false} if escaping is required. | ||
| 187 | + static std::pair<bool, bool> analyzeJSONEncoding(std::string const& name); | ||
| 188 | + }; | ||
| 189 | + | ||
| 190 | + class Stream final: public BaseHandle | ||
| 191 | + { | ||
| 192 | + public: | ||
| 193 | + explicit Stream(std::shared_ptr<QPDFObject> const& obj) : | ||
| 194 | + BaseHandle(obj) | ||
| 195 | + { | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + explicit Stream(std::shared_ptr<QPDFObject>&& obj) : | ||
| 199 | + BaseHandle(std::move(obj)) | ||
| 200 | + { | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + Stream( | ||
| 204 | + QPDF& qpdf, | ||
| 205 | + QPDFObjGen og, | ||
| 206 | + QPDFObjectHandle stream_dict, | ||
| 207 | + qpdf_offset_t offset, | ||
| 208 | + size_t length); | ||
| 209 | + | ||
| 210 | + QPDFObjectHandle | ||
| 211 | + getDict() const | ||
| 212 | + { | ||
| 213 | + return stream()->stream_dict; | ||
| 214 | + } | ||
| 215 | + bool | ||
| 216 | + isDataModified() const | ||
| 217 | + { | ||
| 218 | + return !stream()->token_filters.empty(); | ||
| 219 | + } | ||
| 220 | + void | ||
| 221 | + setFilterOnWrite(bool val) | ||
| 222 | + { | ||
| 223 | + stream()->filter_on_write = val; | ||
| 224 | + } | ||
| 225 | + bool | ||
| 226 | + getFilterOnWrite() const | ||
| 227 | + { | ||
| 228 | + return stream()->filter_on_write; | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + // Methods to help QPDF copy foreign streams | ||
| 232 | + size_t | ||
| 233 | + getLength() const | ||
| 234 | + { | ||
| 235 | + return stream()->length; | ||
| 236 | + } | ||
| 237 | + std::shared_ptr<Buffer> | ||
| 238 | + getStreamDataBuffer() const | ||
| 239 | + { | ||
| 240 | + return stream()->stream_data; | ||
| 241 | + } | ||
| 242 | + std::shared_ptr<QPDFObjectHandle::StreamDataProvider> | ||
| 243 | + getStreamDataProvider() const | ||
| 244 | + { | ||
| 245 | + return stream()->stream_provider; | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + // See comments in QPDFObjectHandle.hh for these methods. | ||
| 249 | + bool pipeStreamData( | ||
| 250 | + Pipeline* p, | ||
| 251 | + bool* tried_filtering, | ||
| 252 | + int encode_flags, | ||
| 253 | + qpdf_stream_decode_level_e decode_level, | ||
| 254 | + bool suppress_warnings, | ||
| 255 | + bool will_retry); | ||
| 256 | + std::shared_ptr<Buffer> getStreamData(qpdf_stream_decode_level_e level); | ||
| 257 | + std::shared_ptr<Buffer> getRawStreamData(); | ||
| 258 | + void replaceStreamData( | ||
| 259 | + std::shared_ptr<Buffer> data, | ||
| 260 | + QPDFObjectHandle const& filter, | ||
| 261 | + QPDFObjectHandle const& decode_parms); | ||
| 262 | + void replaceStreamData( | ||
| 263 | + std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider, | ||
| 264 | + QPDFObjectHandle const& filter, | ||
| 265 | + QPDFObjectHandle const& decode_parms); | ||
| 266 | + void | ||
| 267 | + addTokenFilter(std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter) | ||
| 268 | + { | ||
| 269 | + stream()->token_filters.emplace_back(token_filter); | ||
| 270 | + } | ||
| 271 | + JSON getStreamJSON( | ||
| 272 | + int json_version, | ||
| 273 | + qpdf_json_stream_data_e json_data, | ||
| 274 | + qpdf_stream_decode_level_e decode_level, | ||
| 275 | + Pipeline* p, | ||
| 276 | + std::string const& data_filename); | ||
| 277 | + qpdf_stream_decode_level_e writeStreamJSON( | ||
| 278 | + int json_version, | ||
| 279 | + JSON::Writer& jw, | ||
| 280 | + qpdf_json_stream_data_e json_data, | ||
| 281 | + qpdf_stream_decode_level_e decode_level, | ||
| 282 | + Pipeline* p, | ||
| 283 | + std::string const& data_filename, | ||
| 284 | + bool no_data_key = false); | ||
| 285 | + void | ||
| 286 | + replaceDict(QPDFObjectHandle const& new_dict) | ||
| 287 | + { | ||
| 288 | + auto s = stream(); | ||
| 289 | + s->stream_dict = new_dict; | ||
| 290 | + setDictDescription(); | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + void setDictDescription(); | ||
| 294 | + | ||
| 295 | + static void registerStreamFilter( | ||
| 296 | + std::string const& filter_name, | ||
| 297 | + std::function<std::shared_ptr<QPDFStreamFilter>()> factory); | ||
| 298 | + | ||
| 299 | + private: | ||
| 300 | + QPDF_Stream::Members* | ||
| 301 | + stream() const | ||
| 302 | + { | ||
| 303 | + if (auto s = as<QPDF_Stream>()) { | ||
| 304 | + if (auto ptr = s->m.get()) { | ||
| 305 | + return ptr; | ||
| 306 | + } | ||
| 307 | + throw std::logic_error("QPDF_Stream: unexpected nullptr"); | ||
| 308 | + } | ||
| 309 | + throw std::runtime_error("operation for stream attempted on non-stream object"); | ||
| 310 | + return nullptr; // unreachable | ||
| 311 | + } | ||
| 312 | + bool filterable( | ||
| 313 | + std::vector<std::shared_ptr<QPDFStreamFilter>>& filters, | ||
| 314 | + bool& specialized_compression, | ||
| 315 | + bool& lossy_compression); | ||
| 316 | + void replaceFilterData( | ||
| 317 | + QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length); | ||
| 318 | + | ||
| 319 | + void warn(std::string const& message); | ||
| 320 | + | ||
| 321 | + static std::map<std::string, std::string> filter_abbreviations; | ||
| 322 | + static std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>> | ||
| 323 | + filter_factories; | ||
| 324 | + }; | ||
| 325 | + | ||
| 326 | + template <typename T> | ||
| 327 | + T* | ||
| 328 | + BaseHandle::as() const | ||
| 329 | + { | ||
| 330 | + if (!obj) { | ||
| 331 | + return nullptr; | ||
| 332 | + } | ||
| 333 | + if (std::holds_alternative<T>(obj->value)) { | ||
| 334 | + return &std::get<T>(obj->value); | ||
| 335 | + } | ||
| 336 | + if (std::holds_alternative<QPDF_Unresolved>(obj->value)) { | ||
| 337 | + return BaseHandle(QPDF::Resolver::resolved(obj->qpdf, obj->og)).as<T>(); | ||
| 338 | + } | ||
| 339 | + if (std::holds_alternative<QPDF_Reference>(obj->value)) { | ||
| 340 | + // see comment in QPDF_Reference. | ||
| 341 | + return BaseHandle(std::get<QPDF_Reference>(obj->value).obj).as<T>(); | ||
| 342 | + } | ||
| 343 | + return nullptr; | ||
| 344 | + } | ||
| 345 | + | ||
| 346 | + inline QPDFObjGen | ||
| 347 | + BaseHandle::id_gen() const | ||
| 348 | + { | ||
| 349 | + return obj ? obj->og : QPDFObjGen(); | ||
| 350 | + } | ||
| 351 | + | ||
| 352 | + inline bool | ||
| 353 | + BaseHandle::indirect() const | ||
| 354 | + { | ||
| 355 | + return obj ? obj->og.isIndirect() : false; | ||
| 356 | + } | ||
| 357 | + | ||
| 358 | + inline bool | ||
| 359 | + BaseHandle::null() const | ||
| 360 | + { | ||
| 361 | + return !obj || obj->getResolvedTypeCode() == ::ot_null; | ||
| 362 | + } | ||
| 363 | + | ||
| 364 | + inline QPDF* | ||
| 365 | + BaseHandle::qpdf() const | ||
| 366 | + { | ||
| 367 | + return obj ? obj->qpdf : nullptr; | ||
| 368 | + } | ||
| 369 | + | ||
| 370 | + inline qpdf_object_type_e | ||
| 371 | + BaseHandle::raw_type_code() const | ||
| 372 | + { | ||
| 373 | + return obj ? static_cast<qpdf_object_type_e>(obj->value.index()) : ::ot_uninitialized; | ||
| 374 | + } | ||
| 375 | + | ||
| 376 | + inline qpdf_object_type_e | ||
| 377 | + BaseHandle::type_code() const | ||
| 378 | + { | ||
| 379 | + if (!obj) { | ||
| 380 | + return ::ot_uninitialized; | ||
| 381 | + } | ||
| 382 | + if (raw_type_code() == ::ot_unresolved) { | ||
| 383 | + return QPDF::Resolver::resolved(obj->qpdf, obj->og)->getTypeCode(); | ||
| 384 | + } | ||
| 385 | + if (raw_type_code() == ::ot_reference) { | ||
| 386 | + return std::get<QPDF_Reference>(obj->value).obj->getResolvedTypeCode(); | ||
| 387 | + } | ||
| 388 | + return raw_type_code(); | ||
| 389 | + } | ||
| 390 | + | ||
| 391 | +} // namespace qpdf | ||
| 392 | + | ||
| 393 | +inline QPDF_Dictionary::QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items) : | ||
| 394 | + items(std::move(items)) | ||
| 395 | +{ | ||
| 396 | +} | ||
| 397 | + | ||
| 398 | +inline std::shared_ptr<QPDFObject> | ||
| 399 | +QPDF_Null::create( | ||
| 400 | + std::shared_ptr<QPDFObject> parent, std::string_view const& static_descr, std::string var_descr) | ||
| 401 | +{ | ||
| 402 | + auto n = QPDFObject::create<QPDF_Null>(); | ||
| 403 | + n->setChildDescription(parent->getQPDF(), parent, static_descr, var_descr); | ||
| 404 | + return n; | ||
| 405 | +} | ||
| 406 | + | ||
| 407 | +inline QPDF_Real::QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes) : | ||
| 408 | + val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes)) | ||
| 409 | +{ | ||
| 410 | +} | ||
| 411 | + | ||
| 412 | +template <typename T, typename... Args> | ||
| 413 | +inline std::shared_ptr<QPDFObject> | ||
| 414 | +QPDFObject::create(Args&&... args) | ||
| 415 | +{ | ||
| 416 | + return std::make_shared<QPDFObject>(std::forward<T>(T(std::forward<Args>(args)...))); | ||
| 417 | +} | ||
| 418 | + | ||
| 419 | +inline qpdf::Array | ||
| 420 | +QPDFObjectHandle::as_array(qpdf::typed options) const | ||
| 421 | +{ | ||
| 422 | + if (options & qpdf::error) { | ||
| 423 | + assertType("array", false); | ||
| 424 | + } | ||
| 425 | + if (options & qpdf::any_flag || type_code() == ::ot_array || | ||
| 426 | + (options & qpdf::optional && type_code() == ::ot_null)) { | ||
| 427 | + return qpdf::Array(obj); | ||
| 428 | + } | ||
| 429 | + return qpdf::Array(std::shared_ptr<QPDFObject>()); | ||
| 430 | +} | ||
| 431 | + | ||
| 432 | +inline qpdf::Dictionary | ||
| 433 | +QPDFObjectHandle::as_dictionary(qpdf::typed options) const | ||
| 434 | +{ | ||
| 435 | + if (options & qpdf::any_flag || type_code() == ::ot_dictionary || | ||
| 436 | + (options & qpdf::optional && type_code() == ::ot_null)) { | ||
| 437 | + return qpdf::Dictionary(obj); | ||
| 438 | + } | ||
| 439 | + if (options & qpdf::error) { | ||
| 440 | + assertType("dictionary", false); | ||
| 441 | + } | ||
| 442 | + return qpdf::Dictionary(std::shared_ptr<QPDFObject>()); | ||
| 443 | +} | ||
| 444 | + | ||
| 445 | +inline qpdf::Stream | ||
| 446 | +QPDFObjectHandle::as_stream(qpdf::typed options) const | ||
| 447 | +{ | ||
| 448 | + if (options & qpdf::any_flag || type_code() == ::ot_stream || | ||
| 449 | + (options & qpdf::optional && type_code() == ::ot_null)) { | ||
| 450 | + return qpdf::Stream(obj); | ||
| 451 | + } | ||
| 452 | + if (options & qpdf::error) { | ||
| 453 | + assertType("stream", false); | ||
| 454 | + } | ||
| 455 | + return qpdf::Stream(std::shared_ptr<QPDFObject>()); | ||
| 456 | +} | ||
| 457 | + | ||
| 458 | +#endif // OBJECTHANDLE_PRIVATE_HH |
libqpdf/qpdf/QPDFObject_private.hh
| @@ -6,182 +6,486 @@ | @@ -6,182 +6,486 @@ | ||
| 6 | 6 | ||
| 7 | #include <qpdf/Constants.h> | 7 | #include <qpdf/Constants.h> |
| 8 | #include <qpdf/JSON.hh> | 8 | #include <qpdf/JSON.hh> |
| 9 | +#include <qpdf/JSON_writer.hh> | ||
| 9 | #include <qpdf/QPDF.hh> | 10 | #include <qpdf/QPDF.hh> |
| 10 | -#include <qpdf/QPDFValue.hh> | 11 | +#include <qpdf/QPDFObjGen.hh> |
| 11 | #include <qpdf/Types.h> | 12 | #include <qpdf/Types.h> |
| 12 | 13 | ||
| 14 | +#include <map> | ||
| 15 | +#include <memory> | ||
| 13 | #include <string> | 16 | #include <string> |
| 14 | #include <string_view> | 17 | #include <string_view> |
| 18 | +#include <variant> | ||
| 19 | +#include <vector> | ||
| 15 | 20 | ||
| 16 | -class QPDF; | 21 | +class QPDFObject; |
| 17 | class QPDFObjectHandle; | 22 | class QPDFObjectHandle; |
| 18 | 23 | ||
| 19 | -class QPDFObject | 24 | +namespace qpdf |
| 20 | { | 25 | { |
| 21 | - friend class QPDFValue; | 26 | + class Array; |
| 27 | + class BaseDictionary; | ||
| 28 | + class Dictionary; | ||
| 29 | + class Stream; | ||
| 30 | +} // namespace qpdf | ||
| 22 | 31 | ||
| 23 | - public: | ||
| 24 | - QPDFObject() = default; | 32 | +class QPDF_Array final |
| 33 | +{ | ||
| 34 | + private: | ||
| 35 | + struct Sparse | ||
| 36 | + { | ||
| 37 | + int size{0}; | ||
| 38 | + std::map<int, QPDFObjectHandle> elements; | ||
| 39 | + }; | ||
| 25 | 40 | ||
| 26 | - std::shared_ptr<QPDFObject> | ||
| 27 | - copy(bool shallow = false) | 41 | + public: |
| 42 | + QPDF_Array() = default; | ||
| 43 | + QPDF_Array(QPDF_Array const& other) : | ||
| 44 | + sp(other.sp ? std::make_unique<Sparse>(*other.sp) : nullptr) | ||
| 28 | { | 45 | { |
| 29 | - return value->copy(shallow); | ||
| 30 | } | 46 | } |
| 31 | - std::string | ||
| 32 | - unparse() | 47 | + |
| 48 | + QPDF_Array(QPDF_Array&&) = default; | ||
| 49 | + QPDF_Array& operator=(QPDF_Array&&) = default; | ||
| 50 | + | ||
| 51 | + private: | ||
| 52 | + friend class QPDFObject; | ||
| 53 | + friend class qpdf::Array; | ||
| 54 | + QPDF_Array(std::vector<QPDFObjectHandle> const& items) : | ||
| 55 | + elements(items) | ||
| 33 | { | 56 | { |
| 34 | - return value->unparse(); | ||
| 35 | } | 57 | } |
| 36 | - void | ||
| 37 | - writeJSON(int json_version, JSON::Writer& p) | 58 | + QPDF_Array(std::vector<QPDFObjectHandle>&& items, bool sparse); |
| 59 | + | ||
| 60 | + QPDF_Array(std::vector<QPDFObjectHandle>&& items) : | ||
| 61 | + elements(std::move(items)) | ||
| 38 | { | 62 | { |
| 39 | - return value->writeJSON(json_version, p); | ||
| 40 | } | 63 | } |
| 41 | - std::string | ||
| 42 | - getStringValue() const | 64 | + |
| 65 | + int | ||
| 66 | + size() const | ||
| 43 | { | 67 | { |
| 44 | - return value->getStringValue(); | 68 | + return sp ? sp->size : int(elements.size()); |
| 45 | } | 69 | } |
| 46 | - // Return a unique type code for the resolved object | ||
| 47 | - qpdf_object_type_e | ||
| 48 | - getResolvedTypeCode() const | 70 | + |
| 71 | + std::unique_ptr<Sparse> sp; | ||
| 72 | + std::vector<QPDFObjectHandle> elements; | ||
| 73 | +}; | ||
| 74 | + | ||
| 75 | +class QPDF_Bool final | ||
| 76 | +{ | ||
| 77 | + friend class QPDFObject; | ||
| 78 | + friend class QPDFObjectHandle; | ||
| 79 | + | ||
| 80 | + explicit QPDF_Bool(bool val) : | ||
| 81 | + val(val) | ||
| 49 | { | 82 | { |
| 50 | - auto tc = value->type_code; | ||
| 51 | - return tc == ::ot_unresolved | ||
| 52 | - ? QPDF::Resolver::resolved(value->qpdf, value->og)->value->type_code | ||
| 53 | - : tc; | ||
| 54 | } | 83 | } |
| 55 | - // Return a unique type code for the object | ||
| 56 | - qpdf_object_type_e | ||
| 57 | - getTypeCode() const noexcept | 84 | + bool val; |
| 85 | +}; | ||
| 86 | + | ||
| 87 | +class QPDF_Destroyed final | ||
| 88 | +{ | ||
| 89 | +}; | ||
| 90 | + | ||
| 91 | +class QPDF_Dictionary final | ||
| 92 | +{ | ||
| 93 | + friend class QPDFObject; | ||
| 94 | + friend class qpdf::BaseDictionary; | ||
| 95 | + | ||
| 96 | + QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items) : | ||
| 97 | + items(items) | ||
| 58 | { | 98 | { |
| 59 | - return value->type_code; | ||
| 60 | } | 99 | } |
| 100 | + inline QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items); | ||
| 61 | 101 | ||
| 62 | - QPDF* | ||
| 63 | - getQPDF() const | 102 | + std::map<std::string, QPDFObjectHandle> items; |
| 103 | +}; | ||
| 104 | + | ||
| 105 | +class QPDF_InlineImage final | ||
| 106 | +{ | ||
| 107 | + friend class QPDFObject; | ||
| 108 | + | ||
| 109 | + explicit QPDF_InlineImage(std::string val) : | ||
| 110 | + val(std::move(val)) | ||
| 64 | { | 111 | { |
| 65 | - return value->qpdf; | ||
| 66 | } | 112 | } |
| 67 | - QPDFObjGen | ||
| 68 | - getObjGen() const | 113 | + std::string val; |
| 114 | +}; | ||
| 115 | + | ||
| 116 | +class QPDF_Integer final | ||
| 117 | +{ | ||
| 118 | + friend class QPDFObject; | ||
| 119 | + friend class QPDFObjectHandle; | ||
| 120 | + | ||
| 121 | + QPDF_Integer(long long val) : | ||
| 122 | + val(val) | ||
| 69 | { | 123 | { |
| 70 | - return value->og; | ||
| 71 | } | 124 | } |
| 72 | - void | ||
| 73 | - setDescription( | ||
| 74 | - QPDF* qpdf, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset = -1) | 125 | + long long val; |
| 126 | +}; | ||
| 127 | + | ||
| 128 | +class QPDF_Name final | ||
| 129 | +{ | ||
| 130 | + friend class QPDFObject; | ||
| 131 | + | ||
| 132 | + explicit QPDF_Name(std::string name) : | ||
| 133 | + name(std::move(name)) | ||
| 75 | { | 134 | { |
| 76 | - return value->setDescription(qpdf, description, offset); | ||
| 77 | } | 135 | } |
| 78 | - void | ||
| 79 | - setChildDescription( | 136 | + std::string name; |
| 137 | +}; | ||
| 138 | + | ||
| 139 | +class QPDF_Null final | ||
| 140 | +{ | ||
| 141 | + friend class QPDFObject; | ||
| 142 | + | ||
| 143 | + public: | ||
| 144 | + static inline std::shared_ptr<QPDFObject> create( | ||
| 80 | std::shared_ptr<QPDFObject> parent, | 145 | std::shared_ptr<QPDFObject> parent, |
| 81 | std::string_view const& static_descr, | 146 | std::string_view const& static_descr, |
| 82 | - std::string var_descr) | 147 | + std::string var_descr); |
| 148 | +}; | ||
| 149 | + | ||
| 150 | +class QPDF_Operator final | ||
| 151 | +{ | ||
| 152 | + friend class QPDFObject; | ||
| 153 | + | ||
| 154 | + QPDF_Operator(std::string val) : | ||
| 155 | + val(std::move(val)) | ||
| 83 | { | 156 | { |
| 84 | - auto qpdf = parent ? parent->value->qpdf : nullptr; | ||
| 85 | - value->setChildDescription(qpdf, parent->value, static_descr, var_descr); | ||
| 86 | } | 157 | } |
| 87 | - void | ||
| 88 | - setChildDescription( | ||
| 89 | - std::shared_ptr<QPDFValue> parent, | ||
| 90 | - std::string_view const& static_descr, | ||
| 91 | - std::string var_descr) | 158 | + |
| 159 | + std::string val; | ||
| 160 | +}; | ||
| 161 | + | ||
| 162 | +class QPDF_Real final | ||
| 163 | +{ | ||
| 164 | + friend class QPDFObject; | ||
| 165 | + | ||
| 166 | + QPDF_Real(std::string val) : | ||
| 167 | + val(std::move(val)) | ||
| 92 | { | 168 | { |
| 93 | - auto qpdf = parent ? parent->qpdf : nullptr; | ||
| 94 | - value->setChildDescription(qpdf, parent, static_descr, var_descr); | ||
| 95 | } | 169 | } |
| 96 | - bool | ||
| 97 | - getDescription(QPDF*& qpdf, std::string& description) | 170 | + inline QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes); |
| 171 | + // Store reals as strings to avoid roundoff errors. | ||
| 172 | + std::string val; | ||
| 173 | +}; | ||
| 174 | + | ||
| 175 | +class QPDF_Reference | ||
| 176 | +{ | ||
| 177 | + // This is a minimal implementation to support QPDF::replaceObject. Once we support parsing of | ||
| 178 | + // objects that are an indirect reference we will need to support multiple levels of | ||
| 179 | + // indirection, including the possibility of circular references. | ||
| 180 | + friend class QPDFObject; | ||
| 181 | + friend class qpdf::BaseHandle; | ||
| 182 | + | ||
| 183 | + QPDF_Reference(std::shared_ptr<QPDFObject> obj) : | ||
| 184 | + obj(std::move(obj)) | ||
| 98 | { | 185 | { |
| 99 | - qpdf = value->qpdf; | ||
| 100 | - description = value->getDescription(); | ||
| 101 | - return qpdf != nullptr; | ||
| 102 | } | 186 | } |
| 103 | - bool | ||
| 104 | - hasDescription() | 187 | + |
| 188 | + std::shared_ptr<QPDFObject> obj; | ||
| 189 | +}; | ||
| 190 | + | ||
| 191 | +class QPDF_Reserved final | ||
| 192 | +{ | ||
| 193 | +}; | ||
| 194 | + | ||
| 195 | +class QPDF_Stream final | ||
| 196 | +{ | ||
| 197 | + class Members | ||
| 105 | { | 198 | { |
| 106 | - return value->hasDescription(); | 199 | + friend class QPDF_Stream; |
| 200 | + friend class QPDFObject; | ||
| 201 | + friend class qpdf::Stream; | ||
| 202 | + | ||
| 203 | + public: | ||
| 204 | + Members(QPDFObjectHandle stream_dict, size_t length) : | ||
| 205 | + stream_dict(std::move(stream_dict)), | ||
| 206 | + length(length) | ||
| 207 | + { | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + private: | ||
| 211 | + bool filter_on_write{true}; | ||
| 212 | + QPDFObjectHandle stream_dict; | ||
| 213 | + size_t length{0}; | ||
| 214 | + std::shared_ptr<Buffer> stream_data; | ||
| 215 | + std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider; | ||
| 216 | + std::vector<std::shared_ptr<QPDFObjectHandle::TokenFilter>> token_filters; | ||
| 217 | + }; | ||
| 218 | + | ||
| 219 | + friend class QPDFObject; | ||
| 220 | + friend class qpdf::Stream; | ||
| 221 | + | ||
| 222 | + QPDF_Stream(QPDFObjectHandle stream_dict, size_t length) : | ||
| 223 | + m(std::make_unique<Members>(stream_dict, length)) | ||
| 224 | + { | ||
| 225 | + if (!stream_dict.isDictionary()) { | ||
| 226 | + throw std::logic_error( | ||
| 227 | + "stream object instantiated with non-dictionary object for dictionary"); | ||
| 228 | + } | ||
| 107 | } | 229 | } |
| 108 | - void | ||
| 109 | - setParsedOffset(qpdf_offset_t offset) | 230 | + |
| 231 | + std::unique_ptr<Members> m; | ||
| 232 | +}; | ||
| 233 | + | ||
| 234 | +// QPDF_Strings may included embedded null characters. | ||
| 235 | +class QPDF_String final | ||
| 236 | +{ | ||
| 237 | + friend class QPDFObject; | ||
| 238 | + friend class QPDFWriter; | ||
| 239 | + | ||
| 240 | + public: | ||
| 241 | + static std::shared_ptr<QPDFObject> create_utf16(std::string const& utf8_val); | ||
| 242 | + std::string unparse(bool force_binary = false); | ||
| 243 | + void writeJSON(int json_version, JSON::Writer& p); | ||
| 244 | + std::string getUTF8Val() const; | ||
| 245 | + | ||
| 246 | + private: | ||
| 247 | + QPDF_String(std::string val) : | ||
| 248 | + val(std::move(val)) | ||
| 110 | { | 249 | { |
| 111 | - value->setParsedOffset(offset); | ||
| 112 | } | 250 | } |
| 113 | - qpdf_offset_t | ||
| 114 | - getParsedOffset() | 251 | + bool useHexString() const; |
| 252 | + std::string val; | ||
| 253 | +}; | ||
| 254 | + | ||
| 255 | +class QPDF_Unresolved final | ||
| 256 | +{ | ||
| 257 | +}; | ||
| 258 | + | ||
| 259 | +class QPDFObject | ||
| 260 | +{ | ||
| 261 | + public: | ||
| 262 | + template <typename T> | ||
| 263 | + QPDFObject(T&& value) : | ||
| 264 | + value(std::forward<T>(value)) | ||
| 115 | { | 265 | { |
| 116 | - return value->getParsedOffset(); | ||
| 117 | } | 266 | } |
| 118 | - void | ||
| 119 | - assign(std::shared_ptr<QPDFObject> o) | 267 | + |
| 268 | + template <typename T> | ||
| 269 | + QPDFObject(QPDF* qpdf, QPDFObjGen og, T&& value) : | ||
| 270 | + value(std::forward<T>(value)), | ||
| 271 | + qpdf(qpdf), | ||
| 272 | + og(og) | ||
| 120 | { | 273 | { |
| 121 | - value = o->value; | ||
| 122 | } | 274 | } |
| 123 | - void | ||
| 124 | - swapWith(std::shared_ptr<QPDFObject> o) | 275 | + |
| 276 | + template <typename T, typename... Args> | ||
| 277 | + inline static std::shared_ptr<QPDFObject> create(Args&&... args); | ||
| 278 | + | ||
| 279 | + template <typename T, typename... Args> | ||
| 280 | + inline static std::shared_ptr<QPDFObject> | ||
| 281 | + create(QPDF* qpdf, QPDFObjGen og, Args&&... args) | ||
| 125 | { | 282 | { |
| 126 | - auto v = value; | ||
| 127 | - value = o->value; | ||
| 128 | - o->value = v; | ||
| 129 | - auto og = value->og; | ||
| 130 | - value->og = o->value->og; | ||
| 131 | - o->value->og = og; | 283 | + return std::make_shared<QPDFObject>( |
| 284 | + qpdf, og, std::forward<T>(T(std::forward<Args>(args)...))); | ||
| 132 | } | 285 | } |
| 133 | 286 | ||
| 287 | + std::shared_ptr<QPDFObject> copy(bool shallow = false); | ||
| 288 | + std::string unparse(); | ||
| 289 | + void write_json(int json_version, JSON::Writer& p); | ||
| 290 | + void disconnect(); | ||
| 291 | + std::string getStringValue() const; | ||
| 292 | + | ||
| 293 | + // Return a unique type code for the resolved object | ||
| 294 | + qpdf_object_type_e | ||
| 295 | + getResolvedTypeCode() const | ||
| 296 | + { | ||
| 297 | + if (getTypeCode() == ::ot_unresolved) { | ||
| 298 | + return QPDF::Resolver::resolved(qpdf, og)->getTypeCode(); | ||
| 299 | + } | ||
| 300 | + if (getTypeCode() == ::ot_reference) { | ||
| 301 | + return std::get<QPDF_Reference>(value).obj->getResolvedTypeCode(); | ||
| 302 | + } | ||
| 303 | + return getTypeCode(); | ||
| 304 | + } | ||
| 305 | + // Return a unique type code for the object | ||
| 306 | + qpdf_object_type_e | ||
| 307 | + getTypeCode() const | ||
| 308 | + { | ||
| 309 | + return static_cast<qpdf_object_type_e>(value.index()); | ||
| 310 | + } | ||
| 134 | void | 311 | void |
| 135 | - setDefaultDescription(QPDF* qpdf, QPDFObjGen og) | 312 | + assign_null() |
| 136 | { | 313 | { |
| 137 | - // Intended for use by the QPDF class | ||
| 138 | - value->setDefaultDescription(qpdf, og); | 314 | + value = QPDF_Null(); |
| 315 | + qpdf = nullptr; | ||
| 316 | + og = QPDFObjGen(); | ||
| 317 | + object_description = nullptr; | ||
| 318 | + parsed_offset = -1; | ||
| 139 | } | 319 | } |
| 140 | void | 320 | void |
| 141 | - setObjGen(QPDF* qpdf, QPDFObjGen og) | 321 | + move_to(std::shared_ptr<QPDFObject>& o, bool destroy) |
| 142 | { | 322 | { |
| 143 | - value->qpdf = qpdf; | ||
| 144 | - value->og = og; | 323 | + o->value = std::move(value); |
| 324 | + o->qpdf = qpdf; | ||
| 325 | + o->og = og; | ||
| 326 | + o->object_description = object_description; | ||
| 327 | + o->parsed_offset = parsed_offset; | ||
| 328 | + if (!destroy) { | ||
| 329 | + value = QPDF_Reference(o); | ||
| 330 | + } | ||
| 145 | } | 331 | } |
| 146 | void | 332 | void |
| 147 | - disconnect() | 333 | + swapWith(std::shared_ptr<QPDFObject> o) |
| 334 | + { | ||
| 335 | + std::swap(value, o->value); | ||
| 336 | + std::swap(qpdf, o->qpdf); | ||
| 337 | + std::swap(object_description, o->object_description); | ||
| 338 | + std::swap(parsed_offset, o->parsed_offset); | ||
| 339 | + } | ||
| 340 | + | ||
| 341 | + void | ||
| 342 | + setObjGen(QPDF* a_qpdf, QPDFObjGen a_og) | ||
| 148 | { | 343 | { |
| 149 | - // Disconnect an object from its owning QPDF. This is called by QPDF's destructor. | ||
| 150 | - value->disconnect(); | ||
| 151 | - value->qpdf = nullptr; | ||
| 152 | - value->og = QPDFObjGen(); | 344 | + qpdf = a_qpdf; |
| 345 | + og = a_og; | ||
| 153 | } | 346 | } |
| 154 | // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects. | 347 | // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects. |
| 155 | - void destroy(); | 348 | + void |
| 349 | + destroy() | ||
| 350 | + { | ||
| 351 | + value = QPDF_Destroyed(); | ||
| 352 | + } | ||
| 156 | 353 | ||
| 157 | bool | 354 | bool |
| 158 | isUnresolved() const | 355 | isUnresolved() const |
| 159 | { | 356 | { |
| 160 | - return value->type_code == ::ot_unresolved; | 357 | + return getTypeCode() == ::ot_unresolved; |
| 161 | } | 358 | } |
| 162 | const QPDFObject* | 359 | const QPDFObject* |
| 163 | resolved_object() const | 360 | resolved_object() const |
| 164 | { | 361 | { |
| 165 | - return isUnresolved() ? QPDF::Resolver::resolved(value->qpdf, value->og) : this; | 362 | + return isUnresolved() ? QPDF::Resolver::resolved(qpdf, og).get() : this; |
| 166 | } | 363 | } |
| 167 | 364 | ||
| 168 | - template <typename T> | ||
| 169 | - T* | ||
| 170 | - as() const | ||
| 171 | - { | ||
| 172 | - if (auto result = dynamic_cast<T*>(value.get())) { | ||
| 173 | - return result; | ||
| 174 | - } else { | ||
| 175 | - return isUnresolved() | ||
| 176 | - ? dynamic_cast<T*>(QPDF::Resolver::resolved(value->qpdf, value->og)->value.get()) | ||
| 177 | - : nullptr; | 365 | + struct JSON_Descr |
| 366 | + { | ||
| 367 | + JSON_Descr(std::shared_ptr<std::string> input, std::string const& object) : | ||
| 368 | + input(input), | ||
| 369 | + object(object) | ||
| 370 | + { | ||
| 178 | } | 371 | } |
| 372 | + | ||
| 373 | + std::shared_ptr<std::string> input; | ||
| 374 | + std::string object; | ||
| 375 | + }; | ||
| 376 | + | ||
| 377 | + struct ChildDescr | ||
| 378 | + { | ||
| 379 | + ChildDescr( | ||
| 380 | + std::shared_ptr<QPDFObject> parent, | ||
| 381 | + std::string_view const& static_descr, | ||
| 382 | + std::string var_descr) : | ||
| 383 | + parent(parent), | ||
| 384 | + static_descr(static_descr), | ||
| 385 | + var_descr(var_descr) | ||
| 386 | + { | ||
| 387 | + } | ||
| 388 | + | ||
| 389 | + std::weak_ptr<QPDFObject> parent; | ||
| 390 | + std::string_view const& static_descr; | ||
| 391 | + std::string var_descr; | ||
| 392 | + }; | ||
| 393 | + | ||
| 394 | + using Description = std::variant<std::string, JSON_Descr, ChildDescr>; | ||
| 395 | + | ||
| 396 | + void | ||
| 397 | + setDescription( | ||
| 398 | + QPDF* qpdf_p, std::shared_ptr<Description>& description, qpdf_offset_t offset = -1) | ||
| 399 | + { | ||
| 400 | + qpdf = qpdf_p; | ||
| 401 | + object_description = description; | ||
| 402 | + setParsedOffset(offset); | ||
| 403 | + } | ||
| 404 | + void | ||
| 405 | + setDefaultDescription(QPDF* a_qpdf, QPDFObjGen const& a_og) | ||
| 406 | + { | ||
| 407 | + qpdf = a_qpdf; | ||
| 408 | + og = a_og; | ||
| 409 | + } | ||
| 410 | + void | ||
| 411 | + setChildDescription( | ||
| 412 | + QPDF* a_qpdf, | ||
| 413 | + std::shared_ptr<QPDFObject> parent, | ||
| 414 | + std::string_view const& static_descr, | ||
| 415 | + std::string var_descr) | ||
| 416 | + { | ||
| 417 | + object_description = | ||
| 418 | + std::make_shared<Description>(ChildDescr(parent, static_descr, var_descr)); | ||
| 419 | + qpdf = a_qpdf; | ||
| 420 | + } | ||
| 421 | + std::string getDescription(); | ||
| 422 | + bool | ||
| 423 | + hasDescription() | ||
| 424 | + { | ||
| 425 | + return object_description || og.isIndirect(); | ||
| 426 | + } | ||
| 427 | + void | ||
| 428 | + setParsedOffset(qpdf_offset_t offset) | ||
| 429 | + { | ||
| 430 | + if (parsed_offset < 0) { | ||
| 431 | + parsed_offset = offset; | ||
| 432 | + } | ||
| 433 | + } | ||
| 434 | + bool | ||
| 435 | + getDescription(QPDF*& a_qpdf, std::string& description) | ||
| 436 | + { | ||
| 437 | + a_qpdf = qpdf; | ||
| 438 | + description = getDescription(); | ||
| 439 | + return qpdf != nullptr; | ||
| 440 | + } | ||
| 441 | + qpdf_offset_t | ||
| 442 | + getParsedOffset() | ||
| 443 | + { | ||
| 444 | + return parsed_offset; | ||
| 445 | + } | ||
| 446 | + QPDF* | ||
| 447 | + getQPDF() | ||
| 448 | + { | ||
| 449 | + return qpdf; | ||
| 450 | + } | ||
| 451 | + QPDFObjGen | ||
| 452 | + getObjGen() | ||
| 453 | + { | ||
| 454 | + return og; | ||
| 179 | } | 455 | } |
| 180 | 456 | ||
| 181 | private: | 457 | private: |
| 458 | + friend class QPDF_Stream; | ||
| 459 | + friend class qpdf::BaseHandle; | ||
| 460 | + | ||
| 461 | + typedef std::variant< | ||
| 462 | + std::monostate, | ||
| 463 | + QPDF_Reserved, | ||
| 464 | + QPDF_Null, | ||
| 465 | + QPDF_Bool, | ||
| 466 | + QPDF_Integer, | ||
| 467 | + QPDF_Real, | ||
| 468 | + QPDF_String, | ||
| 469 | + QPDF_Name, | ||
| 470 | + QPDF_Array, | ||
| 471 | + QPDF_Dictionary, | ||
| 472 | + QPDF_Stream, | ||
| 473 | + QPDF_Operator, | ||
| 474 | + QPDF_InlineImage, | ||
| 475 | + QPDF_Unresolved, | ||
| 476 | + QPDF_Destroyed, | ||
| 477 | + QPDF_Reference> | ||
| 478 | + Value; | ||
| 479 | + Value value; | ||
| 480 | + | ||
| 182 | QPDFObject(QPDFObject const&) = delete; | 481 | QPDFObject(QPDFObject const&) = delete; |
| 183 | QPDFObject& operator=(QPDFObject const&) = delete; | 482 | QPDFObject& operator=(QPDFObject const&) = delete; |
| 184 | - std::shared_ptr<QPDFValue> value; | 483 | + |
| 484 | + std::shared_ptr<Description> object_description; | ||
| 485 | + | ||
| 486 | + QPDF* qpdf{nullptr}; | ||
| 487 | + QPDFObjGen og{}; | ||
| 488 | + qpdf_offset_t parsed_offset{-1}; | ||
| 185 | }; | 489 | }; |
| 186 | 490 | ||
| 187 | #endif // QPDFOBJECT_HH | 491 | #endif // QPDFOBJECT_HH |
libqpdf/qpdf/QPDFParser.hh
| 1 | #ifndef QPDFPARSER_HH | 1 | #ifndef QPDFPARSER_HH |
| 2 | #define QPDFPARSER_HH | 2 | #define QPDFPARSER_HH |
| 3 | 3 | ||
| 4 | -#include <qpdf/QPDFObjectHandle.hh> | ||
| 5 | -#include <qpdf/QPDFValue.hh> | 4 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 5 | +#include <qpdf/QPDFObject_private.hh> | ||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| @@ -24,7 +24,7 @@ class QPDFParser | @@ -24,7 +24,7 @@ class QPDFParser | ||
| 24 | decrypter(decrypter), | 24 | decrypter(decrypter), |
| 25 | context(context), | 25 | context(context), |
| 26 | description( | 26 | description( |
| 27 | - std::make_shared<QPDFValue::Description>( | 27 | + std::make_shared<QPDFObject::Description>( |
| 28 | std::string(input.getName() + ", " + object_description + " at offset $PO"))), | 28 | std::string(input.getName() + ", " + object_description + " at offset $PO"))), |
| 29 | parse_pdf(parse_pdf) | 29 | parse_pdf(parse_pdf) |
| 30 | { | 30 | { |
| @@ -46,7 +46,7 @@ class QPDFParser | @@ -46,7 +46,7 @@ class QPDFParser | ||
| 46 | { | 46 | { |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | - std::vector<std::shared_ptr<QPDFObject>> olist; | 49 | + std::vector<QPDFObjectHandle> olist; |
| 50 | std::map<std::string, QPDFObjectHandle> dict; | 50 | std::map<std::string, QPDFObjectHandle> dict; |
| 51 | parser_state_e state; | 51 | parser_state_e state; |
| 52 | std::string key; | 52 | std::string key; |
| @@ -78,7 +78,7 @@ class QPDFParser | @@ -78,7 +78,7 @@ class QPDFParser | ||
| 78 | QPDFTokenizer& tokenizer; | 78 | QPDFTokenizer& tokenizer; |
| 79 | QPDFObjectHandle::StringDecrypter* decrypter; | 79 | QPDFObjectHandle::StringDecrypter* decrypter; |
| 80 | QPDF* context; | 80 | QPDF* context; |
| 81 | - std::shared_ptr<QPDFValue::Description> description; | 81 | + std::shared_ptr<QPDFObject::Description> description; |
| 82 | bool parse_pdf; | 82 | bool parse_pdf; |
| 83 | 83 | ||
| 84 | std::vector<StackFrame> stack; | 84 | std::vector<StackFrame> stack; |
libqpdf/qpdf/QPDFValue.hh deleted
| 1 | -#ifndef QPDFVALUE_HH | ||
| 2 | -#define QPDFVALUE_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/Constants.h> | ||
| 5 | -#include <qpdf/DLL.h> | ||
| 6 | -#include <qpdf/JSON.hh> | ||
| 7 | -#include <qpdf/QPDFObjGen.hh> | ||
| 8 | -#include <qpdf/Types.h> | ||
| 9 | - | ||
| 10 | -#include <string> | ||
| 11 | -#include <string_view> | ||
| 12 | -#include <variant> | ||
| 13 | - | ||
| 14 | -class QPDF; | ||
| 15 | -class QPDFObjectHandle; | ||
| 16 | -class QPDFObject; | ||
| 17 | - | ||
| 18 | -class QPDFValue: public std::enable_shared_from_this<QPDFValue> | ||
| 19 | -{ | ||
| 20 | - friend class QPDFObject; | ||
| 21 | - | ||
| 22 | - public: | ||
| 23 | - virtual ~QPDFValue() = default; | ||
| 24 | - | ||
| 25 | - virtual std::shared_ptr<QPDFObject> copy(bool shallow = false) = 0; | ||
| 26 | - virtual std::string unparse() = 0; | ||
| 27 | - virtual void writeJSON(int json_version, JSON::Writer& p) = 0; | ||
| 28 | - | ||
| 29 | - struct JSON_Descr | ||
| 30 | - { | ||
| 31 | - JSON_Descr(std::shared_ptr<std::string> input, std::string const& object) : | ||
| 32 | - input(input), | ||
| 33 | - object(object) | ||
| 34 | - { | ||
| 35 | - } | ||
| 36 | - | ||
| 37 | - std::shared_ptr<std::string> input; | ||
| 38 | - std::string object; | ||
| 39 | - }; | ||
| 40 | - | ||
| 41 | - struct ChildDescr | ||
| 42 | - { | ||
| 43 | - ChildDescr( | ||
| 44 | - std::shared_ptr<QPDFValue> parent, | ||
| 45 | - std::string_view const& static_descr, | ||
| 46 | - std::string var_descr) : | ||
| 47 | - parent(parent), | ||
| 48 | - static_descr(static_descr), | ||
| 49 | - var_descr(var_descr) | ||
| 50 | - { | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - std::weak_ptr<QPDFValue> parent; | ||
| 54 | - std::string_view const& static_descr; | ||
| 55 | - std::string var_descr; | ||
| 56 | - }; | ||
| 57 | - | ||
| 58 | - using Description = std::variant<std::string, JSON_Descr, ChildDescr>; | ||
| 59 | - | ||
| 60 | - virtual void | ||
| 61 | - setDescription(QPDF* qpdf_p, std::shared_ptr<Description>& description, qpdf_offset_t offset) | ||
| 62 | - { | ||
| 63 | - qpdf = qpdf_p; | ||
| 64 | - object_description = description; | ||
| 65 | - setParsedOffset(offset); | ||
| 66 | - } | ||
| 67 | - void | ||
| 68 | - setDefaultDescription(QPDF* a_qpdf, QPDFObjGen a_og) | ||
| 69 | - { | ||
| 70 | - qpdf = a_qpdf; | ||
| 71 | - og = a_og; | ||
| 72 | - } | ||
| 73 | - void | ||
| 74 | - setChildDescription( | ||
| 75 | - QPDF* a_qpdf, | ||
| 76 | - std::shared_ptr<QPDFValue> parent, | ||
| 77 | - std::string_view const& static_descr, | ||
| 78 | - std::string var_descr) | ||
| 79 | - { | ||
| 80 | - object_description = | ||
| 81 | - std::make_shared<Description>(ChildDescr(parent, static_descr, var_descr)); | ||
| 82 | - qpdf = a_qpdf; | ||
| 83 | - } | ||
| 84 | - std::string getDescription(); | ||
| 85 | - bool | ||
| 86 | - hasDescription() | ||
| 87 | - { | ||
| 88 | - return object_description || og.isIndirect(); | ||
| 89 | - } | ||
| 90 | - void | ||
| 91 | - setParsedOffset(qpdf_offset_t offset) | ||
| 92 | - { | ||
| 93 | - if (parsed_offset < 0) { | ||
| 94 | - parsed_offset = offset; | ||
| 95 | - } | ||
| 96 | - } | ||
| 97 | - qpdf_offset_t | ||
| 98 | - getParsedOffset() | ||
| 99 | - { | ||
| 100 | - return parsed_offset; | ||
| 101 | - } | ||
| 102 | - QPDF* | ||
| 103 | - getQPDF() | ||
| 104 | - { | ||
| 105 | - return qpdf; | ||
| 106 | - } | ||
| 107 | - QPDFObjGen | ||
| 108 | - getObjGen() | ||
| 109 | - { | ||
| 110 | - return og; | ||
| 111 | - } | ||
| 112 | - virtual void | ||
| 113 | - disconnect() | ||
| 114 | - { | ||
| 115 | - } | ||
| 116 | - virtual std::string | ||
| 117 | - getStringValue() const | ||
| 118 | - { | ||
| 119 | - return ""; | ||
| 120 | - } | ||
| 121 | - | ||
| 122 | - protected: | ||
| 123 | - QPDFValue() = default; | ||
| 124 | - | ||
| 125 | - QPDFValue(qpdf_object_type_e type_code) : | ||
| 126 | - type_code(type_code) | ||
| 127 | - { | ||
| 128 | - } | ||
| 129 | - QPDFValue(qpdf_object_type_e type_code, QPDF* qpdf, QPDFObjGen og) : | ||
| 130 | - type_code(type_code), | ||
| 131 | - qpdf(qpdf), | ||
| 132 | - og(og) | ||
| 133 | - { | ||
| 134 | - } | ||
| 135 | - | ||
| 136 | - static std::shared_ptr<QPDFObject> do_create(QPDFValue*); | ||
| 137 | - | ||
| 138 | - private: | ||
| 139 | - QPDFValue(QPDFValue const&) = delete; | ||
| 140 | - QPDFValue& operator=(QPDFValue const&) = delete; | ||
| 141 | - std::shared_ptr<Description> object_description; | ||
| 142 | - | ||
| 143 | - const qpdf_object_type_e type_code{::ot_uninitialized}; | ||
| 144 | - | ||
| 145 | - protected: | ||
| 146 | - QPDF* qpdf{nullptr}; | ||
| 147 | - QPDFObjGen og{}; | ||
| 148 | - qpdf_offset_t parsed_offset{-1}; | ||
| 149 | -}; | ||
| 150 | - | ||
| 151 | -#endif // QPDFVALUE_HH |
libqpdf/qpdf/QPDF_Array.hh deleted
| 1 | -#ifndef QPDF_ARRAY_HH | ||
| 2 | -#define QPDF_ARRAY_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -#include <map> | ||
| 7 | -#include <vector> | ||
| 8 | - | ||
| 9 | -class QPDF_Array: public QPDFValue | ||
| 10 | -{ | ||
| 11 | - private: | ||
| 12 | - struct Sparse | ||
| 13 | - { | ||
| 14 | - int size{0}; | ||
| 15 | - std::map<int, std::shared_ptr<QPDFObject>> elements; | ||
| 16 | - }; | ||
| 17 | - | ||
| 18 | - public: | ||
| 19 | - ~QPDF_Array() override = default; | ||
| 20 | - static std::shared_ptr<QPDFObject> create(std::vector<QPDFObjectHandle> const& items); | ||
| 21 | - static std::shared_ptr<QPDFObject> | ||
| 22 | - create(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse); | ||
| 23 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 24 | - std::string unparse() override; | ||
| 25 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 26 | - void disconnect() override; | ||
| 27 | - | ||
| 28 | - int | ||
| 29 | - size() const noexcept | ||
| 30 | - { | ||
| 31 | - return sp ? sp->size : int(elements.size()); | ||
| 32 | - } | ||
| 33 | - std::pair<bool, QPDFObjectHandle> at(int n) const noexcept; | ||
| 34 | - bool setAt(int n, QPDFObjectHandle const& oh); | ||
| 35 | - std::vector<QPDFObjectHandle> getAsVector() const; | ||
| 36 | - void setFromVector(std::vector<QPDFObjectHandle> const& items); | ||
| 37 | - bool insert(int at, QPDFObjectHandle const& item); | ||
| 38 | - void push_back(QPDFObjectHandle const& item); | ||
| 39 | - bool erase(int at); | ||
| 40 | - | ||
| 41 | - private: | ||
| 42 | - QPDF_Array(); | ||
| 43 | - QPDF_Array(QPDF_Array const&); | ||
| 44 | - QPDF_Array(std::vector<QPDFObjectHandle> const& items); | ||
| 45 | - QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse); | ||
| 46 | - | ||
| 47 | - void checkOwnership(QPDFObjectHandle const& item) const; | ||
| 48 | - | ||
| 49 | - std::unique_ptr<Sparse> sp; | ||
| 50 | - std::vector<std::shared_ptr<QPDFObject>> elements; | ||
| 51 | -}; | ||
| 52 | - | ||
| 53 | -#endif // QPDF_ARRAY_HH |
libqpdf/qpdf/QPDF_Bool.hh deleted
| 1 | -#ifndef QPDF_BOOL_HH | ||
| 2 | -#define QPDF_BOOL_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Bool: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Bool() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(bool val); | ||
| 11 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 12 | - std::string unparse() override; | ||
| 13 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 14 | - | ||
| 15 | - bool getVal() const; | ||
| 16 | - | ||
| 17 | - private: | ||
| 18 | - QPDF_Bool(bool val); | ||
| 19 | - bool val; | ||
| 20 | -}; | ||
| 21 | - | ||
| 22 | -#endif // QPDF_BOOL_HH |
libqpdf/qpdf/QPDF_Destroyed.hh deleted
| 1 | -#ifndef QPDF_DESTROYED_HH | ||
| 2 | -#define QPDF_DESTROYED_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Destroyed: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Destroyed() override = default; | ||
| 10 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 11 | - std::string unparse() override; | ||
| 12 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 13 | - static std::shared_ptr<QPDFValue> getInstance(); | ||
| 14 | - | ||
| 15 | - private: | ||
| 16 | - QPDF_Destroyed(); | ||
| 17 | -}; | ||
| 18 | - | ||
| 19 | -#endif // QPDF_DESTROYED_HH |
libqpdf/qpdf/QPDF_Dictionary.hh deleted
| 1 | -#ifndef QPDF_DICTIONARY_HH | ||
| 2 | -#define QPDF_DICTIONARY_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -#include <map> | ||
| 7 | -#include <set> | ||
| 8 | - | ||
| 9 | -#include <qpdf/QPDFObjectHandle.hh> | ||
| 10 | - | ||
| 11 | -class QPDF_Dictionary: public QPDFValue | ||
| 12 | -{ | ||
| 13 | - public: | ||
| 14 | - ~QPDF_Dictionary() override = default; | ||
| 15 | - static std::shared_ptr<QPDFObject> create(std::map<std::string, QPDFObjectHandle> const& items); | ||
| 16 | - static std::shared_ptr<QPDFObject> create(std::map<std::string, QPDFObjectHandle>&& items); | ||
| 17 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 18 | - std::string unparse() override; | ||
| 19 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 20 | - void disconnect() override; | ||
| 21 | - | ||
| 22 | - // hasKey() and getKeys() treat keys with null values as if they aren't there. getKey() returns | ||
| 23 | - // null for the value of a non-existent key. This is as per the PDF spec. | ||
| 24 | - bool hasKey(std::string const&); | ||
| 25 | - QPDFObjectHandle getKey(std::string const&); | ||
| 26 | - std::set<std::string> getKeys(); | ||
| 27 | - std::map<std::string, QPDFObjectHandle> const& getAsMap() const; | ||
| 28 | - | ||
| 29 | - // If value is null, remove key; otherwise, replace the value of key, adding it if it does not | ||
| 30 | - // exist. | ||
| 31 | - void replaceKey(std::string const& key, QPDFObjectHandle value); | ||
| 32 | - // Remove key, doing nothing if key does not exist | ||
| 33 | - void removeKey(std::string const& key); | ||
| 34 | - | ||
| 35 | - private: | ||
| 36 | - QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items); | ||
| 37 | - QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items); | ||
| 38 | - std::map<std::string, QPDFObjectHandle> items; | ||
| 39 | -}; | ||
| 40 | - | ||
| 41 | -#endif // QPDF_DICTIONARY_HH |
libqpdf/qpdf/QPDF_InlineImage.hh deleted
| 1 | -#ifndef QPDF_INLINEIMAGE_HH | ||
| 2 | -#define QPDF_INLINEIMAGE_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_InlineImage: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_InlineImage() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(std::string const& val); | ||
| 11 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 12 | - std::string unparse() override; | ||
| 13 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 14 | - std::string | ||
| 15 | - getStringValue() const override | ||
| 16 | - { | ||
| 17 | - return val; | ||
| 18 | - } | ||
| 19 | - | ||
| 20 | - private: | ||
| 21 | - QPDF_InlineImage(std::string const& val); | ||
| 22 | - std::string val; | ||
| 23 | -}; | ||
| 24 | - | ||
| 25 | -#endif // QPDF_INLINEIMAGE_HH |
libqpdf/qpdf/QPDF_Integer.hh deleted
| 1 | -#ifndef QPDF_INTEGER_HH | ||
| 2 | -#define QPDF_INTEGER_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Integer: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Integer() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(long long value); | ||
| 11 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 12 | - std::string unparse() override; | ||
| 13 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 14 | - long long getVal() const; | ||
| 15 | - | ||
| 16 | - private: | ||
| 17 | - QPDF_Integer(long long val); | ||
| 18 | - long long val; | ||
| 19 | -}; | ||
| 20 | - | ||
| 21 | -#endif // QPDF_INTEGER_HH |
libqpdf/qpdf/QPDF_Name.hh
| 1 | -#ifndef QPDF_NAME_HH | ||
| 2 | -#define QPDF_NAME_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Name: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Name() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(std::string const& name); | ||
| 11 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 12 | - std::string unparse() override; | ||
| 13 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 14 | - | ||
| 15 | - // Put # into strings with characters unsuitable for name token | ||
| 16 | - static std::string normalizeName(std::string const& name); | ||
| 17 | - | ||
| 18 | - // Check whether name is valid utf-8 and whether it contains characters that require escaping. | ||
| 19 | - // Return {false, false} if the name is not valid utf-8, otherwise return {true, true} if no | ||
| 20 | - // characters require or {true, false} if escaping is required. | ||
| 21 | - static std::pair<bool, bool> analyzeJSONEncoding(std::string const& name); | ||
| 22 | - std::string | ||
| 23 | - getStringValue() const override | ||
| 24 | - { | ||
| 25 | - return name; | ||
| 26 | - } | ||
| 27 | - | ||
| 28 | - private: | ||
| 29 | - QPDF_Name(std::string const& name); | ||
| 30 | - std::string name; | ||
| 31 | -}; | ||
| 32 | - | ||
| 33 | -#endif // QPDF_NAME_HH |
libqpdf/qpdf/QPDF_Null.hh deleted
| 1 | -#ifndef QPDF_NULL_HH | ||
| 2 | -#define QPDF_NULL_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Null: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Null() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen()); | ||
| 11 | - static std::shared_ptr<QPDFObject> create( | ||
| 12 | - std::shared_ptr<QPDFObject> parent, | ||
| 13 | - std::string_view const& static_descr, | ||
| 14 | - std::string var_descr); | ||
| 15 | - static std::shared_ptr<QPDFObject> create( | ||
| 16 | - std::shared_ptr<QPDFValue> parent, | ||
| 17 | - std::string_view const& static_descr, | ||
| 18 | - std::string var_descr); | ||
| 19 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 20 | - std::string unparse() override; | ||
| 21 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 22 | - | ||
| 23 | - private: | ||
| 24 | - QPDF_Null(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen()); | ||
| 25 | -}; | ||
| 26 | - | ||
| 27 | -#endif // QPDF_NULL_HH |
libqpdf/qpdf/QPDF_Operator.hh deleted
| 1 | -#ifndef QPDF_OPERATOR_HH | ||
| 2 | -#define QPDF_OPERATOR_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Operator: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Operator() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(std::string const& val); | ||
| 11 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 12 | - std::string unparse() override; | ||
| 13 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 14 | - std::string | ||
| 15 | - getStringValue() const override | ||
| 16 | - { | ||
| 17 | - return val; | ||
| 18 | - } | ||
| 19 | - | ||
| 20 | - private: | ||
| 21 | - QPDF_Operator(std::string const& val); | ||
| 22 | - std::string val; | ||
| 23 | -}; | ||
| 24 | - | ||
| 25 | -#endif // QPDF_OPERATOR_HH |
libqpdf/qpdf/QPDF_Real.hh deleted
| 1 | -#ifndef QPDF_REAL_HH | ||
| 2 | -#define QPDF_REAL_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Real: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Real() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(std::string const& val); | ||
| 11 | - static std::shared_ptr<QPDFObject> | ||
| 12 | - create(double value, int decimal_places, bool trim_trailing_zeroes); | ||
| 13 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 14 | - std::string unparse() override; | ||
| 15 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 16 | - std::string | ||
| 17 | - getStringValue() const override | ||
| 18 | - { | ||
| 19 | - return val; | ||
| 20 | - } | ||
| 21 | - | ||
| 22 | - private: | ||
| 23 | - QPDF_Real(std::string const& val); | ||
| 24 | - QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes); | ||
| 25 | - // Store reals as strings to avoid roundoff errors. | ||
| 26 | - std::string val; | ||
| 27 | -}; | ||
| 28 | - | ||
| 29 | -#endif // QPDF_REAL_HH |
libqpdf/qpdf/QPDF_Reserved.hh deleted
| 1 | -#ifndef QPDF_RESERVED_HH | ||
| 2 | -#define QPDF_RESERVED_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Reserved: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Reserved() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(); | ||
| 11 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 12 | - std::string unparse() override; | ||
| 13 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 14 | - | ||
| 15 | - private: | ||
| 16 | - QPDF_Reserved(); | ||
| 17 | -}; | ||
| 18 | - | ||
| 19 | -#endif // QPDF_RESERVED_HH |
libqpdf/qpdf/QPDF_Stream.hh deleted
| 1 | -#ifndef QPDF_STREAM_HH | ||
| 2 | -#define QPDF_STREAM_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/Types.h> | ||
| 5 | - | ||
| 6 | -#include <qpdf/QPDFObjectHandle.hh> | ||
| 7 | -#include <qpdf/QPDFStreamFilter.hh> | ||
| 8 | -#include <qpdf/QPDFValue.hh> | ||
| 9 | - | ||
| 10 | -#include <functional> | ||
| 11 | -#include <memory> | ||
| 12 | - | ||
| 13 | -class Pipeline; | ||
| 14 | -class QPDF; | ||
| 15 | - | ||
| 16 | -class QPDF_Stream final: public QPDFValue | ||
| 17 | -{ | ||
| 18 | - public: | ||
| 19 | - ~QPDF_Stream() final = default; | ||
| 20 | - static std::shared_ptr<QPDFObject> | ||
| 21 | - create(QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); | ||
| 22 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) final; | ||
| 23 | - std::string unparse() final; | ||
| 24 | - void writeJSON(int json_version, JSON::Writer& p) final; | ||
| 25 | - void setDescription( | ||
| 26 | - QPDF*, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset) final; | ||
| 27 | - void disconnect() final; | ||
| 28 | - QPDFObjectHandle getDict() const; | ||
| 29 | - bool isDataModified() const; | ||
| 30 | - void setFilterOnWrite(bool); | ||
| 31 | - bool getFilterOnWrite() const; | ||
| 32 | - | ||
| 33 | - // Methods to help QPDF copy foreign streams | ||
| 34 | - size_t getLength() const; | ||
| 35 | - std::shared_ptr<Buffer> getStreamDataBuffer() const; | ||
| 36 | - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> getStreamDataProvider() const; | ||
| 37 | - | ||
| 38 | - // See comments in QPDFObjectHandle.hh for these methods. | ||
| 39 | - bool pipeStreamData( | ||
| 40 | - Pipeline*, | ||
| 41 | - bool* tried_filtering, | ||
| 42 | - int encode_flags, | ||
| 43 | - qpdf_stream_decode_level_e decode_level, | ||
| 44 | - bool suppress_warnings, | ||
| 45 | - bool will_retry); | ||
| 46 | - std::shared_ptr<Buffer> getStreamData(qpdf_stream_decode_level_e); | ||
| 47 | - std::shared_ptr<Buffer> getRawStreamData(); | ||
| 48 | - void replaceStreamData( | ||
| 49 | - std::shared_ptr<Buffer> data, | ||
| 50 | - QPDFObjectHandle const& filter, | ||
| 51 | - QPDFObjectHandle const& decode_parms); | ||
| 52 | - void replaceStreamData( | ||
| 53 | - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider, | ||
| 54 | - QPDFObjectHandle const& filter, | ||
| 55 | - QPDFObjectHandle const& decode_parms); | ||
| 56 | - void addTokenFilter(std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter); | ||
| 57 | - JSON getStreamJSON( | ||
| 58 | - int json_version, | ||
| 59 | - qpdf_json_stream_data_e json_data, | ||
| 60 | - qpdf_stream_decode_level_e decode_level, | ||
| 61 | - Pipeline* p, | ||
| 62 | - std::string const& data_filename); | ||
| 63 | - qpdf_stream_decode_level_e writeStreamJSON( | ||
| 64 | - int json_version, | ||
| 65 | - JSON::Writer& jw, | ||
| 66 | - qpdf_json_stream_data_e json_data, | ||
| 67 | - qpdf_stream_decode_level_e decode_level, | ||
| 68 | - Pipeline* p, | ||
| 69 | - std::string const& data_filename, | ||
| 70 | - bool no_data_key = false); | ||
| 71 | - | ||
| 72 | - void replaceDict(QPDFObjectHandle const& new_dict); | ||
| 73 | - | ||
| 74 | - static void registerStreamFilter( | ||
| 75 | - std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory); | ||
| 76 | - | ||
| 77 | - private: | ||
| 78 | - QPDF_Stream( | ||
| 79 | - QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); | ||
| 80 | - static std::map<std::string, std::string> filter_abbreviations; | ||
| 81 | - static std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>> | ||
| 82 | - filter_factories; | ||
| 83 | - | ||
| 84 | - void replaceFilterData( | ||
| 85 | - QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length); | ||
| 86 | - bool filterable( | ||
| 87 | - std::vector<std::shared_ptr<QPDFStreamFilter>>& filters, | ||
| 88 | - bool& specialized_compression, | ||
| 89 | - bool& lossy_compression); | ||
| 90 | - void warn(std::string const& message); | ||
| 91 | - void setDictDescription(); | ||
| 92 | - | ||
| 93 | - bool filter_on_write; | ||
| 94 | - QPDFObjectHandle stream_dict; | ||
| 95 | - size_t length; | ||
| 96 | - std::shared_ptr<Buffer> stream_data; | ||
| 97 | - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider; | ||
| 98 | - std::vector<std::shared_ptr<QPDFObjectHandle::TokenFilter>> token_filters; | ||
| 99 | -}; | ||
| 100 | - | ||
| 101 | -#endif // QPDF_STREAM_HH |
libqpdf/qpdf/QPDF_String.hh deleted
| 1 | -#ifndef QPDF_STRING_HH | ||
| 2 | -#define QPDF_STRING_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -// QPDF_Strings may included embedded null characters. | ||
| 7 | - | ||
| 8 | -class QPDF_String: public QPDFValue | ||
| 9 | -{ | ||
| 10 | - friend class QPDFWriter; | ||
| 11 | - | ||
| 12 | - public: | ||
| 13 | - ~QPDF_String() override = default; | ||
| 14 | - static std::shared_ptr<QPDFObject> create(std::string const& val); | ||
| 15 | - static std::shared_ptr<QPDFObject> create_utf16(std::string const& utf8_val); | ||
| 16 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 17 | - std::string unparse() override; | ||
| 18 | - std::string unparse(bool force_binary); | ||
| 19 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 20 | - std::string getUTF8Val() const; | ||
| 21 | - std::string | ||
| 22 | - getStringValue() const override | ||
| 23 | - { | ||
| 24 | - return val; | ||
| 25 | - } | ||
| 26 | - | ||
| 27 | - private: | ||
| 28 | - QPDF_String(std::string const& val); | ||
| 29 | - bool useHexString() const; | ||
| 30 | - std::string val; | ||
| 31 | -}; | ||
| 32 | - | ||
| 33 | -#endif // QPDF_STRING_HH |
libqpdf/qpdf/QPDF_Unresolved.hh deleted
| 1 | -#ifndef QPDF_UNRESOLVED_HH | ||
| 2 | -#define QPDF_UNRESOLVED_HH | ||
| 3 | - | ||
| 4 | -#include <qpdf/QPDFValue.hh> | ||
| 5 | - | ||
| 6 | -class QPDF_Unresolved: public QPDFValue | ||
| 7 | -{ | ||
| 8 | - public: | ||
| 9 | - ~QPDF_Unresolved() override = default; | ||
| 10 | - static std::shared_ptr<QPDFObject> create(QPDF* qpdf, QPDFObjGen og); | ||
| 11 | - std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | ||
| 12 | - std::string unparse() override; | ||
| 13 | - void writeJSON(int json_version, JSON::Writer& p) override; | ||
| 14 | - std::string getStringValue() const override; | ||
| 15 | - | ||
| 16 | - private: | ||
| 17 | - QPDF_Unresolved(QPDF* qpdf, QPDFObjGen og); | ||
| 18 | -}; | ||
| 19 | - | ||
| 20 | -#endif // QPDF_UNRESOLVED_HH |
libtests/sparse_array.cc
| 1 | #include <qpdf/assert_test.h> | 1 | #include <qpdf/assert_test.h> |
| 2 | 2 | ||
| 3 | #include <qpdf/QPDF.hh> | 3 | #include <qpdf/QPDF.hh> |
| 4 | -#include <qpdf/QPDFObjectHandle.hh> | 4 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 5 | #include <qpdf/QPDFObject_private.hh> | 5 | #include <qpdf/QPDFObject_private.hh> |
| 6 | -#include <qpdf/QPDF_Array.hh> | ||
| 7 | 6 | ||
| 8 | #include <iostream> | 7 | #include <iostream> |
| 9 | 8 | ||
| 10 | int | 9 | int |
| 11 | main() | 10 | main() |
| 12 | { | 11 | { |
| 13 | - auto obj = QPDF_Array::create({}, true); | ||
| 14 | - QPDF_Array& a = *obj->as<QPDF_Array>(); | 12 | + auto obj = QPDFObject::create<QPDF_Array>(std::vector<QPDFObjectHandle>(), true); |
| 13 | + auto a = qpdf::Array(obj); | ||
| 15 | 14 | ||
| 16 | assert(a.size() == 0); | 15 | assert(a.size() == 0); |
| 17 | 16 | ||
| @@ -88,16 +87,17 @@ main() | @@ -88,16 +87,17 @@ main() | ||
| 88 | QPDF pdf; | 87 | QPDF pdf; |
| 89 | pdf.emptyPDF(); | 88 | pdf.emptyPDF(); |
| 90 | 89 | ||
| 91 | - obj = QPDF_Array::create({10, "null"_qpdf.getObj()}, true); | ||
| 92 | - QPDF_Array& b = *obj->as<QPDF_Array>(); | 90 | + obj = QPDFObject::create<QPDF_Array>( |
| 91 | + std::vector<QPDFObjectHandle>{10, "null"_qpdf.getObj()}, true); | ||
| 92 | + auto b = qpdf::Array(obj); | ||
| 93 | b.setAt(5, pdf.newIndirectNull()); | 93 | b.setAt(5, pdf.newIndirectNull()); |
| 94 | b.setAt(7, "[0 1 2 3]"_qpdf); | 94 | b.setAt(7, "[0 1 2 3]"_qpdf); |
| 95 | assert(b.at(3).second.isNull()); | 95 | assert(b.at(3).second.isNull()); |
| 96 | assert(b.at(8).second.isNull()); | 96 | assert(b.at(8).second.isNull()); |
| 97 | assert(b.at(5).second.isIndirect()); | 97 | assert(b.at(5).second.isIndirect()); |
| 98 | - assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); | ||
| 99 | - auto c = b.copy(true); | ||
| 100 | - auto d = b.copy(false); | 98 | + assert(obj->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); |
| 99 | + auto c = obj->copy(true); | ||
| 100 | + auto d = obj->copy(false); | ||
| 101 | b.at(7).second.setArrayItem(2, "42"_qpdf); | 101 | b.at(7).second.setArrayItem(2, "42"_qpdf); |
| 102 | assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]"); | 102 | assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]"); |
| 103 | assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); | 103 | assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); |
qpdf/sizes.cc
| @@ -109,7 +109,6 @@ main() | @@ -109,7 +109,6 @@ main() | ||
| 109 | print_size(QPDFNumberTreeObjectHelper); | 109 | print_size(QPDFNumberTreeObjectHelper); |
| 110 | print_size(QPDFNumberTreeObjectHelper::iterator); | 110 | print_size(QPDFNumberTreeObjectHelper::iterator); |
| 111 | print_size(QPDFObjGen); | 111 | print_size(QPDFObjGen); |
| 112 | - print_size(QPDFObjGen::set); | ||
| 113 | print_size(QPDFObjectHandle); | 112 | print_size(QPDFObjectHandle); |
| 114 | print_size(QPDFObjectHandle::ParserCallbacks); | 113 | print_size(QPDFObjectHandle::ParserCallbacks); |
| 115 | print_size(QPDFObjectHandle::QPDFArrayItems); | 114 | print_size(QPDFObjectHandle::QPDFArrayItems); |
| @@ -118,6 +117,7 @@ main() | @@ -118,6 +117,7 @@ main() | ||
| 118 | print_size(QPDFObjectHandle::QPDFDictItems::iterator); | 117 | print_size(QPDFObjectHandle::QPDFDictItems::iterator); |
| 119 | print_size(QPDFObjectHandle::StreamDataProvider); | 118 | print_size(QPDFObjectHandle::StreamDataProvider); |
| 120 | print_size(QPDFObjectHandle::TokenFilter); | 119 | print_size(QPDFObjectHandle::TokenFilter); |
| 120 | + print_size(QPDFObjectHelper); | ||
| 121 | print_size(QPDFOutlineDocumentHelper); | 121 | print_size(QPDFOutlineDocumentHelper); |
| 122 | print_size(QPDFOutlineObjectHelper); | 122 | print_size(QPDFOutlineObjectHelper); |
| 123 | print_size(QPDFPageDocumentHelper); | 123 | print_size(QPDFPageDocumentHelper); |