Commit 7061ee1ce14c33b64ab4e12b79882aa4cb43cfcf
1 parent
1a1c640a
Refactor `QPDFParser` internal `parse` methods to return uninitialized object ha…
…ndles on invalid input..
Showing
1 changed file
with
67 additions
and
50 deletions
libqpdf/QPDFParser.cc
| ... | ... | @@ -52,15 +52,18 @@ QPDFParser::parse(InputSource& input, std::string const& object_description, QPD |
| 52 | 52 | { |
| 53 | 53 | qpdf::Tokenizer tokenizer; |
| 54 | 54 | bool empty = false; |
| 55 | - return QPDFParser( | |
| 56 | - input, | |
| 57 | - make_description(input.getName(), object_description), | |
| 58 | - object_description, | |
| 59 | - tokenizer, | |
| 60 | - nullptr, | |
| 61 | - context, | |
| 62 | - false) | |
| 63 | - .parse(empty, false); | |
| 55 | + if (auto result = QPDFParser( | |
| 56 | + input, | |
| 57 | + make_description(input.getName(), object_description), | |
| 58 | + object_description, | |
| 59 | + tokenizer, | |
| 60 | + nullptr, | |
| 61 | + context, | |
| 62 | + false) | |
| 63 | + .parse(empty, false)) { | |
| 64 | + return result; | |
| 65 | + } | |
| 66 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 64 | 67 | } |
| 65 | 68 | |
| 66 | 69 | QPDFObjectHandle |
| ... | ... | @@ -71,18 +74,22 @@ QPDFParser::parse_content( |
| 71 | 74 | QPDF* context) |
| 72 | 75 | { |
| 73 | 76 | bool empty = false; |
| 74 | - return QPDFParser( | |
| 75 | - input, | |
| 76 | - std::move(sp_description), | |
| 77 | - "content", | |
| 78 | - tokenizer, | |
| 79 | - nullptr, | |
| 80 | - context, | |
| 81 | - true, | |
| 82 | - 0, | |
| 83 | - 0, | |
| 84 | - context && context->doc().reconstructed_xref()) | |
| 85 | - .parse(empty, true); | |
| 77 | + if (auto result = QPDFParser( | |
| 78 | + input, | |
| 79 | + std::move(sp_description), | |
| 80 | + "content", | |
| 81 | + tokenizer, | |
| 82 | + nullptr, | |
| 83 | + context, | |
| 84 | + true, | |
| 85 | + 0, | |
| 86 | + 0, | |
| 87 | + context && context->doc().reconstructed_xref()) | |
| 88 | + .parse(empty, true)) { | |
| 89 | + return result; | |
| 90 | + } | |
| 91 | + // In content stream mode, leave object uninitialized to indicate EOF | |
| 92 | + return {empty ? nullptr : QPDFObject::create<QPDF_Null>()}; | |
| 86 | 93 | } |
| 87 | 94 | |
| 88 | 95 | QPDFObjectHandle |
| ... | ... | @@ -94,15 +101,18 @@ QPDFParser::parse( |
| 94 | 101 | QPDFObjectHandle::StringDecrypter* decrypter, |
| 95 | 102 | QPDF* context) |
| 96 | 103 | { |
| 97 | - return QPDFParser( | |
| 98 | - input, | |
| 99 | - make_description(input.getName(), object_description), | |
| 100 | - object_description, | |
| 101 | - *tokenizer.m, | |
| 102 | - decrypter, | |
| 103 | - context, | |
| 104 | - false) | |
| 105 | - .parse(empty, false); | |
| 104 | + if (auto result = QPDFParser( | |
| 105 | + input, | |
| 106 | + make_description(input.getName(), object_description), | |
| 107 | + object_description, | |
| 108 | + *tokenizer.m, | |
| 109 | + decrypter, | |
| 110 | + context, | |
| 111 | + false) | |
| 112 | + .parse(empty, false)) { | |
| 113 | + return result; | |
| 114 | + } | |
| 115 | + return {QPDFObject::create<QPDF_Null>()}; | |
| 106 | 116 | } |
| 107 | 117 | |
| 108 | 118 | std::pair<QPDFObjectHandle, bool> |
| ... | ... | @@ -127,7 +137,10 @@ QPDFParser::parse( |
| 127 | 137 | 0, |
| 128 | 138 | sanity_checks) |
| 129 | 139 | .parse(empty, false); |
| 130 | - return {result, empty}; | |
| 140 | + if (result) { | |
| 141 | + return {result, empty}; | |
| 142 | + } | |
| 143 | + return {QPDFObject::create<QPDF_Null>(), empty}; | |
| 131 | 144 | } |
| 132 | 145 | |
| 133 | 146 | std::pair<QPDFObjectHandle, bool> |
| ... | ... | @@ -147,7 +160,11 @@ QPDFParser::parse( |
| 147 | 160 | stream_id, |
| 148 | 161 | obj_id) |
| 149 | 162 | .parse(empty, false); |
| 150 | - return {result, empty}; | |
| 163 | + | |
| 164 | + if (result) { | |
| 165 | + return {result, empty}; | |
| 166 | + } | |
| 167 | + return {QPDFObject::create<QPDF_Null>(), empty}; | |
| 151 | 168 | } |
| 152 | 169 | |
| 153 | 170 | QPDFObjectHandle |
| ... | ... | @@ -156,14 +173,14 @@ QPDFParser::parse(bool& empty, bool content_stream) |
| 156 | 173 | try { |
| 157 | 174 | return parse_first(empty, content_stream); |
| 158 | 175 | } catch (Error& e) { |
| 159 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 176 | + return {}; | |
| 160 | 177 | } catch (QPDFExc& e) { |
| 161 | 178 | throw e; |
| 162 | 179 | } catch (std::logic_error& e) { |
| 163 | 180 | throw e; |
| 164 | 181 | } catch (std::exception& e) { |
| 165 | 182 | warn("treating object as null because of error during parsing : "s + e.what()); |
| 166 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 183 | + return {}; | |
| 167 | 184 | } |
| 168 | 185 | } |
| 169 | 186 | |
| ... | ... | @@ -186,26 +203,27 @@ QPDFParser::parse_first(bool& empty, bool content_stream) |
| 186 | 203 | case QPDFTokenizer::tt_eof: |
| 187 | 204 | if (content_stream) { |
| 188 | 205 | // In content stream mode, leave object uninitialized to indicate EOF |
| 206 | + empty = true; | |
| 189 | 207 | return {}; |
| 190 | 208 | } |
| 191 | 209 | warn("unexpected EOF"); |
| 192 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 210 | + return {}; | |
| 193 | 211 | |
| 194 | 212 | case QPDFTokenizer::tt_bad: |
| 195 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 213 | + return {}; | |
| 196 | 214 | |
| 197 | 215 | case QPDFTokenizer::tt_brace_open: |
| 198 | 216 | case QPDFTokenizer::tt_brace_close: |
| 199 | 217 | warn("treating unexpected brace token as null"); |
| 200 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 218 | + return {}; | |
| 201 | 219 | |
| 202 | 220 | case QPDFTokenizer::tt_array_close: |
| 203 | 221 | warn("treating unexpected array close token as null"); |
| 204 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 222 | + return {}; | |
| 205 | 223 | |
| 206 | 224 | case QPDFTokenizer::tt_dict_close: |
| 207 | 225 | warn("unexpected dictionary close token"); |
| 208 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 226 | + return {}; | |
| 209 | 227 | |
| 210 | 228 | case QPDFTokenizer::tt_array_open: |
| 211 | 229 | case QPDFTokenizer::tt_dict_open: |
| ... | ... | @@ -241,7 +259,7 @@ QPDFParser::parse_first(bool& empty, bool content_stream) |
| 241 | 259 | // not move the input source's offset. |
| 242 | 260 | input.seek(input.getLastOffset(), SEEK_SET); |
| 243 | 261 | empty = true; |
| 244 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 262 | + return {}; | |
| 245 | 263 | } else { |
| 246 | 264 | warn("unknown token while reading object; treating as string"); |
| 247 | 265 | return withDescription<QPDF_String>(value); |
| ... | ... | @@ -259,7 +277,7 @@ QPDFParser::parse_first(bool& empty, bool content_stream) |
| 259 | 277 | |
| 260 | 278 | default: |
| 261 | 279 | warn("treating unknown token type as null while reading object"); |
| 262 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 280 | + return {}; | |
| 263 | 281 | } |
| 264 | 282 | } |
| 265 | 283 | |
| ... | ... | @@ -297,8 +315,8 @@ QPDFParser::parseRemainder(bool content_stream) |
| 297 | 315 | tokenizer.getValue() == "R") { |
| 298 | 316 | if (!context) { |
| 299 | 317 | throw std::logic_error( |
| 300 | - "QPDFParser::parse called without context on an object " | |
| 301 | - "with indirect references"); | |
| 318 | + "QPDFParser::parse called without context on an object with indirect " | |
| 319 | + "references"); | |
| 302 | 320 | } |
| 303 | 321 | auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]); |
| 304 | 322 | auto gen = QIntC::to_int(int_buffer[(int_count) % 2]); |
| ... | ... | @@ -328,7 +346,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 328 | 346 | return {}; |
| 329 | 347 | } |
| 330 | 348 | warn("unexpected EOF"); |
| 331 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 349 | + return {}; | |
| 332 | 350 | |
| 333 | 351 | case QPDFTokenizer::tt_bad: |
| 334 | 352 | check_too_many_bad_tokens(); |
| ... | ... | @@ -361,7 +379,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 361 | 379 | // During sanity checks, assume nesting of containers is corrupt and object is |
| 362 | 380 | // unusable. |
| 363 | 381 | warn("unexpected array close token; giving up on reading object"); |
| 364 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 382 | + return {}; | |
| 365 | 383 | } |
| 366 | 384 | add_bad_null("treating unexpected array close token as null"); |
| 367 | 385 | } |
| ... | ... | @@ -411,7 +429,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 411 | 429 | // During sanity checks, assume nesting of containers is corrupt and object is |
| 412 | 430 | // unusable. |
| 413 | 431 | warn("unexpected dictionary close token; giving up on reading object"); |
| 414 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 432 | + return {}; | |
| 415 | 433 | } |
| 416 | 434 | add_bad_null("unexpected dictionary close token"); |
| 417 | 435 | } |
| ... | ... | @@ -421,7 +439,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 421 | 439 | case QPDFTokenizer::tt_dict_open: |
| 422 | 440 | if (stack.size() > max_nesting) { |
| 423 | 441 | warn("ignoring excessively deeply nested data structure"); |
| 424 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 442 | + return {}; | |
| 425 | 443 | } else { |
| 426 | 444 | b_contents = false; |
| 427 | 445 | stack.emplace_back( |
| ... | ... | @@ -479,7 +497,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 479 | 497 | warn( |
| 480 | 498 | "unexpected 'endobj' or 'endstream' while reading object; giving up on " |
| 481 | 499 | "reading object"); |
| 482 | - return {QPDFObject::create<QPDF_Null>()}; | |
| 500 | + return {}; | |
| 483 | 501 | } |
| 484 | 502 | |
| 485 | 503 | add_bad_null("unknown token while reading object; treating as null"); |
| ... | ... | @@ -574,8 +592,7 @@ QPDFParser::addScalar(Args&&... args) |
| 574 | 592 | // Stop adding scalars. We are going to abort when the close token or a bad token is |
| 575 | 593 | // encountered. |
| 576 | 594 | max_bad_count = 0; |
| 577 | - check_too_many_bad_tokens(); | |
| 578 | - return; // unreachable | |
| 595 | + check_too_many_bad_tokens(); // always throws Error() | |
| 579 | 596 | } |
| 580 | 597 | auto obj = QPDFObject::create<T>(std::forward<Args>(args)...); |
| 581 | 598 | obj->setDescription(context, description, input.getLastOffset()); | ... | ... |