Commit c912af7384d5abeb281856f7122d427af5e29d73
1 parent
172cc613
In QPDFParser remove state st_top
Showing
2 changed files
with
21 additions
and
46 deletions
libqpdf/QPDFParser.cc
| ... | ... | @@ -33,10 +33,7 @@ QPDFParser::parse(bool& empty, bool content_stream) |
| 33 | 33 | empty = false; |
| 34 | 34 | |
| 35 | 35 | std::shared_ptr<QPDFObject> object; |
| 36 | - stack.clear(); | |
| 37 | - stack.emplace_back(input, st_top); | |
| 38 | - frame = &stack.back(); | |
| 39 | - object = nullptr; | |
| 36 | + auto offset = input->tell(); | |
| 40 | 37 | |
| 41 | 38 | if (!tokenizer.nextToken(*input, object_description)) { |
| 42 | 39 | warn(tokenizer.getErrorMessage()); |
| ... | ... | @@ -74,9 +71,11 @@ QPDFParser::parse(bool& empty, bool content_stream) |
| 74 | 71 | |
| 75 | 72 | case QPDFTokenizer::tt_array_open: |
| 76 | 73 | case QPDFTokenizer::tt_dict_open: |
| 74 | + stack.clear(); | |
| 77 | 75 | stack.emplace_back( |
| 78 | 76 | input, |
| 79 | 77 | (tokenizer.getType() == QPDFTokenizer::tt_array_open) ? st_array : st_dictionary); |
| 78 | + frame = &stack.back(); | |
| 80 | 79 | return parseRemainder(content_stream); |
| 81 | 80 | |
| 82 | 81 | case QPDFTokenizer::tt_bool: |
| ... | ... | @@ -132,7 +131,7 @@ QPDFParser::parse(bool& empty, bool content_stream) |
| 132 | 131 | return {QPDF_Null::create()}; |
| 133 | 132 | } |
| 134 | 133 | |
| 135 | - setDescription(object, frame->offset); | |
| 134 | + setDescription(object, offset); | |
| 136 | 135 | return object; |
| 137 | 136 | } |
| 138 | 137 | |
| ... | ... | @@ -148,14 +147,11 @@ QPDFParser::parseRemainder(bool content_stream) |
| 148 | 147 | |
| 149 | 148 | std::shared_ptr<QPDFObject> object; |
| 150 | 149 | bool set_offset = false; |
| 151 | - | |
| 152 | - bool done = false; | |
| 153 | 150 | bool b_contents = false; |
| 154 | 151 | bool is_null = false; |
| 155 | - frame = &stack.back(); // CHANGED | |
| 156 | 152 | bad_count = 0; |
| 157 | 153 | |
| 158 | - while (!done) { | |
| 154 | + while (true) { | |
| 159 | 155 | bool indirect_ref = false; |
| 160 | 156 | is_null = false; |
| 161 | 157 | object = nullptr; |
| ... | ... | @@ -197,10 +193,6 @@ QPDFParser::parseRemainder(bool content_stream) |
| 197 | 193 | |
| 198 | 194 | case QPDFTokenizer::tt_array_close: |
| 199 | 195 | if (frame->state == st_array) { |
| 200 | - if (stack.size() < 2) { | |
| 201 | - throw std::logic_error("QPDFParser::parseInternal: st_stop encountered with " | |
| 202 | - "insufficient elements in stack"); | |
| 203 | - } | |
| 204 | 196 | object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100); |
| 205 | 197 | setDescription(object, frame->offset - 1); |
| 206 | 198 | // The `offset` points to the next of "[". Set the rewind offset to point to the |
| ... | ... | @@ -208,6 +200,9 @@ QPDFParser::parseRemainder(bool content_stream) |
| 208 | 200 | // array start delimiter. getLastOffset points to the array end token and therefore |
| 209 | 201 | // can't be used here. |
| 210 | 202 | set_offset = true; |
| 203 | + if (stack.size() <= 1) { | |
| 204 | + return object; | |
| 205 | + } | |
| 211 | 206 | stack.pop_back(); |
| 212 | 207 | frame = &stack.back(); |
| 213 | 208 | } else { |
| ... | ... | @@ -222,11 +217,6 @@ QPDFParser::parseRemainder(bool content_stream) |
| 222 | 217 | |
| 223 | 218 | case QPDFTokenizer::tt_dict_close: |
| 224 | 219 | if (frame->state == st_dictionary) { |
| 225 | - if (stack.size() < 2) { | |
| 226 | - throw std::logic_error("QPDFParser::parseInternal: st_stop encountered with " | |
| 227 | - "insufficient elements in stack"); | |
| 228 | - } | |
| 229 | - | |
| 230 | 220 | // Convert list to map. Alternating elements are keys. Attempt to recover more or |
| 231 | 221 | // less gracefully from invalid dictionaries. |
| 232 | 222 | std::set<std::string> names; |
| ... | ... | @@ -278,7 +268,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 278 | 268 | val = QPDF_Null::create(); |
| 279 | 269 | } |
| 280 | 270 | |
| 281 | - dict[std::move(key)] = std::move(val); | |
| 271 | + dict[std::move(key)] = val; | |
| 282 | 272 | } |
| 283 | 273 | if (!frame->contents_string.empty() && dict.count("/Type") && |
| 284 | 274 | dict["/Type"].isNameAndEquals("/Sig") && dict.count("/ByteRange") && |
| ... | ... | @@ -292,6 +282,9 @@ QPDFParser::parseRemainder(bool content_stream) |
| 292 | 282 | // beginning of "<<". This has been explicitly tested with whitespace surrounding |
| 293 | 283 | // the dictionary start delimiter. getLastOffset points to the dictionary end token |
| 294 | 284 | // and therefore can't be used here. |
| 285 | + if (stack.size() <= 1) { | |
| 286 | + return object; | |
| 287 | + } | |
| 295 | 288 | set_offset = true; |
| 296 | 289 | stack.pop_back(); |
| 297 | 290 | frame = &stack.back(); |
| ... | ... | @@ -307,7 +300,7 @@ QPDFParser::parseRemainder(bool content_stream) |
| 307 | 300 | |
| 308 | 301 | case QPDFTokenizer::tt_array_open: |
| 309 | 302 | case QPDFTokenizer::tt_dict_open: |
| 310 | - if (stack.size() > 500) { | |
| 303 | + if (stack.size() > 499) { | |
| 311 | 304 | QTC::TC("qpdf", "QPDFParser too deep"); |
| 312 | 305 | warn("ignoring excessively deeply nested data structure"); |
| 313 | 306 | return {QPDF_Null::create()}; |
| ... | ... | @@ -328,7 +321,6 @@ QPDFParser::parseRemainder(bool content_stream) |
| 328 | 321 | case QPDFTokenizer::tt_null: |
| 329 | 322 | is_null = true; |
| 330 | 323 | ++frame->null_count; |
| 331 | - | |
| 332 | 324 | break; |
| 333 | 325 | |
| 334 | 326 | case QPDFTokenizer::tt_integer: |
| ... | ... | @@ -426,32 +418,15 @@ QPDFParser::parseRemainder(bool content_stream) |
| 426 | 418 | throw std::logic_error("QPDFParser:parseInternal: unexpected uninitialized object"); |
| 427 | 419 | } |
| 428 | 420 | |
| 429 | - switch (frame->state) { | |
| 430 | - case st_dictionary: | |
| 431 | - case st_array: | |
| 432 | - if (is_null) { | |
| 433 | - object = null_oh; | |
| 434 | - // No need to set description for direct nulls - they probably will become implicit. | |
| 435 | - } else if (!indirect_ref && !set_offset) { | |
| 436 | - setDescription(object, input->getLastOffset()); | |
| 437 | - } | |
| 438 | - set_offset = true; | |
| 439 | - frame->olist.push_back(object); | |
| 440 | - break; | |
| 441 | - | |
| 442 | - case st_top: | |
| 443 | - done = true; | |
| 444 | - break; | |
| 421 | + if (is_null) { | |
| 422 | + object = null_oh; | |
| 423 | + // No need to set description for direct nulls - they probably will become implicit. | |
| 424 | + } else if (!indirect_ref && !set_offset) { | |
| 425 | + setDescription(object, input->getLastOffset()); | |
| 445 | 426 | } |
| 427 | + frame->olist.push_back(object); | |
| 446 | 428 | } |
| 447 | - | |
| 448 | - if (is_null) { | |
| 449 | - object = QPDF_Null::create(); | |
| 450 | - } | |
| 451 | - if (!set_offset) { | |
| 452 | - setDescription(object, frame->offset); | |
| 453 | - } | |
| 454 | - return object; | |
| 429 | + return {}; // unreachable | |
| 455 | 430 | } |
| 456 | 431 | |
| 457 | 432 | void | ... | ... |