Commit 70d985f942cb554837163da8746e6abf7ef0ade3
1 parent
97a7ad1d
Optimise QPDFParser::parse for #311 problem
Avoid creating new null objects that later will be discarded and made implicit. Part of #729
Showing
1 changed file
with
20 additions
and
14 deletions
libqpdf/QPDFParser.cc
| @@ -51,9 +51,12 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -51,9 +51,12 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 51 | int bad_count = 0; | 51 | int bad_count = 0; |
| 52 | int good_count = 0; | 52 | int good_count = 0; |
| 53 | bool b_contents = false; | 53 | bool b_contents = false; |
| 54 | + bool is_null = false; | ||
| 55 | + auto null_oh = QPDFObjectHandle::newNull(); | ||
| 54 | 56 | ||
| 55 | while (!done) { | 57 | while (!done) { |
| 56 | bool bad = false; | 58 | bool bad = false; |
| 59 | + is_null = false; | ||
| 57 | auto& frame = stack.back(); | 60 | auto& frame = stack.back(); |
| 58 | auto& olist = frame.olist; | 61 | auto& olist = frame.olist; |
| 59 | parser_state_e state = state_stack.back(); | 62 | parser_state_e state = state_stack.back(); |
| @@ -83,7 +86,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -83,7 +86,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 83 | case QPDFTokenizer::tt_bad: | 86 | case QPDFTokenizer::tt_bad: |
| 84 | QTC::TC("qpdf", "QPDFParser bad token in parse"); | 87 | QTC::TC("qpdf", "QPDFParser bad token in parse"); |
| 85 | bad = true; | 88 | bad = true; |
| 86 | - object = QPDFObjectHandle::newNull(); | 89 | + is_null = true; |
| 87 | break; | 90 | break; |
| 88 | 91 | ||
| 89 | case QPDFTokenizer::tt_brace_open: | 92 | case QPDFTokenizer::tt_brace_open: |
| @@ -91,7 +94,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -91,7 +94,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 91 | QTC::TC("qpdf", "QPDFParser bad brace"); | 94 | QTC::TC("qpdf", "QPDFParser bad brace"); |
| 92 | warn("treating unexpected brace token as null"); | 95 | warn("treating unexpected brace token as null"); |
| 93 | bad = true; | 96 | bad = true; |
| 94 | - object = QPDFObjectHandle::newNull(); | 97 | + is_null = true; |
| 95 | break; | 98 | break; |
| 96 | 99 | ||
| 97 | case QPDFTokenizer::tt_array_close: | 100 | case QPDFTokenizer::tt_array_close: |
| @@ -101,7 +104,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -101,7 +104,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 101 | QTC::TC("qpdf", "QPDFParser bad array close"); | 104 | QTC::TC("qpdf", "QPDFParser bad array close"); |
| 102 | warn("treating unexpected array close token as null"); | 105 | warn("treating unexpected array close token as null"); |
| 103 | bad = true; | 106 | bad = true; |
| 104 | - object = QPDFObjectHandle::newNull(); | 107 | + is_null = true; |
| 105 | } | 108 | } |
| 106 | break; | 109 | break; |
| 107 | 110 | ||
| @@ -112,7 +115,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -112,7 +115,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 112 | QTC::TC("qpdf", "QPDFParser bad dictionary close"); | 115 | QTC::TC("qpdf", "QPDFParser bad dictionary close"); |
| 113 | warn("unexpected dictionary close token"); | 116 | warn("unexpected dictionary close token"); |
| 114 | bad = true; | 117 | bad = true; |
| 115 | - object = QPDFObjectHandle::newNull(); | 118 | + is_null = true; |
| 116 | } | 119 | } |
| 117 | break; | 120 | break; |
| 118 | 121 | ||
| @@ -122,7 +125,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -122,7 +125,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 122 | QTC::TC("qpdf", "QPDFParser too deep"); | 125 | QTC::TC("qpdf", "QPDFParser too deep"); |
| 123 | warn("ignoring excessively deeply nested data structure"); | 126 | warn("ignoring excessively deeply nested data structure"); |
| 124 | bad = true; | 127 | bad = true; |
| 125 | - object = QPDFObjectHandle::newNull(); | 128 | + is_null = true; |
| 126 | state = st_top; | 129 | state = st_top; |
| 127 | } else { | 130 | } else { |
| 128 | state = st_start; | 131 | state = st_start; |
| @@ -140,7 +143,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -140,7 +143,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 140 | break; | 143 | break; |
| 141 | 144 | ||
| 142 | case QPDFTokenizer::tt_null: | 145 | case QPDFTokenizer::tt_null: |
| 143 | - object = QPDFObjectHandle::newNull(); | 146 | + is_null = true; |
| 144 | break; | 147 | break; |
| 145 | 148 | ||
| 146 | case QPDFTokenizer::tt_integer: | 149 | case QPDFTokenizer::tt_integer: |
| @@ -195,7 +198,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -195,7 +198,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 195 | // We just saw endobj without having read | 198 | // We just saw endobj without having read |
| 196 | // anything. Treat this as a null and do not move | 199 | // anything. Treat this as a null and do not move |
| 197 | // the input source's offset. | 200 | // the input source's offset. |
| 198 | - object = QPDFObjectHandle::newNull(); | 201 | + is_null = true; |
| 199 | input->seek(input->getLastOffset(), SEEK_SET); | 202 | input->seek(input->getLastOffset(), SEEK_SET); |
| 200 | empty = true; | 203 | empty = true; |
| 201 | } else { | 204 | } else { |
| @@ -228,16 +231,16 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -228,16 +231,16 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 228 | warn("treating unknown token type as null while " | 231 | warn("treating unknown token type as null while " |
| 229 | "reading object"); | 232 | "reading object"); |
| 230 | bad = true; | 233 | bad = true; |
| 231 | - object = QPDFObjectHandle::newNull(); | 234 | + is_null = true; |
| 232 | break; | 235 | break; |
| 233 | } | 236 | } |
| 234 | 237 | ||
| 235 | - if ((!object.isInitialized()) && | 238 | + if (!object.isInitialized() && !is_null && |
| 236 | (!((state == st_start) || (state == st_stop) || | 239 | (!((state == st_start) || (state == st_stop) || |
| 237 | (state == st_eof)))) { | 240 | (state == st_eof)))) { |
| 238 | throw std::logic_error("QPDFObjectHandle::parseInternal: " | 241 | throw std::logic_error("QPDFObjectHandle::parseInternal: " |
| 239 | "unexpected uninitialized object"); | 242 | "unexpected uninitialized object"); |
| 240 | - object = QPDFObjectHandle::newNull(); | 243 | + is_null = true; |
| 241 | } | 244 | } |
| 242 | 245 | ||
| 243 | if (bad) { | 246 | if (bad) { |
| @@ -254,7 +257,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -254,7 +257,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 254 | // intervening successful objects. Give up. | 257 | // intervening successful objects. Give up. |
| 255 | warn("too many errors; giving up on reading object"); | 258 | warn("too many errors; giving up on reading object"); |
| 256 | state = st_top; | 259 | state = st_top; |
| 257 | - object = QPDFObjectHandle::newNull(); | 260 | + is_null = true; |
| 258 | } | 261 | } |
| 259 | 262 | ||
| 260 | switch (state) { | 263 | switch (state) { |
| @@ -266,7 +269,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -266,7 +269,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 266 | // In content stream mode, leave object uninitialized to | 269 | // In content stream mode, leave object uninitialized to |
| 267 | // indicate EOF | 270 | // indicate EOF |
| 268 | if (!content_stream) { | 271 | if (!content_stream) { |
| 269 | - object = QPDFObjectHandle::newNull(); | 272 | + is_null = true; |
| 270 | } | 273 | } |
| 271 | break; | 274 | break; |
| 272 | 275 | ||
| @@ -279,7 +282,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -279,7 +282,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 279 | object.setParsedOffset(input->getLastOffset()); | 282 | object.setParsedOffset(input->getLastOffset()); |
| 280 | } | 283 | } |
| 281 | set_offset = true; | 284 | set_offset = true; |
| 282 | - olist.push_back(object); | 285 | + olist.push_back(is_null ? null_oh : object); |
| 283 | break; | 286 | break; |
| 284 | 287 | ||
| 285 | case st_top: | 288 | case st_top: |
| @@ -387,11 +390,14 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -387,11 +390,14 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 387 | if (state_stack.back() == st_top) { | 390 | if (state_stack.back() == st_top) { |
| 388 | done = true; | 391 | done = true; |
| 389 | } else { | 392 | } else { |
| 390 | - stack.back().olist.push_back(object); | 393 | + stack.back().olist.push_back(is_null ? null_oh : object); |
| 391 | } | 394 | } |
| 392 | } | 395 | } |
| 393 | } | 396 | } |
| 394 | 397 | ||
| 398 | + if (is_null) { | ||
| 399 | + object = QPDFObjectHandle::newNull(); | ||
| 400 | + } | ||
| 395 | if (!set_offset) { | 401 | if (!set_offset) { |
| 396 | setDescriptionFromInput(object, offset); | 402 | setDescriptionFromInput(object, offset); |
| 397 | object.setParsedOffset(offset); | 403 | object.setParsedOffset(offset); |