Commit 70d985f942cb554837163da8746e6abf7ef0ade3

Authored by m-holger
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);