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,10 +33,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 33 | empty = false; | 33 | empty = false; |
| 34 | 34 | ||
| 35 | std::shared_ptr<QPDFObject> object; | 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 | if (!tokenizer.nextToken(*input, object_description)) { | 38 | if (!tokenizer.nextToken(*input, object_description)) { |
| 42 | warn(tokenizer.getErrorMessage()); | 39 | warn(tokenizer.getErrorMessage()); |
| @@ -74,9 +71,11 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -74,9 +71,11 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 74 | 71 | ||
| 75 | case QPDFTokenizer::tt_array_open: | 72 | case QPDFTokenizer::tt_array_open: |
| 76 | case QPDFTokenizer::tt_dict_open: | 73 | case QPDFTokenizer::tt_dict_open: |
| 74 | + stack.clear(); | ||
| 77 | stack.emplace_back( | 75 | stack.emplace_back( |
| 78 | input, | 76 | input, |
| 79 | (tokenizer.getType() == QPDFTokenizer::tt_array_open) ? st_array : st_dictionary); | 77 | (tokenizer.getType() == QPDFTokenizer::tt_array_open) ? st_array : st_dictionary); |
| 78 | + frame = &stack.back(); | ||
| 80 | return parseRemainder(content_stream); | 79 | return parseRemainder(content_stream); |
| 81 | 80 | ||
| 82 | case QPDFTokenizer::tt_bool: | 81 | case QPDFTokenizer::tt_bool: |
| @@ -132,7 +131,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -132,7 +131,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 132 | return {QPDF_Null::create()}; | 131 | return {QPDF_Null::create()}; |
| 133 | } | 132 | } |
| 134 | 133 | ||
| 135 | - setDescription(object, frame->offset); | 134 | + setDescription(object, offset); |
| 136 | return object; | 135 | return object; |
| 137 | } | 136 | } |
| 138 | 137 | ||
| @@ -148,14 +147,11 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -148,14 +147,11 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 148 | 147 | ||
| 149 | std::shared_ptr<QPDFObject> object; | 148 | std::shared_ptr<QPDFObject> object; |
| 150 | bool set_offset = false; | 149 | bool set_offset = false; |
| 151 | - | ||
| 152 | - bool done = false; | ||
| 153 | bool b_contents = false; | 150 | bool b_contents = false; |
| 154 | bool is_null = false; | 151 | bool is_null = false; |
| 155 | - frame = &stack.back(); // CHANGED | ||
| 156 | bad_count = 0; | 152 | bad_count = 0; |
| 157 | 153 | ||
| 158 | - while (!done) { | 154 | + while (true) { |
| 159 | bool indirect_ref = false; | 155 | bool indirect_ref = false; |
| 160 | is_null = false; | 156 | is_null = false; |
| 161 | object = nullptr; | 157 | object = nullptr; |
| @@ -197,10 +193,6 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -197,10 +193,6 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 197 | 193 | ||
| 198 | case QPDFTokenizer::tt_array_close: | 194 | case QPDFTokenizer::tt_array_close: |
| 199 | if (frame->state == st_array) { | 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 | object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100); | 196 | object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100); |
| 205 | setDescription(object, frame->offset - 1); | 197 | setDescription(object, frame->offset - 1); |
| 206 | // The `offset` points to the next of "[". Set the rewind offset to point to the | 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,6 +200,9 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 208 | // array start delimiter. getLastOffset points to the array end token and therefore | 200 | // array start delimiter. getLastOffset points to the array end token and therefore |
| 209 | // can't be used here. | 201 | // can't be used here. |
| 210 | set_offset = true; | 202 | set_offset = true; |
| 203 | + if (stack.size() <= 1) { | ||
| 204 | + return object; | ||
| 205 | + } | ||
| 211 | stack.pop_back(); | 206 | stack.pop_back(); |
| 212 | frame = &stack.back(); | 207 | frame = &stack.back(); |
| 213 | } else { | 208 | } else { |
| @@ -222,11 +217,6 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -222,11 +217,6 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 222 | 217 | ||
| 223 | case QPDFTokenizer::tt_dict_close: | 218 | case QPDFTokenizer::tt_dict_close: |
| 224 | if (frame->state == st_dictionary) { | 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 | // Convert list to map. Alternating elements are keys. Attempt to recover more or | 220 | // Convert list to map. Alternating elements are keys. Attempt to recover more or |
| 231 | // less gracefully from invalid dictionaries. | 221 | // less gracefully from invalid dictionaries. |
| 232 | std::set<std::string> names; | 222 | std::set<std::string> names; |
| @@ -278,7 +268,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -278,7 +268,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 278 | val = QPDF_Null::create(); | 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 | if (!frame->contents_string.empty() && dict.count("/Type") && | 273 | if (!frame->contents_string.empty() && dict.count("/Type") && |
| 284 | dict["/Type"].isNameAndEquals("/Sig") && dict.count("/ByteRange") && | 274 | dict["/Type"].isNameAndEquals("/Sig") && dict.count("/ByteRange") && |
| @@ -292,6 +282,9 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -292,6 +282,9 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 292 | // beginning of "<<". This has been explicitly tested with whitespace surrounding | 282 | // beginning of "<<". This has been explicitly tested with whitespace surrounding |
| 293 | // the dictionary start delimiter. getLastOffset points to the dictionary end token | 283 | // the dictionary start delimiter. getLastOffset points to the dictionary end token |
| 294 | // and therefore can't be used here. | 284 | // and therefore can't be used here. |
| 285 | + if (stack.size() <= 1) { | ||
| 286 | + return object; | ||
| 287 | + } | ||
| 295 | set_offset = true; | 288 | set_offset = true; |
| 296 | stack.pop_back(); | 289 | stack.pop_back(); |
| 297 | frame = &stack.back(); | 290 | frame = &stack.back(); |
| @@ -307,7 +300,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -307,7 +300,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 307 | 300 | ||
| 308 | case QPDFTokenizer::tt_array_open: | 301 | case QPDFTokenizer::tt_array_open: |
| 309 | case QPDFTokenizer::tt_dict_open: | 302 | case QPDFTokenizer::tt_dict_open: |
| 310 | - if (stack.size() > 500) { | 303 | + if (stack.size() > 499) { |
| 311 | QTC::TC("qpdf", "QPDFParser too deep"); | 304 | QTC::TC("qpdf", "QPDFParser too deep"); |
| 312 | warn("ignoring excessively deeply nested data structure"); | 305 | warn("ignoring excessively deeply nested data structure"); |
| 313 | return {QPDF_Null::create()}; | 306 | return {QPDF_Null::create()}; |
| @@ -328,7 +321,6 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -328,7 +321,6 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 328 | case QPDFTokenizer::tt_null: | 321 | case QPDFTokenizer::tt_null: |
| 329 | is_null = true; | 322 | is_null = true; |
| 330 | ++frame->null_count; | 323 | ++frame->null_count; |
| 331 | - | ||
| 332 | break; | 324 | break; |
| 333 | 325 | ||
| 334 | case QPDFTokenizer::tt_integer: | 326 | case QPDFTokenizer::tt_integer: |
| @@ -426,32 +418,15 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -426,32 +418,15 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 426 | throw std::logic_error("QPDFParser:parseInternal: unexpected uninitialized object"); | 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 | void | 432 | void |
libqpdf/qpdf/QPDFParser.hh
| @@ -32,7 +32,7 @@ class QPDFParser | @@ -32,7 +32,7 @@ class QPDFParser | ||
| 32 | 32 | ||
| 33 | private: | 33 | private: |
| 34 | struct StackFrame; | 34 | struct StackFrame; |
| 35 | - enum parser_state_e { st_top, st_dictionary, st_array }; | 35 | + enum parser_state_e { st_dictionary, st_array }; |
| 36 | 36 | ||
| 37 | struct StackFrame | 37 | struct StackFrame |
| 38 | { | 38 | { |