Commit 1548b8d8be4b57e4087caaced1794a25a01c3488
1 parent
4c8836d5
In QPDFParser::parseRemainder eliminate most temporary variables
Showing
2 changed files
with
68 additions
and
63 deletions
libqpdf/QPDFParser.cc
| @@ -113,11 +113,11 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -113,11 +113,11 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 113 | 113 | ||
| 114 | case QPDFTokenizer::tt_string: | 114 | case QPDFTokenizer::tt_string: |
| 115 | if (decrypter) { | 115 | if (decrypter) { |
| 116 | - std::string s{tokenizer.getValue()}; | ||
| 117 | - decrypter->decryptString(s); | ||
| 118 | - return withDescription<QPDF_String>(s); | 116 | + std::string s{tokenizer.getValue()}; |
| 117 | + decrypter->decryptString(s); | ||
| 118 | + return withDescription<QPDF_String>(s); | ||
| 119 | } else { | 119 | } else { |
| 120 | - return withDescription<QPDF_String>(tokenizer.getValue()); | 120 | + return withDescription<QPDF_String>(tokenizer.getValue()); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | default: | 123 | default: |
| @@ -134,20 +134,10 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -134,20 +134,10 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 134 | // effect of reading the object and changing the file pointer. If you do this, it will cause a | 134 | // effect of reading the object and changing the file pointer. If you do this, it will cause a |
| 135 | // logic error to be thrown from QPDF::inParse(). | 135 | // logic error to be thrown from QPDF::inParse(). |
| 136 | 136 | ||
| 137 | - const static ObjectPtr null_oh = QPDF_Null::create(); | ||
| 138 | - | ||
| 139 | - ObjectPtr object; | ||
| 140 | - bool set_offset = false; | ||
| 141 | - bool b_contents = false; | ||
| 142 | - bool is_null = false; | ||
| 143 | bad_count = 0; | 137 | bad_count = 0; |
| 138 | + bool b_contents = false; | ||
| 144 | 139 | ||
| 145 | while (true) { | 140 | while (true) { |
| 146 | - bool indirect_ref = false; | ||
| 147 | - is_null = false; | ||
| 148 | - object = nullptr; | ||
| 149 | - set_offset = false; | ||
| 150 | - | ||
| 151 | if (!tokenizer.nextToken(*input, object_description)) { | 141 | if (!tokenizer.nextToken(*input, object_description)) { |
| 152 | warn(tokenizer.getErrorMessage()); | 142 | warn(tokenizer.getErrorMessage()); |
| 153 | } | 143 | } |
| @@ -169,8 +159,8 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -169,8 +159,8 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 169 | if (tooManyBadTokens()) { | 159 | if (tooManyBadTokens()) { |
| 170 | return {QPDF_Null::create()}; | 160 | return {QPDF_Null::create()}; |
| 171 | } | 161 | } |
| 172 | - is_null = true; | ||
| 173 | - break; | 162 | + addNull(); |
| 163 | + continue; | ||
| 174 | 164 | ||
| 175 | case QPDFTokenizer::tt_brace_open: | 165 | case QPDFTokenizer::tt_brace_open: |
| 176 | case QPDFTokenizer::tt_brace_close: | 166 | case QPDFTokenizer::tt_brace_close: |
| @@ -179,32 +169,32 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -179,32 +169,32 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 179 | if (tooManyBadTokens()) { | 169 | if (tooManyBadTokens()) { |
| 180 | return {QPDF_Null::create()}; | 170 | return {QPDF_Null::create()}; |
| 181 | } | 171 | } |
| 182 | - is_null = true; | ||
| 183 | - break; | 172 | + addNull(); |
| 173 | + continue; | ||
| 184 | 174 | ||
| 185 | case QPDFTokenizer::tt_array_close: | 175 | case QPDFTokenizer::tt_array_close: |
| 186 | if (frame->state == st_array) { | 176 | if (frame->state == st_array) { |
| 187 | - object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100); | 177 | + auto object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100); |
| 188 | setDescription(object, frame->offset - 1); | 178 | setDescription(object, frame->offset - 1); |
| 189 | // The `offset` points to the next of "[". Set the rewind offset to point to the | 179 | // The `offset` points to the next of "[". Set the rewind offset to point to the |
| 190 | // beginning of "[". This has been explicitly tested with whitespace surrounding the | 180 | // beginning of "[". This has been explicitly tested with whitespace surrounding the |
| 191 | // array start delimiter. getLastOffset points to the array end token and therefore | 181 | // array start delimiter. getLastOffset points to the array end token and therefore |
| 192 | // can't be used here. | 182 | // can't be used here. |
| 193 | - set_offset = true; | ||
| 194 | if (stack.size() <= 1) { | 183 | if (stack.size() <= 1) { |
| 195 | return object; | 184 | return object; |
| 196 | } | 185 | } |
| 197 | stack.pop_back(); | 186 | stack.pop_back(); |
| 198 | frame = &stack.back(); | 187 | frame = &stack.back(); |
| 188 | + add(std::move(object)); | ||
| 199 | } else { | 189 | } else { |
| 200 | QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); | 190 | QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); |
| 201 | warn("treating unexpected array close token as null"); | 191 | warn("treating unexpected array close token as null"); |
| 202 | if (tooManyBadTokens()) { | 192 | if (tooManyBadTokens()) { |
| 203 | return {QPDF_Null::create()}; | 193 | return {QPDF_Null::create()}; |
| 204 | } | 194 | } |
| 205 | - is_null = true; | 195 | + addNull(); |
| 206 | } | 196 | } |
| 207 | - break; | 197 | + continue; |
| 208 | 198 | ||
| 209 | case QPDFTokenizer::tt_dict_close: | 199 | case QPDFTokenizer::tt_dict_close: |
| 210 | if (frame->state == st_dictionary) { | 200 | if (frame->state == st_dictionary) { |
| @@ -267,7 +257,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -267,7 +257,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 267 | dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string); | 257 | dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string); |
| 268 | dict["/Contents"].setParsedOffset(frame->contents_offset); | 258 | dict["/Contents"].setParsedOffset(frame->contents_offset); |
| 269 | } | 259 | } |
| 270 | - object = QPDF_Dictionary::create(std::move(dict)); | 260 | + auto object = QPDF_Dictionary::create(std::move(dict)); |
| 271 | setDescription(object, frame->offset - 2); | 261 | setDescription(object, frame->offset - 2); |
| 272 | // The `offset` points to the next of "<<". Set the rewind offset to point to the | 262 | // The `offset` points to the next of "<<". Set the rewind offset to point to the |
| 273 | // beginning of "<<". This has been explicitly tested with whitespace surrounding | 263 | // beginning of "<<". This has been explicitly tested with whitespace surrounding |
| @@ -276,18 +266,18 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -276,18 +266,18 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 276 | if (stack.size() <= 1) { | 266 | if (stack.size() <= 1) { |
| 277 | return object; | 267 | return object; |
| 278 | } | 268 | } |
| 279 | - set_offset = true; | ||
| 280 | stack.pop_back(); | 269 | stack.pop_back(); |
| 281 | frame = &stack.back(); | 270 | frame = &stack.back(); |
| 271 | + add(std::move(object)); | ||
| 282 | } else { | 272 | } else { |
| 283 | QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder"); | 273 | QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder"); |
| 284 | warn("unexpected dictionary close token"); | 274 | warn("unexpected dictionary close token"); |
| 285 | if (tooManyBadTokens()) { | 275 | if (tooManyBadTokens()) { |
| 286 | return {QPDF_Null::create()}; | 276 | return {QPDF_Null::create()}; |
| 287 | } | 277 | } |
| 288 | - is_null = true; | 278 | + addNull(); |
| 289 | } | 279 | } |
| 290 | - break; | 280 | + continue; |
| 291 | 281 | ||
| 292 | case QPDFTokenizer::tt_array_open: | 282 | case QPDFTokenizer::tt_array_open: |
| 293 | case QPDFTokenizer::tt_dict_open: | 283 | case QPDFTokenizer::tt_dict_open: |
| @@ -306,26 +296,25 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -306,26 +296,25 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 306 | } | 296 | } |
| 307 | 297 | ||
| 308 | case QPDFTokenizer::tt_bool: | 298 | case QPDFTokenizer::tt_bool: |
| 309 | - object = QPDF_Bool::create((tokenizer.getValue() == "true")); | ||
| 310 | - break; | 299 | + addScalar<QPDF_Bool>(tokenizer.getValue() == "true"); |
| 300 | + continue; | ||
| 311 | 301 | ||
| 312 | case QPDFTokenizer::tt_null: | 302 | case QPDFTokenizer::tt_null: |
| 313 | - is_null = true; | ||
| 314 | - ++frame->null_count; | ||
| 315 | - break; | 303 | + addNull(); |
| 304 | + continue; | ||
| 316 | 305 | ||
| 317 | case QPDFTokenizer::tt_integer: | 306 | case QPDFTokenizer::tt_integer: |
| 318 | - object = QPDF_Integer::create(QUtil::string_to_ll(tokenizer.getValue().c_str())); | ||
| 319 | - break; | 307 | + addScalar<QPDF_Integer>(QUtil::string_to_ll(tokenizer.getValue().c_str())); |
| 308 | + continue; | ||
| 320 | 309 | ||
| 321 | case QPDFTokenizer::tt_real: | 310 | case QPDFTokenizer::tt_real: |
| 322 | - object = QPDF_Real::create(tokenizer.getValue()); | ||
| 323 | - break; | 311 | + addScalar<QPDF_Real>(tokenizer.getValue()); |
| 312 | + continue; | ||
| 324 | 313 | ||
| 325 | case QPDFTokenizer::tt_name: | 314 | case QPDFTokenizer::tt_name: |
| 326 | { | 315 | { |
| 327 | auto const& name = tokenizer.getValue(); | 316 | auto const& name = tokenizer.getValue(); |
| 328 | - object = QPDF_Name::create(name); | 317 | + addScalar<QPDF_Name>(name); |
| 329 | 318 | ||
| 330 | if (name == "/Contents") { | 319 | if (name == "/Contents") { |
| 331 | b_contents = true; | 320 | b_contents = true; |
| @@ -333,14 +322,14 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -333,14 +322,14 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 333 | b_contents = false; | 322 | b_contents = false; |
| 334 | } | 323 | } |
| 335 | } | 324 | } |
| 336 | - break; | 325 | + continue; |
| 337 | 326 | ||
| 338 | case QPDFTokenizer::tt_word: | 327 | case QPDFTokenizer::tt_word: |
| 339 | { | 328 | { |
| 340 | auto const& value = tokenizer.getValue(); | 329 | auto const& value = tokenizer.getValue(); |
| 341 | auto size = frame->olist.size(); | 330 | auto size = frame->olist.size(); |
| 342 | if (content_stream) { | 331 | if (content_stream) { |
| 343 | - object = QPDF_Operator::create(value); | 332 | + addScalar<QPDF_Operator>(value); |
| 344 | } else if ( | 333 | } else if ( |
| 345 | value == "R" && size >= 2 && frame->olist.back() && | 334 | value == "R" && size >= 2 && frame->olist.back() && |
| 346 | frame->olist.back()->getTypeCode() == ::ot_integer && | 335 | frame->olist.back()->getTypeCode() == ::ot_integer && |
| @@ -359,24 +348,25 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -359,24 +348,25 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 359 | // This action has the desirable side effect of causing dangling references | 348 | // This action has the desirable side effect of causing dangling references |
| 360 | // (references to indirect objects that don't appear in the PDF) in any | 349 | // (references to indirect objects that don't appear in the PDF) in any |
| 361 | // parsed object to appear in the object cache. | 350 | // parsed object to appear in the object cache. |
| 362 | - object = context->getObject(ref_og).obj; | ||
| 363 | - indirect_ref = true; | 351 | + frame->olist.pop_back(); |
| 352 | + frame->olist.pop_back(); | ||
| 353 | + add(std::move(context->getObject(ref_og).obj)); | ||
| 364 | } else { | 354 | } else { |
| 365 | QTC::TC("qpdf", "QPDFParser indirect with 0 objid"); | 355 | QTC::TC("qpdf", "QPDFParser indirect with 0 objid"); |
| 366 | - is_null = true; | 356 | + frame->olist.pop_back(); |
| 357 | + frame->olist.pop_back(); | ||
| 358 | + addNull(); | ||
| 367 | } | 359 | } |
| 368 | - frame->olist.pop_back(); | ||
| 369 | - frame->olist.pop_back(); | ||
| 370 | } else { | 360 | } else { |
| 371 | QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); | 361 | QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); |
| 372 | warn("unknown token while reading object; treating as string"); | 362 | warn("unknown token while reading object; treating as string"); |
| 373 | if (tooManyBadTokens()) { | 363 | if (tooManyBadTokens()) { |
| 374 | return {QPDF_Null::create()}; | 364 | return {QPDF_Null::create()}; |
| 375 | } | 365 | } |
| 376 | - object = QPDF_String::create(value); | 366 | + addScalar<QPDF_String>(value); |
| 377 | } | 367 | } |
| 378 | } | 368 | } |
| 379 | - break; | 369 | + continue; |
| 380 | 370 | ||
| 381 | case QPDFTokenizer::tt_string: | 371 | case QPDFTokenizer::tt_string: |
| 382 | { | 372 | { |
| @@ -389,37 +379,48 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -389,37 +379,48 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 389 | } | 379 | } |
| 390 | std::string s{val}; | 380 | std::string s{val}; |
| 391 | decrypter->decryptString(s); | 381 | decrypter->decryptString(s); |
| 392 | - object = QPDF_String::create(s); | 382 | + addScalar<QPDF_String>(s); |
| 393 | } else { | 383 | } else { |
| 394 | - object = QPDF_String::create(val); | 384 | + addScalar<QPDF_String>(val); |
| 395 | } | 385 | } |
| 396 | } | 386 | } |
| 397 | - break; | 387 | + continue; |
| 398 | 388 | ||
| 399 | default: | 389 | default: |
| 400 | warn("treating unknown token type as null while reading object"); | 390 | warn("treating unknown token type as null while reading object"); |
| 401 | if (tooManyBadTokens()) { | 391 | if (tooManyBadTokens()) { |
| 402 | return {QPDF_Null::create()}; | 392 | return {QPDF_Null::create()}; |
| 403 | } | 393 | } |
| 404 | - is_null = true; | ||
| 405 | - break; | ||
| 406 | - } | ||
| 407 | - | ||
| 408 | - if (object == nullptr && !is_null) { | ||
| 409 | - throw std::logic_error("QPDFParser:parseInternal: unexpected uninitialized object"); | 394 | + addNull(); |
| 410 | } | 395 | } |
| 411 | - | ||
| 412 | - if (is_null) { | ||
| 413 | - object = null_oh; | ||
| 414 | - // No need to set description for direct nulls - they probably will become implicit. | ||
| 415 | - } else if (!indirect_ref && !set_offset) { | ||
| 416 | - setDescription(object, input->getLastOffset()); | ||
| 417 | - } | ||
| 418 | - frame->olist.push_back(object); | ||
| 419 | } | 396 | } |
| 420 | return {}; // unreachable | 397 | return {}; // unreachable |
| 421 | } | 398 | } |
| 422 | 399 | ||
| 400 | +void | ||
| 401 | +QPDFParser::add(std::shared_ptr<QPDFObject>&& obj) | ||
| 402 | +{ | ||
| 403 | + frame->olist.emplace_back(std::move(obj)); | ||
| 404 | +} | ||
| 405 | + | ||
| 406 | +void | ||
| 407 | +QPDFParser::addNull() | ||
| 408 | +{ | ||
| 409 | + const static ObjectPtr null_obj = QPDF_Null::create(); | ||
| 410 | + | ||
| 411 | + frame->olist.emplace_back(null_obj); | ||
| 412 | + ++frame->null_count; | ||
| 413 | +} | ||
| 414 | + | ||
| 415 | +template <typename T, typename... Args> | ||
| 416 | +void | ||
| 417 | +QPDFParser::addScalar(Args&&... args) | ||
| 418 | +{ | ||
| 419 | + auto obj = T::create(args...); | ||
| 420 | + obj->setDescription(context, description, input->getLastOffset()); | ||
| 421 | + add(std::move(obj)); | ||
| 422 | +} | ||
| 423 | + | ||
| 423 | template <typename T, typename... Args> | 424 | template <typename T, typename... Args> |
| 424 | QPDFObjectHandle | 425 | QPDFObjectHandle |
| 425 | QPDFParser::withDescription(Args&&... args) | 426 | QPDFParser::withDescription(Args&&... args) |
libqpdf/qpdf/QPDFParser.hh
| @@ -51,6 +51,10 @@ class QPDFParser | @@ -51,6 +51,10 @@ class QPDFParser | ||
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | QPDFObjectHandle parseRemainder(bool content_stream); | 53 | QPDFObjectHandle parseRemainder(bool content_stream); |
| 54 | + void add(std::shared_ptr<QPDFObject>&& obj); | ||
| 55 | + void addNull(); | ||
| 56 | + template <typename T, typename... Args> | ||
| 57 | + void addScalar(Args&&... args); | ||
| 54 | bool tooManyBadTokens(); | 58 | bool tooManyBadTokens(); |
| 55 | void warn(qpdf_offset_t offset, std::string const& msg) const; | 59 | void warn(qpdf_offset_t offset, std::string const& msg) const; |
| 56 | void warn(std::string const& msg) const; | 60 | void warn(std::string const& msg) const; |