Commit 7061ee1ce14c33b64ab4e12b79882aa4cb43cfcf

Authored by m-holger
1 parent 1a1c640a

Refactor `QPDFParser` internal `parse` methods to return uninitialized object ha…

…ndles on invalid input..
Showing 1 changed file with 67 additions and 50 deletions
libqpdf/QPDFParser.cc
... ... @@ -52,15 +52,18 @@ QPDFParser::parse(InputSource& input, std::string const& object_description, QPD
52 52 {
53 53 qpdf::Tokenizer tokenizer;
54 54 bool empty = false;
55   - return QPDFParser(
56   - input,
57   - make_description(input.getName(), object_description),
58   - object_description,
59   - tokenizer,
60   - nullptr,
61   - context,
62   - false)
63   - .parse(empty, false);
  55 + if (auto result = QPDFParser(
  56 + input,
  57 + make_description(input.getName(), object_description),
  58 + object_description,
  59 + tokenizer,
  60 + nullptr,
  61 + context,
  62 + false)
  63 + .parse(empty, false)) {
  64 + return result;
  65 + }
  66 + return {QPDFObject::create<QPDF_Null>()};
64 67 }
65 68  
66 69 QPDFObjectHandle
... ... @@ -71,18 +74,22 @@ QPDFParser::parse_content(
71 74 QPDF* context)
72 75 {
73 76 bool empty = false;
74   - return QPDFParser(
75   - input,
76   - std::move(sp_description),
77   - "content",
78   - tokenizer,
79   - nullptr,
80   - context,
81   - true,
82   - 0,
83   - 0,
84   - context && context->doc().reconstructed_xref())
85   - .parse(empty, true);
  77 + if (auto result = QPDFParser(
  78 + input,
  79 + std::move(sp_description),
  80 + "content",
  81 + tokenizer,
  82 + nullptr,
  83 + context,
  84 + true,
  85 + 0,
  86 + 0,
  87 + context && context->doc().reconstructed_xref())
  88 + .parse(empty, true)) {
  89 + return result;
  90 + }
  91 + // In content stream mode, leave object uninitialized to indicate EOF
  92 + return {empty ? nullptr : QPDFObject::create<QPDF_Null>()};
86 93 }
87 94  
88 95 QPDFObjectHandle
... ... @@ -94,15 +101,18 @@ QPDFParser::parse(
94 101 QPDFObjectHandle::StringDecrypter* decrypter,
95 102 QPDF* context)
96 103 {
97   - return QPDFParser(
98   - input,
99   - make_description(input.getName(), object_description),
100   - object_description,
101   - *tokenizer.m,
102   - decrypter,
103   - context,
104   - false)
105   - .parse(empty, false);
  104 + if (auto result = QPDFParser(
  105 + input,
  106 + make_description(input.getName(), object_description),
  107 + object_description,
  108 + *tokenizer.m,
  109 + decrypter,
  110 + context,
  111 + false)
  112 + .parse(empty, false)) {
  113 + return result;
  114 + }
  115 + return {QPDFObject::create<QPDF_Null>()};
106 116 }
107 117  
108 118 std::pair<QPDFObjectHandle, bool>
... ... @@ -127,7 +137,10 @@ QPDFParser::parse(
127 137 0,
128 138 sanity_checks)
129 139 .parse(empty, false);
130   - return {result, empty};
  140 + if (result) {
  141 + return {result, empty};
  142 + }
  143 + return {QPDFObject::create<QPDF_Null>(), empty};
131 144 }
132 145  
133 146 std::pair<QPDFObjectHandle, bool>
... ... @@ -147,7 +160,11 @@ QPDFParser::parse(
147 160 stream_id,
148 161 obj_id)
149 162 .parse(empty, false);
150   - return {result, empty};
  163 +
  164 + if (result) {
  165 + return {result, empty};
  166 + }
  167 + return {QPDFObject::create<QPDF_Null>(), empty};
151 168 }
152 169  
153 170 QPDFObjectHandle
... ... @@ -156,14 +173,14 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
156 173 try {
157 174 return parse_first(empty, content_stream);
158 175 } catch (Error& e) {
159   - return {QPDFObject::create<QPDF_Null>()};
  176 + return {};
160 177 } catch (QPDFExc& e) {
161 178 throw e;
162 179 } catch (std::logic_error& e) {
163 180 throw e;
164 181 } catch (std::exception& e) {
165 182 warn("treating object as null because of error during parsing : "s + e.what());
166   - return {QPDFObject::create<QPDF_Null>()};
  183 + return {};
167 184 }
168 185 }
169 186  
... ... @@ -186,26 +203,27 @@ QPDFParser::parse_first(bool&amp; empty, bool content_stream)
186 203 case QPDFTokenizer::tt_eof:
187 204 if (content_stream) {
188 205 // In content stream mode, leave object uninitialized to indicate EOF
  206 + empty = true;
189 207 return {};
190 208 }
191 209 warn("unexpected EOF");
192   - return {QPDFObject::create<QPDF_Null>()};
  210 + return {};
