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
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 | 798 | { |
| 799 | 799 | friend class QPDFObject; |
| 800 | 800 | friend class QPDF_Unresolved; |
| 801 | + friend class qpdf::BaseHandle; | |
| 801 | 802 | |
| 802 | 803 | private: |
| 803 | - static QPDFObject* | |
| 804 | + static std::shared_ptr<QPDFObject> const& | |
| 804 | 805 | resolved(QPDF* qpdf, QPDFObjGen og) |
| 805 | 806 | { |
| 806 | 807 | return qpdf->resolve(og); |
| ... | ... | @@ -854,6 +855,7 @@ class QPDF |
| 854 | 855 | class Pipe |
| 855 | 856 | { |
| 856 | 857 | friend class QPDF_Stream; |
| 858 | + friend class qpdf::Stream; | |
| 857 | 859 | |
| 858 | 860 | private: |
| 859 | 861 | static bool |
| ... | ... | @@ -1071,7 +1073,7 @@ class QPDF |
| 1071 | 1073 | QPDFObjGen exp_og, |
| 1072 | 1074 | QPDFObjGen& og, |
| 1073 | 1075 | bool skip_cache_if_in_xref); |
| 1074 | - QPDFObject* resolve(QPDFObjGen og); | |
| 1076 | + std::shared_ptr<QPDFObject> const& resolve(QPDFObjGen og); | |
| 1075 | 1077 | void resolveObjectsInStream(int obj_stream_number); |
| 1076 | 1078 | void stopOnError(std::string const& message); |
| 1077 | 1079 | QPDFObjGen nextObjGen(); |
| ... | ... | @@ -1086,7 +1088,8 @@ class QPDF |
| 1086 | 1088 | QPDFObjGen og, |
| 1087 | 1089 | std::shared_ptr<QPDFObject> const& object, |
| 1088 | 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 | 1093 | static QPDFExc damagedPDF( |
| 1091 | 1094 | InputSource& input, |
| 1092 | 1095 | std::string const& object, | ... | ... |
include/qpdf/QPDFObjGen.hh
| ... | ... | @@ -130,12 +130,6 @@ class QPDFObjGen |
| 130 | 130 | } |
| 131 | 131 | |
| 132 | 132 | QPDF_DLL |
| 133 | - bool add(QPDFObjectHandle const& oh); | |
| 134 | - | |
| 135 | - QPDF_DLL | |
| 136 | - bool add(QPDFObjectHelper const& oh); | |
| 137 | - | |
| 138 | - QPDF_DLL | |
| 139 | 133 | void |
| 140 | 134 | erase(QPDFObjGen og) |
| 141 | 135 | { |
| ... | ... | @@ -143,12 +137,6 @@ class QPDFObjGen |
| 143 | 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 | 142 | private: | ... | ... |
include/qpdf/QPDFObjectHandle.hh
| ... | ... | @@ -37,6 +37,7 @@ |
| 37 | 37 | #include <qpdf/Buffer.hh> |
| 38 | 38 | #include <qpdf/InputSource.hh> |
| 39 | 39 | #include <qpdf/JSON.hh> |
| 40 | +#include <qpdf/ObjectHandle.hh> | |
| 40 | 41 | #include <qpdf/QPDFObjGen.hh> |
| 41 | 42 | #include <qpdf/QPDFTokenizer.hh> |
| 42 | 43 | |
| ... | ... | @@ -55,13 +56,14 @@ class QPDF_Reserved; |
| 55 | 56 | class QPDF_Stream; |
| 56 | 57 | class QPDF_String; |
| 57 | 58 | class QPDFObject; |
| 59 | +class QPDFObjectHandle; | |
| 58 | 60 | class QPDFTokenizer; |
| 59 | 61 | class QPDFExc; |
| 60 | 62 | class Pl_QPDFTokenizer; |
| 61 | 63 | class QPDFMatrix; |
| 62 | 64 | class QPDFParser; |
| 63 | 65 | |
| 64 | -class QPDFObjectHandle | |
| 66 | +class QPDFObjectHandle final: public qpdf::BaseHandle | |
| 65 | 67 | { |
| 66 | 68 | friend class QPDFParser; |
| 67 | 69 | |
| ... | ... | @@ -290,25 +292,19 @@ class QPDFObjectHandle |
| 290 | 292 | QPDFObjectHandle(QPDFObjectHandle const&) = default; |
| 291 | 293 | QPDF_DLL |
| 292 | 294 | QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default; |
| 293 | - | |
| 294 | 295 | QPDF_DLL |
| 295 | 296 | QPDFObjectHandle(QPDFObjectHandle&&) = default; |
| 296 | 297 | QPDF_DLL |
| 297 | 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 | 302 | // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying |
| 307 | 303 | // object, meaning that changes to one are reflected in the other, or "if you paint one, the |
| 308 | 304 | // other one changes color." This does not perform a structural comparison of the contents of |
| 309 | 305 | // the objects. |
| 310 | 306 | QPDF_DLL |
| 311 | - bool isSameObjectAs(QPDFObjectHandle const&) const noexcept; | |
| 307 | + bool isSameObjectAs(QPDFObjectHandle const&) const; | |
| 312 | 308 | |
| 313 | 309 | // Return type code and type name of underlying object. These are useful for doing rapid type |
| 314 | 310 | // tests (like switch statements) or for testing and debugging. |
| ... | ... | @@ -1258,8 +1254,7 @@ class QPDFObjectHandle |
| 1258 | 1254 | // Provide access to specific classes for recursive disconnected(). |
| 1259 | 1255 | class DisconnectAccess |
| 1260 | 1256 | { |
| 1261 | - friend class QPDF_Dictionary; | |
| 1262 | - friend class QPDF_Stream; | |
| 1257 | + friend class QPDFObject; | |
| 1263 | 1258 | |
| 1264 | 1259 | private: |
| 1265 | 1260 | static void |
| ... | ... | @@ -1329,7 +1324,11 @@ class QPDFObjectHandle |
| 1329 | 1324 | // The following methods do not form part of the public API and are for internal use only. |
| 1330 | 1325 | |
| 1331 | 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 | 1334 | std::shared_ptr<QPDFObject> |
| ... | ... | @@ -1355,21 +1354,11 @@ class QPDFObjectHandle |
| 1355 | 1354 | |
| 1356 | 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 | 1362 | void typeWarning(char const* expected_type, std::string const& warning) const; |
| 1374 | 1363 | void objectWarning(std::string const& warning) const; |
| 1375 | 1364 | void assertType(char const* type_name, bool istype) const; |
| ... | ... | @@ -1386,10 +1375,6 @@ class QPDFObjectHandle |
| 1386 | 1375 | arrayOrStreamToStreamArray(std::string const& description, std::string& all_description); |
| 1387 | 1376 | static void warn(QPDF*, QPDFExc const&); |
| 1388 | 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 | 1380 | #ifndef QPDF_NO_QPDF_STRING |
| ... | ... | @@ -1606,6 +1591,22 @@ class QPDFObjectHandle::QPDFArrayItems |
| 1606 | 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 | 1610 | inline int |
| 1610 | 1611 | QPDFObjectHandle::getObjectID() const |
| 1611 | 1612 | { |
| ... | ... | @@ -1625,15 +1626,9 @@ QPDFObjectHandle::isIndirect() const |
| 1625 | 1626 | } |
| 1626 | 1627 | |
| 1627 | 1628 | inline bool |
| 1628 | -QPDFObjectHandle::isInitialized() const noexcept | |
| 1629 | +QPDFObjectHandle::isInitialized() const | |
| 1629 | 1630 | { |
| 1630 | 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 | 1634 | #endif // QPDFOBJECTHANDLE_HH | ... | ... |
include/qpdf/QPDFObjectHandle_future.hh deleted
include/qpdf/QPDFObjectHelper.hh
| ... | ... | @@ -31,13 +31,12 @@ |
| 31 | 31 | // underlying QPDF objects unless there is a specific comment in a specific helper method that says |
| 32 | 32 | // otherwise. The pattern of using helper objects was introduced to allow creation of higher level |
| 33 | 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 | 36 | public: |
| 38 | 37 | QPDF_DLL |
| 39 | 38 | QPDFObjectHelper(QPDFObjectHandle oh) : |
| 40 | - oh(oh) | |
| 39 | + qpdf::BaseHandle(oh.getObj()) | |
| 41 | 40 | { |
| 42 | 41 | } |
| 43 | 42 | QPDF_DLL |
| ... | ... | @@ -46,17 +45,29 @@ class QPDF_DLL_CLASS QPDFObjectHelper |
| 46 | 45 | QPDFObjectHandle |
| 47 | 46 | getObjectHandle() |
| 48 | 47 | { |
| 49 | - return this->oh; | |
| 48 | + return {obj}; | |
| 50 | 49 | } |
| 51 | 50 | QPDF_DLL |
| 52 | 51 | QPDFObjectHandle const |
| 53 | 52 | getObjectHandle() const |
| 54 | 53 | { |
| 55 | - return this->oh; | |
| 54 | + return {obj}; | |
| 56 | 55 | } |
| 57 | 56 | |
| 58 | 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 | 73 | #endif // QPDFOBJECTHELPER_HH | ... | ... |
libqpdf/CMakeLists.txt
| ... | ... | @@ -76,7 +76,6 @@ set(libqpdf_SOURCES |
| 76 | 76 | QPDFObject.cc |
| 77 | 77 | QPDFObjectHandle.cc |
| 78 | 78 | QPDFObjectHelper.cc |
| 79 | - QPDFObjGen.cc | |
| 80 | 79 | QPDFOutlineDocumentHelper.cc |
| 81 | 80 | QPDFOutlineObjectHelper.cc |
| 82 | 81 | QPDFPageDocumentHelper.cc |
| ... | ... | @@ -87,23 +86,12 @@ set(libqpdf_SOURCES |
| 87 | 86 | QPDFSystemError.cc |
| 88 | 87 | QPDFTokenizer.cc |
| 89 | 88 | QPDFUsage.cc |
| 90 | - QPDFValue.cc | |
| 91 | 89 | QPDFWriter.cc |
| 92 | 90 | QPDFXRefEntry.cc |
| 93 | 91 | QPDF_Array.cc |
| 94 | - QPDF_Bool.cc | |
| 95 | - QPDF_Destroyed.cc | |
| 96 | 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 | 93 | QPDF_Stream.cc |
| 105 | 94 | QPDF_String.cc |
| 106 | - QPDF_Unresolved.cc | |
| 107 | 95 | QPDF_encryption.cc |
| 108 | 96 | QPDF_json.cc |
| 109 | 97 | QPDF_linearization.cc | ... | ... |
libqpdf/ContentNormalizer.cc
| 1 | 1 | #include <qpdf/ContentNormalizer.hh> |
| 2 | 2 | |
| 3 | -#include <qpdf/QPDF_Name.hh> | |
| 3 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 4 | 4 | #include <qpdf/QUtil.hh> |
| 5 | 5 | |
| 6 | +using namespace qpdf; | |
| 7 | + | |
| 6 | 8 | ContentNormalizer::ContentNormalizer() : |
| 7 | 9 | any_bad_tokens(false), |
| 8 | 10 | last_token_was_bad(false) |
| ... | ... | @@ -55,7 +57,7 @@ ContentNormalizer::handleToken(QPDFTokenizer::Token const& token) |
| 55 | 57 | break; |
| 56 | 58 | |
| 57 | 59 | case QPDFTokenizer::tt_name: |
| 58 | - write(QPDF_Name::normalizeName(token.getValue())); | |
| 60 | + write(Name::normalize(token.getValue())); | |
| 59 | 61 | break; |
| 60 | 62 | |
| 61 | 63 | default: | ... | ... |
libqpdf/QPDF.cc
| ... | ... | @@ -17,14 +17,9 @@ |
| 17 | 17 | #include <qpdf/Pipeline.hh> |
| 18 | 18 | #include <qpdf/QPDFExc.hh> |
| 19 | 19 | #include <qpdf/QPDFLogger.hh> |
| 20 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 20 | 21 | #include <qpdf/QPDFObject_private.hh> |
| 21 | 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 | 23 | #include <qpdf/QTC.hh> |
| 29 | 24 | #include <qpdf/QUtil.hh> |
| 30 | 25 | |
| ... | ... | @@ -298,7 +293,7 @@ void |
| 298 | 293 | QPDF::registerStreamFilter( |
| 299 | 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 | 299 | void |
| ... | ... | @@ -1565,7 +1560,7 @@ QPDF::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) |
| 1565 | 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 | 1566 | void |
| ... | ... | @@ -1872,11 +1867,11 @@ QPDF::readObjectAtOffset( |
| 1872 | 1867 | return oh; |
| 1873 | 1868 | } |
| 1874 | 1869 | |
| 1875 | -QPDFObject* | |
| 1870 | +std::shared_ptr<QPDFObject> const& | |
| 1876 | 1871 | QPDF::resolve(QPDFObjGen og) |
| 1877 | 1872 | { |
| 1878 | 1873 | if (!isUnresolved(og)) { |
| 1879 | - return m->obj_cache[og].object.get(); | |
| 1874 | + return m->obj_cache[og].object; | |
| 1880 | 1875 | } |
| 1881 | 1876 | |
| 1882 | 1877 | if (m->resolving.count(og)) { |
| ... | ... | @@ -1884,8 +1879,8 @@ QPDF::resolve(QPDFObjGen og) |
| 1884 | 1879 | // has to be resolved during object parsing, such as stream length. |
| 1885 | 1880 | QTC::TC("qpdf", "QPDF recursion loop in resolve"); |
| 1886 | 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 | 1885 | ResolveRecorder rr(this, og); |
| 1891 | 1886 | |
| ... | ... | @@ -1921,12 +1916,12 @@ QPDF::resolve(QPDFObjGen og) |
| 1921 | 1916 | if (isUnresolved(og)) { |
| 1922 | 1917 | // PDF spec says unknown objects resolve to the null object. |
| 1923 | 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 | 1923 | result->setDefaultDescription(this, og); |
| 1929 | - return result.get(); | |
| 1924 | + return result; | |
| 1930 | 1925 | } |
| 1931 | 1926 | |
| 1932 | 1927 | void |
| ... | ... | @@ -2034,12 +2029,13 @@ QPDF::updateCache( |
| 2034 | 2029 | QPDFObjGen og, |
| 2035 | 2030 | std::shared_ptr<QPDFObject> const& object, |
| 2036 | 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 | 2035 | object->setObjGen(this, og); |
| 2040 | 2036 | if (isCached(og)) { |
| 2041 | 2037 | auto& cache = m->obj_cache[og]; |
| 2042 | - cache.object->assign(object); | |
| 2038 | + object->move_to(cache.object, destroy); | |
| 2043 | 2039 | cache.end_before_space = end_before_space; |
| 2044 | 2040 | cache.end_after_space = end_after_space; |
| 2045 | 2041 | } else { |
| ... | ... | @@ -2089,20 +2085,20 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) |
| 2089 | 2085 | QPDFObjectHandle |
| 2090 | 2086 | QPDF::newReserved() |
| 2091 | 2087 | { |
| 2092 | - return makeIndirectFromQPDFObject(QPDF_Reserved::create()); | |
| 2088 | + return makeIndirectFromQPDFObject(QPDFObject::create<QPDF_Reserved>()); | |
| 2093 | 2089 | } |
| 2094 | 2090 | |
| 2095 | 2091 | QPDFObjectHandle |
| 2096 | 2092 | QPDF::newIndirectNull() |
| 2097 | 2093 | { |
| 2098 | - return makeIndirectFromQPDFObject(QPDF_Null::create()); | |
| 2094 | + return makeIndirectFromQPDFObject(QPDFObject::create<QPDF_Null>()); | |
| 2099 | 2095 | } |
| 2100 | 2096 | |
| 2101 | 2097 | QPDFObjectHandle |
| 2102 | 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 | 2104 | QPDFObjectHandle |
| ... | ... | @@ -2130,12 +2126,13 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf) |
| 2130 | 2126 | return iter->second.object; |
| 2131 | 2127 | } |
| 2132 | 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 | 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 | 2138 | std::shared_ptr<QPDFObject> |
| ... | ... | @@ -2145,8 +2142,9 @@ QPDF::getObjectForJSON(int id, int gen) |
| 2145 | 2142 | auto [it, inserted] = m->obj_cache.try_emplace(og); |
| 2146 | 2143 | auto& obj = it->second.object; |
| 2147 | 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 | 2149 | return obj; |
| 2152 | 2150 | } |
| ... | ... | @@ -2157,9 +2155,10 @@ QPDF::getObject(QPDFObjGen og) |
| 2157 | 2155 | if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) { |
| 2158 | 2156 | return {it->second.object}; |
| 2159 | 2157 | } else if (m->parsed && !m->xref_table.count(og)) { |
| 2160 | - return QPDF_Null::create(); | |
| 2158 | + return QPDFObject::create<QPDF_Null>(); | |
| 2161 | 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 | 2162 | return {result.first->second.object}; |
| 2164 | 2163 | } |
| 2165 | 2164 | } |
| ... | ... | @@ -2195,7 +2194,7 @@ QPDF::replaceObject(QPDFObjGen og, QPDFObjectHandle oh) |
| 2195 | 2194 | QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); |
| 2196 | 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 | 2200 | void |
| ... | ... | @@ -2204,7 +2203,7 @@ QPDF::removeObject(QPDFObjGen og) |
| 2204 | 2203 | m->xref_table.erase(og); |
| 2205 | 2204 | if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) { |
| 2206 | 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 | 2207 | cached->second.object->setObjGen(nullptr, QPDFObjGen()); |
| 2209 | 2208 | m->obj_cache.erase(cached); |
| 2210 | 2209 | } |
| ... | ... | @@ -2347,14 +2346,15 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top) |
| 2347 | 2346 | |
| 2348 | 2347 | if (foreign_tc == ::ot_array) { |
| 2349 | 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 | 2352 | } else if (foreign_tc == ::ot_dictionary) { |
| 2355 | 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 | 2359 | } else if (foreign_tc == ::ot_stream) { |
| 2360 | 2360 | QTC::TC("qpdf", "QPDF reserve stream"); |
| ... | ... | @@ -2383,30 +2383,26 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_cop |
| 2383 | 2383 | } else if (foreign_tc == ::ot_array) { |
| 2384 | 2384 | QTC::TC("qpdf", "QPDF replace array"); |
| 2385 | 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 | 2389 | } else if (foreign_tc == ::ot_dictionary) { |
| 2393 | 2390 | QTC::TC("qpdf", "QPDF replace dictionary"); |
| 2394 | 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 | 2397 | } else if (foreign_tc == ::ot_stream) { |
| 2401 | 2398 | QTC::TC("qpdf", "QPDF replace stream"); |
| 2402 | 2399 | result = obj_copier.object_map[foreign.getObjGen()]; |
| 2403 | - result.assertStream(); | |
| 2404 | 2400 | QPDFObjectHandle dict = result.getDict(); |
| 2405 | 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 | 2407 | copyStreamData(result, foreign); |
| 2412 | 2408 | } else { |
| ... | ... | @@ -2442,13 +2438,11 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) |
| 2442 | 2438 | QPDF& foreign_stream_qpdf = |
| 2443 | 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 | 2446 | if ((foreign_stream_qpdf.m->immediate_copy_from) && (stream_buffer == nullptr)) { |
| 2453 | 2447 | // Pull the stream data into a buffer before attempting the copy operation. Do it on the |
| 2454 | 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 | 2452 | foreign.getRawStreamData(), |
| 2459 | 2453 | old_dict.getKey("/Filter"), |
| 2460 | 2454 | old_dict.getKey("/DecodeParms")); |
| 2461 | - stream_buffer = stream->getStreamDataBuffer(); | |
| 2455 | + stream_buffer = stream.getStreamDataBuffer(); | |
| 2462 | 2456 | } |
| 2463 | 2457 | std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider = |
| 2464 | - stream->getStreamDataProvider(); | |
| 2458 | + stream.getStreamDataProvider(); | |
| 2465 | 2459 | if (stream_buffer.get()) { |
| 2466 | 2460 | QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); |
| 2467 | 2461 | result.replaceStreamData( |
| ... | ... | @@ -2476,9 +2470,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) |
| 2476 | 2470 | auto foreign_stream_data = std::make_shared<ForeignStreamData>( |
| 2477 | 2471 | foreign_stream_qpdf.m->encp, |
| 2478 | 2472 | foreign_stream_qpdf.m->file, |
| 2479 | - foreign.getObjGen(), | |
| 2480 | - stream->getParsedOffset(), | |
| 2481 | - stream->getLength(), | |
| 2473 | + foreign, | |
| 2474 | + foreign.getParsedOffset(), | |
| 2475 | + stream.getLength(), | |
| 2482 | 2476 | dict); |
| 2483 | 2477 | m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); |
| 2484 | 2478 | result.replaceStreamData( |
| ... | ... | @@ -2692,30 +2686,32 @@ QPDF::getCompressibleObjGens() |
| 2692 | 2686 | } |
| 2693 | 2687 | } |
| 2694 | 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 | 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 | 1 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/Pl_Buffer.hh> |
| 4 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 4 | 5 | #include <qpdf/QPDFPageDocumentHelper.hh> |
| 5 | 6 | #include <qpdf/QTC.hh> |
| 6 | 7 | #include <qpdf/QUtil.hh> |
| 7 | 8 | #include <qpdf/ResourceFinder.hh> |
| 8 | 9 | |
| 10 | +using namespace qpdf; | |
| 11 | + | |
| 9 | 12 | QPDFAcroFormDocumentHelper::Members::Members() : |
| 10 | 13 | cache_valid(false) |
| 11 | 14 | { |
| ... | ... | @@ -238,26 +241,25 @@ QPDFAcroFormDocumentHelper::analyze() |
| 238 | 241 | return; |
| 239 | 242 | } |
| 240 | 243 | m->cache_valid = true; |
| 241 | - QPDFObjectHandle acroform = this->qpdf.getRoot().getKey("/AcroForm"); | |
| 244 | + QPDFObjectHandle acroform = qpdf.getRoot().getKey("/AcroForm"); | |
| 242 | 245 | if (!(acroform.isDictionary() && acroform.hasKey("/Fields"))) { |
| 243 | 246 | return; |
| 244 | 247 | } |
| 245 | 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 | 258 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array"); |
| 248 | 259 | acroform.warnIfPossible("/Fields key of /AcroForm dictionary is not an array; ignoring"); |
| 249 | 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 | 263 | // All Widget annotations should have been encountered by traversing /AcroForm, but in case any |
| 262 | 264 | // weren't, find them by walking through pages, and treat any widget annotation that is not |
| 263 | 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 | 326 | |
| 325 | 327 | bool is_annotation = false; |
| 326 | 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 | 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 | 334 | } else { |
| 335 | 335 | if (field.hasKey("/Parent")) { |
| ... | ... | @@ -975,17 +975,14 @@ QPDFAcroFormDocumentHelper::transformAnnotations( |
| 975 | 975 | auto replace_stream = [](auto& dict, auto& key, auto& old) { |
| 976 | 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 | 13 | std::string |
| 14 | 14 | QPDFAnnotationObjectHelper::getSubtype() |
| 15 | 15 | { |
| 16 | - return this->oh.getKey("/Subtype").getName(); | |
| 16 | + return oh().getKey("/Subtype").getName(); | |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | QPDFObjectHandle::Rectangle |
| 20 | 20 | QPDFAnnotationObjectHelper::getRect() |
| 21 | 21 | { |
| 22 | - return this->oh.getKey("/Rect").getArrayAsRectangle(); | |
| 22 | + return oh().getKey("/Rect").getArrayAsRectangle(); | |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | QPDFObjectHandle |
| 26 | 26 | QPDFAnnotationObjectHelper::getAppearanceDictionary() |
| 27 | 27 | { |
| 28 | - return this->oh.getKey("/AP"); | |
| 28 | + return oh().getKey("/AP"); | |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | std::string |
| 32 | 32 | QPDFAnnotationObjectHelper::getAppearanceState() |
| 33 | 33 | { |
| 34 | - if (this->oh.getKey("/AS").isName()) { | |
| 34 | + if (oh().getKey("/AS").isName()) { | |
| 35 | 35 | QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS present"); |
| 36 | - return this->oh.getKey("/AS").getName(); | |
| 36 | + return oh().getKey("/AS").getName(); | |
| 37 | 37 | } |
| 38 | 38 | QTC::TC("qpdf", "QPDFAnnotationObjectHelper AS absent"); |
| 39 | 39 | return ""; |
| ... | ... | @@ -42,7 +42,7 @@ QPDFAnnotationObjectHelper::getAppearanceState() |
| 42 | 42 | int |
| 43 | 43 | QPDFAnnotationObjectHelper::getFlags() |
| 44 | 44 | { |
| 45 | - QPDFObjectHandle flags_obj = this->oh.getKey("/F"); | |
| 45 | + QPDFObjectHandle flags_obj = oh().getKey("/F"); | |
| 46 | 46 | return flags_obj.isInteger() ? flags_obj.getIntValueAsInt() : 0; |
| 47 | 47 | } |
| 48 | 48 | |
| ... | ... | @@ -143,7 +143,7 @@ QPDFAnnotationObjectHelper::getPageContentForAppearance( |
| 143 | 143 | |
| 144 | 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 | 147 | QPDFObjectHandle as = getAppearanceStream("/N").getDict(); |
| 148 | 148 | QPDFObjectHandle bbox_obj = as.getKey("/BBox"); |
| 149 | 149 | QPDFObjectHandle matrix_obj = as.getKey("/Matrix"); | ... | ... |
libqpdf/QPDFEFStreamObjectHelper.cc
| ... | ... | @@ -16,7 +16,7 @@ QPDFEFStreamObjectHelper::QPDFEFStreamObjectHelper(QPDFObjectHandle oh) : |
| 16 | 16 | QPDFObjectHandle |
| 17 | 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 | 20 | if (params.isDictionary()) { |
| 21 | 21 | return params.getKey(pkey); |
| 22 | 22 | } |
| ... | ... | @@ -26,10 +26,9 @@ QPDFEFStreamObjectHelper::getParam(std::string const& pkey) |
| 26 | 26 | void |
| 27 | 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 | 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 | 33 | params.replaceKey(pkey, pval); |
| 35 | 34 | } |
| ... | ... | @@ -67,7 +66,7 @@ QPDFEFStreamObjectHelper::getSize() |
| 67 | 66 | std::string |
| 68 | 67 | QPDFEFStreamObjectHelper::getSubtype() |
| 69 | 68 | { |
| 70 | - auto val = this->oh.getDict().getKey("/Subtype"); | |
| 69 | + auto val = oh().getDict().getKey("/Subtype"); | |
| 71 | 70 | if (val.isName()) { |
| 72 | 71 | auto n = val.getName(); |
| 73 | 72 | if (n.length() > 1) { |
| ... | ... | @@ -124,7 +123,7 @@ QPDFEFStreamObjectHelper::setModDate(std::string const& date) |
| 124 | 123 | QPDFEFStreamObjectHelper& |
| 125 | 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 | 127 | return *this; |
| 129 | 128 | } |
| 130 | 129 | ... | ... |
libqpdf/QPDFFileSpecObjectHelper.cc
| ... | ... | @@ -25,7 +25,7 @@ std::string |
| 25 | 25 | QPDFFileSpecObjectHelper::getDescription() |
| 26 | 26 | { |
| 27 | 27 | std::string result; |
| 28 | - auto desc = this->oh.getKey("/Desc"); | |
| 28 | + auto desc = oh().getKey("/Desc"); | |
| 29 | 29 | if (desc.isString()) { |
| 30 | 30 | result = desc.getUTF8Value(); |
| 31 | 31 | } |
| ... | ... | @@ -36,7 +36,7 @@ std::string |
| 36 | 36 | QPDFFileSpecObjectHelper::getFilename() |
| 37 | 37 | { |
| 38 | 38 | for (auto const& i: name_keys) { |
| 39 | - auto k = this->oh.getKey(i); | |
| 39 | + auto k = oh().getKey(i); | |
| 40 | 40 | if (k.isString()) { |
| 41 | 41 | return k.getUTF8Value(); |
| 42 | 42 | } |
| ... | ... | @@ -49,7 +49,7 @@ QPDFFileSpecObjectHelper::getFilenames() |
| 49 | 49 | { |
| 50 | 50 | std::map<std::string, std::string> result; |
| 51 | 51 | for (auto const& i: name_keys) { |
| 52 | - auto k = this->oh.getKey(i); | |
| 52 | + auto k = oh().getKey(i); | |
| 53 | 53 | if (k.isString()) { |
| 54 | 54 | result[i] = k.getUTF8Value(); |
| 55 | 55 | } |
| ... | ... | @@ -60,7 +60,7 @@ QPDFFileSpecObjectHelper::getFilenames() |
| 60 | 60 | QPDFObjectHandle |
| 61 | 61 | QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key) |
| 62 | 62 | { |
| 63 | - auto ef = this->oh.getKey("/EF"); | |
| 63 | + auto ef = oh().getKey("/EF"); | |
| 64 | 64 | if (!ef.isDictionary()) { |
| 65 | 65 | return QPDFObjectHandle::newNull(); |
| 66 | 66 | } |
| ... | ... | @@ -79,7 +79,7 @@ QPDFFileSpecObjectHelper::getEmbeddedFileStream(std::string const& key) |
| 79 | 79 | QPDFObjectHandle |
| 80 | 80 | QPDFFileSpecObjectHelper::getEmbeddedFileStreams() |
| 81 | 81 | { |
| 82 | - return this->oh.getKey("/EF"); | |
| 82 | + return oh().getKey("/EF"); | |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | 85 | QPDFFileSpecObjectHelper |
| ... | ... | @@ -110,7 +110,7 @@ QPDFFileSpecObjectHelper::createFileSpec( |
| 110 | 110 | QPDFFileSpecObjectHelper& |
| 111 | 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 | 114 | return *this; |
| 115 | 115 | } |
| 116 | 116 | |
| ... | ... | @@ -119,13 +119,13 @@ QPDFFileSpecObjectHelper::setFilename( |
| 119 | 119 | std::string const& unicode_name, std::string const& compat_name) |
| 120 | 120 | { |
| 121 | 121 | auto uf = QPDFObjectHandle::newUnicodeString(unicode_name); |
| 122 | - this->oh.replaceKey("/UF", uf); | |
| 122 | + oh().replaceKey("/UF", uf); | |
| 123 | 123 | if (compat_name.empty()) { |
| 124 | 124 | QTC::TC("qpdf", "QPDFFileSpecObjectHelper empty compat_name"); |
| 125 | - this->oh.replaceKey("/F", uf); | |
| 125 | + oh().replaceKey("/F", uf); | |
| 126 | 126 | } else { |
| 127 | 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 | 130 | return *this; |
| 131 | 131 | } | ... | ... |
libqpdf/QPDFFormFieldObjectHelper.cc
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | #include <qpdf/QIntC.hh> |
| 5 | 5 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> |
| 6 | 6 | #include <qpdf/QPDFAnnotationObjectHelper.hh> |
| 7 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 7 | 8 | #include <qpdf/QTC.hh> |
| 8 | 9 | #include <qpdf/QUtil.hh> |
| 9 | 10 | #include <cstdlib> |
| ... | ... | @@ -23,19 +24,19 @@ QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper() : |
| 23 | 24 | bool |
| 24 | 25 | QPDFFormFieldObjectHelper::isNull() |
| 25 | 26 | { |
| 26 | - return this->oh.isNull(); | |
| 27 | + return oh().isNull(); | |
| 27 | 28 | } |
| 28 | 29 | |
| 29 | 30 | QPDFFormFieldObjectHelper |
| 30 | 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 | 36 | QPDFFormFieldObjectHelper |
| 36 | 37 | QPDFFormFieldObjectHelper::getTopLevelField(bool* is_different) |
| 37 | 38 | { |
| 38 | - auto top_field = this->oh; | |
| 39 | + auto top_field = oh(); | |
| 39 | 40 | QPDFObjGen::set seen; |
| 40 | 41 | while (seen.add(top_field) && !top_field.getKeyIfDict("/Parent").isNull()) { |
| 41 | 42 | top_field = top_field.getKey("/Parent"); |
| ... | ... | @@ -51,7 +52,7 @@ QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const& name) |
| 51 | 52 | { |
| 52 | 53 | QPDFObjectHandle result = QPDFObjectHandle::newNull(); |
| 53 | 54 | // Fields are supposed to be indirect, so this should work. |
| 54 | - QPDF* q = this->oh.getOwningQPDF(); | |
| 55 | + QPDF* q = oh().getOwningQPDF(); | |
| 55 | 56 | if (!q) { |
| 56 | 57 | return result; |
| 57 | 58 | } |
| ... | ... | @@ -65,7 +66,7 @@ QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const& name) |
| 65 | 66 | QPDFObjectHandle |
| 66 | 67 | QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name) |
| 67 | 68 | { |
| 68 | - QPDFObjectHandle node = this->oh; | |
| 69 | + QPDFObjectHandle node = oh(); | |
| 69 | 70 | if (!node.isDictionary()) { |
| 70 | 71 | return QPDFObjectHandle::newNull(); |
| 71 | 72 | } |
| ... | ... | @@ -116,7 +117,7 @@ std::string |
| 116 | 117 | QPDFFormFieldObjectHelper::getFullyQualifiedName() |
| 117 | 118 | { |
| 118 | 119 | std::string result; |
| 119 | - QPDFObjectHandle node = this->oh; | |
| 120 | + QPDFObjectHandle node = oh(); | |
| 120 | 121 | QPDFObjGen::set seen; |
| 121 | 122 | while (!node.isNull() && seen.add(node)) { |
| 122 | 123 | if (node.getKey("/T").isString()) { |
| ... | ... | @@ -135,8 +136,8 @@ std::string |
| 135 | 136 | QPDFFormFieldObjectHelper::getPartialName() |
| 136 | 137 | { |
| 137 | 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 | 142 | return result; |
| 142 | 143 | } |
| ... | ... | @@ -144,9 +145,9 @@ QPDFFormFieldObjectHelper::getPartialName() |
| 144 | 145 | std::string |
| 145 | 146 | QPDFFormFieldObjectHelper::getAlternativeName() |
| 146 | 147 | { |
| 147 | - if (this->oh.getKey("/TU").isString()) { | |
| 148 | + if (oh().getKey("/TU").isString()) { | |
| 148 | 149 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU present"); |
| 149 | - return this->oh.getKey("/TU").getUTF8Value(); | |
| 150 | + return oh().getKey("/TU").getUTF8Value(); | |
| 150 | 151 | } |
| 151 | 152 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU absent"); |
| 152 | 153 | return getFullyQualifiedName(); |
| ... | ... | @@ -155,9 +156,9 @@ QPDFFormFieldObjectHelper::getAlternativeName() |
| 155 | 156 | std::string |
| 156 | 157 | QPDFFormFieldObjectHelper::getMappingName() |
| 157 | 158 | { |
| 158 | - if (this->oh.getKey("/TM").isString()) { | |
| 159 | + if (oh().getKey("/TM").isString()) { | |
| 159 | 160 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM present"); |
| 160 | - return this->oh.getKey("/TM").getUTF8Value(); | |
| 161 | + return oh().getKey("/TM").getUTF8Value(); | |
| 161 | 162 | } |
| 162 | 163 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM absent"); |
| 163 | 164 | return getAlternativeName(); |
| ... | ... | @@ -271,14 +272,9 @@ QPDFFormFieldObjectHelper::getChoices() |
| 271 | 272 | if (!isChoice()) { |
| 272 | 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 | 280 | return result; |
| ... | ... | @@ -287,13 +283,13 @@ QPDFFormFieldObjectHelper::getChoices() |
| 287 | 283 | void |
| 288 | 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 | 289 | void |
| 294 | 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 | 295 | void |
| ... | ... | @@ -310,18 +306,18 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) |
| 310 | 306 | setCheckBoxValue((name != "/Off")); |
| 311 | 307 | } |
| 312 | 308 | if (!okay) { |
| 313 | - this->oh.warnIfPossible( | |
| 309 | + oh().warnIfPossible( | |
| 314 | 310 | "ignoring attempt to set a checkbox field to a value whose type is not name"); |
| 315 | 311 | } |
| 316 | 312 | } else if (isRadioButton()) { |
| 317 | 313 | if (value.isName()) { |
| 318 | 314 | setRadioButtonValue(value); |
| 319 | 315 | } else { |
| 320 | - this->oh.warnIfPossible( | |
| 316 | + oh().warnIfPossible( | |
| 321 | 317 | "ignoring attempt to set a radio button field to an object that is not a name"); |
| 322 | 318 | } |
| 323 | 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 | 322 | return; |
| 327 | 323 | } |
| ... | ... | @@ -331,7 +327,7 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) |
| 331 | 327 | setFieldAttribute("/V", value); |
| 332 | 328 | } |
| 333 | 329 | if (need_appearances) { |
| 334 | - QPDF& qpdf = this->oh.getQPDF( | |
| 330 | + QPDF& qpdf = oh().getQPDF( | |
| 335 | 331 | "QPDFFormFieldObjectHelper::setV called with need_appearances = " |
| 336 | 332 | "true on an object that is not associated with an owning QPDF"); |
| 337 | 333 | QPDFAcroFormDocumentHelper(qpdf).setNeedAppearances(true); |
| ... | ... | @@ -355,7 +351,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) |
| 355 | 351 | // its /AP (i.e. its normal appearance stream dictionary), set /AS to name; otherwise, if /Off |
| 356 | 352 | // is a member, set /AS to /Off. |
| 357 | 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 | 355 | if (parent.isDictionary() && parent.getKey("/Parent").isNull()) { |
| 360 | 356 | QPDFFormFieldObjectHelper ph(parent); |
| 361 | 357 | if (ph.isRadioButton()) { |
| ... | ... | @@ -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 | 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 | 368 | return; |
| 375 | 369 | } |
| 376 | 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 | 372 | QPDFObjectHandle AP = kid.getKey("/AP"); |
| 381 | 373 | QPDFObjectHandle annot; |
| 382 | - if (AP.isNull()) { | |
| 374 | + if (AP.null()) { | |
| 383 | 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 | 384 | } else { |
| ... | ... | @@ -399,7 +386,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) |
| 399 | 386 | } |
| 400 | 387 | if (!annot) { |
| 401 | 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 | 390 | continue; |
| 404 | 391 | } |
| 405 | 392 | if (AP.isDictionary() && AP.getKey("/N").isDictionary() && |
| ... | ... | @@ -416,39 +403,32 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) |
| 416 | 403 | void |
| 417 | 404 | QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) |
| 418 | 405 | { |
| 419 | - QPDFObjectHandle AP = this->oh.getKey("/AP"); | |
| 406 | + QPDFObjectHandle AP = oh().getKey("/AP"); | |
| 420 | 407 | QPDFObjectHandle annot; |
| 421 | - if (AP.isNull()) { | |
| 408 | + if (AP.null()) { | |
| 422 | 409 | // The widget may be below. If there is more than one, just |
| 423 | 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 | 420 | } else { |
| 438 | - annot = this->oh; | |
| 421 | + annot = oh(); | |
| 439 | 422 | } |
| 440 | 423 | std::string on_value; |
| 441 | 424 | if (value) { |
| 442 | 425 | // Set the "on" value to the first value in the appearance stream's normal state dictionary |
| 443 | 426 | // that isn't /Off. If not found, fall back to /Yes. |
| 444 | 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 | 442 | setFieldAttribute("/V", name); |
| 463 | 443 | if (!annot) { |
| 464 | 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 | 446 | return; |
| 467 | 447 | } |
| 468 | 448 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper set checkbox AS"); |
| ... | ... | @@ -775,7 +755,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper& ao |
| 775 | 755 | "<< /Resources << /ProcSet [ /PDF /Text ] >>" |
| 776 | 756 | " /Type /XObject /Subtype /Form >>"); |
| 777 | 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 | 759 | AS.replaceDict(dict); |
| 780 | 760 | QPDFObjectHandle AP = aoh.getAppearanceDictionary(); |
| 781 | 761 | if (AP.isNull()) { | ... | ... |
libqpdf/QPDFJob.cc
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | #include <qpdf/QPDFEmbeddedFileDocumentHelper.hh> |
| 20 | 20 | #include <qpdf/QPDFExc.hh> |
| 21 | 21 | #include <qpdf/QPDFLogger.hh> |
| 22 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 22 | 23 | #include <qpdf/QPDFOutlineDocumentHelper.hh> |
| 23 | 24 | #include <qpdf/QPDFPageDocumentHelper.hh> |
| 24 | 25 | #include <qpdf/QPDFPageLabelDocumentHelper.hh> |
| ... | ... | @@ -916,10 +917,13 @@ QPDFJob::doListAttachments(QPDF& pdf) |
| 916 | 917 | v << " " << i2.first << " -> " << i2.second << "\n"; |
| 917 | 918 | } |
| 918 | 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 | 927 | v << " creation date: " << efs.getCreationDate() << "\n" |
| 924 | 928 | << " modification date: " << efs.getModDate() << "\n" |
| 925 | 929 | << " mime type: " << efs.getSubtype() << "\n" |
| ... | ... | @@ -1338,9 +1342,12 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf) |
| 1338 | 1342 | j_names.addDictionaryMember(i2.first, JSON::makeString(i2.second)); |
| 1339 | 1343 | } |
| 1340 | 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 | 1351 | j_stream.addDictionaryMember( |
| 1345 | 1352 | "creationdate", null_or_string(to_iso8601(efs.getCreationDate()))); |
| 1346 | 1353 | j_stream.addDictionaryMember( |
| ... | ... | @@ -2347,12 +2354,10 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) |
| 2347 | 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 | 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 | 3 | #include <qpdf/BufferInputSource.hh> |
| 4 | 4 | #include <qpdf/JSON_writer.hh> |
| ... | ... | @@ -11,19 +11,6 @@ |
| 11 | 11 | #include <qpdf/QPDFObject_private.hh> |
| 12 | 12 | #include <qpdf/QPDFPageObjectHelper.hh> |
| 13 | 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 | 15 | #include <qpdf/QIntC.hh> |
| 29 | 16 | #include <qpdf/QTC.hh> |
| ... | ... | @@ -38,6 +25,13 @@ |
| 38 | 25 | #include <stdexcept> |
| 39 | 26 | |
| 40 | 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 | 36 | namespace |
| 43 | 37 | { |
| ... | ... | @@ -221,8 +215,441 @@ LastChar::getLastChar() |
| 221 | 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 | 651 | bool |
| 225 | -QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const noexcept | |
| 652 | +QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const | |
| 226 | 653 | { |
| 227 | 654 | return this->obj == rhs.obj; |
| 228 | 655 | } |
| ... | ... | @@ -246,7 +673,7 @@ QPDFObjectHandle::getTypeCode() const |
| 246 | 673 | char const* |
| 247 | 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 | 677 | "uninitialized", |
| 251 | 678 | "reserved", |
| 252 | 679 | "null", |
| ... | ... | @@ -261,100 +688,21 @@ QPDFObjectHandle::getTypeName() const |
| 261 | 688 | "operator", |
| 262 | 689 | "inline-image", |
| 263 | 690 | "unresolved", |
| 264 | - "destroyed"}; | |
| 691 | + "destroyed", | |
| 692 | + "reference"}; | |
| 265 | 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 | 696 | bool |
| 349 | 697 | QPDFObjectHandle::isDestroyed() const |
| 350 | 698 | { |
| 351 | - return obj && obj->getResolvedTypeCode() == ::ot_destroyed; | |
| 699 | + return type_code() == ::ot_destroyed; | |
| 352 | 700 | } |
| 353 | 701 | |
| 354 | 702 | bool |
| 355 | 703 | QPDFObjectHandle::isBool() const |
| 356 | 704 | { |
| 357 | - return obj && obj->getResolvedTypeCode() == ::ot_boolean; | |
| 705 | + return type_code() == ::ot_boolean; | |
| 358 | 706 | } |
| 359 | 707 | |
| 360 | 708 | bool |
| ... | ... | @@ -362,25 +710,25 @@ QPDFObjectHandle::isDirectNull() const |
| 362 | 710 | { |
| 363 | 711 | // Don't call dereference() -- this is a const method, and we know |
| 364 | 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 | 716 | bool |
| 369 | 717 | QPDFObjectHandle::isNull() const |
| 370 | 718 | { |
| 371 | - return obj && obj->getResolvedTypeCode() == ::ot_null; | |
| 719 | + return type_code() == ::ot_null; | |
| 372 | 720 | } |
| 373 | 721 | |
| 374 | 722 | bool |
| 375 | 723 | QPDFObjectHandle::isInteger() const |
| 376 | 724 | { |
| 377 | - return obj && obj->getResolvedTypeCode() == ::ot_integer; | |
| 725 | + return type_code() == ::ot_integer; | |
| 378 | 726 | } |
| 379 | 727 | |
| 380 | 728 | bool |
| 381 | 729 | QPDFObjectHandle::isReal() const |
| 382 | 730 | { |
| 383 | - return obj && obj->getResolvedTypeCode() == ::ot_real; | |
| 731 | + return type_code() == ::ot_real; | |
| 384 | 732 | } |
| 385 | 733 | |
| 386 | 734 | bool |
| ... | ... | @@ -416,49 +764,49 @@ QPDFObjectHandle::getValueAsNumber(double& value) const |
| 416 | 764 | bool |
| 417 | 765 | QPDFObjectHandle::isName() const |
| 418 | 766 | { |
| 419 | - return obj && obj->getResolvedTypeCode() == ::ot_name; | |
| 767 | + return type_code() == ::ot_name; | |
| 420 | 768 | } |
| 421 | 769 | |
| 422 | 770 | bool |
| 423 | 771 | QPDFObjectHandle::isString() const |
| 424 | 772 | { |
| 425 | - return obj && obj->getResolvedTypeCode() == ::ot_string; | |
| 773 | + return type_code() == ::ot_string; | |
| 426 | 774 | } |
| 427 | 775 | |
| 428 | 776 | bool |
| 429 | 777 | QPDFObjectHandle::isOperator() const |
| 430 | 778 | { |
| 431 | - return obj && obj->getResolvedTypeCode() == ::ot_operator; | |
| 779 | + return type_code() == ::ot_operator; | |
| 432 | 780 | } |
| 433 | 781 | |
| 434 | 782 | bool |
| 435 | 783 | QPDFObjectHandle::isInlineImage() const |
| 436 | 784 | { |
| 437 | - return obj && obj->getResolvedTypeCode() == ::ot_inlineimage; | |
| 785 | + return type_code() == ::ot_inlineimage; | |
| 438 | 786 | } |
| 439 | 787 | |
| 440 | 788 | bool |
| 441 | 789 | QPDFObjectHandle::isArray() const |
| 442 | 790 | { |
| 443 | - return obj && obj->getResolvedTypeCode() == ::ot_array; | |
| 791 | + return type_code() == ::ot_array; | |
| 444 | 792 | } |
| 445 | 793 | |
| 446 | 794 | bool |
| 447 | 795 | QPDFObjectHandle::isDictionary() const |
| 448 | 796 | { |
| 449 | - return obj && obj->getResolvedTypeCode() == ::ot_dictionary; | |
| 797 | + return type_code() == ::ot_dictionary; | |
| 450 | 798 | } |
| 451 | 799 | |
| 452 | 800 | bool |
| 453 | 801 | QPDFObjectHandle::isStream() const |
| 454 | 802 | { |
| 455 | - return obj && obj->getResolvedTypeCode() == ::ot_stream; | |
| 803 | + return type_code() == ::ot_stream; | |
| 456 | 804 | } |
| 457 | 805 | |
| 458 | 806 | bool |
| 459 | 807 | QPDFObjectHandle::isReserved() const |
| 460 | 808 | { |
| 461 | - return obj && obj->getResolvedTypeCode() == ::ot_reserved; | |
| 809 | + return type_code() == ::ot_reserved; | |
| 462 | 810 | } |
| 463 | 811 | |
| 464 | 812 | bool |
| ... | ... | @@ -491,9 +839,8 @@ QPDFObjectHandle::isStreamOfType(std::string const& type, std::string const& sub |
| 491 | 839 | bool |
| 492 | 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 | 844 | } else { |
| 498 | 845 | typeWarning("boolean", "returning false"); |
| 499 | 846 | QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); |
| ... | ... | @@ -504,12 +851,11 @@ QPDFObjectHandle::getBoolValue() const |
| 504 | 851 | bool |
| 505 | 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 | 861 | // Integer accessors |
| ... | ... | @@ -517,9 +863,8 @@ QPDFObjectHandle::getValueAsBool(bool& value) const |
| 517 | 863 | long long |
| 518 | 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 | 868 | } else { |
| 524 | 869 | typeWarning("integer", "returning 0"); |
| 525 | 870 | QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); |
| ... | ... | @@ -530,12 +875,11 @@ QPDFObjectHandle::getIntValue() const |
| 530 | 875 | bool |
| 531 | 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 | 885 | int |
| ... | ... | @@ -692,8 +1036,7 @@ QPDFObjectHandle::getValueAsString(std::string& value) const |
| 692 | 1036 | std::string |
| 693 | 1037 | QPDFObjectHandle::getUTF8Value() const |
| 694 | 1038 | { |
| 695 | - auto str = asString(); | |
| 696 | - if (str) { | |
| 1039 | + if (auto str = as<QPDF_String>()) { | |
| 697 | 1040 | return str->getUTF8Val(); |
| 698 | 1041 | } else { |
| 699 | 1042 | typeWarning("string", "returning empty string"); |
| ... | ... | @@ -705,12 +1048,11 @@ QPDFObjectHandle::getUTF8Value() const |
| 705 | 1048 | bool |
| 706 | 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 | 1058 | // Operator and Inline Image accessors |
| ... | ... | @@ -759,7 +1101,7 @@ QPDFObjectHandle::getValueAsInlineImage(std::string& value) const |
| 759 | 1101 | return true; |
| 760 | 1102 | } |
| 761 | 1103 | |
| 762 | -// Array accessors | |
| 1104 | +// Array accessors and mutators are in QPDF_Array.cc | |
| 763 | 1105 | |
| 764 | 1106 | QPDFObjectHandle::QPDFArrayItems |
| 765 | 1107 | QPDFObjectHandle::aitems() |
| ... | ... | @@ -767,207 +1109,7 @@ QPDFObjectHandle::aitems() |
| 767 | 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 | 1114 | QPDFObjectHandle::QPDFDictItems |
| 973 | 1115 | QPDFObjectHandle::ditems() |
| ... | ... | @@ -975,66 +1117,6 @@ QPDFObjectHandle::ditems() |
| 975 | 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 | 1120 | // Array and Name accessors |
| 1039 | 1121 | |
| 1040 | 1122 | bool |
| ... | ... | @@ -1055,19 +1137,10 @@ QPDFObjectHandle::isOrHasName(std::string const& value) const |
| 1055 | 1137 | void |
| 1056 | 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 | 1157 | |
| 1085 | 1158 | auto make_og_to_name = [](QPDFObjectHandle& dict, |
| 1086 | 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 | 1167 | // This algorithm is described in comments in QPDFObjectHandle.hh |
| 1095 | 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 | 1171 | if (hasKey(rtype)) { |
| 1100 | 1172 | QPDFObjectHandle this_val = getKey(rtype); |
| 1101 | 1173 | if (this_val.isDictionary() && other_val.isDictionary()) { |
| ... | ... | @@ -1110,9 +1182,8 @@ QPDFObjectHandle::mergeResources( |
| 1110 | 1182 | std::set<std::string> rnames; |
| 1111 | 1183 | int min_suffix = 1; |
| 1112 | 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 | 1187 | if (!this_val.hasKey(key)) { |
| 1117 | 1188 | if (!rval.isIndirect()) { |
| 1118 | 1189 | QTC::TC("qpdf", "QPDFObjectHandle merge shallow copy"); |
| ... | ... | @@ -1171,14 +1242,10 @@ QPDFObjectHandle::getResourceNames() const |
| 1171 | 1242 | { |
| 1172 | 1243 | // Return second-level dictionary keys |
| 1173 | 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 | 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 | 1282 | std::map<std::string, QPDFObjectHandle> |
| 1441 | 1283 | QPDFObjectHandle::getPageImages() |
| ... | ... | @@ -1449,12 +1291,12 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( |
| 1449 | 1291 | { |
| 1450 | 1292 | all_description = description; |
| 1451 | 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 | 1296 | for (int i = 0; i < n_items; ++i) { |
| 1455 | - QPDFObjectHandle item = array->at(i).second; | |
| 1297 | + QPDFObjectHandle item = array.at(i).second; | |
| 1456 | 1298 | if (item.isStream()) { |
| 1457 | - result.push_back(item); | |
| 1299 | + result.emplace_back(item); | |
| 1458 | 1300 | } else { |
| 1459 | 1301 | QTC::TC("qpdf", "QPDFObjectHandle non-stream in stream array"); |
| 1460 | 1302 | warn( |
| ... | ... | @@ -1468,7 +1310,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( |
| 1468 | 1310 | } |
| 1469 | 1311 | } |
| 1470 | 1312 | } else if (isStream()) { |
| 1471 | - result.push_back(*this); | |
| 1313 | + result.emplace_back(*this); | |
| 1472 | 1314 | } else if (!isNull()) { |
| 1473 | 1315 | warn( |
| 1474 | 1316 | getOwningQPDF(), |
| ... | ... | @@ -1602,7 +1444,7 @@ QPDFObjectHandle::unparseResolved() const |
| 1602 | 1444 | std::string |
| 1603 | 1445 | QPDFObjectHandle::unparseBinary() const |
| 1604 | 1446 | { |
| 1605 | - if (auto str = asString()) { | |
| 1447 | + if (auto str = as<QPDF_String>()) { | |
| 1606 | 1448 | return str->unparse(true); |
| 1607 | 1449 | } else { |
| 1608 | 1450 | return unparse(); |
| ... | ... | @@ -1633,7 +1475,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_ |
| 1633 | 1475 | } else if (!obj) { |
| 1634 | 1476 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); |
| 1635 | 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 | 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 | 1490 | QPDFObjectHandle |
| 1661 | 1491 | QPDFObjectHandle::wrapInArray() |
| 1662 | 1492 | { |
| ... | ... | @@ -1857,7 +1687,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr<TokenFilter> filter) |
| 1857 | 1687 | void |
| 1858 | 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 | 1693 | QPDFObjectHandle |
| ... | ... | @@ -1882,43 +1712,43 @@ QPDFObjectHandle::getParsedOffset() const |
| 1882 | 1712 | QPDFObjectHandle |
| 1883 | 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 | 1718 | QPDFObjectHandle |
| 1889 | 1719 | QPDFObjectHandle::newNull() |
| 1890 | 1720 | { |
| 1891 | - return {QPDF_Null::create()}; | |
| 1721 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 1892 | 1722 | } |
| 1893 | 1723 | |
| 1894 | 1724 | QPDFObjectHandle |
| 1895 | 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 | 1730 | QPDFObjectHandle |
| 1901 | 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 | 1736 | QPDFObjectHandle |
| 1907 | 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 | 1742 | QPDFObjectHandle |
| 1913 | 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 | 1748 | QPDFObjectHandle |
| 1919 | 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 | 1754 | QPDFObjectHandle |
| ... | ... | @@ -1930,13 +1760,13 @@ QPDFObjectHandle::newUnicodeString(std::string const& utf8_str) |
| 1930 | 1760 | QPDFObjectHandle |
| 1931 | 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 | 1766 | QPDFObjectHandle |
| 1937 | 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 | 1772 | QPDFObjectHandle |
| ... | ... | @@ -1948,7 +1778,7 @@ QPDFObjectHandle::newArray() |
| 1948 | 1778 | QPDFObjectHandle |
| 1949 | 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 | 1784 | QPDFObjectHandle |
| ... | ... | @@ -2008,7 +1838,7 @@ QPDFObjectHandle::newDictionary() |
| 2008 | 1838 | QPDFObjectHandle |
| 2009 | 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 | 1844 | QPDFObjectHandle |
| ... | ... | @@ -2054,7 +1884,7 @@ void |
| 2054 | 1884 | QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) |
| 2055 | 1885 | { |
| 2056 | 1886 | if (obj) { |
| 2057 | - auto descr = std::make_shared<QPDFValue::Description>(object_description); | |
| 1887 | + auto descr = std::make_shared<QPDFObject::Description>(object_description); | |
| 2058 | 1888 | obj->setDescription(owning_qpdf, descr); |
| 2059 | 1889 | } |
| 2060 | 1890 | } |
| ... | ... | @@ -2096,23 +1926,22 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set& visited, bool stop_at_streams) |
| 2096 | 1926 | |
| 2097 | 1927 | if (isBool() || isInteger() || isName() || isNull() || isReal() || isString()) { |
| 2098 | 1928 | this->obj = obj->copy(true); |
| 2099 | - } else if (isArray()) { | |
| 1929 | + } else if (auto a = as_array(strict)) { | |
| 2100 | 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 | 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 | 1936 | } else if (isDictionary()) { |
| 2109 | 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 | 1945 | } else if (isStream()) { |
| 2117 | 1946 | QTC::TC("qpdf", "QPDFObjectHandle copy stream", stop_at_streams ? 0 : 1); |
| 2118 | 1947 | if (!stop_at_streams) { |
| ... | ... | @@ -2349,19 +2178,6 @@ QPDFObjectHandle::isImage(bool exclude_imagemask) const |
| 2349 | 2178 | } |
| 2350 | 2179 | |
| 2351 | 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 | 2181 | QPDFObjectHandle::assertPageObject() const |
| 2366 | 2182 | { |
| 2367 | 2183 | if (!isPageObject()) { | ... | ... |
libqpdf/QPDFOutlineObjectHelper.cc
| ... | ... | @@ -9,8 +9,8 @@ QPDFOutlineObjectHelper::Members::Members(QPDFOutlineDocumentHelper& dh) : |
| 9 | 9 | } |
| 10 | 10 | |
| 11 | 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 | 14 | m(new Members(dh)) |
| 15 | 15 | { |
| 16 | 16 | if (depth > 50) { |
| ... | ... | @@ -18,13 +18,13 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper( |
| 18 | 18 | // to 1. |
| 19 | 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 | 22 | QTC::TC("qpdf", "QPDFOutlineObjectHelper loop"); |
| 23 | 23 | return; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | 26 | QPDFObjGen::set children; |
| 27 | - QPDFObjectHandle cur = oh.getKey("/First"); | |
| 27 | + QPDFObjectHandle cur = a_oh.getKey("/First"); | |
| 28 | 28 | while (!cur.isNull() && cur.isIndirect() && children.add(cur)) { |
| 29 | 29 | QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth); |
| 30 | 30 | new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this); |
| ... | ... | @@ -50,11 +50,11 @@ QPDFOutlineObjectHelper::getDest() |
| 50 | 50 | { |
| 51 | 51 | QPDFObjectHandle dest; |
| 52 | 52 | QPDFObjectHandle A; |
| 53 | - if (this->oh.hasKey("/Dest")) { | |
| 53 | + if (oh().hasKey("/Dest")) { | |
| 54 | 54 | QTC::TC("qpdf", "QPDFOutlineObjectHelper direct dest"); |
| 55 | - dest = this->oh.getKey("/Dest"); | |
| 55 | + dest = oh().getKey("/Dest"); | |
| 56 | 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 | 58 | (A.getKey("/S").getName() == "/GoTo") && A.hasKey("/D")) { |
| 59 | 59 | QTC::TC("qpdf", "QPDFOutlineObjectHelper action dest"); |
| 60 | 60 | dest = A.getKey("/D"); |
| ... | ... | @@ -85,8 +85,8 @@ int |
| 85 | 85 | QPDFOutlineObjectHelper::getCount() |
| 86 | 86 | { |
| 87 | 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 | 91 | return count; |
| 92 | 92 | } |
| ... | ... | @@ -95,8 +95,8 @@ std::string |
| 95 | 95 | QPDFOutlineObjectHelper::getTitle() |
| 96 | 96 | { |
| 97 | 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 | 101 | return result; |
| 102 | 102 | } | ... | ... |
libqpdf/QPDFPageObjectHelper.cc
| ... | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> |
| 8 | 8 | #include <qpdf/QPDFExc.hh> |
| 9 | 9 | #include <qpdf/QPDFMatrix.hh> |
| 10 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 10 | 11 | #include <qpdf/QTC.hh> |
| 11 | 12 | #include <qpdf/QUtil.hh> |
| 12 | 13 | #include <qpdf/ResourceFinder.hh> |
| ... | ... | @@ -72,9 +73,12 @@ InlineImageTracker::convertIIDict(QPDFObjectHandle odict) |
| 72 | 73 | QPDFObjectHandle dict = QPDFObjectHandle::newDictionary(); |
| 73 | 74 | dict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); |
| 74 | 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 | 82 | if (key == "/BPC") { |
| 79 | 83 | key = "/BitsPerComponent"; |
| 80 | 84 | } else if (key == "/CS") { |
| ... | ... | @@ -227,9 +231,9 @@ QPDFPageObjectHelper::getAttribute( |
| 227 | 231 | std::function<QPDFObjectHandle()> get_fallback, |
| 228 | 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 | 235 | bool inherited = false; |
| 232 | - auto dict = is_form_xobject ? oh.getDict() : oh; | |
| 236 | + auto dict = is_form_xobject ? oh().getDict() : oh(); | |
| 233 | 237 | auto result = dict.getKey(name); |
| 234 | 238 | |
| 235 | 239 | if (!is_form_xobject && result.isNull() && |
| ... | ... | @@ -324,23 +328,24 @@ QPDFPageObjectHelper::forEachXObject( |
| 324 | 328 | QTC::TC( |
| 325 | 329 | "qpdf", |
| 326 | 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 | 332 | QPDFObjGen::set seen; |
| 329 | 333 | std::list<QPDFPageObjectHelper> queue; |
| 330 | - queue.push_back(*this); | |
| 334 | + queue.emplace_back(*this); | |
| 331 | 335 | while (!queue.empty()) { |
| 332 | 336 | auto& ph = queue.front(); |
| 333 | 337 | if (seen.add(ph)) { |
| 334 | 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 | 407 | // Calling mergeResources also ensures that /XObject becomes direct and is not shared with |
| 403 | 408 | // other pages. |
| 404 | 409 | resources.mergeResources("<< /XObject << >> >>"_qpdf); |
| 405 | - InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources); | |
| 410 | + InlineImageTracker iit(oh().getOwningQPDF(), min_size, resources); | |
| 406 | 411 | Pl_Buffer b("new page content"); |
| 407 | 412 | bool filtered = false; |
| 408 | 413 | try { |
| 409 | 414 | filterContents(&iit, &b); |
| 410 | 415 | filtered = true; |
| 411 | 416 | } catch (std::exception& e) { |
| 412 | - this->oh.warnIfPossible( | |
| 417 | + oh().warnIfPossible( | |
| 413 | 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 | 421 | if (filtered && iit.any_images) { |
| 418 | - if (this->oh.isFormXObject()) { | |
| 419 | - this->oh.replaceStreamData( | |
| 422 | + if (oh().isFormXObject()) { | |
| 423 | + oh().replaceStreamData( | |
| 420 | 424 | b.getBufferSharedPointer(), |
| 421 | 425 | QPDFObjectHandle::newNull(), |
| 422 | 426 | QPDFObjectHandle::newNull()); |
| 423 | 427 | } else { |
| 424 | - this->oh.replaceKey( | |
| 428 | + oh().replaceKey( | |
| 425 | 429 | "/Contents", |
| 426 | - QPDFObjectHandle::newStream(&this->oh.getQPDF(), b.getBufferSharedPointer())); | |
| 430 | + QPDFObjectHandle::newStream(&oh().getQPDF(), b.getBufferSharedPointer())); | |
| 427 | 431 | } |
| 428 | 432 | } |
| 429 | 433 | } else { |
| ... | ... | @@ -439,7 +443,7 @@ std::vector<QPDFAnnotationObjectHelper> |
| 439 | 443 | QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) |
| 440 | 444 | { |
| 441 | 445 | std::vector<QPDFAnnotationObjectHelper> result; |
| 442 | - QPDFObjectHandle annots = this->oh.getKey("/Annots"); | |
| 446 | + QPDFObjectHandle annots = oh().getKey("/Annots"); | |
| 443 | 447 | if (annots.isArray()) { |
| 444 | 448 | int nannots = annots.getArrayNItems(); |
| 445 | 449 | for (int i = 0; i < nannots; ++i) { |
| ... | ... | @@ -455,25 +459,25 @@ QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) |
| 455 | 459 | std::vector<QPDFObjectHandle> |
| 456 | 460 | QPDFPageObjectHelper::getPageContents() |
| 457 | 461 | { |
| 458 | - return this->oh.getPageContents(); | |
| 462 | + return oh().getPageContents(); | |
| 459 | 463 | } |
| 460 | 464 | |
| 461 | 465 | void |
| 462 | 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 | 471 | void |
| 468 | 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 | 477 | void |
| 474 | 478 | QPDFPageObjectHelper::coalesceContentStreams() |
| 475 | 479 | { |
| 476 | - this->oh.coalesceContentStreams(); | |
| 480 | + oh().coalesceContentStreams(); | |
| 477 | 481 | } |
| 478 | 482 | |
| 479 | 483 | void |
| ... | ... | @@ -485,10 +489,10 @@ QPDFPageObjectHelper::parsePageContents(QPDFObjectHandle::ParserCallbacks* callb |
| 485 | 489 | void |
| 486 | 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 | 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 | 505 | void |
| 502 | 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 | 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 | 521 | void |
| 518 | 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 | 526 | } else { |
| 523 | - this->oh.pipePageContents(p); | |
| 527 | + oh().pipePageContents(p); | |
| 524 | 528 | } |
| 525 | 529 | } |
| 526 | 530 | |
| ... | ... | @@ -528,10 +532,10 @@ void |
| 528 | 532 | QPDFPageObjectHelper::addContentTokenFilter( |
| 529 | 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 | 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 | 543 | QPDFPageObjectHelper::removeUnreferencedResourcesHelper( |
| 540 | 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 | 547 | if (!is_page) { |
| 544 | 548 | QTC::TC("qpdf", "QPDFPageObjectHelper filter form xobject"); |
| 545 | 549 | } |
| 546 | 550 | |
| 547 | 551 | ResourceFinder rf; |
| 548 | 552 | try { |
| 549 | - auto q = ph.oh.getOwningQPDF(); | |
| 553 | + auto q = ph.oh().getOwningQPDF(); | |
| 550 | 554 | size_t before_nw = (q ? q->numWarnings() : 0); |
| 551 | 555 | ph.parseContents(&rf); |
| 552 | 556 | size_t after_nw = (q ? q->numWarnings() : 0); |
| 553 | 557 | if (after_nw > before_nw) { |
| 554 | - ph.oh.warnIfPossible( | |
| 558 | + ph.oh().warnIfPossible( | |
| 555 | 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 | 561 | return false; |
| 559 | 562 | } |
| 560 | 563 | } catch (std::exception& e) { |
| 561 | 564 | QTC::TC("qpdf", "QPDFPageObjectHelper bad token finding names"); |
| 562 | - ph.oh.warnIfPossible( | |
| 565 | + ph.oh().warnIfPossible( | |
| 563 | 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 | 568 | return false; |
| 567 | 569 | } |
| 568 | 570 | |
| ... | ... | @@ -646,7 +648,7 @@ QPDFPageObjectHelper::removeUnreferencedResources() |
| 646 | 648 | any_failures = true; |
| 647 | 649 | } |
| 648 | 650 | }); |
| 649 | - if (this->oh.isFormXObject() || (!any_failures)) { | |
| 651 | + if (oh().isFormXObject() || (!any_failures)) { | |
| 650 | 652 | removeUnreferencedResourcesHelper(*this, unresolved); |
| 651 | 653 | } |
| 652 | 654 | } |
| ... | ... | @@ -654,9 +656,8 @@ QPDFPageObjectHelper::removeUnreferencedResources() |
| 654 | 656 | QPDFPageObjectHelper |
| 655 | 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 | 661 | return {qpdf.makeIndirectObject(new_page)}; |
| 661 | 662 | } |
| 662 | 663 | |
| ... | ... | @@ -707,7 +708,7 @@ QPDFObjectHandle |
| 707 | 708 | QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) |
| 708 | 709 | { |
| 709 | 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 | 712 | .newStream(); |
| 712 | 713 | QPDFObjectHandle newdict = result.getDict(); |
| 713 | 714 | newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); |
| ... | ... | @@ -716,13 +717,13 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) |
| 716 | 717 | newdict.replaceKey("/Group", getAttribute("/Group", false).shallowCopy()); |
| 717 | 718 | QPDFObjectHandle bbox = getTrimBox(false).shallowCopy(); |
| 718 | 719 | if (!bbox.isRectangle()) { |
| 719 | - this->oh.warnIfPossible( | |
| 720 | + oh().warnIfPossible( | |
| 720 | 721 | "bounding box is invalid; form" |
| 721 | 722 | " XObject created from page will not work"); |
| 722 | 723 | } |
| 723 | 724 | newdict.replaceKey("/BBox", bbox); |
| 724 | 725 | auto provider = |
| 725 | - std::shared_ptr<QPDFObjectHandle::StreamDataProvider>(new ContentProvider(this->oh)); | |
| 726 | + std::shared_ptr<QPDFObjectHandle::StreamDataProvider>(new ContentProvider(oh())); | |
| 726 | 727 | result.replaceStreamData(provider, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull()); |
| 727 | 728 | QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); |
| 728 | 729 | QPDFObjectHandle scale_obj = getAttribute("/UserUnit", false); |
| ... | ... | @@ -863,9 +864,8 @@ QPDFPageObjectHelper::placeFormXObject( |
| 863 | 864 | void |
| 864 | 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 | 869 | int rotate = 0; |
| 870 | 870 | if (rotate_oh.isInteger()) { |
| 871 | 871 | rotate = rotate_oh.getIntValueAsInt(); |
| ... | ... | @@ -873,7 +873,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) |
| 873 | 873 | if (!((rotate == 90) || (rotate == 180) || (rotate == 270))) { |
| 874 | 874 | return; |
| 875 | 875 | } |
| 876 | - auto mediabox = this->oh.getKey("/MediaBox"); | |
| 876 | + auto mediabox = oh().getKey("/MediaBox"); | |
| 877 | 877 | if (!mediabox.isRectangle()) { |
| 878 | 878 | return; |
| 879 | 879 | } |
| ... | ... | @@ -887,7 +887,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) |
| 887 | 887 | "/ArtBox", |
| 888 | 888 | }; |
| 889 | 889 | for (auto const& boxkey: boxes) { |
| 890 | - auto box = this->oh.getKey(boxkey); | |
| 890 | + auto box = oh().getKey(boxkey); | |
| 891 | 891 | if (!box.isRectangle()) { |
| 892 | 892 | continue; |
| 893 | 893 | } |
| ... | ... | @@ -930,7 +930,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) |
| 930 | 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 | 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 | 962 | break; |
| 963 | 963 | } |
| 964 | 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 | 968 | QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); |
| 969 | 969 | if (!rotate_obj.isNull()) { |
| 970 | 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 | 975 | if (annots.isArray()) { |
| 976 | 976 | std::vector<QPDFObjectHandle> new_annots; |
| 977 | 977 | std::vector<QPDFObjectHandle> new_fields; |
| ... | ... | @@ -986,7 +986,7 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) |
| 986 | 986 | for (auto const& f: new_fields) { |
| 987 | 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 | 1005 | QPDF& from_qpdf = from_page.getObjectHandle().getQPDF( |
| 1006 | 1006 | "QPDFPageObjectHelper::copyAnnotations: from page is a direct object"); |
| 1007 | 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 | 1010 | std::vector<QPDFObjectHandle> new_annots; |
| 1011 | 1011 | std::vector<QPDFObjectHandle> new_fields; |
| ... | ... | @@ -1032,9 +1032,9 @@ QPDFPageObjectHelper::copyAnnotations( |
| 1032 | 1032 | afdh->transformAnnotations( |
| 1033 | 1033 | old_annots, new_annots, new_fields, old_fields, cm, &from_qpdf, from_afdh); |
| 1034 | 1034 | afdh->addAndRenameFormFields(new_fields); |
| 1035 | - auto annots = this->oh.getKey("/Annots"); | |
| 1035 | + auto annots = oh().getKey("/Annots"); | |
| 1036 | 1036 | if (!annots.isArray()) { |
| 1037 | - annots = this->oh.replaceKeyAndGetNew("/Annots", QPDFObjectHandle::newArray()); | |
| 1037 | + annots = oh().replaceKeyAndGetNew("/Annots", QPDFObjectHandle::newArray()); | |
| 1038 | 1038 | } |
| 1039 | 1039 | for (auto const& annot: new_annots) { |
| 1040 | 1040 | annots.appendItem(annot); | ... | ... |
libqpdf/QPDFParser.cc
| ... | ... | @@ -4,18 +4,6 @@ |
| 4 | 4 | #include <qpdf/QPDFObjGen.hh> |
| 5 | 5 | #include <qpdf/QPDFObjectHandle.hh> |
| 6 | 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 | 7 | #include <qpdf/QTC.hh> |
| 20 | 8 | #include <qpdf/QUtil.hh> |
| 21 | 9 | |
| ... | ... | @@ -47,27 +35,27 @@ QPDFParser::parse(bool& empty, bool content_stream) |
| 47 | 35 | } |
| 48 | 36 | QTC::TC("qpdf", "QPDFParser eof in parse"); |
| 49 | 37 | warn("unexpected EOF"); |
| 50 | - return {QPDF_Null::create()}; | |
| 38 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 51 | 39 | |
| 52 | 40 | case QPDFTokenizer::tt_bad: |
| 53 | 41 | QTC::TC("qpdf", "QPDFParser bad token in parse"); |
| 54 | - return {QPDF_Null::create()}; | |
| 42 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 55 | 43 | |
| 56 | 44 | case QPDFTokenizer::tt_brace_open: |
| 57 | 45 | case QPDFTokenizer::tt_brace_close: |
| 58 | 46 | QTC::TC("qpdf", "QPDFParser bad brace"); |
| 59 | 47 | warn("treating unexpected brace token as null"); |
| 60 | - return {QPDF_Null::create()}; | |
| 48 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 61 | 49 | |
| 62 | 50 | case QPDFTokenizer::tt_array_close: |
| 63 | 51 | QTC::TC("qpdf", "QPDFParser bad array close"); |
| 64 | 52 | warn("treating unexpected array close token as null"); |
| 65 | - return {QPDF_Null::create()}; | |
| 53 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 66 | 54 | |
| 67 | 55 | case QPDFTokenizer::tt_dict_close: |
| 68 | 56 | QTC::TC("qpdf", "QPDFParser bad dictionary close"); |
| 69 | 57 | warn("unexpected dictionary close token"); |
| 70 | - return {QPDF_Null::create()}; | |
| 58 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 71 | 59 | |
| 72 | 60 | case QPDFTokenizer::tt_array_open: |
| 73 | 61 | case QPDFTokenizer::tt_dict_open: |
| ... | ... | @@ -82,7 +70,7 @@ QPDFParser::parse(bool& empty, bool content_stream) |
| 82 | 70 | return withDescription<QPDF_Bool>(tokenizer.getValue() == "true"); |
| 83 | 71 | |
| 84 | 72 | case QPDFTokenizer::tt_null: |
| 85 | - return {QPDF_Null::create()}; | |
| 73 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 86 | 74 | |
| 87 | 75 | case QPDFTokenizer::tt_integer: |
| 88 | 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 | 91 | // not move the input source's offset. |
| 104 | 92 | input.seek(input.getLastOffset(), SEEK_SET); |
| 105 | 93 | empty = true; |
| 106 | - return {QPDF_Null::create()}; | |
| 94 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 107 | 95 | } else { |
| 108 | 96 | QTC::TC("qpdf", "QPDFParser treat word as string"); |
| 109 | 97 | warn("unknown token while reading object; treating as string"); |
| ... | ... | @@ -122,7 +110,7 @@ QPDFParser::parse(bool& empty, bool content_stream) |
| 122 | 110 | |
| 123 | 111 | default: |
| 124 | 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 | 182 | } |
| 195 | 183 | QTC::TC("qpdf", "QPDFParser eof in parseRemainder"); |
| 196 | 184 | warn("unexpected EOF"); |
| 197 | - return {QPDF_Null::create()}; | |
| 185 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 198 | 186 | |
| 199 | 187 | case QPDFTokenizer::tt_bad: |
| 200 | 188 | QTC::TC("qpdf", "QPDFParser bad token in parseRemainder"); |
| 201 | 189 | if (tooManyBadTokens()) { |
| 202 | - return {QPDF_Null::create()}; | |
| 190 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 203 | 191 | } |
| 204 | 192 | addNull(); |
| 205 | 193 | continue; |
| ... | ... | @@ -209,7 +197,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 209 | 197 | QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder"); |
| 210 | 198 | warn("treating unexpected brace token as null"); |
| 211 | 199 | if (tooManyBadTokens()) { |
| 212 | - return {QPDF_Null::create()}; | |
| 200 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 213 | 201 | } |
| 214 | 202 | addNull(); |
| 215 | 203 | continue; |
| ... | ... | @@ -218,10 +206,12 @@ QPDFParser::parseRemainder(bool content_stream) |
| 218 | 206 | if (bad_count && !max_bad_count) { |
| 219 | 207 | // Trigger warning. |
| 220 | 208 | (void)tooManyBadTokens(); |
| 221 | - return {QPDF_Null::create()}; | |
| 209 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 222 | 210 | } |
| 223 | 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 | 215 | setDescription(object, frame->offset - 1); |
| 226 | 216 | // The `offset` points to the next of "[". Set the rewind offset to point to the |
| 227 | 217 | // beginning of "[". This has been explicitly tested with whitespace surrounding the |
| ... | ... | @@ -237,7 +227,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 237 | 227 | QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); |
| 238 | 228 | warn("treating unexpected array close token as null"); |
| 239 | 229 | if (tooManyBadTokens()) { |
| 240 | - return {QPDF_Null::create()}; | |
| 230 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 241 | 231 | } |
| 242 | 232 | addNull(); |
| 243 | 233 | } |
| ... | ... | @@ -247,7 +237,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 247 | 237 | if (bad_count && !max_bad_count) { |
| 248 | 238 | // Trigger warning. |
| 249 | 239 | (void)tooManyBadTokens(); |
| 250 | - return {QPDF_Null::create()}; | |
| 240 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 251 | 241 | } |
| 252 | 242 | if (frame->state <= st_dictionary_value) { |
| 253 | 243 | // Attempt to recover more or less gracefully from invalid dictionaries. |
| ... | ... | @@ -258,7 +248,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 258 | 248 | warn( |
| 259 | 249 | frame->offset, |
| 260 | 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 | 254 | if (!frame->olist.empty()) { |
| ... | ... | @@ -271,7 +261,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 271 | 261 | dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string); |
| 272 | 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 | 265 | setDescription(object, frame->offset - 2); |
| 276 | 266 | // The `offset` points to the next of "<<". Set the rewind offset to point to the |
| 277 | 267 | // beginning of "<<". This has been explicitly tested with whitespace surrounding |
| ... | ... | @@ -287,7 +277,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 287 | 277 | QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder"); |
| 288 | 278 | warn("unexpected dictionary close token"); |
| 289 | 279 | if (tooManyBadTokens()) { |
| 290 | - return {QPDF_Null::create()}; | |
| 280 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 291 | 281 | } |
| 292 | 282 | addNull(); |
| 293 | 283 | } |
| ... | ... | @@ -298,7 +288,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 298 | 288 | if (stack.size() > 499) { |
| 299 | 289 | QTC::TC("qpdf", "QPDFParser too deep"); |
| 300 | 290 | warn("ignoring excessively deeply nested data structure"); |
| 301 | - return {QPDF_Null::create()}; | |
| 291 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 302 | 292 | } else { |
| 303 | 293 | b_contents = false; |
| 304 | 294 | stack.emplace_back( |
| ... | ... | @@ -350,7 +340,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 350 | 340 | QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); |
| 351 | 341 | warn("unknown token while reading object; treating as string"); |
| 352 | 342 | if (tooManyBadTokens()) { |
| 353 | - return {QPDF_Null::create()}; | |
| 343 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 354 | 344 | } |
| 355 | 345 | addScalar<QPDF_String>(tokenizer.getValue()); |
| 356 | 346 | } |
| ... | ... | @@ -377,7 +367,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 377 | 367 | default: |
| 378 | 368 | warn("treating unknown token type as null while reading object"); |
| 379 | 369 | if (tooManyBadTokens()) { |
| 380 | - return {QPDF_Null::create()}; | |
| 370 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 381 | 371 | } |
| 382 | 372 | addNull(); |
| 383 | 373 | } |
| ... | ... | @@ -402,7 +392,7 @@ QPDFParser::add(std::shared_ptr<QPDFObject>&& obj) |
| 402 | 392 | void |
| 403 | 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 | 397 | if (frame->state != st_dictionary_value) { |
| 408 | 398 | // If state is st_dictionary_key then there is a missing key. Push onto olist for |
| ... | ... | @@ -420,7 +410,7 @@ QPDFParser::addNull() |
| 420 | 410 | void |
| 421 | 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 | 414 | obj->setDescription(context, description, last_offset_buffer[count % 2]); |
| 425 | 415 | add(std::move(obj)); |
| 426 | 416 | } |
| ... | ... | @@ -435,7 +425,7 @@ QPDFParser::addScalar(Args&&... args) |
| 435 | 425 | max_bad_count = 0; |
| 436 | 426 | return; |
| 437 | 427 | } |
| 438 | - auto obj = T::create(args...); | |
| 428 | + auto obj = QPDFObject::create<T>(std::forward<Args>(args)...); | |
| 439 | 429 | obj->setDescription(context, description, input.getLastOffset()); |
| 440 | 430 | add(std::move(obj)); |
| 441 | 431 | } |
| ... | ... | @@ -444,7 +434,7 @@ template <typename T, typename... Args> |
| 444 | 434 | QPDFObjectHandle |
| 445 | 435 | QPDFParser::withDescription(Args&&... args) |
| 446 | 436 | { |
| 447 | - auto obj = T::create(args...); | |
| 437 | + auto obj = QPDFObject::create<T>(std::forward<Args>(args)...); | |
| 448 | 438 | obj->setDescription(context, description, start); |
| 449 | 439 | return {obj}; |
| 450 | 440 | } |
| ... | ... | @@ -462,8 +452,8 @@ QPDFParser::fixMissingKeys() |
| 462 | 452 | { |
| 463 | 453 | std::set<std::string> names; |
| 464 | 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 | 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 | 15 | #include <qpdf/Pl_StdioFile.hh> |
| 16 | 16 | #include <qpdf/QIntC.hh> |
| 17 | 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 | 20 | #include <qpdf/QTC.hh> |
| 22 | 21 | #include <qpdf/QUtil.hh> |
| 23 | 22 | #include <qpdf/RC4.hh> |
| ... | ... | @@ -27,6 +26,7 @@ |
| 27 | 26 | #include <stdexcept> |
| 28 | 27 | |
| 29 | 28 | using namespace std::literals; |
| 29 | +using namespace qpdf; | |
| 30 | 30 | |
| 31 | 31 | QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) |
| 32 | 32 | { |
| ... | ... | @@ -1129,12 +1129,12 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) |
| 1129 | 1129 | return; |
| 1130 | 1130 | } else if (!m->linearized) { |
| 1131 | 1131 | if (object.isArray()) { |
| 1132 | - for (auto& item: object.getArrayAsVector()) { | |
| 1132 | + for (auto& item: object.as_array()) { | |
| 1133 | 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 | 1138 | enqueueObject(item.second); |
| 1139 | 1139 | } |
| 1140 | 1140 | } |
| ... | ... | @@ -1173,10 +1173,13 @@ QPDFWriter::writeTrailer( |
| 1173 | 1173 | writeString(" /Size "); |
| 1174 | 1174 | writeString(std::to_string(size)); |
| 1175 | 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 | 1180 | writeStringQDF(" "); |
| 1178 | 1181 | writeStringNoQDF(" "); |
| 1179 | - writeString(QPDF_Name::normalizeName(key)); | |
| 1182 | + writeString(Name::normalize(key)); | |
| 1180 | 1183 | writeString(" "); |
| 1181 | 1184 | if (key == "/Size") { |
| 1182 | 1185 | writeString(std::to_string(size)); |
| ... | ... | @@ -1187,7 +1190,7 @@ QPDFWriter::writeTrailer( |
| 1187 | 1190 | writePad(QIntC::to_size(pos - m->pipeline->getCount() + 21)); |
| 1188 | 1191 | } |
| 1189 | 1192 | } else { |
| 1190 | - unparseChild(trailer.getKey(key), 1, 0); | |
| 1193 | + unparseChild(value, 1, 0); | |
| 1191 | 1194 | } |
| 1192 | 1195 | writeStringQDF("\n"); |
| 1193 | 1196 | } |
| ... | ... | @@ -1347,7 +1350,7 @@ QPDFWriter::unparseObject( |
| 1347 | 1350 | // [ in the /H key of the linearization parameter dictionary. We'll do this unconditionally |
| 1348 | 1351 | // for all arrays because it looks nicer and doesn't make the files that much bigger. |
| 1349 | 1352 | writeString("["); |
| 1350 | - for (auto const& item: object.getArrayAsVector()) { | |
| 1353 | + for (auto const& item: object.as_array()) { | |
| 1351 | 1354 | writeString(indent); |
| 1352 | 1355 | writeStringQDF(" "); |
| 1353 | 1356 | unparseChild(item, level + 1, child_flags); |
| ... | ... | @@ -1498,20 +1501,18 @@ QPDFWriter::unparseObject( |
| 1498 | 1501 | |
| 1499 | 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 | 1506 | writeString(indent); |
| 1505 | 1507 | writeStringQDF(" "); |
| 1506 | - writeString(QPDF_Name::normalizeName(key)); | |
| 1508 | + writeString(Name::normalize(key)); | |
| 1507 | 1509 | writeString(" "); |
| 1508 | 1510 | if (key == "/Contents" && object.isDictionaryOfType("/Sig") && |
| 1509 | 1511 | object.hasKey("/ByteRange")) { |
| 1510 | 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 | 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 | 1892 | } |
| 1892 | 1893 | seed += " QPDF "; |
| 1893 | 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 | 1897 | seed += " "; |
| 1899 | - seed += obj.getStringValue(); | |
| 1898 | + seed += item.second.getStringValue(); | |
| 1900 | 1899 | } |
| 1901 | 1900 | } |
| 1902 | 1901 | } |
| ... | ... | @@ -1922,8 +1921,7 @@ QPDFWriter::generateID() |
| 1922 | 1921 | void |
| 1923 | 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 | 1925 | std::vector<QPDFObjectHandle> pages = m->pdf.getAllPages(); |
| 1928 | 1926 | int num = 0; |
| 1929 | 1927 | for (auto& page: pages) { |
| ... | ... | @@ -2939,8 +2937,10 @@ QPDFWriter::enqueueObjectsStandard() |
| 2939 | 2937 | |
| 2940 | 2938 | // Next place any other objects referenced from the trailer dictionary into the queue, handling |
| 2941 | 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 | 2962 | |
| 2963 | 2963 | // enqueue all the strips for each page |
| 2964 | 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 | 3 | #include <qpdf/QTC.hh> |
| 7 | 4 | |
| 5 | +using namespace std::literals; | |
| 6 | +using namespace qpdf; | |
| 7 | + | |
| 8 | 8 | static const QPDFObjectHandle null_oh = QPDFObjectHandle::newNull(); |
| 9 | 9 | |
| 10 | 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 | 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 | 25 | if (sparse) { |
| 49 | 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 | 29 | sp->elements[sp->size] = std::move(item); |
| 53 | 30 | } |
| 54 | 31 | ++sp->size; |
| ... | ... | @@ -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 | 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 | 156 | if (n < 0 || n >= size()) { |
| 191 | 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 | 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 | 171 | std::vector<QPDFObjectHandle> v; |
| 205 | 172 | v.reserve(size_t(size())); |
| 206 | - for (auto const& item: sp->elements) { | |
| 173 | + for (auto const& item: a->sp->elements) { | |
| 207 | 174 | v.resize(size_t(item.first), null_oh); |
| 208 | 175 | v.emplace_back(item.second); |
| 209 | 176 | } |
| 210 | 177 | v.resize(size_t(size()), null_oh); |
| 211 | 178 | return v; |
| 212 | 179 | } else { |
| 213 | - return {elements.cbegin(), elements.cend()}; | |
| 180 | + return a->elements; | |
| 214 | 181 | } |
| 215 | 182 | } |
| 216 | 183 | |
| 217 | 184 | bool |
| 218 | -QPDF_Array::setAt(int at, QPDFObjectHandle const& oh) | |
| 185 | +Array::setAt(int at, QPDFObjectHandle const& oh) | |
| 219 | 186 | { |
| 220 | 187 | if (at < 0 || at >= size()) { |
| 221 | 188 | return false; |
| 222 | 189 | } |
| 190 | + auto a = array(); | |
| 223 | 191 | checkOwnership(oh); |
| 224 | - if (sp) { | |
| 225 | - sp->elements[at] = oh.getObj(); | |
| 192 | + if (a->sp) { | |
| 193 | + a->sp->elements[at] = oh; | |
| 226 | 194 | } else { |
| 227 | - elements[size_t(at)] = oh.getObj(); | |
| 195 | + a->elements[size_t(at)] = oh; | |
| 228 | 196 | } |
| 229 | 197 | return true; |
| 230 | 198 | } |
| 231 | 199 | |
| 232 | 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 | 206 | for (auto const& item: v) { |
| 238 | 207 | checkOwnership(item); |
| 239 | - elements.push_back(item.getObj()); | |
| 208 | + a->elements.emplace_back(item); | |
| 240 | 209 | } |
| 241 | 210 | } |
| 242 | 211 | |
| 243 | 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 | 216 | int sz = size(); |
| 247 | 217 | if (at < 0 || at > sz) { |
| 248 | 218 | // As special case, also allow insert beyond the end |
| ... | ... | @@ -251,61 +221,257 @@ QPDF_Array::insert(int at, QPDFObjectHandle const& item) |
| 251 | 221 | push_back(item); |
| 252 | 222 | } else { |
| 253 | 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 | 227 | auto key = (iter++)->first; |
| 258 | 228 | if (key >= at) { |
| 259 | - auto nh = sp->elements.extract(key); | |
| 229 | + auto nh = a->sp->elements.extract(key); | |
| 260 | 230 | ++nh.key(); |
| 261 | - sp->elements.insert(std::move(nh)); | |
| 231 | + a->sp->elements.insert(std::move(nh)); | |
| 262 | 232 | } else { |
| 263 | 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 | 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 | 242 | return true; |
| 273 | 243 | } |
| 274 | 244 | |
| 275 | 245 | void |
| 276 | -QPDF_Array::push_back(QPDFObjectHandle const& item) | |
| 246 | +Array::push_back(QPDFObjectHandle const& item) | |
| 277 | 247 | { |
| 248 | + auto a = array(); | |
| 278 | 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 | 252 | } else { |
| 282 | - elements.push_back(item.getObj()); | |
| 253 | + a->elements.emplace_back(item); | |
| 283 | 254 | } |
| 284 | 255 | } |
| 285 | 256 | |
| 286 | 257 | bool |
| 287 | -QPDF_Array::erase(int at) | |
| 258 | +Array::erase(int at) | |
| 288 | 259 | { |
| 260 | + auto a = array(); | |
| 289 | 261 | if (at < 0 || at >= size()) { |
| 290 | 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 | 267 | if (iter->first == at) { |
| 296 | 268 | iter++; |
| 297 | - sp->elements.erase(at); | |
| 269 | + a->sp->elements.erase(at); | |
| 298 | 270 | } |
| 299 | 271 | |
| 300 | 272 | while (iter != end) { |
| 301 | - auto nh = sp->elements.extract(iter++); | |
| 273 | + auto nh = a->sp->elements.extract(iter++); | |
| 302 | 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 | 279 | } else { |
| 308 | - elements.erase(elements.cbegin() + at); | |
| 280 | + a->elements.erase(a->elements.cbegin() + at); | |
| 309 | 281 | } |
| 310 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 3 | #include <qpdf/ContentNormalizer.hh> |
| 4 | 4 | #include <qpdf/JSON_writer.hh> |
| ... | ... | @@ -22,6 +22,9 @@ |
| 22 | 22 | |
| 23 | 23 | #include <stdexcept> |
| 24 | 24 | |
| 25 | +using namespace std::literals; | |
| 26 | +using namespace qpdf; | |
| 27 | + | |
| 25 | 28 | namespace |
| 26 | 29 | { |
| 27 | 30 | class SF_Crypt: public QPDFStreamFilter |
| ... | ... | @@ -60,16 +63,24 @@ namespace |
| 60 | 63 | class StreamBlobProvider |
| 61 | 64 | { |
| 62 | 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 | 77 | private: |
| 67 | - QPDF_Stream* stream; | |
| 78 | + Stream stream; | |
| 68 | 79 | qpdf_stream_decode_level_e decode_level; |
| 69 | 80 | }; |
| 70 | 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 | 84 | // The PDF specification provides these filter abbreviations for use in inline images, but |
| 74 | 85 | // according to table H.1 in the pre-ISO versions of the PDF specification, Adobe Reader also |
| 75 | 86 | // accepts them for stream filters. |
| ... | ... | @@ -82,8 +93,8 @@ std::map<std::string, std::string> QPDF_Stream::filter_abbreviations = { |
| 82 | 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 | 98 | {"/Crypt", []() { return std::make_shared<SF_Crypt>(); }}, |
| 88 | 99 | {"/FlateDecode", SF_FlateLzwDecode::flate_factory}, |
| 89 | 100 | {"/LZWDecode", SF_FlateLzwDecode::lzw_factory}, |
| ... | ... | @@ -93,90 +104,25 @@ std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>> |
| 93 | 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 | 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 | 119 | std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory) |
| 142 | 120 | { |
| 143 | 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 | 124 | JSON |
| 179 | -QPDF_Stream::getStreamJSON( | |
| 125 | +Stream::getStreamJSON( | |
| 180 | 126 | int json_version, |
| 181 | 127 | qpdf_json_stream_data_e json_data, |
| 182 | 128 | qpdf_stream_decode_level_e decode_level, |
| ... | ... | @@ -190,13 +136,13 @@ QPDF_Stream::getStreamJSON( |
| 190 | 136 | pb.finish(); |
| 191 | 137 | auto result = JSON::parse(pb.getString()); |
| 192 | 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 | 141 | return result; |
| 196 | 142 | } |
| 197 | 143 | |
| 198 | 144 | qpdf_stream_decode_level_e |
| 199 | -QPDF_Stream::writeStreamJSON( | |
| 145 | +Stream::writeStreamJSON( | |
| 200 | 146 | int json_version, |
| 201 | 147 | JSON::Writer& jw, |
| 202 | 148 | qpdf_json_stream_data_e json_data, |
| ... | ... | @@ -205,6 +151,7 @@ QPDF_Stream::writeStreamJSON( |
| 205 | 151 | std::string const& data_filename, |
| 206 | 152 | bool no_data_key) |
| 207 | 153 | { |
| 154 | + auto s = stream(); | |
| 208 | 155 | switch (json_data) { |
| 209 | 156 | case qpdf_sj_none: |
| 210 | 157 | case qpdf_sj_inline: |
| ... | ... | @@ -232,7 +179,7 @@ QPDF_Stream::writeStreamJSON( |
| 232 | 179 | if (json_data == qpdf_sj_none) { |
| 233 | 180 | jw.writeNext(); |
| 234 | 181 | jw << R"("dict": )"; |
| 235 | - stream_dict.writeJSON(json_version, jw); | |
| 182 | + s->stream_dict.writeJSON(json_version, jw); | |
| 236 | 183 | jw.writeEnd('}'); |
| 237 | 184 | return decode_level; |
| 238 | 185 | } |
| ... | ... | @@ -264,7 +211,7 @@ QPDF_Stream::writeStreamJSON( |
| 264 | 211 | throw std::logic_error("QPDF_Stream: failed to get stream data"); |
| 265 | 212 | } |
| 266 | 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 | 215 | dict.removeKey("/Length"); |
| 269 | 216 | if (filter && filtered) { |
| 270 | 217 | dict.removeKey("/Filter"); |
| ... | ... | @@ -290,53 +237,17 @@ QPDF_Stream::writeStreamJSON( |
| 290 | 237 | } |
| 291 | 238 | |
| 292 | 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 | 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 | 252 | Pl_Buffer buf("stream data buffer"); |
| 342 | 253 | bool filtered; |
| ... | ... | @@ -344,9 +255,9 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) |
| 344 | 255 | if (!filtered) { |
| 345 | 256 | throw QPDFExc( |
| 346 | 257 | qpdf_e_unsupported, |
| 347 | - qpdf->getFilename(), | |
| 258 | + obj->getQPDF()->getFilename(), | |
| 348 | 259 | "", |
| 349 | - this->parsed_offset, | |
| 260 | + obj->getParsedOffset(), | |
| 350 | 261 | "getStreamData called on unfilterable stream"); |
| 351 | 262 | } |
| 352 | 263 | QTC::TC("qpdf", "QPDF_Stream getStreamData"); |
| ... | ... | @@ -354,15 +265,15 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) |
| 354 | 265 | } |
| 355 | 266 | |
| 356 | 267 | std::shared_ptr<Buffer> |
| 357 | -QPDF_Stream::getRawStreamData() | |
| 268 | +Stream::getRawStreamData() | |
| 358 | 269 | { |
| 359 | 270 | Pl_Buffer buf("stream data buffer"); |
| 360 | 271 | if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) { |
| 361 | 272 | throw QPDFExc( |
| 362 | 273 | qpdf_e_unsupported, |
| 363 | - qpdf->getFilename(), | |
| 274 | + obj->getQPDF()->getFilename(), | |
| 364 | 275 | "", |
| 365 | - this->parsed_offset, | |
| 276 | + obj->getParsedOffset(), | |
| 366 | 277 | "error getting raw stream data"); |
| 367 | 278 | } |
| 368 | 279 | QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); |
| ... | ... | @@ -370,14 +281,15 @@ QPDF_Stream::getRawStreamData() |
| 370 | 281 | } |
| 371 | 282 | |
| 372 | 283 | bool |
| 373 | -QPDF_Stream::filterable( | |
| 284 | +Stream::filterable( | |
| 374 | 285 | std::vector<std::shared_ptr<QPDFStreamFilter>>& filters, |
| 375 | 286 | bool& specialized_compression, |
| 376 | 287 | bool& lossy_compression) |
| 377 | 288 | { |
| 289 | + auto s = stream(); | |
| 378 | 290 | // Check filters |
| 379 | 291 | |
| 380 | - QPDFObjectHandle filter_obj = this->stream_dict.getKey("/Filter"); | |
| 292 | + QPDFObjectHandle filter_obj = s->stream_dict.getKey("/Filter"); | |
| 381 | 293 | bool filters_okay = true; |
| 382 | 294 | |
| 383 | 295 | std::vector<std::string> filter_names; |
| ... | ... | @@ -432,7 +344,7 @@ QPDF_Stream::filterable( |
| 432 | 344 | |
| 433 | 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 | 348 | std::vector<QPDFObjectHandle> decode_parms; |
| 437 | 349 | if (decode_obj.isArray() && (decode_obj.getArrayNItems() == 0)) { |
| 438 | 350 | decode_obj = QPDFObjectHandle::newNull(); |
| ... | ... | @@ -479,7 +391,7 @@ QPDF_Stream::filterable( |
| 479 | 391 | } |
| 480 | 392 | |
| 481 | 393 | bool |
| 482 | -QPDF_Stream::pipeStreamData( | |
| 394 | +Stream::pipeStreamData( | |
| 483 | 395 | Pipeline* pipeline, |
| 484 | 396 | bool* filterp, |
| 485 | 397 | int encode_flags, |
| ... | ... | @@ -487,6 +399,7 @@ QPDF_Stream::pipeStreamData( |
| 487 | 399 | bool suppress_warnings, |
| 488 | 400 | bool will_retry) |
| 489 | 401 | { |
| 402 | + auto s = stream(); | |
| 490 | 403 | std::vector<std::shared_ptr<QPDFStreamFilter>> filters; |
| 491 | 404 | bool specialized_compression = false; |
| 492 | 405 | bool lossy_compression = false; |
| ... | ... | @@ -543,7 +456,7 @@ QPDF_Stream::pipeStreamData( |
| 543 | 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 | 460 | new_pipeline = |
| 548 | 461 | std::make_shared<Pl_QPDFTokenizer>("token filter", (*iter).get(), pipeline); |
| 549 | 462 | to_delete.push_back(new_pipeline); |
| ... | ... | @@ -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 | 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 | 481 | pipeline->finish(); |
| 569 | - } else if (this->stream_provider.get()) { | |
| 482 | + } else if (s->stream_provider.get()) { | |
| 570 | 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 | 487 | filter = false; |
| 575 | 488 | success = false; |
| 576 | 489 | } |
| 577 | 490 | } else { |
| 578 | - this->stream_provider->provideStreamData(og, &count); | |
| 491 | + s->stream_provider->provideStreamData(obj->getObjGen(), &count); | |
| 579 | 492 | } |
| 580 | 493 | qpdf_offset_t actual_length = count.getCount(); |
| 581 | 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 | 497 | if (actual_length == desired_length) { |
| 585 | 498 | QTC::TC("qpdf", "QPDF_Stream pipe use stream provider"); |
| 586 | 499 | } else { |
| ... | ... | @@ -588,25 +501,25 @@ QPDF_Stream::pipeStreamData( |
| 588 | 501 | // This would be caused by programmer error on the part of a library user, not by |
| 589 | 502 | // invalid input data. |
| 590 | 503 | throw std::runtime_error( |
| 591 | - "stream data provider for " + og.unparse(' ') + " provided " + | |
| 504 | + "stream data provider for " + obj->getObjGen().unparse(' ') + " provided " + | |
| 592 | 505 | std::to_string(actual_length) + " bytes instead of expected " + |
| 593 | 506 | std::to_string(desired_length) + " bytes"); |
| 594 | 507 | } |
| 595 | 508 | } else if (success) { |
| 596 | 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 | 513 | QTC::TC("qpdf", "QPDF_Stream pipe no stream data"); |
| 601 | 514 | throw std::logic_error("pipeStreamData called for stream with no data"); |
| 602 | 515 | } else { |
| 603 | 516 | QTC::TC("qpdf", "QPDF_Stream pipe original stream data"); |
| 604 | 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 | 523 | pipeline, |
| 611 | 524 | suppress_warnings, |
| 612 | 525 | will_retry)) { |
| ... | ... | @@ -634,60 +547,235 @@ QPDF_Stream::pipeStreamData( |
| 634 | 547 | } |
| 635 | 548 | |
| 636 | 549 | void |
| 637 | -QPDF_Stream::replaceStreamData( | |
| 550 | +Stream::replaceStreamData( | |
| 638 | 551 | std::shared_ptr<Buffer> data, |
| 639 | 552 | QPDFObjectHandle const& filter, |
| 640 | 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 | 558 | replaceFilterData(filter, decode_parms, data->getSize()); |
| 645 | 559 | } |
| 646 | 560 | |
| 647 | 561 | void |
| 648 | -QPDF_Stream::replaceStreamData( | |
| 562 | +Stream::replaceStreamData( | |
| 649 | 563 | std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider, |
| 650 | 564 | QPDFObjectHandle const& filter, |
| 651 | 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 | 570 | replaceFilterData(filter, decode_parms, 0); |
| 656 | 571 | } |
| 657 | 572 | |
| 658 | 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 | 575 | QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length) |
| 667 | 576 | { |
| 577 | + auto s = stream(); | |
| 668 | 578 | if (filter) { |
| 669 | - stream_dict.replaceKey("/Filter", filter); | |
| 579 | + s->stream_dict.replaceKey("/Filter", filter); | |
| 670 | 580 | } |
| 671 | 581 | if (decode_parms) { |
| 672 | - stream_dict.replaceKey("/DecodeParms", decode_parms); | |
| 582 | + s->stream_dict.replaceKey("/DecodeParms", decode_parms); | |
| 673 | 583 | } |
| 674 | 584 | if (length == 0) { |
| 675 | 585 | QTC::TC("qpdf", "QPDF_Stream unknown stream length"); |
| 676 | - stream_dict.removeKey("/Length"); | |
| 586 | + s->stream_dict.removeKey("/Length"); | |
| 677 | 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 | 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 | 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 | 4 | #include <qpdf/QUtil.hh> |
| 5 | 5 | |
| 6 | 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 | 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 | 15 | std::shared_ptr<QPDFObject> |
| 28 | 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 | if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) { |
| 32 | 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 | 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 | 5 | #include <qpdf/Pl_Base64.hh> |
| 6 | 6 | #include <qpdf/Pl_StdioFile.hh> |
| 7 | 7 | #include <qpdf/QIntC.hh> |
| 8 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 8 | 9 | #include <qpdf/QPDFObject_private.hh> |
| 9 | -#include <qpdf/QPDFValue.hh> | |
| 10 | -#include <qpdf/QPDF_Null.hh> | |
| 11 | -#include <qpdf/QPDF_Stream.hh> | |
| 12 | 10 | #include <qpdf/QTC.hh> |
| 13 | 11 | #include <qpdf/QUtil.hh> |
| 14 | 12 | #include <algorithm> |
| ... | ... | @@ -238,8 +236,8 @@ class QPDF::JSONReactor: public JSON::Reactor |
| 238 | 236 | is(is), |
| 239 | 237 | must_be_complete(must_be_complete), |
| 240 | 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 | 243 | ~JSONReactor() override = default; |
| ... | ... | @@ -286,7 +284,7 @@ class QPDF::JSONReactor: public JSON::Reactor |
| 286 | 284 | QPDF& pdf; |
| 287 | 285 | std::shared_ptr<InputSource> is; |
| 288 | 286 | bool must_be_complete{true}; |
| 289 | - std::shared_ptr<QPDFValue::Description> descr; | |
| 287 | + std::shared_ptr<QPDFObject::Description> descr; | |
| 290 | 288 | bool errors{false}; |
| 291 | 289 | bool saw_qpdf{false}; |
| 292 | 290 | bool saw_qpdf_meta{false}; |
| ... | ... | @@ -576,8 +574,8 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) |
| 576 | 574 | } else { |
| 577 | 575 | this_stream_needs_data = true; |
| 578 | 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 | 579 | value); |
| 582 | 580 | } |
| 583 | 581 | next_obj = tos.object; |
| ... | ... | @@ -706,10 +704,10 @@ QPDF::JSONReactor::arrayItem(JSON const& value) |
| 706 | 704 | void |
| 707 | 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 | 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 | 713 | oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart()); |
| ... | ... | @@ -821,7 +819,7 @@ void |
| 821 | 819 | writeJSONStreamFile( |
| 822 | 820 | int version, |
| 823 | 821 | JSON::Writer& jw, |
| 824 | - QPDF_Stream& stream, | |
| 822 | + qpdf::Stream& stream, | |
| 825 | 823 | int id, |
| 826 | 824 | qpdf_stream_decode_level_e decode_level, |
| 827 | 825 | std::string const& file_prefix) |
| ... | ... | @@ -894,13 +892,13 @@ QPDF::writeJSON( |
| 894 | 892 | } else { |
| 895 | 893 | jw << "\n },\n \"" << key; |
| 896 | 894 | } |
| 897 | - if (auto* stream = obj.getObjectPtr()->as<QPDF_Stream>()) { | |
| 895 | + if (auto stream = obj.as_stream()) { | |
| 898 | 896 | jw << "\": {\n \"stream\": "; |
| 899 | 897 | if (json_stream_data == qpdf_sj_file) { |
| 900 | 898 | writeJSONStreamFile( |
| 901 | - version, jw, *stream, og.getObj(), decode_level, file_prefix); | |
| 899 | + version, jw, stream, og.getObj(), decode_level, file_prefix); | |
| 902 | 900 | } else { |
| 903 | - stream->writeStreamJSON( | |
| 901 | + stream.writeStreamJSON( | |
| 904 | 902 | version, jw, json_stream_data, decode_level, nullptr, ""); |
| 905 | 903 | } |
| 906 | 904 | } else { | ... | ... |
libqpdf/QPDF_optimization.cc
| ... | ... | @@ -5,9 +5,8 @@ |
| 5 | 5 | #include <qpdf/QPDF.hh> |
| 6 | 6 | |
| 7 | 7 | #include <qpdf/QPDFExc.hh> |
| 8 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 8 | 9 | #include <qpdf/QPDFWriter_private.hh> |
| 9 | -#include <qpdf/QPDF_Array.hh> | |
| 10 | -#include <qpdf/QPDF_Dictionary.hh> | |
| 11 | 10 | #include <qpdf/QTC.hh> |
| 12 | 11 | |
| 13 | 12 | QPDF::ObjUser::ObjUser() : |
| ... | ... | @@ -115,24 +114,25 @@ QPDF::optimize_internal( |
| 115 | 114 | } |
| 116 | 115 | |
| 117 | 116 | // Traverse document-level items |
| 118 | - for (auto const& key: m->trailer.getKeys()) { | |
| 117 | + for (auto const& [key, value]: m->trailer.as_dictionary()) { | |
| 119 | 118 | if (key == "/Root") { |
| 120 | 119 | // handled separately |
| 121 | 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 | 129 | // Technically, /I keys from /Thread dictionaries are supposed to be handled separately, but |
| 131 | 130 | // we are going to disregard that specification for now. There is loads of evidence that |
| 132 | 131 | // pdlin and Acrobat both disregard things like this from time to time, so this is almost |
| 133 | 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 | 138 | ObjUser root_ou = ObjUser(ObjUser::ou_root); |
| ... | ... | @@ -319,9 +319,8 @@ QPDF::updateObjectMaps( |
| 319 | 319 | } |
| 320 | 320 | |
| 321 | 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 | 325 | } else if (cur.oh.isDictionary() || cur.oh.isStream()) { |
| 327 | 326 | QPDFObjectHandle dict = cur.oh; |
| ... | ... | @@ -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 | 341 | if (is_page_node && (key == "/Thumb")) { |
| 339 | 342 | // Traverse page thumbnail dictionaries as a special case. There can only ever |
| 340 | 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 | 350 | ((ssp >= 2) && ((key == "/Filter") || (key == "/DecodeParms")))) { |
| 348 | 351 | // Don't traverse into stream parameters that we are not going to write. |
| 349 | 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 | 1 | #include <qpdf/QPDF.hh> |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/QPDFExc.hh> |
| 4 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 4 | 5 | #include <qpdf/QTC.hh> |
| 5 | 6 | #include <qpdf/QUtil.hh> |
| 6 | 7 | |
| ... | ... | @@ -108,9 +109,9 @@ QPDF::getAllPagesInternal( |
| 108 | 109 | QTC::TC("qpdf", "QPDF inherit mediabox", media_box ? 0 : 1); |
| 109 | 110 | } |
| 110 | 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 | 115 | if (!kid.isDictionary()) { |
| 115 | 116 | kid.warnIfPossible("Pages tree includes non-dictionary object; ignoring"); |
| 116 | 117 | m->invalid_page_found = true; |
| ... | ... | @@ -133,7 +134,6 @@ QPDF::getAllPagesInternal( |
| 133 | 134 | cur_node.warnIfPossible( |
| 134 | 135 | "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect"); |
| 135 | 136 | kid = makeIndirectObject(kid); |
| 136 | - kids.setArrayItem(i, kid); | |
| 137 | 137 | } else if (!seen.add(kid)) { |
| 138 | 138 | // Make a copy of the page. This does the same as shallowCopyPage in |
| 139 | 139 | // QPDFPageObjectHelper. |
| ... | ... | @@ -144,7 +144,6 @@ QPDF::getAllPagesInternal( |
| 144 | 144 | " creating a new page object as a copy"); |
| 145 | 145 | kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy()); |
| 146 | 146 | seen.add(kid); |
| 147 | - kids.setArrayItem(i, kid); | |
| 148 | 147 | } |
| 149 | 148 | if (!kid.isDictionaryOfType("/Page")) { |
| 150 | 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 | 6 | |
| 7 | 7 | #include <qpdf/Constants.h> |
| 8 | 8 | #include <qpdf/JSON.hh> |
| 9 | +#include <qpdf/JSON_writer.hh> | |
| 9 | 10 | #include <qpdf/QPDF.hh> |
| 10 | -#include <qpdf/QPDFValue.hh> | |
| 11 | +#include <qpdf/QPDFObjGen.hh> | |
| 11 | 12 | #include <qpdf/Types.h> |
| 12 | 13 | |
| 14 | +#include <map> | |
| 15 | +#include <memory> | |
| 13 | 16 | #include <string> |
| 14 | 17 | #include <string_view> |
| 18 | +#include <variant> | |
| 19 | +#include <vector> | |
| 15 | 20 | |
| 16 | -class QPDF; | |
| 21 | +class QPDFObject; | |
| 17 | 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 | 145 | std::shared_ptr<QPDFObject> parent, |
| 81 | 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 | 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 | 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 | 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 | 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 | 354 | bool |
| 158 | 355 | isUnresolved() const |
| 159 | 356 | { |
| 160 | - return value->type_code == ::ot_unresolved; | |
| 357 | + return getTypeCode() == ::ot_unresolved; | |
| 161 | 358 | } |
| 162 | 359 | const QPDFObject* |
| 163 | 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 | 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 | 481 | QPDFObject(QPDFObject const&) = delete; |
| 183 | 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 | 491 | #endif // QPDFOBJECT_HH | ... | ... |
libqpdf/qpdf/QPDFParser.hh
| 1 | 1 | #ifndef QPDFPARSER_HH |
| 2 | 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 | 7 | #include <memory> |
| 8 | 8 | #include <string> |
| ... | ... | @@ -24,7 +24,7 @@ class QPDFParser |
| 24 | 24 | decrypter(decrypter), |
| 25 | 25 | context(context), |
| 26 | 26 | description( |
| 27 | - std::make_shared<QPDFValue::Description>( | |
| 27 | + std::make_shared<QPDFObject::Description>( | |
| 28 | 28 | std::string(input.getName() + ", " + object_description + " at offset $PO"))), |
| 29 | 29 | parse_pdf(parse_pdf) |
| 30 | 30 | { |
| ... | ... | @@ -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 | 50 | std::map<std::string, QPDFObjectHandle> dict; |
| 51 | 51 | parser_state_e state; |
| 52 | 52 | std::string key; |
| ... | ... | @@ -78,7 +78,7 @@ class QPDFParser |
| 78 | 78 | QPDFTokenizer& tokenizer; |
| 79 | 79 | QPDFObjectHandle::StringDecrypter* decrypter; |
| 80 | 80 | QPDF* context; |
| 81 | - std::shared_ptr<QPDFValue::Description> description; | |
| 81 | + std::shared_ptr<QPDFObject::Description> description; | |
| 82 | 82 | bool parse_pdf; |
| 83 | 83 | |
| 84 | 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 | 1 | #include <qpdf/assert_test.h> |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/QPDF.hh> |
| 4 | -#include <qpdf/QPDFObjectHandle.hh> | |
| 4 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 5 | 5 | #include <qpdf/QPDFObject_private.hh> |
| 6 | -#include <qpdf/QPDF_Array.hh> | |
| 7 | 6 | |
| 8 | 7 | #include <iostream> |
| 9 | 8 | |
| 10 | 9 | int |
| 11 | 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 | 15 | assert(a.size() == 0); |
| 17 | 16 | |
| ... | ... | @@ -88,16 +87,17 @@ main() |
| 88 | 87 | QPDF pdf; |
| 89 | 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 | 93 | b.setAt(5, pdf.newIndirectNull()); |
| 94 | 94 | b.setAt(7, "[0 1 2 3]"_qpdf); |
| 95 | 95 | assert(b.at(3).second.isNull()); |
| 96 | 96 | assert(b.at(8).second.isNull()); |
| 97 | 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 | 101 | b.at(7).second.setArrayItem(2, "42"_qpdf); |
| 102 | 102 | assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]"); |
| 103 | 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 | 109 | print_size(QPDFNumberTreeObjectHelper); |
| 110 | 110 | print_size(QPDFNumberTreeObjectHelper::iterator); |
| 111 | 111 | print_size(QPDFObjGen); |
| 112 | - print_size(QPDFObjGen::set); | |
| 113 | 112 | print_size(QPDFObjectHandle); |
| 114 | 113 | print_size(QPDFObjectHandle::ParserCallbacks); |
| 115 | 114 | print_size(QPDFObjectHandle::QPDFArrayItems); |
| ... | ... | @@ -118,6 +117,7 @@ main() |
| 118 | 117 | print_size(QPDFObjectHandle::QPDFDictItems::iterator); |
| 119 | 118 | print_size(QPDFObjectHandle::StreamDataProvider); |
| 120 | 119 | print_size(QPDFObjectHandle::TokenFilter); |
| 120 | + print_size(QPDFObjectHelper); | |
| 121 | 121 | print_size(QPDFOutlineDocumentHelper); |
| 122 | 122 | print_size(QPDFOutlineObjectHelper); |
| 123 | 123 | print_size(QPDFPageDocumentHelper); | ... | ... |