Commit 8f54319f7a6514110f4b05cbbf1cb1c9fc8cb6a0

Authored by m-holger
Committed by GitHub
2 parents 4b245364 266d4797

Merge pull request #1179 from m-holger/null

In FUTURE, treat uninitialized object handles as null
examples/pdf-mod-info.cc
@@ -131,7 +131,7 @@ main(int argc, char* argv[]) @@ -131,7 +131,7 @@ main(int argc, char* argv[])
131 QPDFObjectHandle fileinfo; 131 QPDFObjectHandle fileinfo;
132 132
133 for (auto const& it: Keys) { 133 for (auto const& it: Keys) {
134 - if (!fileinfo.isInitialized()) { 134 + if (!fileinfo) {
135 if (filetrailer.hasKey("/Info")) { 135 if (filetrailer.hasKey("/Info")) {
136 QTC::TC("examples", "pdf-mod-info has info"); 136 QTC::TC("examples", "pdf-mod-info has info");
137 fileinfo = filetrailer.getKey("/Info"); 137 fileinfo = filetrailer.getKey("/Info");
include/qpdf/QPDFObjectHandle.hh
@@ -295,8 +295,12 @@ class QPDFObjectHandle @@ -295,8 +295,12 @@ class QPDFObjectHandle
295 QPDF_DLL 295 QPDF_DLL
296 QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default; 296 QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default;
297 297
  298 + // Return true if the QPDFObjectHandle is initialized. This allows object handles to be used in
  299 + // if statements with initializer.
298 QPDF_DLL 300 QPDF_DLL
299 - inline bool isInitialized() const; 301 + explicit inline operator bool() const noexcept;
  302 +
  303 + [[deprecated("use operator bool()")]] QPDF_DLL inline bool isInitialized() const;
300 304
301 // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying 305 // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying
302 // object, meaning that changes to one are reflected in the other, or "if you paint one, the 306 // object, meaning that changes to one are reflected in the other, or "if you paint one, the
@@ -1634,5 +1638,10 @@ QPDFObjectHandle::isInitialized() const @@ -1634,5 +1638,10 @@ QPDFObjectHandle::isInitialized() const
1634 return obj != nullptr; 1638 return obj != nullptr;
1635 } 1639 }
1636 1640
  1641 +inline QPDFObjectHandle::operator bool() const noexcept
  1642 +{
  1643 + return static_cast<bool>(obj);
  1644 +}
  1645 +
1637 #endif // QPDF_FUTURE 1646 #endif // QPDF_FUTURE
1638 #endif // QPDFOBJECTHANDLE_HH 1647 #endif // QPDFOBJECTHANDLE_HH
include/qpdf/QPDFObjectHandle_future.hh
@@ -295,8 +295,12 @@ class QPDFObjectHandle @@ -295,8 +295,12 @@ class QPDFObjectHandle
295 QPDF_DLL 295 QPDF_DLL
296 QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default; 296 QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default;
297 297
  298 + // Return true if the QPDFObjectHandle is initialized. This allows object handles to be used in
  299 + // if statements with initializer.
298 QPDF_DLL 300 QPDF_DLL
299 - inline bool isInitialized() const noexcept; 301 + explicit inline operator bool() const noexcept;
  302 +
  303 + [[deprecated("use operator bool()")]] QPDF_DLL inline bool isInitialized() const noexcept;
300 304
301 // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying 305 // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying
302 // object, meaning that changes to one are reflected in the other, or "if you paint one, the 306 // object, meaning that changes to one are reflected in the other, or "if you paint one, the
@@ -1634,4 +1638,9 @@ QPDFObjectHandle::isInitialized() const noexcept @@ -1634,4 +1638,9 @@ QPDFObjectHandle::isInitialized() const noexcept
1634 return obj != nullptr; 1638 return obj != nullptr;
1635 } 1639 }
1636 1640
  1641 +inline QPDFObjectHandle::operator bool() const noexcept
  1642 +{
  1643 + return static_cast<bool>(obj);
  1644 +}
  1645 +
1637 #endif // QPDFOBJECTHANDLE_FUTURE_HH 1646 #endif // QPDFOBJECTHANDLE_FUTURE_HH
libqpdf/NNTree.cc
@@ -188,7 +188,7 @@ NNTreeIterator::resetLimits(QPDFObjectHandle node, std::list&lt;PathElement&gt;::itera @@ -188,7 +188,7 @@ NNTreeIterator::resetLimits(QPDFObjectHandle node, std::list&lt;PathElement&gt;::itera
188 } 188 }
189 } 189 }
190 } 190 }
191 - if (first.isInitialized() && last.isInitialized()) { 191 + if (first && last) {
192 auto limits = QPDFObjectHandle::newArray(); 192 auto limits = QPDFObjectHandle::newArray();
193 limits.appendItem(first); 193 limits.appendItem(first);
194 limits.appendItem(last); 194 limits.appendItem(last);
libqpdf/QPDF.cc
@@ -526,7 +526,7 @@ QPDF::warn( @@ -526,7 +526,7 @@ QPDF::warn(
526 void 526 void
527 QPDF::setTrailer(QPDFObjectHandle obj) 527 QPDF::setTrailer(QPDFObjectHandle obj)
528 { 528 {
529 - if (m->trailer.isInitialized()) { 529 + if (m->trailer) {
530 return; 530 return;
531 } 531 }
532 m->trailer = obj; 532 m->trailer = obj;
@@ -591,7 +591,7 @@ QPDF::reconstruct_xref(QPDFExc&amp; e) @@ -591,7 +591,7 @@ QPDF::reconstruct_xref(QPDFExc&amp; e)
591 } 591 }
592 } 592 }
593 m->file->seek(pos, SEEK_SET); 593 m->file->seek(pos, SEEK_SET);
594 - } else if (!m->trailer.isInitialized() && t1.isWord("trailer")) { 594 + } else if (!m->trailer && t1.isWord("trailer")) {
595 auto pos = m->file->tell(); 595 auto pos = m->file->tell();
596 QPDFObjectHandle t = readTrailer(); 596 QPDFObjectHandle t = readTrailer();
597 if (!t.isDictionary()) { 597 if (!t.isDictionary()) {
@@ -606,7 +606,7 @@ QPDF::reconstruct_xref(QPDFExc&amp; e) @@ -606,7 +606,7 @@ QPDF::reconstruct_xref(QPDFExc&amp; e)
606 } 606 }
607 m->deleted_objects.clear(); 607 m->deleted_objects.clear();
608 608
609 - if (!m->trailer.isInitialized()) { 609 + if (!m->trailer) {
610 qpdf_offset_t max_offset{0}; 610 qpdf_offset_t max_offset{0};
611 // If there are any xref streams, take the last one to appear. 611 // If there are any xref streams, take the last one to appear.
612 for (auto const& iter: m->xref_table) { 612 for (auto const& iter: m->xref_table) {
@@ -640,7 +640,7 @@ QPDF::reconstruct_xref(QPDFExc&amp; e) @@ -640,7 +640,7 @@ QPDF::reconstruct_xref(QPDFExc&amp; e)
640 } 640 }
641 } 641 }
642 642
643 - if (!m->trailer.isInitialized()) { 643 + if (!m->trailer) {
644 // We could check the last encountered object to see if it was an xref stream. If so, we 644 // We could check the last encountered object to see if it was an xref stream. If so, we
645 // could try to get the trailer from there. This may make it possible to recover files with 645 // could try to get the trailer from there. This may make it possible to recover files with
646 // bad startxref pointers even when they have object streams. 646 // bad startxref pointers even when they have object streams.
@@ -730,7 +730,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) @@ -730,7 +730,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
730 } 730 }
731 } 731 }
732 732
733 - if (!m->trailer.isInitialized()) { 733 + if (!m->trailer) {
734 throw damagedPDF("", 0, "unable to find trailer while reading xref"); 734 throw damagedPDF("", 0, "unable to find trailer while reading xref");
735 } 735 }
736 int size = m->trailer.getKey("/Size").getIntValueAsInt(); 736 int size = m->trailer.getKey("/Size").getIntValueAsInt();
@@ -1000,7 +1000,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) @@ -1000,7 +1000,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
1000 throw damagedPDF("", "expected trailer dictionary"); 1000 throw damagedPDF("", "expected trailer dictionary");
1001 } 1001 }
1002 1002
1003 - if (!m->trailer.isInitialized()) { 1003 + if (!m->trailer) {
1004 setTrailer(cur_trailer); 1004 setTrailer(cur_trailer);
1005 1005
1006 if (!m->trailer.hasKey("/Size")) { 1006 if (!m->trailer.hasKey("/Size")) {
@@ -1258,7 +1258,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle&amp; xref_obj) @@ -1258,7 +1258,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle&amp; xref_obj)
1258 } 1258 }
1259 } 1259 }
1260 1260
1261 - if (!m->trailer.isInitialized()) { 1261 + if (!m->trailer) {
1262 setTrailer(dict); 1262 setTrailer(dict);
1263 } 1263 }
1264 1264
@@ -2052,7 +2052,7 @@ QPDF::makeIndirectFromQPDFObject(std::shared_ptr&lt;QPDFObject&gt; const&amp; obj) @@ -2052,7 +2052,7 @@ QPDF::makeIndirectFromQPDFObject(std::shared_ptr&lt;QPDFObject&gt; const&amp; obj)
2052 QPDFObjectHandle 2052 QPDFObjectHandle
2053 QPDF::makeIndirectObject(QPDFObjectHandle oh) 2053 QPDF::makeIndirectObject(QPDFObjectHandle oh)
2054 { 2054 {
2055 - if (!oh.isInitialized()) { 2055 + if (!oh) {
2056 throw std::logic_error("attempted to make an uninitialized QPDFObjectHandle indirect"); 2056 throw std::logic_error("attempted to make an uninitialized QPDFObjectHandle indirect");
2057 } 2057 }
2058 return makeIndirectFromQPDFObject(oh.getObj()); 2058 return makeIndirectFromQPDFObject(oh.getObj());
@@ -2163,7 +2163,7 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh) @@ -2163,7 +2163,7 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
2163 void 2163 void
2164 QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh) 2164 QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
2165 { 2165 {
2166 - if (!oh.isInitialized() || (oh.isIndirect() && !(oh.isStream() && oh.getObjGen() == og))) { 2166 + if (!oh || (oh.isIndirect() && !(oh.isStream() && oh.getObjGen() == og))) {
2167 QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); 2167 QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
2168 throw std::logic_error("QPDF::replaceObject called with indirect object handle"); 2168 throw std::logic_error("QPDF::replaceObject called with indirect object handle");
2169 } 2169 }
libqpdf/QPDFFormFieldObjectHelper.cc
@@ -396,7 +396,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) @@ -396,7 +396,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
396 } else { 396 } else {
397 annot = kid; 397 annot = kid;
398 } 398 }
399 - if (!annot.isInitialized()) { 399 + if (!annot) {
400 QTC::TC("qpdf", "QPDFObjectHandle broken radio button"); 400 QTC::TC("qpdf", "QPDFObjectHandle broken radio button");
401 this->oh.warnIfPossible("unable to set the value of this radio button"); 401 this->oh.warnIfPossible("unable to set the value of this radio button");
402 continue; 402 continue;
@@ -459,7 +459,7 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) @@ -459,7 +459,7 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value)
459 // Set /AS to the on value or /Off in addition to setting /V. 459 // Set /AS to the on value or /Off in addition to setting /V.
460 QPDFObjectHandle name = QPDFObjectHandle::newName(value ? on_value : "/Off"); 460 QPDFObjectHandle name = QPDFObjectHandle::newName(value ? on_value : "/Off");
461 setFieldAttribute("/V", name); 461 setFieldAttribute("/V", name);
462 - if (!annot.isInitialized()) { 462 + if (!annot) {
463 QTC::TC("qpdf", "QPDFObjectHandle broken checkbox"); 463 QTC::TC("qpdf", "QPDFObjectHandle broken checkbox");
464 this->oh.warnIfPossible("unable to set the value of this checkbox"); 464 this->oh.warnIfPossible("unable to set the value of this checkbox");
465 return; 465 return;
@@ -815,7 +815,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper&amp; ao @@ -815,7 +815,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper&amp; ao
815 QPDFObjectHandle resources = AS.getDict().getKey("/Resources"); 815 QPDFObjectHandle resources = AS.getDict().getKey("/Resources");
816 QPDFObjectHandle font = getFontFromResource(resources, font_name); 816 QPDFObjectHandle font = getFontFromResource(resources, font_name);
817 bool found_font_in_dr = false; 817 bool found_font_in_dr = false;
818 - if (!font.isInitialized()) { 818 + if (!font) {
819 QPDFObjectHandle dr = getDefaultResources(); 819 QPDFObjectHandle dr = getDefaultResources();
820 font = getFontFromResource(dr, font_name); 820 font = getFontFromResource(dr, font_name);
821 found_font_in_dr = font.isDictionary(); 821 found_font_in_dr = font.isDictionary();
libqpdf/QPDFObjectHandle.cc
@@ -1021,8 +1021,9 @@ QPDFObjectHandle::getArrayItem(int n) const @@ -1021,8 +1021,9 @@ QPDFObjectHandle::getArrayItem(int n) const
1021 #endif 1021 #endif
1022 { 1022 {
1023 if (auto array = asArray()) { 1023 if (auto array = asArray()) {
1024 - if (auto result = array->at(n); result.obj != nullptr) {  
1025 - return result; 1024 + auto result = array->at(n);
  1025 + if (result.first) {
  1026 + return result.second;
1026 } else { 1027 } else {
1027 objectWarning("returning null for out of bounds array access"); 1028 objectWarning("returning null for out of bounds array access");
1028 QTC::TC("qpdf", "QPDFObjectHandle array bounds"); 1029 QTC::TC("qpdf", "QPDFObjectHandle array bounds");
@@ -1045,7 +1046,7 @@ QPDFObjectHandle::isRectangle() const @@ -1045,7 +1046,7 @@ QPDFObjectHandle::isRectangle() const
1045 { 1046 {
1046 if (auto array = asArray()) { 1047 if (auto array = asArray()) {
1047 for (int i = 0; i < 4; ++i) { 1048 for (int i = 0; i < 4; ++i) {
1048 - if (auto item = array->at(i); !(item.obj && item.isNumber())) { 1049 + if (auto item = array->at(i).second; !item.isNumber()) {
1049 return false; 1050 return false;
1050 } 1051 }
1051 } 1052 }
@@ -1064,7 +1065,7 @@ QPDFObjectHandle::isMatrix() const @@ -1064,7 +1065,7 @@ QPDFObjectHandle::isMatrix() const
1064 { 1065 {
1065 if (auto array = asArray()) { 1066 if (auto array = asArray()) {
1066 for (int i = 0; i < 6; ++i) { 1067 for (int i = 0; i < 6; ++i) {
1067 - if (auto item = array->at(i); !(item.obj && item.isNumber())) { 1068 + if (auto item = array->at(i).second; !item.isNumber()) {
1068 return false; 1069 return false;
1069 } 1070 }
1070 } 1071 }
@@ -1087,7 +1088,7 @@ QPDFObjectHandle::getArrayAsRectangle() const @@ -1087,7 +1088,7 @@ QPDFObjectHandle::getArrayAsRectangle() const
1087 } 1088 }
1088 double items[4]; 1089 double items[4];
1089 for (int i = 0; i < 4; ++i) { 1090 for (int i = 0; i < 4; ++i) {
1090 - if (!array->at(i).getValueAsNumber(items[i])) { 1091 + if (auto item = array->at(i).second; !item.getValueAsNumber(items[i])) {
1091 return {}; 1092 return {};
1092 } 1093 }
1093 } 1094 }
@@ -1114,7 +1115,7 @@ QPDFObjectHandle::getArrayAsMatrix() const @@ -1114,7 +1115,7 @@ QPDFObjectHandle::getArrayAsMatrix() const
1114 } 1115 }
1115 double items[6]; 1116 double items[6];
1116 for (int i = 0; i < 6; ++i) { 1117 for (int i = 0; i < 6; ++i) {
1117 - if (!array->at(i).getValueAsNumber(items[i])) { 1118 + if (auto item = array->at(i).second; !item.getValueAsNumber(items[i])) {
1118 return {}; 1119 return {};
1119 } 1120 }
1120 } 1121 }
@@ -1224,7 +1225,7 @@ QPDFObjectHandle @@ -1224,7 +1225,7 @@ QPDFObjectHandle
1224 QPDFObjectHandle::eraseItemAndGetOld(int at) 1225 QPDFObjectHandle::eraseItemAndGetOld(int at)
1225 { 1226 {
1226 auto array = asArray(); 1227 auto array = asArray();
1227 - auto result = (array && at < array->size() && at >= 0) ? array->at(at) : newNull(); 1228 + auto result = (array && at < array->size() && at >= 0) ? array->at(at).second : newNull();
1228 eraseItem(at); 1229 eraseItem(at);
1229 return result; 1230 return result;
1230 } 1231 }
@@ -1764,7 +1765,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( @@ -1764,7 +1765,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
1764 if (auto array = asArray()) { 1765 if (auto array = asArray()) {
1765 int n_items = array->size(); 1766 int n_items = array->size();
1766 for (int i = 0; i < n_items; ++i) { 1767 for (int i = 0; i < n_items; ++i) {
1767 - QPDFObjectHandle item = array->at(i); 1768 + QPDFObjectHandle item = array->at(i).second;
1768 if (item.isStream()) { 1769 if (item.isStream()) {
1769 result.push_back(item); 1770 result.push_back(item);
1770 } else { 1771 } else {
@@ -2165,7 +2166,7 @@ QPDFObjectHandle::parseContentStream_data( @@ -2165,7 +2166,7 @@ QPDFObjectHandle::parseContentStream_data(
2165 input->seek(offset, SEEK_SET); 2166 input->seek(offset, SEEK_SET);
2166 auto obj = 2167 auto obj =
2167 QPDFParser(*input, "content", tokenizer, nullptr, context, false).parse(empty, true); 2168 QPDFParser(*input, "content", tokenizer, nullptr, context, false).parse(empty, true);
2168 - if (!obj.isInitialized()) { 2169 + if (!obj) {
2169 // EOF 2170 // EOF
2170 break; 2171 break;
2171 } 2172 }
@@ -2465,7 +2466,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams) @@ -2465,7 +2466,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
2465 auto array = asArray(); 2466 auto array = asArray();
2466 int n = array->size(); 2467 int n = array->size();
2467 for (int i = 0; i < n; ++i) { 2468 for (int i = 0; i < n; ++i) {
2468 - items.push_back(array->at(i)); 2469 + items.push_back(array->at(i).second);
2469 items.back().makeDirect(visited, stop_at_streams); 2470 items.back().makeDirect(visited, stop_at_streams);
2470 } 2471 }
2471 this->obj = QPDF_Array::create(items); 2472 this->obj = QPDF_Array::create(items);
@@ -2520,7 +2521,7 @@ QPDFObjectHandle::makeDirect(bool allow_streams) @@ -2520,7 +2521,7 @@ QPDFObjectHandle::makeDirect(bool allow_streams)
2520 void 2521 void
2521 QPDFObjectHandle::assertInitialized() const 2522 QPDFObjectHandle::assertInitialized() const
2522 { 2523 {
2523 - if (!isInitialized()) { 2524 + if (!obj) {
2524 throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle"); 2525 throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle");
2525 } 2526 }
2526 } 2527 }
@@ -3018,34 +3019,30 @@ QPDFObjectHandle::QPDFArrayItems::end() @@ -3018,34 +3019,30 @@ QPDFObjectHandle::QPDFArrayItems::end()
3018 QPDFObjGen 3019 QPDFObjGen
3019 QPDFObjectHandle::getObjGen() const 3020 QPDFObjectHandle::getObjGen() const
3020 { 3021 {
3021 - return isInitialized() ? obj->getObjGen() : QPDFObjGen(); 3022 + return obj ? obj->getObjGen() : QPDFObjGen();
3022 } 3023 }
3023 3024
3024 // Indirect object accessors 3025 // Indirect object accessors
3025 QPDF* 3026 QPDF*
3026 QPDFObjectHandle::getOwningQPDF() const 3027 QPDFObjectHandle::getOwningQPDF() const
3027 { 3028 {
3028 - return isInitialized() ? this->obj->getQPDF() : nullptr; 3029 + return obj ? obj->getQPDF() : nullptr;
3029 } 3030 }
3030 3031
3031 QPDF& 3032 QPDF&
3032 QPDFObjectHandle::getQPDF(std::string const& error_msg) const 3033 QPDFObjectHandle::getQPDF(std::string const& error_msg) const
3033 { 3034 {
3034 - auto result = isInitialized() ? this->obj->getQPDF() : nullptr;  
3035 - if (result == nullptr) {  
3036 - throw std::runtime_error(  
3037 - error_msg.empty() ? "attempt to use a null qpdf object" : error_msg); 3035 + if (auto result = obj ? obj->getQPDF() : nullptr) {
  3036 + return *result;
3038 } 3037 }
3039 - return *result; 3038 + throw std::runtime_error(error_msg.empty() ? "attempt to use a null qpdf object" : error_msg);
3040 } 3039 }
3041 3040
3042 void 3041 void
3043 QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset) 3042 QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset)
3044 { 3043 {
3045 - // This is called during parsing on newly created direct objects,  
3046 - // so we can't call dereference() here.  
3047 - if (isInitialized()) {  
3048 - this->obj->setParsedOffset(offset); 3044 + if (obj) {
  3045 + obj->setParsedOffset(offset);
3049 } 3046 }
3050 } 3047 }
3051 3048
libqpdf/QPDFOutlineDocumentHelper.cc
@@ -67,7 +67,7 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name) @@ -67,7 +67,7 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
67 { 67 {
68 QPDFObjectHandle result; 68 QPDFObjectHandle result;
69 if (name.isName()) { 69 if (name.isName()) {
70 - if (!m->dest_dict.isInitialized()) { 70 + if (!m->dest_dict) {
71 m->dest_dict = qpdf.getRoot().getKey("/Dests"); 71 m->dest_dict = qpdf.getRoot().getKey("/Dests");
72 } 72 }
73 QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest"); 73 QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest");
@@ -85,7 +85,7 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name) @@ -85,7 +85,7 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
85 } 85 }
86 } 86 }
87 } 87 }
88 - if (!result.isInitialized()) { 88 + if (!result) {
89 return QPDFObjectHandle::newNull(); 89 return QPDFObjectHandle::newNull();
90 } 90 }
91 if (result.isDictionary()) { 91 if (result.isDictionary()) {
libqpdf/QPDFOutlineObjectHelper.cc
@@ -59,8 +59,8 @@ QPDFOutlineObjectHelper::getDest() @@ -59,8 +59,8 @@ QPDFOutlineObjectHelper::getDest()
59 QTC::TC("qpdf", "QPDFOutlineObjectHelper action dest"); 59 QTC::TC("qpdf", "QPDFOutlineObjectHelper action dest");
60 dest = A.getKey("/D"); 60 dest = A.getKey("/D");
61 } 61 }
62 - if (!dest.isInitialized()) {  
63 - dest = QPDFObjectHandle::newNull(); 62 + if (!dest) {
  63 + return QPDFObjectHandle::newNull();
64 } 64 }
65 65
66 if (dest.isName() || dest.isString()) { 66 if (dest.isName() || dest.isString()) {
libqpdf/QPDFWriter.cc
@@ -1381,7 +1381,7 @@ QPDFWriter::unparseObject( @@ -1381,7 +1381,7 @@ QPDFWriter::unparseObject(
1381 } 1381 }
1382 } 1382 }
1383 1383
1384 - if (extensions.isInitialized()) { 1384 + if (extensions) {
1385 std::set<std::string> keys = extensions.getKeys(); 1385 std::set<std::string> keys = extensions.getKeys();
1386 if (keys.count("/ADBE") > 0) { 1386 if (keys.count("/ADBE") > 0) {
1387 have_extensions_adbe = true; 1387 have_extensions_adbe = true;
@@ -1412,7 +1412,7 @@ QPDFWriter::unparseObject( @@ -1412,7 +1412,7 @@ QPDFWriter::unparseObject(
1412 } 1412 }
1413 } 1413 }
1414 1414
1415 - if (extensions.isInitialized()) { 1415 + if (extensions) {
1416 QTC::TC("qpdf", "QPDFWriter preserve Extensions"); 1416 QTC::TC("qpdf", "QPDFWriter preserve Extensions");
1417 QPDFObjectHandle adbe = extensions.getKey("/ADBE"); 1417 QPDFObjectHandle adbe = extensions.getKey("/ADBE");
1418 if (adbe.isDictionary() && 1418 if (adbe.isDictionary() &&
libqpdf/QPDF_Array.cc
@@ -184,16 +184,16 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer&amp; p) @@ -184,16 +184,16 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer&amp; p)
184 p.writeEnd(']'); 184 p.writeEnd(']');
185 } 185 }
186 186
187 -QPDFObjectHandle 187 +std::pair<bool, QPDFObjectHandle>
188 QPDF_Array::at(int n) const noexcept 188 QPDF_Array::at(int n) const noexcept
189 { 189 {
190 if (n < 0 || n >= size()) { 190 if (n < 0 || n >= size()) {
191 - return {}; 191 + return {false, {}};
192 } else if (sp) { 192 } else if (sp) {
193 auto const& iter = sp->elements.find(n); 193 auto const& iter = sp->elements.find(n);
194 - return iter == sp->elements.end() ? null_oh : (*iter).second; 194 + return {true, iter == sp->elements.end() ? null_oh : (*iter).second};
195 } else { 195 } else {
196 - return elements[size_t(n)]; 196 + return {true, elements[size_t(n)]};
197 } 197 }
198 } 198 }
199 199
libqpdf/QPDF_Stream.cc
@@ -661,18 +661,17 @@ void @@ -661,18 +661,17 @@ void
661 QPDF_Stream::replaceFilterData( 661 QPDF_Stream::replaceFilterData(
662 QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length) 662 QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length)
663 { 663 {
664 - if (filter.isInitialized()) {  
665 - this->stream_dict.replaceKey("/Filter", filter); 664 + if (filter) {
  665 + stream_dict.replaceKey("/Filter", filter);
666 } 666 }
667 - if (decode_parms.isInitialized()) {  
668 - this->stream_dict.replaceKey("/DecodeParms", decode_parms); 667 + if (decode_parms) {
  668 + stream_dict.replaceKey("/DecodeParms", decode_parms);
669 } 669 }
670 if (length == 0) { 670 if (length == 0) {
671 QTC::TC("qpdf", "QPDF_Stream unknown stream length"); 671 QTC::TC("qpdf", "QPDF_Stream unknown stream length");
672 - this->stream_dict.removeKey("/Length"); 672 + stream_dict.removeKey("/Length");
673 } else { 673 } else {
674 - this->stream_dict.replaceKey(  
675 - "/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length))); 674 + stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length)));
676 } 675 }
677 } 676 }
678 677
libqpdf/QPDF_json.cc
@@ -325,7 +325,7 @@ QPDF::JSONReactor::anyErrors() const @@ -325,7 +325,7 @@ QPDF::JSONReactor::anyErrors() const
325 void 325 void
326 QPDF::JSONReactor::containerStart() 326 QPDF::JSONReactor::containerStart()
327 { 327 {
328 - if (next_obj.isInitialized()) { 328 + if (next_obj) {
329 stack.emplace_back(next_state, std::move(next_obj)); 329 stack.emplace_back(next_state, std::move(next_obj));
330 next_obj = QPDFObjectHandle(); 330 next_obj = QPDFObjectHandle();
331 } else { 331 } else {
@@ -558,7 +558,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value) @@ -558,7 +558,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value)
558 throw std::logic_error("stack empty in st_object_top"); 558 throw std::logic_error("stack empty in st_object_top");
559 } 559 }
560 auto& tos = stack.back(); 560 auto& tos = stack.back();
561 - if (!tos.object.isInitialized()) { 561 + if (!tos.object) {
562 throw std::logic_error("current object uninitialized in st_object_top"); 562 throw std::logic_error("current object uninitialized in st_object_top");
563 } 563 }
564 if (key == "value") { 564 if (key == "value") {
@@ -767,7 +767,7 @@ QPDF::JSONReactor::makeObject(JSON const&amp; value) @@ -767,7 +767,7 @@ QPDF::JSONReactor::makeObject(JSON const&amp; value)
767 result = QPDFObjectHandle::newNull(); 767 result = QPDFObjectHandle::newNull();
768 } 768 }
769 } 769 }
770 - if (!result.isInitialized()) { 770 + if (!result) {
771 throw std::logic_error("JSONReactor::makeObject didn't initialize the object"); 771 throw std::logic_error("JSONReactor::makeObject didn't initialize the object");
772 } 772 }
773 773
libqpdf/qpdf-c.cc
@@ -955,7 +955,7 @@ qpdf_oh_is_initialized(qpdf_data qpdf, qpdf_oh oh) @@ -955,7 +955,7 @@ qpdf_oh_is_initialized(qpdf_data qpdf, qpdf_oh oh)
955 { 955 {
956 QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_initialized"); 956 QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_initialized");
957 return do_with_oh<QPDF_BOOL>( 957 return do_with_oh<QPDF_BOOL>(
958 - qpdf, oh, return_false, [](QPDFObjectHandle& o) { return o.isInitialized(); }); 958 + qpdf, oh, return_false, [](QPDFObjectHandle& o) { return static_cast<bool>(o); });
959 } 959 }
960 960
961 QPDF_BOOL 961 QPDF_BOOL
libqpdf/qpdf/QPDF_Array.hh
@@ -30,7 +30,7 @@ class QPDF_Array: public QPDFValue @@ -30,7 +30,7 @@ class QPDF_Array: public QPDFValue
30 { 30 {
31 return sp ? sp->size : int(elements.size()); 31 return sp ? sp->size : int(elements.size());
32 } 32 }
33 - QPDFObjectHandle at(int n) const noexcept; 33 + std::pair<bool, QPDFObjectHandle> at(int n) const noexcept;
34 bool setAt(int n, QPDFObjectHandle const& oh); 34 bool setAt(int n, QPDFObjectHandle const& oh);
35 std::vector<QPDFObjectHandle> getAsVector() const; 35 std::vector<QPDFObjectHandle> getAsVector() const;
36 void setFromVector(std::vector<QPDFObjectHandle> const& items); 36 void setFromVector(std::vector<QPDFObjectHandle> const& items);
libtests/sparse_array.cc
@@ -21,69 +21,69 @@ main() @@ -21,69 +21,69 @@ main()
21 a.push_back(QPDFObjectHandle::parse("null")); 21 a.push_back(QPDFObjectHandle::parse("null"));
22 a.push_back(QPDFObjectHandle::parse("/Quack")); 22 a.push_back(QPDFObjectHandle::parse("/Quack"));
23 assert(a.size() == 5); 23 assert(a.size() == 5);
24 - assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1));  
25 - assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato"));  
26 - assert(a.at(2).isNull());  
27 - assert(a.at(3).isNull());  
28 - assert(a.at(4).isName() && (a.at(4).getName() == "/Quack")); 24 + assert(a.at(0).second.isInteger() && (a.at(0).second.getIntValue() == 1));
  25 + assert(a.at(1).second.isString() && (a.at(1).second.getStringValue() == "potato"));
  26 + assert(a.at(2).second.isNull());
  27 + assert(a.at(3).second.isNull());
  28 + assert(a.at(4).second.isName() && (a.at(4).second.getName() == "/Quack"));
29 29
30 a.insert(4, QPDFObjectHandle::parse("/BeforeQuack")); 30 a.insert(4, QPDFObjectHandle::parse("/BeforeQuack"));
31 assert(a.size() == 6); 31 assert(a.size() == 6);
32 - assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1));  
33 - assert(a.at(4).isName() && (a.at(4).getName() == "/BeforeQuack"));  
34 - assert(a.at(5).isName() && (a.at(5).getName() == "/Quack")); 32 + assert(a.at(0).second.isInteger() && (a.at(0).second.getIntValue() == 1));
  33 + assert(a.at(4).second.isName() && (a.at(4).second.getName() == "/BeforeQuack"));
  34 + assert(a.at(5).second.isName() && (a.at(5).second.getName() == "/Quack"));
35 35
36 a.insert(2, QPDFObjectHandle::parse("/Third")); 36 a.insert(2, QPDFObjectHandle::parse("/Third"));
37 assert(a.size() == 7); 37 assert(a.size() == 7);
38 - assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato"));  
39 - assert(a.at(2).isName() && (a.at(2).getName() == "/Third"));  
40 - assert(a.at(3).isNull());  
41 - assert(a.at(6).isName() && (a.at(6).getName() == "/Quack")); 38 + assert(a.at(1).second.isString() && (a.at(1).second.getStringValue() == "potato"));
  39 + assert(a.at(2).second.isName() && (a.at(2).second.getName() == "/Third"));
  40 + assert(a.at(3).second.isNull());
  41 + assert(a.at(6).second.isName() && (a.at(6).second.getName() == "/Quack"));
42 42
43 a.insert(0, QPDFObjectHandle::parse("/First")); 43 a.insert(0, QPDFObjectHandle::parse("/First"));
44 assert(a.size() == 8); 44 assert(a.size() == 8);
45 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
46 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
47 - assert(a.at(7).isName() && (a.at(7).getName() == "/Quack")); 45 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  46 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  47 + assert(a.at(7).second.isName() && (a.at(7).second.getName() == "/Quack"));
48 48
49 a.erase(6); 49 a.erase(6);
50 assert(a.size() == 7); 50 assert(a.size() == 7);
51 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
52 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
53 - assert(a.at(5).isNull());  
54 - assert(a.at(6).isName() && (a.at(6).getName() == "/Quack")); 51 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  52 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  53 + assert(a.at(5).second.isNull());
  54 + assert(a.at(6).second.isName() && (a.at(6).second.getName() == "/Quack"));
55 55
56 a.erase(6); 56 a.erase(6);
57 assert(a.size() == 6); 57 assert(a.size() == 6);
58 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
59 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
60 - assert(a.at(3).isName() && (a.at(3).getName() == "/Third"));  
61 - assert(a.at(4).isNull());  
62 - assert(a.at(5).isNull()); 58 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  59 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  60 + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
  61 + assert(a.at(4).second.isNull());
  62 + assert(a.at(5).second.isNull());
63 63
64 a.setAt(4, QPDFObjectHandle::parse("12")); 64 a.setAt(4, QPDFObjectHandle::parse("12"));
65 - assert(a.at(4).isInteger() && (a.at(4).getIntValue() == 12)); 65 + assert(a.at(4).second.isInteger() && (a.at(4).second.getIntValue() == 12));
66 a.setAt(4, QPDFObjectHandle::newNull()); 66 a.setAt(4, QPDFObjectHandle::newNull());
67 - assert(a.at(4).isNull()); 67 + assert(a.at(4).second.isNull());
68 68
69 a.erase(a.size() - 1); 69 a.erase(a.size() - 1);
70 assert(a.size() == 5); 70 assert(a.size() == 5);
71 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
72 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
73 - assert(a.at(3).isName() && (a.at(3).getName() == "/Third"));  
74 - assert(a.at(4).isNull()); 71 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  72 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  73 + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
  74 + assert(a.at(4).second.isNull());
75 75
76 a.erase(a.size() - 1); 76 a.erase(a.size() - 1);
77 assert(a.size() == 4); 77 assert(a.size() == 4);
78 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
79 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
80 - assert(a.at(3).isName() && (a.at(3).getName() == "/Third")); 78 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  79 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  80 + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
81 81
82 a.erase(a.size() - 1); 82 a.erase(a.size() - 1);
83 assert(a.size() == 3); 83 assert(a.size() == 3);
84 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
85 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
86 - assert(a.at(2).isString() && (a.at(2).getStringValue() == "potato")); 84 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  85 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  86 + assert(a.at(2).second.isString() && (a.at(2).second.getStringValue() == "potato"));
87 87
88 QPDF pdf; 88 QPDF pdf;
89 pdf.emptyPDF(); 89 pdf.emptyPDF();
@@ -92,13 +92,13 @@ main() @@ -92,13 +92,13 @@ main()
92 QPDF_Array& b = *obj->as<QPDF_Array>(); 92 QPDF_Array& b = *obj->as<QPDF_Array>();
93 b.setAt(5, pdf.newIndirectNull()); 93 b.setAt(5, pdf.newIndirectNull());
94 b.setAt(7, "[0 1 2 3]"_qpdf); 94 b.setAt(7, "[0 1 2 3]"_qpdf);
95 - assert(b.at(3).isNull());  
96 - assert(b.at(8).isNull());  
97 - assert(b.at(5).isIndirect()); 95 + assert(b.at(3).second.isNull());
  96 + assert(b.at(8).second.isNull());
  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 ]"); 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); 99 auto c = b.copy(true);
100 auto d = b.copy(false); 100 auto d = b.copy(false);
101 - b.at(7).setArrayItem(2, "42"_qpdf); 101 + b.at(7).second.setArrayItem(2, "42"_qpdf);
102 assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]"); 102 assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]");
103 assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); 103 assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
104 104
qpdf/test_driver.cc
@@ -1428,7 +1428,7 @@ test_42(QPDF&amp; pdf, char const* arg2) @@ -1428,7 +1428,7 @@ test_42(QPDF&amp; pdf, char const* arg2)
1428 assert(i == ai.end()); 1428 assert(i == ai.end());
1429 ++i; 1429 ++i;
1430 assert(i == ai.end()); 1430 assert(i == ai.end());
1431 - assert(!i_value.isInitialized()); 1431 + assert(!i_value);
1432 --i; 1432 --i;
1433 assert(i_value.getName() == "/Item2"); 1433 assert(i_value.getName() == "/Item2");
1434 assert(i->getName() == "/Item2"); 1434 assert(i->getName() == "/Item2");
@@ -1444,7 +1444,7 @@ test_42(QPDF&amp; pdf, char const* arg2) @@ -1444,7 +1444,7 @@ test_42(QPDF&amp; pdf, char const* arg2)
1444 ++i; 1444 ++i;
1445 ++i; 1445 ++i;
1446 assert(i == di.end()); 1446 assert(i == di.end());
1447 - assert(!i_value.second.isInitialized()); 1447 + assert(!i_value.second);
1448 } 1448 }
1449 assert("" == qtest.getStringValue()); 1449 assert("" == qtest.getStringValue());
1450 array.getArrayItem(-1).assertNull(); 1450 array.getArrayItem(-1).assertNull();
@@ -1542,7 +1542,7 @@ test_42(QPDF&amp; pdf, char const* arg2) @@ -1542,7 +1542,7 @@ test_42(QPDF&amp; pdf, char const* arg2)
1542 assert(m1.a == 0 && m1.b == 0 && m1.c == 0 && m1.d == 0 && m1.e == 0 && m1.f == 0); 1542 assert(m1.a == 0 && m1.b == 0 && m1.c == 0 && m1.d == 0 && m1.e == 0 && m1.f == 0);
1543 // Uninitialized 1543 // Uninitialized
1544 QPDFObjectHandle uninitialized; 1544 QPDFObjectHandle uninitialized;
1545 - assert(!uninitialized.isInitialized()); 1545 + assert(!uninitialized);
1546 assert(!uninitialized.isInteger()); 1546 assert(!uninitialized.isInteger());
1547 assert(!uninitialized.isDictionary()); 1547 assert(!uninitialized.isDictionary());
1548 assert(!uninitialized.isScalar()); 1548 assert(!uninitialized.isScalar());
@@ -1692,7 +1692,7 @@ test_46(QPDF&amp; pdf, char const* arg2) @@ -1692,7 +1692,7 @@ test_46(QPDF&amp; pdf, char const* arg2)
1692 assert(iter1_val.first == 2); 1692 assert(iter1_val.first == 2);
1693 ++iter1; 1693 ++iter1;
1694 assert(iter1 == new1.end()); 1694 assert(iter1 == new1.end());
1695 - assert(!iter1_val.second.isInitialized()); 1695 + assert(!iter1_val.second);
1696 ++iter1; 1696 ++iter1;
1697 assert(iter1->first == 1); 1697 assert(iter1->first == 1);
1698 --iter1; 1698 --iter1;
@@ -1842,7 +1842,7 @@ test_48(QPDF&amp; pdf, char const* arg2) @@ -1842,7 +1842,7 @@ test_48(QPDF&amp; pdf, char const* arg2)
1842 assert(iter1_val.first == "2"); 1842 assert(iter1_val.first == "2");
1843 ++iter1; 1843 ++iter1;
1844 assert(iter1 == new1.end()); 1844 assert(iter1 == new1.end());
1845 - assert(!iter1_val.second.isInitialized()); 1845 + assert(!iter1_val.second);
1846 ++iter1; 1846 ++iter1;
1847 assert(iter1->first == "1"); 1847 assert(iter1->first == "1");
1848 --iter1; 1848 --iter1;