Commit 05a49cecf1b1caa12575fa34fa478560ba25e31b
1 parent
a85635b8
Add new method QPDF::newReserved
Showing
4 changed files
with
37 additions
and
13 deletions
include/qpdf/QPDF.hh
| @@ -413,6 +413,24 @@ class QPDF | @@ -413,6 +413,24 @@ class QPDF | ||
| 413 | QPDF_DLL | 413 | QPDF_DLL |
| 414 | QPDFObjectHandle newStream(std::string const& data); | 414 | QPDFObjectHandle newStream(std::string const& data); |
| 415 | 415 | ||
| 416 | + // A reserved object is a special sentinel used for qpdf to | ||
| 417 | + // reserve a spot for an object that is going to be added to the | ||
| 418 | + // QPDF object. Normally you don't have to use this type since | ||
| 419 | + // you can just call QPDF::makeIndirectObject. However, in some | ||
| 420 | + // cases, if you have to create objects with circular references, | ||
| 421 | + // you may need to create a reserved object so that you can have a | ||
| 422 | + // reference to it and then replace the object later. Reserved | ||
| 423 | + // objects have the special property that they can't be resolved | ||
| 424 | + // to direct objects. This makes it possible to replace a | ||
| 425 | + // reserved object with a new object while preserving existing | ||
| 426 | + // references to them. When you are ready to replace a reserved | ||
| 427 | + // object with its replacement, use QPDF::replaceReserved for this | ||
| 428 | + // purpose rather than the more general QPDF::replaceObject. It | ||
| 429 | + // is an error to try to write a QPDF with QPDFWriter if it has | ||
| 430 | + // any reserved objects in it. | ||
| 431 | + QPDF_DLL | ||
| 432 | + QPDFObjectHandle newReserved(); | ||
| 433 | + | ||
| 416 | // Install this object handle as an indirect object and return an | 434 | // Install this object handle as an indirect object and return an |
| 417 | // indirect reference to it. | 435 | // indirect reference to it. |
| 418 | QPDF_DLL | 436 | QPDF_DLL |
include/qpdf/QPDFObjectHandle.hh
| @@ -668,7 +668,8 @@ class QPDFObjectHandle | @@ -668,7 +668,8 @@ class QPDFObjectHandle | ||
| 668 | // object with its replacement, use QPDF::replaceReserved for this | 668 | // object with its replacement, use QPDF::replaceReserved for this |
| 669 | // purpose rather than the more general QPDF::replaceObject. It | 669 | // purpose rather than the more general QPDF::replaceObject. It |
| 670 | // is an error to try to write a QPDF with QPDFWriter if it has | 670 | // is an error to try to write a QPDF with QPDFWriter if it has |
| 671 | - // any reserved objects in it. | 671 | + // any reserved objects in it. From QPDF 11.4, you can |
| 672 | + // call QPDF::newReserved() instead. | ||
| 672 | QPDF_DLL | 673 | QPDF_DLL |
| 673 | static QPDFObjectHandle newReserved(QPDF* qpdf); | 674 | static QPDFObjectHandle newReserved(QPDF* qpdf); |
| 674 | 675 |
libqpdf/QPDF.cc
| @@ -4,13 +4,13 @@ | @@ -4,13 +4,13 @@ | ||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <atomic> | 6 | #include <atomic> |
| 7 | +#include <cstdlib> | ||
| 8 | +#include <cstring> | ||
| 7 | #include <limits> | 9 | #include <limits> |
| 8 | #include <map> | 10 | #include <map> |
| 9 | #include <memory.h> | 11 | #include <memory.h> |
| 10 | #include <regex> | 12 | #include <regex> |
| 11 | #include <sstream> | 13 | #include <sstream> |
| 12 | -#include <cstdlib> | ||
| 13 | -#include <cstring> | ||
| 14 | #include <vector> | 14 | #include <vector> |
| 15 | 15 | ||
| 16 | #include <qpdf/BufferInputSource.hh> | 16 | #include <qpdf/BufferInputSource.hh> |
| @@ -1985,6 +1985,12 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) | @@ -1985,6 +1985,12 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) | ||
| 1985 | } | 1985 | } |
| 1986 | 1986 | ||
| 1987 | QPDFObjectHandle | 1987 | QPDFObjectHandle |
| 1988 | +QPDF::newReserved() | ||
| 1989 | +{ | ||
| 1990 | + return makeIndirectFromQPDFObject(QPDF_Reserved::create()); | ||
| 1991 | +} | ||
| 1992 | + | ||
| 1993 | +QPDFObjectHandle | ||
| 1988 | QPDF::newStream() | 1994 | QPDF::newStream() |
| 1989 | { | 1995 | { |
| 1990 | return makeIndirectFromQPDFObject(QPDF_Stream::create( | 1996 | return makeIndirectFromQPDFObject(QPDF_Stream::create( |
| @@ -2207,9 +2213,8 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top) | @@ -2207,9 +2213,8 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top) | ||
| 2207 | QTC::TC("qpdf", "QPDF copy indirect"); | 2213 | QTC::TC("qpdf", "QPDF copy indirect"); |
| 2208 | if (obj_copier.object_map.count(foreign_og) == 0) { | 2214 | if (obj_copier.object_map.count(foreign_og) == 0) { |
| 2209 | obj_copier.to_copy.push_back(foreign); | 2215 | obj_copier.to_copy.push_back(foreign); |
| 2210 | - obj_copier.object_map[foreign_og] = foreign.isStream() | ||
| 2211 | - ? newStream() | ||
| 2212 | - : QPDFObjectHandle::newReserved(this); | 2216 | + obj_copier.object_map[foreign_og] = |
| 2217 | + foreign.isStream() ? newStream() : newReserved(); | ||
| 2213 | } | 2218 | } |
| 2214 | } | 2219 | } |
| 2215 | 2220 | ||
| @@ -2528,9 +2533,7 @@ QPDF::getCompressibleObjGens() | @@ -2528,9 +2533,7 @@ QPDF::getCompressibleObjGens() | ||
| 2528 | if (obj.isStream()) { | 2533 | if (obj.isStream()) { |
| 2529 | QPDFObjectHandle dict = obj.getDict(); | 2534 | QPDFObjectHandle dict = obj.getDict(); |
| 2530 | std::set<std::string> keys = dict.getKeys(); | 2535 | std::set<std::string> keys = dict.getKeys(); |
| 2531 | - for (auto iter = keys.rbegin(); | ||
| 2532 | - iter != keys.rend(); | ||
| 2533 | - ++iter) { | 2536 | + for (auto iter = keys.rbegin(); iter != keys.rend(); ++iter) { |
| 2534 | std::string const& key = *iter; | 2537 | std::string const& key = *iter; |
| 2535 | QPDFObjectHandle value = dict.getKey(key); | 2538 | QPDFObjectHandle value = dict.getKey(key); |
| 2536 | if (key == "/Length") { | 2539 | if (key == "/Length") { |
| @@ -2544,9 +2547,7 @@ QPDF::getCompressibleObjGens() | @@ -2544,9 +2547,7 @@ QPDF::getCompressibleObjGens() | ||
| 2544 | } | 2547 | } |
| 2545 | } else if (obj.isDictionary()) { | 2548 | } else if (obj.isDictionary()) { |
| 2546 | std::set<std::string> keys = obj.getKeys(); | 2549 | std::set<std::string> keys = obj.getKeys(); |
| 2547 | - for (auto iter = keys.rbegin(); | ||
| 2548 | - iter != keys.rend(); | ||
| 2549 | - ++iter) { | 2550 | + for (auto iter = keys.rbegin(); iter != keys.rend(); ++iter) { |
| 2550 | queue.push_front(obj.getKey(*iter)); | 2551 | queue.push_front(obj.getKey(*iter)); |
| 2551 | } | 2552 | } |
| 2552 | } else if (obj.isArray()) { | 2553 | } else if (obj.isArray()) { |
libqpdf/QPDFObjectHandle.cc
| @@ -2128,7 +2128,11 @@ QPDFObjectHandle::newStream(QPDF* qpdf, std::string const& data) | @@ -2128,7 +2128,11 @@ QPDFObjectHandle::newStream(QPDF* qpdf, std::string const& data) | ||
| 2128 | QPDFObjectHandle | 2128 | QPDFObjectHandle |
| 2129 | QPDFObjectHandle::newReserved(QPDF* qpdf) | 2129 | QPDFObjectHandle::newReserved(QPDF* qpdf) |
| 2130 | { | 2130 | { |
| 2131 | - return qpdf->makeIndirectObject(QPDFObjectHandle(QPDF_Reserved::create())); | 2131 | + if (qpdf == nullptr) { |
| 2132 | + throw std::runtime_error( | ||
| 2133 | + "attempt to create reserved object in null qpdf object"); | ||
| 2134 | + } | ||
| 2135 | + return qpdf->newReserved(); | ||
| 2132 | } | 2136 | } |
| 2133 | 2137 | ||
| 2134 | void | 2138 | void |