Commit 7402c02c808224932bd766a18f22b780a4d30b63

Authored by m-holger
1 parent 74162a2d

Combine stacks in QPDFParser::parse

Part of #729
Showing 1 changed file with 35 additions and 31 deletions
libqpdf/QPDFParser.cc
@@ -7,6 +7,24 @@ @@ -7,6 +7,24 @@
7 #include <qpdf/QUtil.hh> 7 #include <qpdf/QUtil.hh>
8 #include <qpdf/SparseOHArray.hh> 8 #include <qpdf/SparseOHArray.hh>
9 9
  10 +namespace
  11 +{
  12 + struct StackFrame
  13 + {
  14 + StackFrame(std::shared_ptr<InputSource> input) :
  15 + offset(input->tell()),
  16 + contents_string(""),
  17 + contents_offset(-1)
  18 + {
  19 + }
  20 +
  21 + std::vector<QPDFObjectHandle> olist;
  22 + qpdf_offset_t offset;
  23 + std::string contents_string;
  24 + qpdf_offset_t contents_offset;
  25 + };
  26 +} // namespace
  27 +
10 QPDFObjectHandle 28 QPDFObjectHandle
11 QPDFParser::parse(bool& empty, bool content_stream) 29 QPDFParser::parse(bool& empty, bool content_stream)
12 { 30 {
@@ -17,8 +35,6 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -17,8 +35,6 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
17 // this, it will cause a logic error to be thrown from 35 // this, it will cause a logic error to be thrown from
18 // QPDF::inParse(). 36 // QPDF::inParse().
19 37
20 - using OHVector = std::vector<QPDFObjectHandle>;  
21 -  
22 QPDF::ParseGuard pg(context); 38 QPDF::ParseGuard pg(context);
23 39
24 empty = false; 40 empty = false;
@@ -26,28 +42,22 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -26,28 +42,22 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
26 QPDFObjectHandle object; 42 QPDFObjectHandle object;
27 bool set_offset = false; 43 bool set_offset = false;
28 44
29 - std::vector<OHVector> olist_stack;  
30 - olist_stack.push_back(OHVector()); 45 + std::vector<StackFrame> stack;
  46 + stack.push_back(StackFrame(input));
31 std::vector<parser_state_e> state_stack; 47 std::vector<parser_state_e> state_stack;
32 state_stack.push_back(st_top); 48 state_stack.push_back(st_top);
33 - std::vector<qpdf_offset_t> offset_stack;  
34 - qpdf_offset_t offset = input->tell();  
35 - offset_stack.push_back(offset); 49 + qpdf_offset_t offset;
36 bool done = false; 50 bool done = false;
37 int bad_count = 0; 51 int bad_count = 0;
38 int good_count = 0; 52 int good_count = 0;
39 bool b_contents = false; 53 bool b_contents = false;
40 - std::vector<std::string> contents_string_stack;  
41 - contents_string_stack.push_back("");  
42 - std::vector<qpdf_offset_t> contents_offset_stack;  
43 - contents_offset_stack.push_back(-1); 54 +
44 while (!done) { 55 while (!done) {
45 bool bad = false; 56 bool bad = false;
46 - auto& olist = olist_stack.back(); 57 + auto& frame = stack.back();
  58 + auto& olist = frame.olist;
47 parser_state_e state = state_stack.back(); 59 parser_state_e state = state_stack.back();
48 - offset = offset_stack.back();  
49 - std::string& contents_string = contents_string_stack.back();  
50 - qpdf_offset_t& contents_offset = contents_offset_stack.back(); 60 + offset = frame.offset;
51 61
52 object = QPDFObjectHandle(); 62 object = QPDFObjectHandle();
53 set_offset = false; 63 set_offset = false;
@@ -108,23 +118,20 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -108,23 +118,20 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
108 118
109 case QPDFTokenizer::tt_array_open: 119 case QPDFTokenizer::tt_array_open:
110 case QPDFTokenizer::tt_dict_open: 120 case QPDFTokenizer::tt_dict_open:
111 - if (olist_stack.size() > 500) { 121 + if (stack.size() > 500) {
112 QTC::TC("qpdf", "QPDFParser too deep"); 122 QTC::TC("qpdf", "QPDFParser too deep");
113 warn("ignoring excessively deeply nested data structure"); 123 warn("ignoring excessively deeply nested data structure");
114 bad = true; 124 bad = true;
115 object = QPDFObjectHandle::newNull(); 125 object = QPDFObjectHandle::newNull();
116 state = st_top; 126 state = st_top;
117 } else { 127 } else {
118 - olist_stack.push_back(OHVector());  
119 state = st_start; 128 state = st_start;
120 - offset_stack.push_back(input->tell());  
121 state_stack.push_back( 129 state_stack.push_back(
122 (token.getType() == QPDFTokenizer::tt_array_open) 130 (token.getType() == QPDFTokenizer::tt_array_open)
123 ? st_array 131 ? st_array
124 : st_dictionary); 132 : st_dictionary);
125 b_contents = false; 133 b_contents = false;
126 - contents_string_stack.push_back("");  
127 - contents_offset_stack.push_back(-1); 134 + stack.push_back(StackFrame(input));
128 } 135 }
129 break; 136 break;
130 137
@@ -206,8 +213,8 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -206,8 +213,8 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
206 std::string val = token.getValue(); 213 std::string val = token.getValue();
207 if (decrypter) { 214 if (decrypter) {
208 if (b_contents) { 215 if (b_contents) {
209 - contents_string = val;  
210 - contents_offset = input->getLastOffset(); 216 + frame.contents_string = val;
  217 + frame.contents_offset = input->getLastOffset();
211 b_contents = false; 218 b_contents = false;
212 } 219 }
213 decrypter->decryptString(val); 220 decrypter->decryptString(val);
@@ -279,7 +286,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -279,7 +286,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
279 break; 286 break;
280 287
281 case st_stop: 288 case st_stop:
282 - if ((state_stack.size() < 2) || (olist_stack.size() < 2)) { 289 + if ((state_stack.size() < 2) || (stack.size() < 2)) {
283 throw std::logic_error( 290 throw std::logic_error(
284 "QPDFObjectHandle::parseInternal: st_stop encountered" 291 "QPDFObjectHandle::parseInternal: st_stop encountered"
285 " with insufficient elements in stack"); 292 " with insufficient elements in stack");
@@ -354,13 +361,13 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -354,13 +361,13 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
354 } 361 }
355 dict[key] = val; 362 dict[key] = val;
356 } 363 }
357 - if (!contents_string.empty() && dict.count("/Type") && 364 + if (!frame.contents_string.empty() && dict.count("/Type") &&
358 dict["/Type"].isNameAndEquals("/Sig") && 365 dict["/Type"].isNameAndEquals("/Sig") &&
359 dict.count("/ByteRange") && dict.count("/Contents") && 366 dict.count("/ByteRange") && dict.count("/Contents") &&
360 dict["/Contents"].isString()) { 367 dict["/Contents"].isString()) {
361 dict["/Contents"] = 368 dict["/Contents"] =
362 - QPDFObjectHandle::newString(contents_string);  
363 - dict["/Contents"].setParsedOffset(contents_offset); 369 + QPDFObjectHandle::newString(frame.contents_string);
  370 + dict["/Contents"].setParsedOffset(frame.contents_offset);
364 } 371 }
365 object = QPDFObjectHandle::newDictionary(dict); 372 object = QPDFObjectHandle::newDictionary(dict);
366 setDescriptionFromInput(object, offset); 373 setDescriptionFromInput(object, offset);
@@ -372,15 +379,12 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -372,15 +379,12 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
372 object.setParsedOffset(offset - 2); 379 object.setParsedOffset(offset - 2);
373 set_offset = true; 380 set_offset = true;
374 } 381 }
375 - olist_stack.pop_back();  
376 - offset_stack.pop_back(); 382 + stack.pop_back();
377 if (state_stack.back() == st_top) { 383 if (state_stack.back() == st_top) {
378 done = true; 384 done = true;
379 } else { 385 } else {
380 - olist_stack.back().push_back(object); 386 + stack.back().olist.push_back(object);
381 } 387 }
382 - contents_string_stack.pop_back();  
383 - contents_offset_stack.pop_back();  
384 } 388 }
385 } 389 }
386 390