Commit 1548b8d8be4b57e4087caaced1794a25a01c3488

Authored by m-holger
1 parent 4c8836d5

In QPDFParser::parseRemainder eliminate most temporary variables

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;