193 211  
194 212 case QPDFTokenizer::tt_bad:
195   - return {QPDFObject::create<QPDF_Null>()};
  213 + return {};
196 214  
197 215 case QPDFTokenizer::tt_brace_open:
198 216 case QPDFTokenizer::tt_brace_close:
199 217 warn("treating unexpected brace token as null");
200   - return {QPDFObject::create<QPDF_Null>()};
  218 + return {};
201 219  
202 220 case QPDFTokenizer::tt_array_close:
203 221 warn("treating unexpected array close token as null");
204   - return {QPDFObject::create<QPDF_Null>()};
  222 + return {};
205 223  
206 224 case QPDFTokenizer::tt_dict_close:
207 225 warn("unexpected dictionary close token");
208   - return {QPDFObject::create<QPDF_Null>()};
  226 + return {};
209 227  
210 228 case QPDFTokenizer::tt_array_open:
211 229 case QPDFTokenizer::tt_dict_open:
... ... @@ -241,7 +259,7 @@ QPDFParser::parse_first(bool&amp; empty, bool content_stream)
241 259 // not move the input source's offset.
242 260 input.seek(input.getLastOffset(), SEEK_SET);
243 261 empty = true;
244   - return {QPDFObject::create<QPDF_Null>()};
  262 + return {};
245 263 } else {
246 264 warn("unknown token while reading object; treating as string");
247 265 return withDescription<QPDF_String>(value);
... ... @@ -259,7 +277,7 @@ QPDFParser::parse_first(bool&amp; empty, bool content_stream)
259 277  
260 278 default:
261 279 warn("treating unknown token type as null while reading object");
262   - return {QPDFObject::create<QPDF_Null>()};
  280 + return {};
263 281 }
264 282 }
265 283  
... ... @@ -297,8 +315,8 @@ QPDFParser::parseRemainder(bool content_stream)
297 315 tokenizer.getValue() == "R") {
298 316 if (!context) {
299 317 throw std::logic_error(
300   - "QPDFParser::parse called without context on an object "
301   - "with indirect references");
  318 + "QPDFParser::parse called without context on an object with indirect "
  319 + "references");
302 320 }
303 321 auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]);
304 322 auto gen = QIntC::to_int(int_buffer[(int_count) % 2]);
... ... @@ -328,7 +346,7 @@ QPDFParser::parseRemainder(bool content_stream)
328 346 return {};
329 347 }
330 348 warn("unexpected EOF");
331   - return {QPDFObject::create<QPDF_Null>()};
  349 + return {};
332 350  
333 351 case QPDFTokenizer::tt_bad:
334 352 check_too_many_bad_tokens();
... ... @@ -361,7 +379,7 @@ QPDFParser::parseRemainder(bool content_stream)
361 379 // During sanity checks, assume nesting of containers is corrupt and object is
362 380 // unusable.
363 381 warn("unexpected array close token; giving up on reading object");
364   - return {QPDFObject::create<QPDF_Null>()};
  382 + return {};
365 383 }
366 384 add_bad_null("treating unexpected array close token as null");
367 385 }
... ... @@ -411,7 +429,7 @@ QPDFParser::parseRemainder(bool content_stream)
411 429 // During sanity checks, assume nesting of containers is corrupt and object is
412 430 // unusable.
413 431 warn("unexpected dictionary close token; giving up on reading object");
414   - return {QPDFObject::create<QPDF_Null>()};
  432 + return {};
415 433 }
416 434 add_bad_null("unexpected dictionary close token");
417 435 }
... ... @@ -421,7 +439,7 @@ QPDFParser::parseRemainder(bool content_stream)
421 439 case QPDFTokenizer::tt_dict_open:
422 440 if (stack.size() > max_nesting) {
423 441 warn("ignoring excessively deeply nested data structure");
424   - return {QPDFObject::create<QPDF_Null>()};
  442 + return {};
425 443 } else {
426 444 b_contents = false;
427 445 stack.emplace_back(
... ... @@ -479,7 +497,7 @@ QPDFParser::parseRemainder(bool content_stream)
479 497 warn(
480 498 "unexpected 'endobj' or 'endstream' while reading object; giving up on "
481 499 "reading object");
482   - return {QPDFObject::create<QPDF_Null>()};
  500 + return {};
483 501 }
484 502  
485 503 add_bad_null("unknown token while reading object; treating as null");
... ... @@ -574,8 +592,7 @@ QPDFParser::addScalar(Args&amp;&amp;... args)
574 592 // Stop adding scalars. We are going to abort when the close token or a bad token is
575 593 // encountered.
576 594 max_bad_count = 0;
577   - check_too_many_bad_tokens();
578   - return; // unreachable
  595 + check_too_many_bad_tokens(); // always throws Error()
579 596 }
580 597 auto obj = QPDFObject::create<T>(std::forward<Args>(args)...);
581 598 obj->setDescription(context, description, input.getLastOffset());
... ...