Commit 628cf87315e36d3646a28aa45020326040ff4aed
Committed by
GitHub
Merge pull request #1577 from m-holger/global
Refactor QPDFParser
Showing
18 changed files
with
285 additions
and
254 deletions
libqpdf/CMakeLists.txt
| @@ -100,6 +100,7 @@ set(libqpdf_SOURCES | @@ -100,6 +100,7 @@ set(libqpdf_SOURCES | ||
| 100 | ResourceFinder.cc | 100 | ResourceFinder.cc |
| 101 | SecureRandomDataProvider.cc | 101 | SecureRandomDataProvider.cc |
| 102 | SF_FlateLzwDecode.cc | 102 | SF_FlateLzwDecode.cc |
| 103 | + global.cc | ||
| 103 | qpdf-c.cc | 104 | qpdf-c.cc |
| 104 | qpdfjob-c.cc | 105 | qpdfjob-c.cc |
| 105 | qpdflogger-c.cc) | 106 | qpdflogger-c.cc) |
libqpdf/QPDFParser.cc
| @@ -15,6 +15,8 @@ using namespace qpdf; | @@ -15,6 +15,8 @@ using namespace qpdf; | ||
| 15 | 15 | ||
| 16 | using ObjectPtr = std::shared_ptr<QPDFObject>; | 16 | using ObjectPtr = std::shared_ptr<QPDFObject>; |
| 17 | 17 | ||
| 18 | +static uint32_t const& max_nesting{global::Limits::objects_max_nesting()}; | ||
| 19 | + | ||
| 18 | // The ParseGuard class allows QPDFParser to detect re-entrant parsing. It also provides | 20 | // The ParseGuard class allows QPDFParser to detect re-entrant parsing. It also provides |
| 19 | // special access to allow the parser to create unresolved objects and dangling references. | 21 | // special access to allow the parser to create unresolved objects and dangling references. |
| 20 | class QPDF::Doc::ParseGuard | 22 | class QPDF::Doc::ParseGuard |
| @@ -49,16 +51,18 @@ QPDFObjectHandle | @@ -49,16 +51,18 @@ QPDFObjectHandle | ||
| 49 | QPDFParser::parse(InputSource& input, std::string const& object_description, QPDF* context) | 51 | QPDFParser::parse(InputSource& input, std::string const& object_description, QPDF* context) |
| 50 | { | 52 | { |
| 51 | qpdf::Tokenizer tokenizer; | 53 | qpdf::Tokenizer tokenizer; |
| 52 | - bool empty = false; | ||
| 53 | - return QPDFParser( | ||
| 54 | - input, | ||
| 55 | - make_description(input.getName(), object_description), | ||
| 56 | - object_description, | ||
| 57 | - tokenizer, | ||
| 58 | - nullptr, | ||
| 59 | - context, | ||
| 60 | - false) | ||
| 61 | - .parse(empty, false); | 54 | + if (auto result = QPDFParser( |
| 55 | + input, | ||
| 56 | + make_description(input.getName(), object_description), | ||
| 57 | + object_description, | ||
| 58 | + tokenizer, | ||
| 59 | + nullptr, | ||
| 60 | + context, | ||
| 61 | + false) | ||
| 62 | + .parse()) { | ||
| 63 | + return result; | ||
| 64 | + } | ||
| 65 | + return {QPDFObject::create<QPDF_Null>()}; | ||
| 62 | } | 66 | } |
| 63 | 67 | ||
| 64 | QPDFObjectHandle | 68 | QPDFObjectHandle |
| @@ -68,19 +72,24 @@ QPDFParser::parse_content( | @@ -68,19 +72,24 @@ QPDFParser::parse_content( | ||
| 68 | qpdf::Tokenizer& tokenizer, | 72 | qpdf::Tokenizer& tokenizer, |
| 69 | QPDF* context) | 73 | QPDF* context) |
| 70 | { | 74 | { |
| 71 | - bool empty = false; | ||
| 72 | - return QPDFParser( | ||
| 73 | - input, | ||
| 74 | - std::move(sp_description), | ||
| 75 | - "content", | ||
| 76 | - tokenizer, | ||
| 77 | - nullptr, | ||
| 78 | - context, | ||
| 79 | - true, | ||
| 80 | - 0, | ||
| 81 | - 0, | ||
| 82 | - context && context->doc().reconstructed_xref()) | ||
| 83 | - .parse(empty, true); | 75 | + static const std::string content("content"); // GCC12 - make constexpr |
| 76 | + auto p = QPDFParser( | ||
| 77 | + input, | ||
| 78 | + std::move(sp_description), | ||
| 79 | + content, | ||
| 80 | + tokenizer, | ||
| 81 | + nullptr, | ||
| 82 | + context, | ||
| 83 | + true, | ||
| 84 | + 0, | ||
| 85 | + 0, | ||
| 86 | + context && context->doc().reconstructed_xref()); | ||
| 87 | + auto result = p.parse(true); | ||
| 88 | + if (result || p.empty_) { | ||
| 89 | + // In content stream mode, leave object uninitialized to indicate EOF | ||
| 90 | + return result; | ||
| 91 | + } | ||
| 92 | + return {QPDFObject::create<QPDF_Null>()}; | ||
| 84 | } | 93 | } |
| 85 | 94 | ||
| 86 | QPDFObjectHandle | 95 | QPDFObjectHandle |
| @@ -92,18 +101,25 @@ QPDFParser::parse( | @@ -92,18 +101,25 @@ QPDFParser::parse( | ||
| 92 | QPDFObjectHandle::StringDecrypter* decrypter, | 101 | QPDFObjectHandle::StringDecrypter* decrypter, |
| 93 | QPDF* context) | 102 | QPDF* context) |
| 94 | { | 103 | { |
| 95 | - return QPDFParser( | ||
| 96 | - input, | ||
| 97 | - make_description(input.getName(), object_description), | ||
| 98 | - object_description, | ||
| 99 | - *tokenizer.m, | ||
| 100 | - decrypter, | ||
| 101 | - context, | ||
| 102 | - false) | ||
| 103 | - .parse(empty, false); | 104 | + // ABI: This parse overload is only used by the deprecated QPDFObjectHandle::parse. It is the |
| 105 | + // only user of the 'empty' member. When removing this overload also remove 'empty'. | ||
| 106 | + auto p = QPDFParser( | ||
| 107 | + input, | ||
| 108 | + make_description(input.getName(), object_description), | ||
| 109 | + object_description, | ||
| 110 | + *tokenizer.m, | ||
| 111 | + decrypter, | ||
| 112 | + context, | ||
| 113 | + false); | ||
| 114 | + auto result = p.parse(); | ||
| 115 | + empty = p.empty_; | ||
| 116 | + if (result) { | ||
| 117 | + return result; | ||
| 118 | + } | ||
| 119 | + return {QPDFObject::create<QPDF_Null>()}; | ||
| 104 | } | 120 | } |
| 105 | 121 | ||
| 106 | -std::pair<QPDFObjectHandle, bool> | 122 | +QPDFObjectHandle |
| 107 | QPDFParser::parse( | 123 | QPDFParser::parse( |
| 108 | InputSource& input, | 124 | InputSource& input, |
| 109 | std::string const& object_description, | 125 | std::string const& object_description, |
| @@ -112,54 +128,65 @@ QPDFParser::parse( | @@ -112,54 +128,65 @@ QPDFParser::parse( | ||
| 112 | QPDF& context, | 128 | QPDF& context, |
| 113 | bool sanity_checks) | 129 | bool sanity_checks) |
| 114 | { | 130 | { |
| 115 | - bool empty{false}; | ||
| 116 | - auto result = QPDFParser( | ||
| 117 | - input, | ||
| 118 | - make_description(input.getName(), object_description), | ||
| 119 | - object_description, | ||
| 120 | - tokenizer, | ||
| 121 | - decrypter, | ||
| 122 | - &context, | ||
| 123 | - true, | ||
| 124 | - 0, | ||
| 125 | - 0, | ||
| 126 | - sanity_checks) | ||
| 127 | - .parse(empty, false); | ||
| 128 | - return {result, empty}; | 131 | + return QPDFParser( |
| 132 | + input, | ||
| 133 | + make_description(input.getName(), object_description), | ||
| 134 | + object_description, | ||
| 135 | + tokenizer, | ||
| 136 | + decrypter, | ||
| 137 | + &context, | ||
| 138 | + true, | ||
| 139 | + 0, | ||
| 140 | + 0, | ||
| 141 | + sanity_checks) | ||
| 142 | + .parse(); | ||
| 129 | } | 143 | } |
| 130 | 144 | ||
| 131 | -std::pair<QPDFObjectHandle, bool> | 145 | +QPDFObjectHandle |
| 132 | QPDFParser::parse( | 146 | QPDFParser::parse( |
| 133 | is::OffsetBuffer& input, int stream_id, int obj_id, qpdf::Tokenizer& tokenizer, QPDF& context) | 147 | is::OffsetBuffer& input, int stream_id, int obj_id, qpdf::Tokenizer& tokenizer, QPDF& context) |
| 134 | { | 148 | { |
| 135 | - bool empty{false}; | ||
| 136 | - auto result = QPDFParser( | ||
| 137 | - input, | ||
| 138 | - std::make_shared<QPDFObject::Description>( | ||
| 139 | - QPDFObject::ObjStreamDescr(stream_id, obj_id)), | ||
| 140 | - "", | ||
| 141 | - tokenizer, | ||
| 142 | - nullptr, | ||
| 143 | - &context, | ||
| 144 | - true, | ||
| 145 | - stream_id, | ||
| 146 | - obj_id) | ||
| 147 | - .parse(empty, false); | ||
| 148 | - return {result, empty}; | 149 | + return QPDFParser( |
| 150 | + input, | ||
| 151 | + std::make_shared<QPDFObject::Description>( | ||
| 152 | + QPDFObject::ObjStreamDescr(stream_id, obj_id)), | ||
| 153 | + "", | ||
| 154 | + tokenizer, | ||
| 155 | + nullptr, | ||
| 156 | + &context, | ||
| 157 | + true, | ||
| 158 | + stream_id, | ||
| 159 | + obj_id) | ||
| 160 | + .parse(); | ||
| 161 | +} | ||
| 162 | + | ||
| 163 | +QPDFObjectHandle | ||
| 164 | +QPDFParser::parse(bool content_stream) | ||
| 165 | +{ | ||
| 166 | + try { | ||
| 167 | + return parse_first(content_stream); | ||
| 168 | + } catch (Error&) { | ||
| 169 | + return {}; | ||
| 170 | + } catch (QPDFExc& e) { | ||
| 171 | + throw e; | ||
| 172 | + } catch (std::logic_error& e) { | ||
| 173 | + throw e; | ||
| 174 | + } catch (std::exception& e) { | ||
| 175 | + warn("treating object as null because of error during parsing : "s + e.what()); | ||
| 176 | + return {}; | ||
| 177 | + } | ||
| 149 | } | 178 | } |
| 150 | 179 | ||
| 151 | QPDFObjectHandle | 180 | QPDFObjectHandle |
| 152 | -QPDFParser::parse(bool& empty, bool content_stream) | 181 | +QPDFParser::parse_first(bool content_stream) |
| 153 | { | 182 | { |
| 154 | // This method must take care not to resolve any objects. Don't check the type of any object | 183 | // This method must take care not to resolve any objects. Don't check the type of any object |
| 155 | // without first ensuring that it is a direct object. Otherwise, doing so may have the side | 184 | // without first ensuring that it is a direct object. Otherwise, doing so may have the side |
| 156 | // effect of reading the object and changing the file pointer. If you do this, it will cause a | 185 | // effect of reading the object and changing the file pointer. If you do this, it will cause a |
| 157 | // logic error to be thrown from QPDF::inParse(). | 186 | // logic error to be thrown from QPDF::inParse(). |
| 158 | 187 | ||
| 159 | - ParseGuard pg(context); | ||
| 160 | - empty = false; | 188 | + QPDF::Doc::ParseGuard pg(context); |
| 161 | start = input.tell(); | 189 | start = input.tell(); |
| 162 | - | ||
| 163 | if (!tokenizer.nextToken(input, object_description)) { | 190 | if (!tokenizer.nextToken(input, object_description)) { |
| 164 | warn(tokenizer.getErrorMessage()); | 191 | warn(tokenizer.getErrorMessage()); |
| 165 | } | 192 | } |
| @@ -168,31 +195,27 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -168,31 +195,27 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 168 | case QPDFTokenizer::tt_eof: | 195 | case QPDFTokenizer::tt_eof: |
| 169 | if (content_stream) { | 196 | if (content_stream) { |
| 170 | // In content stream mode, leave object uninitialized to indicate EOF | 197 | // In content stream mode, leave object uninitialized to indicate EOF |
| 198 | + empty_ = true; | ||
| 171 | return {}; | 199 | return {}; |
| 172 | } | 200 | } |
| 173 | - QTC::TC("qpdf", "QPDFParser eof in parse"); | ||
| 174 | warn("unexpected EOF"); | 201 | warn("unexpected EOF"); |
| 175 | - return {QPDFObject::create<QPDF_Null>()}; | 202 | + return {}; |
| 176 | 203 | ||
| 177 | case QPDFTokenizer::tt_bad: | 204 | case QPDFTokenizer::tt_bad: |
| 178 | - QTC::TC("qpdf", "QPDFParser bad token in parse"); | ||
| 179 | - return {QPDFObject::create<QPDF_Null>()}; | 205 | + return {}; |
| 180 | 206 | ||
| 181 | case QPDFTokenizer::tt_brace_open: | 207 | case QPDFTokenizer::tt_brace_open: |
| 182 | case QPDFTokenizer::tt_brace_close: | 208 | case QPDFTokenizer::tt_brace_close: |
| 183 | - QTC::TC("qpdf", "QPDFParser bad brace"); | ||
| 184 | warn("treating unexpected brace token as null"); | 209 | warn("treating unexpected brace token as null"); |
| 185 | - return {QPDFObject::create<QPDF_Null>()}; | 210 | + return {}; |
| 186 | 211 | ||
| 187 | case QPDFTokenizer::tt_array_close: | 212 | case QPDFTokenizer::tt_array_close: |
| 188 | - QTC::TC("qpdf", "QPDFParser bad array close"); | ||
| 189 | warn("treating unexpected array close token as null"); | 213 | warn("treating unexpected array close token as null"); |
| 190 | - return {QPDFObject::create<QPDF_Null>()}; | 214 | + return {}; |
| 191 | 215 | ||
| 192 | case QPDFTokenizer::tt_dict_close: | 216 | case QPDFTokenizer::tt_dict_close: |
| 193 | - QTC::TC("qpdf", "QPDFParser bad dictionary close"); | ||
| 194 | warn("unexpected dictionary close token"); | 217 | warn("unexpected dictionary close token"); |
| 195 | - return {QPDFObject::create<QPDF_Null>()}; | 218 | + return {}; |
| 196 | 219 | ||
| 197 | case QPDFTokenizer::tt_array_open: | 220 | case QPDFTokenizer::tt_array_open: |
| 198 | case QPDFTokenizer::tt_dict_open: | 221 | case QPDFTokenizer::tt_dict_open: |
| @@ -224,13 +247,17 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -224,13 +247,17 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 224 | if (content_stream) { | 247 | if (content_stream) { |
| 225 | return withDescription<QPDF_Operator>(value); | 248 | return withDescription<QPDF_Operator>(value); |
| 226 | } else if (value == "endobj") { | 249 | } else if (value == "endobj") { |
| 227 | - // We just saw endobj without having read anything. Treat this as a null and do | ||
| 228 | - // not move the input source's offset. | 250 | + // We just saw endobj without having read anything. Nothing in the PDF spec appears |
| 251 | + // to allow empty objects, but they have been encountered in actual PDF files and | ||
| 252 | + // Adobe Reader appears to ignore them. Treat this as a null and do not move the | ||
| 253 | + // input source's offset. | ||
| 254 | + empty_ = true; | ||
| 229 | input.seek(input.getLastOffset(), SEEK_SET); | 255 | input.seek(input.getLastOffset(), SEEK_SET); |
| 230 | - empty = true; | ||
| 231 | - return {QPDFObject::create<QPDF_Null>()}; | 256 | + if (!content_stream) { |
| 257 | + warn("empty object treated as null"); | ||
| 258 | + } | ||
| 259 | + return {}; | ||
| 232 | } else { | 260 | } else { |
| 233 | - QTC::TC("qpdf", "QPDFParser treat word as string"); | ||
| 234 | warn("unknown token while reading object; treating as string"); | 261 | warn("unknown token while reading object; treating as string"); |
| 235 | return withDescription<QPDF_String>(value); | 262 | return withDescription<QPDF_String>(value); |
| 236 | } | 263 | } |
| @@ -247,7 +274,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | @@ -247,7 +274,7 @@ QPDFParser::parse(bool& empty, bool content_stream) | ||
| 247 | 274 | ||
| 248 | default: | 275 | default: |
| 249 | warn("treating unknown token type as null while reading object"); | 276 | warn("treating unknown token type as null while reading object"); |
| 250 | - return {QPDFObject::create<QPDF_Null>()}; | 277 | + return {}; |
| 251 | } | 278 | } |
| 252 | } | 279 | } |
| 253 | 280 | ||
| @@ -283,19 +310,19 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -283,19 +310,19 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 283 | } else if ( | 310 | } else if ( |
| 284 | int_count >= 2 && tokenizer.getType() == QPDFTokenizer::tt_word && | 311 | int_count >= 2 && tokenizer.getType() == QPDFTokenizer::tt_word && |
| 285 | tokenizer.getValue() == "R") { | 312 | tokenizer.getValue() == "R") { |
| 286 | - if (context == nullptr) { | ||
| 287 | - QTC::TC("qpdf", "QPDFParser indirect without context"); | 313 | + if (!context) { |
| 288 | throw std::logic_error( | 314 | throw std::logic_error( |
| 289 | - "QPDFParser::parse called without context on an object " | ||
| 290 | - "with indirect references"); | 315 | + "QPDFParser::parse called without context on an object with indirect " |
| 316 | + "references"); | ||
| 291 | } | 317 | } |
| 292 | auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]); | 318 | auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]); |
| 293 | auto gen = QIntC::to_int(int_buffer[(int_count) % 2]); | 319 | auto gen = QIntC::to_int(int_buffer[(int_count) % 2]); |
| 294 | if (!(id < 1 || gen < 0 || gen >= 65535)) { | 320 | if (!(id < 1 || gen < 0 || gen >= 65535)) { |
| 295 | add(ParseGuard::getObject(context, id, gen, parse_pdf)); | 321 | add(ParseGuard::getObject(context, id, gen, parse_pdf)); |
| 296 | } else { | 322 | } else { |
| 297 | - QTC::TC("qpdf", "QPDFParser invalid objgen"); | ||
| 298 | - addNull(); | 323 | + add_bad_null( |
| 324 | + "treating bad indirect reference (" + std::to_string(id) + " " + | ||
| 325 | + std::to_string(gen) + " R) as null"); | ||
| 299 | } | 326 | } |
| 300 | int_count = 0; | 327 | int_count = 0; |
| 301 | continue; | 328 | continue; |
| @@ -317,34 +344,20 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -317,34 +344,20 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 317 | // In content stream mode, leave object uninitialized to indicate EOF | 344 | // In content stream mode, leave object uninitialized to indicate EOF |
| 318 | return {}; | 345 | return {}; |
| 319 | } | 346 | } |
| 320 | - QTC::TC("qpdf", "QPDFParser eof in parseRemainder"); | ||
| 321 | warn("unexpected EOF"); | 347 | warn("unexpected EOF"); |
| 322 | - return {QPDFObject::create<QPDF_Null>()}; | 348 | + return {}; |
| 323 | 349 | ||
| 324 | case QPDFTokenizer::tt_bad: | 350 | case QPDFTokenizer::tt_bad: |
| 325 | - QTC::TC("qpdf", "QPDFParser bad token in parseRemainder"); | ||
| 326 | - if (tooManyBadTokens()) { | ||
| 327 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 328 | - } | 351 | + check_too_many_bad_tokens(); |
| 329 | addNull(); | 352 | addNull(); |
| 330 | continue; | 353 | continue; |
| 331 | 354 | ||
| 332 | case QPDFTokenizer::tt_brace_open: | 355 | case QPDFTokenizer::tt_brace_open: |
| 333 | case QPDFTokenizer::tt_brace_close: | 356 | case QPDFTokenizer::tt_brace_close: |
| 334 | - QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder"); | ||
| 335 | - warn("treating unexpected brace token as null"); | ||
| 336 | - if (tooManyBadTokens()) { | ||
| 337 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 338 | - } | ||
| 339 | - addNull(); | 357 | + add_bad_null("treating unexpected brace token as null"); |
| 340 | continue; | 358 | continue; |
| 341 | 359 | ||
| 342 | case QPDFTokenizer::tt_array_close: | 360 | case QPDFTokenizer::tt_array_close: |
| 343 | - if ((bad_count || sanity_checks) && !max_bad_count) { | ||
| 344 | - // Trigger warning. | ||
| 345 | - (void)tooManyBadTokens(); | ||
| 346 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 347 | - } | ||
| 348 | if (frame->state == st_array) { | 361 | if (frame->state == st_array) { |
| 349 | auto object = frame->null_count > 100 | 362 | auto object = frame->null_count > 100 |
| 350 | ? QPDFObject::create<QPDF_Array>(std::move(frame->olist), true) | 363 | ? QPDFObject::create<QPDF_Array>(std::move(frame->olist), true) |
| @@ -361,33 +374,22 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -361,33 +374,22 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 361 | frame = &stack.back(); | 374 | frame = &stack.back(); |
| 362 | add(std::move(object)); | 375 | add(std::move(object)); |
| 363 | } else { | 376 | } else { |
| 364 | - QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); | ||
| 365 | if (sanity_checks) { | 377 | if (sanity_checks) { |
| 366 | // During sanity checks, assume nesting of containers is corrupt and object is | 378 | // During sanity checks, assume nesting of containers is corrupt and object is |
| 367 | // unusable. | 379 | // unusable. |
| 368 | warn("unexpected array close token; giving up on reading object"); | 380 | warn("unexpected array close token; giving up on reading object"); |
| 369 | - return {QPDFObject::create<QPDF_Null>()}; | 381 | + return {}; |
| 370 | } | 382 | } |
| 371 | - warn("treating unexpected array close token as null"); | ||
| 372 | - if (tooManyBadTokens()) { | ||
| 373 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 374 | - } | ||
| 375 | - addNull(); | 383 | + add_bad_null("treating unexpected array close token as null"); |
| 376 | } | 384 | } |
| 377 | continue; | 385 | continue; |
| 378 | 386 | ||
| 379 | case QPDFTokenizer::tt_dict_close: | 387 | case QPDFTokenizer::tt_dict_close: |
| 380 | - if ((bad_count || sanity_checks) && !max_bad_count) { | ||
| 381 | - // Trigger warning. | ||
| 382 | - (void)tooManyBadTokens(); | ||
| 383 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 384 | - } | ||
| 385 | if (frame->state <= st_dictionary_value) { | 388 | if (frame->state <= st_dictionary_value) { |
| 386 | // Attempt to recover more or less gracefully from invalid dictionaries. | 389 | // Attempt to recover more or less gracefully from invalid dictionaries. |
| 387 | auto& dict = frame->dict; | 390 | auto& dict = frame->dict; |
| 388 | 391 | ||
| 389 | if (frame->state == st_dictionary_value) { | 392 | if (frame->state == st_dictionary_value) { |
| 390 | - QTC::TC("qpdf", "QPDFParser no val for last key"); | ||
| 391 | warn( | 393 | warn( |
| 392 | frame->offset, | 394 | frame->offset, |
| 393 | "dictionary ended prematurely; using null as value for last key"); | 395 | "dictionary ended prematurely; using null as value for last key"); |
| @@ -426,22 +428,17 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -426,22 +428,17 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 426 | // During sanity checks, assume nesting of containers is corrupt and object is | 428 | // During sanity checks, assume nesting of containers is corrupt and object is |
| 427 | // unusable. | 429 | // unusable. |
| 428 | warn("unexpected dictionary close token; giving up on reading object"); | 430 | warn("unexpected dictionary close token; giving up on reading object"); |
| 429 | - return {QPDFObject::create<QPDF_Null>()}; | 431 | + return {}; |
| 430 | } | 432 | } |
| 431 | - warn("unexpected dictionary close token"); | ||
| 432 | - if (tooManyBadTokens()) { | ||
| 433 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 434 | - } | ||
| 435 | - addNull(); | 433 | + add_bad_null("unexpected dictionary close token"); |
| 436 | } | 434 | } |
| 437 | continue; | 435 | continue; |
| 438 | 436 | ||
| 439 | case QPDFTokenizer::tt_array_open: | 437 | case QPDFTokenizer::tt_array_open: |
| 440 | case QPDFTokenizer::tt_dict_open: | 438 | case QPDFTokenizer::tt_dict_open: |
| 441 | - if (stack.size() > 499) { | ||
| 442 | - QTC::TC("qpdf", "QPDFParser too deep"); | 439 | + if (stack.size() > max_nesting) { |
| 443 | warn("ignoring excessively deeply nested data structure"); | 440 | warn("ignoring excessively deeply nested data structure"); |
| 444 | - return {QPDFObject::create<QPDF_Null>()}; | 441 | + return {}; |
| 445 | } else { | 442 | } else { |
| 446 | b_contents = false; | 443 | b_contents = false; |
| 447 | stack.emplace_back( | 444 | stack.emplace_back( |
| @@ -499,22 +496,15 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -499,22 +496,15 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 499 | warn( | 496 | warn( |
| 500 | "unexpected 'endobj' or 'endstream' while reading object; giving up on " | 497 | "unexpected 'endobj' or 'endstream' while reading object; giving up on " |
| 501 | "reading object"); | 498 | "reading object"); |
| 502 | - return {QPDFObject::create<QPDF_Null>()}; | 499 | + return {}; |
| 503 | } | 500 | } |
| 504 | 501 | ||
| 505 | - warn("unknown token while reading object; treating as null"); | ||
| 506 | - if (tooManyBadTokens()) { | ||
| 507 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 508 | - } | ||
| 509 | - addNull(); | 502 | + add_bad_null("unknown token while reading object; treating as null"); |
| 510 | continue; | 503 | continue; |
| 511 | } | 504 | } |
| 512 | 505 | ||
| 513 | - QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); | ||
| 514 | warn("unknown token while reading object; treating as string"); | 506 | warn("unknown token while reading object; treating as string"); |
| 515 | - if (tooManyBadTokens()) { | ||
| 516 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 517 | - } | 507 | + check_too_many_bad_tokens(); |
| 518 | addScalar<QPDF_String>(tokenizer.getValue()); | 508 | addScalar<QPDF_String>(tokenizer.getValue()); |
| 519 | 509 | ||
| 520 | continue; | 510 | continue; |
| @@ -538,11 +528,7 @@ QPDFParser::parseRemainder(bool content_stream) | @@ -538,11 +528,7 @@ QPDFParser::parseRemainder(bool content_stream) | ||
| 538 | continue; | 528 | continue; |
| 539 | 529 | ||
| 540 | default: | 530 | default: |
| 541 | - warn("treating unknown token type as null while reading object"); | ||
| 542 | - if (tooManyBadTokens()) { | ||
| 543 | - return {QPDFObject::create<QPDF_Null>()}; | ||
| 544 | - } | ||
| 545 | - addNull(); | 531 | + add_bad_null("treating unknown token type as null while reading object"); |
| 546 | } | 532 | } |
| 547 | } | 533 | } |
| 548 | } | 534 | } |
| @@ -581,6 +567,14 @@ QPDFParser::addNull() | @@ -581,6 +567,14 @@ QPDFParser::addNull() | ||
| 581 | } | 567 | } |
| 582 | 568 | ||
| 583 | void | 569 | void |
| 570 | +QPDFParser::add_bad_null(std::string const& msg) | ||
| 571 | +{ | ||
| 572 | + warn(msg); | ||
| 573 | + check_too_many_bad_tokens(); | ||
| 574 | + addNull(); | ||
| 575 | +} | ||
| 576 | + | ||
| 577 | +void | ||
| 584 | QPDFParser::addInt(int count) | 578 | QPDFParser::addInt(int count) |
| 585 | { | 579 | { |
| 586 | auto obj = QPDFObject::create<QPDF_Integer>(int_buffer[count % 2]); | 580 | auto obj = QPDFObject::create<QPDF_Integer>(int_buffer[count % 2]); |
| @@ -592,12 +586,12 @@ template <typename T, typename... Args> | @@ -592,12 +586,12 @@ template <typename T, typename... Args> | ||
| 592 | void | 586 | void |
| 593 | QPDFParser::addScalar(Args&&... args) | 587 | QPDFParser::addScalar(Args&&... args) |
| 594 | { | 588 | { |
| 595 | - if ((bad_count || sanity_checks) && | ||
| 596 | - (frame->olist.size() > 5'000 || frame->dict.size() > 5'000)) { | 589 | + auto limit = Limits::objects_max_container_size(bad_count || sanity_checks); |
| 590 | + if (frame->olist.size() > limit || frame->dict.size() > limit) { | ||
| 597 | // Stop adding scalars. We are going to abort when the close token or a bad token is | 591 | // Stop adding scalars. We are going to abort when the close token or a bad token is |
| 598 | // encountered. | 592 | // encountered. |
| 599 | max_bad_count = 0; | 593 | max_bad_count = 0; |
| 600 | - return; | 594 | + check_too_many_bad_tokens(); // always throws Error() |
| 601 | } | 595 | } |
| 602 | auto obj = QPDFObject::create<T>(std::forward<Args>(args)...); | 596 | auto obj = QPDFObject::create<T>(std::forward<Args>(args)...); |
| 603 | obj->setDescription(context, description, input.getLastOffset()); | 597 | obj->setDescription(context, description, input.getLastOffset()); |
| @@ -647,34 +641,34 @@ QPDFParser::fixMissingKeys() | @@ -647,34 +641,34 @@ QPDFParser::fixMissingKeys() | ||
| 647 | } | 641 | } |
| 648 | } | 642 | } |
| 649 | 643 | ||
| 650 | -bool | ||
| 651 | -QPDFParser::tooManyBadTokens() | 644 | +void |
| 645 | +QPDFParser::check_too_many_bad_tokens() | ||
| 652 | { | 646 | { |
| 653 | - if (frame->olist.size() > 5'000 || frame->dict.size() > 5'000) { | 647 | + auto limit = Limits::objects_max_container_size(bad_count || sanity_checks); |
| 648 | + if (frame->olist.size() > limit || frame->dict.size() > limit) { | ||
| 654 | if (bad_count) { | 649 | if (bad_count) { |
| 655 | warn( | 650 | warn( |
| 656 | - "encountered errors while parsing an array or dictionary with more than 5000 " | ||
| 657 | - "elements; giving up on reading object"); | ||
| 658 | - return true; | 651 | + "encountered errors while parsing an array or dictionary with more than " + |
| 652 | + std::to_string(limit) + " elements; giving up on reading object"); | ||
| 653 | + throw Error(); | ||
| 659 | } | 654 | } |
| 660 | warn( | 655 | warn( |
| 661 | - "encountered an array or dictionary with more than 5000 elements during xref recovery; " | ||
| 662 | - "giving up on reading object"); | 656 | + "encountered an array or dictionary with more than " + std::to_string(limit) + |
| 657 | + " elements during xref recovery; giving up on reading object"); | ||
| 663 | } | 658 | } |
| 664 | if (max_bad_count && --max_bad_count > 0 && good_count > 4) { | 659 | if (max_bad_count && --max_bad_count > 0 && good_count > 4) { |
| 665 | good_count = 0; | 660 | good_count = 0; |
| 666 | bad_count = 1; | 661 | bad_count = 1; |
| 667 | - return false; | 662 | + return; |
| 668 | } | 663 | } |
| 669 | if (++bad_count > 5 || | 664 | if (++bad_count > 5 || |
| 670 | (frame->state != st_array && QIntC::to_size(max_bad_count) < frame->olist.size())) { | 665 | (frame->state != st_array && QIntC::to_size(max_bad_count) < frame->olist.size())) { |
| 671 | // Give up after 5 errors in close proximity or if the number of missing dictionary keys | 666 | // Give up after 5 errors in close proximity or if the number of missing dictionary keys |
| 672 | // exceeds the remaining number of allowable total errors. | 667 | // exceeds the remaining number of allowable total errors. |
| 673 | warn("too many errors; giving up on reading object"); | 668 | warn("too many errors; giving up on reading object"); |
| 674 | - return true; | 669 | + throw Error(); |
| 675 | } | 670 | } |
| 676 | good_count = 0; | 671 | good_count = 0; |
| 677 | - return false; | ||
| 678 | } | 672 | } |
| 679 | 673 | ||
| 680 | void | 674 | void |
| @@ -693,7 +687,6 @@ QPDFParser::warn(QPDFExc const& e) const | @@ -693,7 +687,6 @@ QPDFParser::warn(QPDFExc const& e) const | ||
| 693 | void | 687 | void |
| 694 | QPDFParser::warnDuplicateKey() | 688 | QPDFParser::warnDuplicateKey() |
| 695 | { | 689 | { |
| 696 | - QTC::TC("qpdf", "QPDFParser duplicate dict key"); | ||
| 697 | warn( | 690 | warn( |
| 698 | frame->offset, | 691 | frame->offset, |
| 699 | "dictionary has duplicated key " + frame->key + "; last occurrence overrides earlier ones"); | 692 | "dictionary has duplicated key " + frame->key + "; last occurrence overrides earlier ones"); |
libqpdf/QPDF_objects.cc
| @@ -1233,13 +1233,9 @@ QPDFObjectHandle | @@ -1233,13 +1233,9 @@ QPDFObjectHandle | ||
| 1233 | Objects::readTrailer() | 1233 | Objects::readTrailer() |
| 1234 | { | 1234 | { |
| 1235 | qpdf_offset_t offset = m->file->tell(); | 1235 | qpdf_offset_t offset = m->file->tell(); |
| 1236 | - auto [object, empty] = | 1236 | + auto object = |
| 1237 | QPDFParser::parse(*m->file, "trailer", m->tokenizer, nullptr, qpdf, m->reconstructed_xref); | 1237 | QPDFParser::parse(*m->file, "trailer", m->tokenizer, nullptr, qpdf, m->reconstructed_xref); |
| 1238 | - if (empty) { | ||
| 1239 | - // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in | ||
| 1240 | - // actual PDF files and Adobe Reader appears to ignore them. | ||
| 1241 | - warn(damagedPDF("trailer", "empty object treated as null")); | ||
| 1242 | - } else if (object.isDictionary() && m->objects.readToken(*m->file).isWord("stream")) { | 1238 | + if (object.isDictionary() && m->objects.readToken(*m->file).isWord("stream")) { |
| 1243 | warn(damagedPDF("trailer", m->file->tell(), "stream keyword found in trailer")); | 1239 | warn(damagedPDF("trailer", m->file->tell(), "stream keyword found in trailer")); |
| 1244 | } | 1240 | } |
| 1245 | // Override last_offset so that it points to the beginning of the object we just read | 1241 | // Override last_offset so that it points to the beginning of the object we just read |
| @@ -1255,19 +1251,15 @@ Objects::readObject(std::string const& description, QPDFObjGen og) | @@ -1255,19 +1251,15 @@ Objects::readObject(std::string const& description, QPDFObjGen og) | ||
| 1255 | 1251 | ||
| 1256 | StringDecrypter decrypter{&qpdf, og}; | 1252 | StringDecrypter decrypter{&qpdf, og}; |
| 1257 | StringDecrypter* decrypter_ptr = m->encp->encrypted ? &decrypter : nullptr; | 1253 | StringDecrypter* decrypter_ptr = m->encp->encrypted ? &decrypter : nullptr; |
| 1258 | - auto [object, empty] = QPDFParser::parse( | 1254 | + auto object = QPDFParser::parse( |
| 1259 | *m->file, | 1255 | *m->file, |
| 1260 | m->last_object_description, | 1256 | m->last_object_description, |
| 1261 | m->tokenizer, | 1257 | m->tokenizer, |
| 1262 | decrypter_ptr, | 1258 | decrypter_ptr, |
| 1263 | qpdf, | 1259 | qpdf, |
| 1264 | m->reconstructed_xref || m->in_read_xref_stream); | 1260 | m->reconstructed_xref || m->in_read_xref_stream); |
| 1265 | - ; | ||
| 1266 | - if (empty) { | ||
| 1267 | - // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in | ||
| 1268 | - // actual PDF files and Adobe Reader appears to ignore them. | ||
| 1269 | - warn(damagedPDF(*m->file, m->file->getLastOffset(), "empty object treated as null")); | ||
| 1270 | - return object; | 1261 | + if (!object) { |
| 1262 | + return {}; | ||
| 1271 | } | 1263 | } |
| 1272 | auto token = readToken(*m->file); | 1264 | auto token = readToken(*m->file); |
| 1273 | if (object.isDictionary() && token.isWord("stream")) { | 1265 | if (object.isDictionary() && token.isWord("stream")) { |
| @@ -1366,24 +1358,6 @@ Objects::validateStreamLineEnd(QPDFObjectHandle& object, QPDFObjGen og, qpdf_off | @@ -1366,24 +1358,6 @@ Objects::validateStreamLineEnd(QPDFObjectHandle& object, QPDFObjGen og, qpdf_off | ||
| 1366 | } | 1358 | } |
| 1367 | } | 1359 | } |
| 1368 | 1360 | ||
| 1369 | -QPDFObjectHandle | ||
| 1370 | -Objects::readObjectInStream(is::OffsetBuffer& input, int stream_id, int obj_id) | ||
| 1371 | -{ | ||
| 1372 | - auto [object, empty] = QPDFParser::parse(input, stream_id, obj_id, m->tokenizer, qpdf); | ||
| 1373 | - if (empty) { | ||
| 1374 | - // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in | ||
| 1375 | - // actual PDF files and Adobe Reader appears to ignore them. | ||
| 1376 | - warn(QPDFExc( | ||
| 1377 | - qpdf_e_damaged_pdf, | ||
| 1378 | - m->file->getName() + " object stream " + std::to_string(stream_id), | ||
| 1379 | - +"object " + std::to_string(obj_id) + " 0, offset " + | ||
| 1380 | - std::to_string(input.getLastOffset()), | ||
| 1381 | - 0, | ||
| 1382 | - "empty object treated as null")); | ||
| 1383 | - } | ||
| 1384 | - return object; | ||
| 1385 | -} | ||
| 1386 | - | ||
| 1387 | bool | 1361 | bool |
| 1388 | Objects ::findEndstream() | 1362 | Objects ::findEndstream() |
| 1389 | { | 1363 | { |
| @@ -1536,25 +1510,25 @@ Objects::readObjectAtOffset( | @@ -1536,25 +1510,25 @@ Objects::readObjectAtOffset( | ||
| 1536 | return; | 1510 | return; |
| 1537 | } | 1511 | } |
| 1538 | 1512 | ||
| 1539 | - QPDFObjectHandle oh = readObject(description, og); | 1513 | + if (auto oh = readObject(description, og)) { |
| 1514 | + // Determine the end offset of this object before and after white space. We use these | ||
| 1515 | + // numbers to validate linearization hint tables. Offsets and lengths of objects may imply | ||
| 1516 | + // the end of an object to be anywhere between these values. | ||
| 1517 | + qpdf_offset_t end_before_space = m->file->tell(); | ||
| 1540 | 1518 | ||
| 1541 | - // Determine the end offset of this object before and after white space. We use these | ||
| 1542 | - // numbers to validate linearization hint tables. Offsets and lengths of objects may imply | ||
| 1543 | - // the end of an object to be anywhere between these values. | ||
| 1544 | - qpdf_offset_t end_before_space = m->file->tell(); | ||
| 1545 | - | ||
| 1546 | - // skip over spaces | ||
| 1547 | - while (true) { | ||
| 1548 | - char ch; | ||
| 1549 | - if (!m->file->read(&ch, 1)) { | ||
| 1550 | - throw damagedPDF(m->file->tell(), "EOF after endobj"); | ||
| 1551 | - } | ||
| 1552 | - if (!isspace(static_cast<unsigned char>(ch))) { | ||
| 1553 | - m->file->seek(-1, SEEK_CUR); | ||
| 1554 | - break; | 1519 | + // skip over spaces |
| 1520 | + while (true) { | ||
| 1521 | + char ch; | ||
| 1522 | + if (!m->file->read(&ch, 1)) { | ||
| 1523 | + throw damagedPDF(m->file->tell(), "EOF after endobj"); | ||
| 1524 | + } | ||
| 1525 | + if (!isspace(static_cast<unsigned char>(ch))) { | ||
| 1526 | + m->file->seek(-1, SEEK_CUR); | ||
| 1527 | + break; | ||
| 1528 | + } | ||
| 1555 | } | 1529 | } |
| 1530 | + m->objects.updateCache(og, oh.obj_sp(), end_before_space, m->file->tell()); | ||
| 1556 | } | 1531 | } |
| 1557 | - m->objects.updateCache(og, oh.obj_sp(), end_before_space, m->file->tell()); | ||
| 1558 | } | 1532 | } |
| 1559 | 1533 | ||
| 1560 | QPDFObjectHandle | 1534 | QPDFObjectHandle |
| @@ -1564,7 +1538,7 @@ Objects::readObjectAtOffset( | @@ -1564,7 +1538,7 @@ Objects::readObjectAtOffset( | ||
| 1564 | auto og = read_object_start(offset); | 1538 | auto og = read_object_start(offset); |
| 1565 | auto oh = readObject(description, og); | 1539 | auto oh = readObject(description, og); |
| 1566 | 1540 | ||
| 1567 | - if (!m->objects.isUnresolved(og)) { | 1541 | + if (!oh || !m->objects.isUnresolved(og)) { |
| 1568 | return oh; | 1542 | return oh; |
| 1569 | } | 1543 | } |
| 1570 | 1544 | ||
| @@ -1804,8 +1778,9 @@ Objects::resolveObjectsInStream(int obj_stream_number) | @@ -1804,8 +1778,9 @@ Objects::resolveObjectsInStream(int obj_stream_number) | ||
| 1804 | if (entry != m->xref_table.end() && entry->second.getType() == 2 && | 1778 | if (entry != m->xref_table.end() && entry->second.getType() == 2 && |
| 1805 | entry->second.getObjStreamNumber() == obj_stream_number) { | 1779 | entry->second.getObjStreamNumber() == obj_stream_number) { |
| 1806 | is::OffsetBuffer in("", {b_start + obj_offset, obj_size}, obj_offset); | 1780 | is::OffsetBuffer in("", {b_start + obj_offset, obj_size}, obj_offset); |
| 1807 | - auto oh = readObjectInStream(in, obj_stream_number, obj_id); | ||
| 1808 | - updateCache(og, oh.obj_sp(), end_before_space, end_after_space); | 1781 | + if (auto oh = QPDFParser::parse(in, obj_stream_number, obj_id, m->tokenizer, qpdf)) { |
| 1782 | + updateCache(og, oh.obj_sp(), end_before_space, end_after_space); | ||
| 1783 | + } | ||
| 1809 | } else { | 1784 | } else { |
| 1810 | QTC::TC("qpdf", "QPDF not caching overridden objstm object"); | 1785 | QTC::TC("qpdf", "QPDF not caching overridden objstm object"); |
| 1811 | } | 1786 | } |
libqpdf/global.cc
0 โ 100644
libqpdf/qpdf/QPDFObject_private.hh
| @@ -5,11 +5,12 @@ | @@ -5,11 +5,12 @@ | ||
| 5 | // include/qpdf/QPDFObject.hh. See comments there for an explanation. | 5 | // include/qpdf/QPDFObject.hh. See comments there for an explanation. |
| 6 | 6 | ||
| 7 | #include <qpdf/Constants.h> | 7 | #include <qpdf/Constants.h> |
| 8 | +#include <qpdf/Types.h> | ||
| 9 | + | ||
| 8 | #include <qpdf/JSON.hh> | 10 | #include <qpdf/JSON.hh> |
| 9 | #include <qpdf/JSON_writer.hh> | 11 | #include <qpdf/JSON_writer.hh> |
| 10 | #include <qpdf/QPDF.hh> | 12 | #include <qpdf/QPDF.hh> |
| 11 | #include <qpdf/QPDFObjGen.hh> | 13 | #include <qpdf/QPDFObjGen.hh> |
| 12 | -#include <qpdf/Types.h> | ||
| 13 | 14 | ||
| 14 | #include <map> | 15 | #include <map> |
| 15 | #include <memory> | 16 | #include <memory> |
libqpdf/qpdf/QPDFParser.hh
| @@ -5,13 +5,24 @@ | @@ -5,13 +5,24 @@ | ||
| 5 | #include <qpdf/QPDFObjectHandle_private.hh> | 5 | #include <qpdf/QPDFObjectHandle_private.hh> |
| 6 | #include <qpdf/QPDFObject_private.hh> | 6 | #include <qpdf/QPDFObject_private.hh> |
| 7 | #include <qpdf/QPDFTokenizer_private.hh> | 7 | #include <qpdf/QPDFTokenizer_private.hh> |
| 8 | +#include <qpdf/global_private.hh> | ||
| 8 | 9 | ||
| 9 | #include <memory> | 10 | #include <memory> |
| 10 | #include <string> | 11 | #include <string> |
| 11 | 12 | ||
| 13 | +using namespace qpdf; | ||
| 14 | +using namespace qpdf::global; | ||
| 15 | + | ||
| 12 | class QPDFParser | 16 | class QPDFParser |
| 13 | { | 17 | { |
| 14 | public: | 18 | public: |
| 19 | + class Error: public std::exception | ||
| 20 | + { | ||
| 21 | + public: | ||
| 22 | + Error() = default; | ||
| 23 | + virtual ~Error() noexcept = default; | ||
| 24 | + }; | ||
| 25 | + | ||
| 15 | static QPDFObjectHandle | 26 | static QPDFObjectHandle |
| 16 | parse(InputSource& input, std::string const& object_description, QPDF* context); | 27 | parse(InputSource& input, std::string const& object_description, QPDF* context); |
| 17 | 28 | ||
| @@ -30,8 +41,8 @@ class QPDFParser | @@ -30,8 +41,8 @@ class QPDFParser | ||
| 30 | QPDFObjectHandle::StringDecrypter* decrypter, | 41 | QPDFObjectHandle::StringDecrypter* decrypter, |
| 31 | QPDF* context); | 42 | QPDF* context); |
| 32 | 43 | ||
| 33 | - // For use by QPDF. Return parsed object and whether it is empty. | ||
| 34 | - static std::pair<QPDFObjectHandle, bool> parse( | 44 | + // For use by QPDF. |
| 45 | + static QPDFObjectHandle parse( | ||
| 35 | InputSource& input, | 46 | InputSource& input, |
| 36 | std::string const& object_description, | 47 | std::string const& object_description, |
| 37 | qpdf::Tokenizer& tokenizer, | 48 | qpdf::Tokenizer& tokenizer, |
| @@ -39,7 +50,7 @@ class QPDFParser | @@ -39,7 +50,7 @@ class QPDFParser | ||
| 39 | QPDF& context, | 50 | QPDF& context, |
| 40 | bool sanity_checks); | 51 | bool sanity_checks); |
| 41 | 52 | ||
| 42 | - static std::pair<QPDFObjectHandle, bool> parse( | 53 | + static QPDFObjectHandle parse( |
| 43 | qpdf::is::OffsetBuffer& input, | 54 | qpdf::is::OffsetBuffer& input, |
| 44 | int stream_id, | 55 | int stream_id, |
| 45 | int obj_id, | 56 | int obj_id, |
| @@ -101,14 +112,16 @@ class QPDFParser | @@ -101,14 +112,16 @@ class QPDFParser | ||
| 101 | int null_count{0}; | 112 | int null_count{0}; |
| 102 | }; | 113 | }; |
| 103 | 114 | ||
| 104 | - QPDFObjectHandle parse(bool& empty, bool content_stream); | 115 | + QPDFObjectHandle parse(bool content_stream = false); |
| 116 | + QPDFObjectHandle parse_first(bool content_stream); | ||
| 105 | QPDFObjectHandle parseRemainder(bool content_stream); | 117 | QPDFObjectHandle parseRemainder(bool content_stream); |
| 106 | void add(std::shared_ptr<QPDFObject>&& obj); | 118 | void add(std::shared_ptr<QPDFObject>&& obj); |
| 107 | void addNull(); | 119 | void addNull(); |
| 120 | + void add_bad_null(std::string const& msg); | ||
| 108 | void addInt(int count); | 121 | void addInt(int count); |
| 109 | template <typename T, typename... Args> | 122 | template <typename T, typename... Args> |
| 110 | void addScalar(Args&&... args); | 123 | void addScalar(Args&&... args); |
| 111 | - bool tooManyBadTokens(); | 124 | + void check_too_many_bad_tokens(); |
| 112 | void warnDuplicateKey(); | 125 | void warnDuplicateKey(); |
| 113 | void fixMissingKeys(); | 126 | void fixMissingKeys(); |
| 114 | void warn(qpdf_offset_t offset, std::string const& msg) const; | 127 | void warn(qpdf_offset_t offset, std::string const& msg) const; |
| @@ -136,7 +149,7 @@ class QPDFParser | @@ -136,7 +149,7 @@ class QPDFParser | ||
| 136 | // it only gets incremented or reset when a bad token is encountered. | 149 | // it only gets incremented or reset when a bad token is encountered. |
| 137 | int bad_count{0}; | 150 | int bad_count{0}; |
| 138 | // Number of bad tokens (remaining) before giving up. | 151 | // Number of bad tokens (remaining) before giving up. |
| 139 | - int max_bad_count{15}; | 152 | + uint32_t max_bad_count{Limits::objects_max_errors()}; |
| 140 | // Number of good tokens since last bad token. Irrelevant if bad_count == 0. | 153 | // Number of good tokens since last bad token. Irrelevant if bad_count == 0. |
| 141 | int good_count{0}; | 154 | int good_count{0}; |
| 142 | // Start offset including any leading whitespace. | 155 | // Start offset including any leading whitespace. |
| @@ -145,6 +158,7 @@ class QPDFParser | @@ -145,6 +158,7 @@ class QPDFParser | ||
| 145 | int int_count{0}; | 158 | int int_count{0}; |
| 146 | long long int_buffer[2]{0, 0}; | 159 | long long int_buffer[2]{0, 0}; |
| 147 | qpdf_offset_t last_offset_buffer[2]{0, 0}; | 160 | qpdf_offset_t last_offset_buffer[2]{0, 0}; |
| 161 | + bool empty_{false}; | ||
| 148 | }; | 162 | }; |
| 149 | 163 | ||
| 150 | #endif // QPDFPARSER_HH | 164 | #endif // QPDFPARSER_HH |
libqpdf/qpdf/QPDF_private.hh
| @@ -1039,7 +1039,6 @@ class QPDF::Doc::Objects: Common | @@ -1039,7 +1039,6 @@ class QPDF::Doc::Objects: Common | ||
| 1039 | QPDFObjectHandle readObject(std::string const& description, QPDFObjGen og); | 1039 | QPDFObjectHandle readObject(std::string const& description, QPDFObjGen og); |
| 1040 | void readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset); | 1040 | void readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset); |
| 1041 | void validateStreamLineEnd(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset); | 1041 | void validateStreamLineEnd(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset); |
| 1042 | - QPDFObjectHandle readObjectInStream(qpdf::is::OffsetBuffer& input, int stream_id, int obj_id); | ||
| 1043 | size_t recoverStreamLength( | 1042 | size_t recoverStreamLength( |
| 1044 | std::shared_ptr<InputSource> input, QPDFObjGen og, qpdf_offset_t stream_offset); | 1043 | std::shared_ptr<InputSource> input, QPDFObjGen og, qpdf_offset_t stream_offset); |
| 1045 | 1044 |
libqpdf/qpdf/global_private.hh
0 โ 100644
| 1 | + | ||
| 2 | +#ifndef GLOBAL_PRIVATE_HH | ||
| 3 | +#define GLOBAL_PRIVATE_HH | ||
| 4 | + | ||
| 5 | +#include <qpdf/Constants.h> | ||
| 6 | + | ||
| 7 | +#include <cstdint> | ||
| 8 | +#include <limits> | ||
| 9 | + | ||
| 10 | +namespace qpdf | ||
| 11 | +{ | ||
| 12 | + namespace global | ||
| 13 | + { | ||
| 14 | + class Limits | ||
| 15 | + { | ||
| 16 | + public: | ||
| 17 | + Limits(Limits const&) = delete; | ||
| 18 | + Limits(Limits&&) = delete; | ||
| 19 | + Limits& operator=(Limits const&) = delete; | ||
| 20 | + Limits& operator=(Limits&&) = delete; | ||
| 21 | + | ||
| 22 | + static uint32_t const& | ||
| 23 | + objects_max_nesting() | ||
| 24 | + { | ||
| 25 | + return l.objects_max_nesting_; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + static uint32_t const& | ||
| 29 | + objects_max_errors() | ||
| 30 | + { | ||
| 31 | + return l.objects_max_errors_; | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + static uint32_t const& | ||
| 35 | + objects_max_container_size(bool damaged) | ||
| 36 | + { | ||
| 37 | + return damaged ? l.objects_max_container_size_damaged_ | ||
| 38 | + : l.objects_max_container_size_; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + private: | ||
| 42 | + Limits() = default; | ||
| 43 | + ~Limits() = default; | ||
| 44 | + | ||
| 45 | + static Limits l; | ||
| 46 | + | ||
| 47 | + uint32_t objects_max_nesting_{499}; | ||
| 48 | + uint32_t objects_max_errors_{15}; | ||
| 49 | + uint32_t objects_max_container_size_{std::numeric_limits<uint32_t>::max()}; | ||
| 50 | + uint32_t objects_max_container_size_damaged_{5'000}; | ||
| 51 | + }; | ||
| 52 | + | ||
| 53 | + } // namespace global | ||
| 54 | + | ||
| 55 | +} // namespace qpdf | ||
| 56 | + | ||
| 57 | +#endif // GLOBAL_PRIVATE_HH |
qpdf/qpdf.testcov
| @@ -27,11 +27,6 @@ main QTest stream 0 | @@ -27,11 +27,6 @@ main QTest stream 0 | ||
| 27 | QPDF lin write nshared_total > nshared_first_page 1 | 27 | QPDF lin write nshared_total > nshared_first_page 1 |
| 28 | QPDFWriter encrypted hint stream 0 | 28 | QPDFWriter encrypted hint stream 0 |
| 29 | QPDF xref gen > 0 1 | 29 | QPDF xref gen > 0 1 |
| 30 | -QPDFParser bad brace 0 | ||
| 31 | -QPDFParser bad brace in parseRemainder 0 | ||
| 32 | -QPDFParser bad array close 0 | ||
| 33 | -QPDFParser bad array close in parseRemainder 0 | ||
| 34 | -QPDFParser bad dictionary close 0 | ||
| 35 | QPDFTokenizer bad ) 0 | 30 | QPDFTokenizer bad ) 0 |
| 36 | QPDFTokenizer bad > 0 | 31 | QPDFTokenizer bad > 0 |
| 37 | QPDFTokenizer bad hexstring character 0 | 32 | QPDFTokenizer bad hexstring character 0 |
| @@ -123,7 +118,6 @@ QPDF_Stream provider length not provided 0 | @@ -123,7 +118,6 @@ QPDF_Stream provider length not provided 0 | ||
| 123 | QPDF_Stream unknown stream length 0 | 118 | QPDF_Stream unknown stream length 0 |
| 124 | QPDF replaceReserved 0 | 119 | QPDF replaceReserved 0 |
| 125 | QPDFWriter copy use_aes 1 | 120 | QPDFWriter copy use_aes 1 |
| 126 | -QPDFParser indirect without context 0 | ||
| 127 | QPDFObjectHandle trailing data in parse 0 | 121 | QPDFObjectHandle trailing data in parse 0 |
| 128 | QPDFTokenizer EOF reading token 0 | 122 | QPDFTokenizer EOF reading token 0 |
| 129 | QPDFTokenizer EOF reading appendable token 0 | 123 | QPDFTokenizer EOF reading appendable token 0 |
| @@ -145,11 +139,7 @@ QPDFJob pages range omitted in middle 0 | @@ -145,11 +139,7 @@ QPDFJob pages range omitted in middle 0 | ||
| 145 | QPDFWriter standard deterministic ID 1 | 139 | QPDFWriter standard deterministic ID 1 |
| 146 | QPDFWriter linearized deterministic ID 1 | 140 | QPDFWriter linearized deterministic ID 1 |
| 147 | qpdf-c called qpdf_set_deterministic_ID 0 | 141 | qpdf-c called qpdf_set_deterministic_ID 0 |
| 148 | -QPDFParser invalid objgen 0 | ||
| 149 | -QPDFParser treat word as string 0 | ||
| 150 | -QPDFParser treat word as string in parseRemainder 0 | ||
| 151 | QPDFParser found fake 1 | 142 | QPDFParser found fake 1 |
| 152 | -QPDFParser no val for last key 0 | ||
| 153 | QPDFObjectHandle errors in parsecontent 0 | 143 | QPDFObjectHandle errors in parsecontent 0 |
| 154 | QPDFJob split-pages %d 0 | 144 | QPDFJob split-pages %d 0 |
| 155 | QPDFJob split-pages .pdf 0 | 145 | QPDFJob split-pages .pdf 0 |
| @@ -168,10 +158,6 @@ Pl_QPDFTokenizer found ID 0 | @@ -168,10 +158,6 @@ Pl_QPDFTokenizer found ID 0 | ||
| 168 | QPDFObjectHandle coalesce called on stream 0 | 158 | QPDFObjectHandle coalesce called on stream 0 |
| 169 | QPDFObjectHandle coalesce provide stream data 0 | 159 | QPDFObjectHandle coalesce provide stream data 0 |
| 170 | QPDF_Stream bad token at end during normalize 0 | 160 | QPDF_Stream bad token at end during normalize 0 |
| 171 | -QPDFParser bad token in parse 0 | ||
| 172 | -QPDFParser bad token in parseRemainder 0 | ||
| 173 | -QPDFParser eof in parse 0 | ||
| 174 | -QPDFParser eof in parseRemainder 0 | ||
| 175 | QPDFObjectHandle boolean returning false 0 | 161 | QPDFObjectHandle boolean returning false 0 |
| 176 | QPDFObjectHandle real returning 0.0 0 | 162 | QPDFObjectHandle real returning 0.0 0 |
| 177 | QPDFObjectHandle operator returning fake value 0 | 163 | QPDFObjectHandle operator returning fake value 0 |
| @@ -189,7 +175,6 @@ QPDFObjectHandle dictionary ignoring replaceKey 0 | @@ -189,7 +175,6 @@ QPDFObjectHandle dictionary ignoring replaceKey 0 | ||
| 189 | QPDFObjectHandle numeric non-numeric 0 | 175 | QPDFObjectHandle numeric non-numeric 0 |
| 190 | QPDFObjectHandle erase array bounds 0 | 176 | QPDFObjectHandle erase array bounds 0 |
| 191 | qpdf-c called qpdf_check_pdf 0 | 177 | qpdf-c called qpdf_check_pdf 0 |
| 192 | -QPDFParser too deep 0 | ||
| 193 | QPDFFormFieldObjectHelper TU present 0 | 178 | QPDFFormFieldObjectHelper TU present 0 |
| 194 | QPDFFormFieldObjectHelper TM present 0 | 179 | QPDFFormFieldObjectHelper TM present 0 |
| 195 | QPDFFormFieldObjectHelper TU absent 0 | 180 | QPDFFormFieldObjectHelper TU absent 0 |
| @@ -252,7 +237,6 @@ QPDFJob image optimize bits per component 0 | @@ -252,7 +237,6 @@ QPDFJob image optimize bits per component 0 | ||
| 252 | QPDF eof skipping spaces before xref 1 | 237 | QPDF eof skipping spaces before xref 1 |
| 253 | QPDF_encryption user matches owner V < 5 0 | 238 | QPDF_encryption user matches owner V < 5 0 |
| 254 | QPDF_encryption same password 1 | 239 | QPDF_encryption same password 1 |
| 255 | -QPDFParser duplicate dict key 0 | ||
| 256 | QPDFWriter no encryption sig contents 0 | 240 | QPDFWriter no encryption sig contents 0 |
| 257 | QPDFPageObjectHelper colorspace lookup 0 | 241 | QPDFPageObjectHelper colorspace lookup 0 |
| 258 | QPDFPageObjectHelper filter form xobject 0 | 242 | QPDFPageObjectHelper filter form xobject 0 |
qpdf/qtest/qpdf/issue-100.out
| @@ -7,7 +7,6 @@ WARNING: issue-100.pdf (trailer, offset 950): recovered trailer has no /Root ent | @@ -7,7 +7,6 @@ WARNING: issue-100.pdf (trailer, offset 950): recovered trailer has no /Root ent | ||
| 7 | WARNING: issue-100.pdf (trailer, offset 488): stream keyword found in trailer | 7 | WARNING: issue-100.pdf (trailer, offset 488): stream keyword found in trailer |
| 8 | WARNING: issue-100.pdf (trailer, offset 418): recovered trailer has no /Root entry | 8 | WARNING: issue-100.pdf (trailer, offset 418): recovered trailer has no /Root entry |
| 9 | WARNING: issue-100.pdf (object 1 0, offset 83): unexpected dictionary close token | 9 | WARNING: issue-100.pdf (object 1 0, offset 83): unexpected dictionary close token |
| 10 | -WARNING: issue-100.pdf (object 1 0, offset 87): expected endobj | ||
| 11 | WARNING: issue-100.pdf (object 5 0, offset 268): unknown token while reading object; treating as null | 10 | WARNING: issue-100.pdf (object 5 0, offset 268): unknown token while reading object; treating as null |
| 12 | WARNING: issue-100.pdf (object 5 0, offset 286): unknown token while reading object; treating as null | 11 | WARNING: issue-100.pdf (object 5 0, offset 286): unknown token while reading object; treating as null |
| 13 | WARNING: issue-100.pdf (object 5 0, offset 289): unknown token while reading object; treating as null | 12 | WARNING: issue-100.pdf (object 5 0, offset 289): unknown token while reading object; treating as null |
| @@ -15,9 +14,7 @@ WARNING: issue-100.pdf (object 5 0, offset 294): unknown token while reading obj | @@ -15,9 +14,7 @@ WARNING: issue-100.pdf (object 5 0, offset 294): unknown token while reading obj | ||
| 15 | WARNING: issue-100.pdf (object 5 0, offset 297): unknown token while reading object; treating as null | 14 | WARNING: issue-100.pdf (object 5 0, offset 297): unknown token while reading object; treating as null |
| 16 | WARNING: issue-100.pdf (object 5 0, offset 304): unknown token while reading object; treating as null | 15 | WARNING: issue-100.pdf (object 5 0, offset 304): unknown token while reading object; treating as null |
| 17 | WARNING: issue-100.pdf (object 5 0, offset 304): too many errors; giving up on reading object | 16 | WARNING: issue-100.pdf (object 5 0, offset 304): too many errors; giving up on reading object |
| 18 | -WARNING: issue-100.pdf (object 5 0, offset 308): expected endobj | ||
| 19 | WARNING: issue-100.pdf (object 8 0, offset 107): invalid character ()) in hexstring | 17 | WARNING: issue-100.pdf (object 8 0, offset 107): invalid character ()) in hexstring |
| 20 | -WARNING: issue-100.pdf (object 8 0, offset 109): expected endobj | ||
| 21 | WARNING: issue-100.pdf (object 9 0, offset 527): unknown token while reading object; treating as string | 18 | WARNING: issue-100.pdf (object 9 0, offset 527): unknown token while reading object; treating as string |
| 22 | WARNING: issue-100.pdf (object 9 0, offset 529): expected endobj | 19 | WARNING: issue-100.pdf (object 9 0, offset 529): expected endobj |
| 23 | WARNING: issue-100.pdf (object 10 0, offset 573): expected endobj | 20 | WARNING: issue-100.pdf (object 10 0, offset 573): expected endobj |
qpdf/qtest/qpdf/issue-101.out
| @@ -8,7 +8,6 @@ WARNING: issue-101.pdf (object 11 0, offset 637): unknown token while reading ob | @@ -8,7 +8,6 @@ WARNING: issue-101.pdf (object 11 0, offset 637): unknown token while reading ob | ||
| 8 | WARNING: issue-101.pdf (object 11 0, offset 639): unknown token while reading object; treating as null | 8 | WARNING: issue-101.pdf (object 11 0, offset 639): unknown token while reading object; treating as null |
| 9 | WARNING: issue-101.pdf (object 11 0, offset 644): unknown token while reading object; treating as null | 9 | WARNING: issue-101.pdf (object 11 0, offset 644): unknown token while reading object; treating as null |
| 10 | WARNING: issue-101.pdf (object 11 0, offset 644): too many errors; giving up on reading object | 10 | WARNING: issue-101.pdf (object 11 0, offset 644): too many errors; giving up on reading object |
| 11 | -WARNING: issue-101.pdf (object 11 0, offset 647): expected endobj | ||
| 12 | WARNING: issue-101.pdf (trailer, offset 4433): recovered trailer has no /Root entry | 11 | WARNING: issue-101.pdf (trailer, offset 4433): recovered trailer has no /Root entry |
| 13 | WARNING: issue-101.pdf (trailer, offset 4183): stream keyword found in trailer | 12 | WARNING: issue-101.pdf (trailer, offset 4183): stream keyword found in trailer |
| 14 | WARNING: issue-101.pdf (trailer, offset 4113): recovered trailer has no /Root entry | 13 | WARNING: issue-101.pdf (trailer, offset 4113): recovered trailer has no /Root entry |
| @@ -31,6 +30,8 @@ WARNING: issue-101.pdf (trailer, offset 1508): stream keyword found in trailer | @@ -31,6 +30,8 @@ WARNING: issue-101.pdf (trailer, offset 1508): stream keyword found in trailer | ||
| 31 | WARNING: issue-101.pdf (trailer, offset 1438): recovered trailer has no /Root entry | 30 | WARNING: issue-101.pdf (trailer, offset 1438): recovered trailer has no /Root entry |
| 32 | WARNING: issue-101.pdf (object 2 0, offset 244): unknown token while reading object; treating as null | 31 | WARNING: issue-101.pdf (object 2 0, offset 244): unknown token while reading object; treating as null |
| 33 | WARNING: issue-101.pdf (object 2 0, offset 29): dictionary has duplicated key /Parent; last occurrence overrides earlier ones | 32 | WARNING: issue-101.pdf (object 2 0, offset 29): dictionary has duplicated key /Parent; last occurrence overrides earlier ones |
| 33 | +WARNING: issue-101.pdf (object 2 0, offset 333): treating bad indirect reference (0 0 R) as null | ||
| 34 | +WARNING: issue-101.pdf (object 5 0, offset 1247): treating bad indirect reference (0 0 R) as null | ||
| 34 | WARNING: issue-101.pdf (object 5 0, offset 1242): dictionary ended prematurely; using null as value for last key | 35 | WARNING: issue-101.pdf (object 5 0, offset 1242): dictionary ended prematurely; using null as value for last key |
| 35 | WARNING: issue-101.pdf (object 5 0, offset 1242): expected dictionary keys but found non-name objects; ignoring | 36 | WARNING: issue-101.pdf (object 5 0, offset 1242): expected dictionary keys but found non-name objects; ignoring |
| 36 | WARNING: issue-101.pdf (object 7 0, offset 3855): unknown token while reading object; treating as null | 37 | WARNING: issue-101.pdf (object 7 0, offset 3855): unknown token while reading object; treating as null |
| @@ -40,9 +41,7 @@ WARNING: issue-101.pdf (object 7 0, offset 3866): unknown token while reading ob | @@ -40,9 +41,7 @@ WARNING: issue-101.pdf (object 7 0, offset 3866): unknown token while reading ob | ||
| 40 | WARNING: issue-101.pdf (object 7 0, offset 3873): unknown token while reading object; treating as null | 41 | WARNING: issue-101.pdf (object 7 0, offset 3873): unknown token while reading object; treating as null |
| 41 | WARNING: issue-101.pdf (object 7 0, offset 3879): unknown token while reading object; treating as null | 42 | WARNING: issue-101.pdf (object 7 0, offset 3879): unknown token while reading object; treating as null |
| 42 | WARNING: issue-101.pdf (object 7 0, offset 3879): too many errors; giving up on reading object | 43 | WARNING: issue-101.pdf (object 7 0, offset 3879): too many errors; giving up on reading object |
| 43 | -WARNING: issue-101.pdf (object 7 0, offset 3888): expected endobj | ||
| 44 | WARNING: issue-101.pdf (object 8 0, offset 4067): invalid character ()) in hexstring | 44 | WARNING: issue-101.pdf (object 8 0, offset 4067): invalid character ()) in hexstring |
| 45 | -WARNING: issue-101.pdf (object 8 0, offset 4069): expected endobj | ||
| 46 | WARNING: issue-101.pdf (object 9 0, offset 2832): unknown token while reading object; treating as string | 45 | WARNING: issue-101.pdf (object 9 0, offset 2832): unknown token while reading object; treating as string |
| 47 | WARNING: issue-101.pdf (object 9 0, offset 2834): expected endobj | 46 | WARNING: issue-101.pdf (object 9 0, offset 2834): expected endobj |
| 48 | qpdf: issue-101.pdf: unable to find trailer dictionary while recovering damaged file | 47 | qpdf: issue-101.pdf: unable to find trailer dictionary while recovering damaged file |
qpdf/qtest/qpdf/issue-118.out
| 1 | WARNING: issue-118.pdf: can't find PDF header | 1 | WARNING: issue-118.pdf: can't find PDF header |
| 2 | +WARNING: issue-118.pdf (xref stream: object 8 0, offset 720): treating bad indirect reference (0 0 R) as null | ||
| 2 | WARNING: issue-118.pdf (xref stream, offset 732): self-referential object stream 2 | 3 | WARNING: issue-118.pdf (xref stream, offset 732): self-referential object stream 2 |
| 3 | WARNING: issue-118.pdf (xref stream, offset 732): object stream id 12336 for object 3 is impossibly large | 4 | WARNING: issue-118.pdf (xref stream, offset 732): object stream id 12336 for object 3 is impossibly large |
| 4 | WARNING: issue-118.pdf (xref stream, offset 732): object stream id 12336 for object 4 is impossibly large | 5 | WARNING: issue-118.pdf (xref stream, offset 732): object stream id 12336 for object 4 is impossibly large |
qpdf/qtest/qpdf/issue-150.out
| 1 | WARNING: issue-150.pdf: can't find PDF header | 1 | WARNING: issue-150.pdf: can't find PDF header |
| 2 | +WARNING: issue-150.pdf (xref stream: object 8 0, offset 56): treating object as null because of error during parsing : overflow/underflow converting 9900000000000000000 to 64-bit integer | ||
| 2 | WARNING: issue-150.pdf: file is damaged | 3 | WARNING: issue-150.pdf: file is damaged |
| 3 | -WARNING: issue-150.pdf: error reading xref: overflow/underflow converting 9900000000000000000 to 64-bit integer | 4 | +WARNING: issue-150.pdf (offset 4): xref not found |
| 4 | WARNING: issue-150.pdf: Attempting to reconstruct cross-reference table | 5 | WARNING: issue-150.pdf: Attempting to reconstruct cross-reference table |
| 5 | WARNING: issue-150.pdf (object 8 0): object has offset 0 | 6 | WARNING: issue-150.pdf (object 8 0): object has offset 0 |
| 6 | qpdf: issue-150.pdf: unable to find trailer dictionary while recovering damaged file | 7 | qpdf: issue-150.pdf: unable to find trailer dictionary while recovering damaged file |
qpdf/qtest/qpdf/issue-1503.out
| @@ -6,11 +6,8 @@ WARNING: issue-1503.pdf (object 31 0, offset 813): unknown token while reading o | @@ -6,11 +6,8 @@ WARNING: issue-1503.pdf (object 31 0, offset 813): unknown token while reading o | ||
| 6 | WARNING: issue-1503.pdf (object 31 0, offset 851): unknown token while reading object; treating as null | 6 | WARNING: issue-1503.pdf (object 31 0, offset 851): unknown token while reading object; treating as null |
| 7 | WARNING: issue-1503.pdf (object 31 0, offset 856): unknown token while reading object; treating as null | 7 | WARNING: issue-1503.pdf (object 31 0, offset 856): unknown token while reading object; treating as null |
| 8 | WARNING: issue-1503.pdf (object 31 0, offset 861): unexpected 'endobj' or 'endstream' while reading object; giving up on reading object | 8 | WARNING: issue-1503.pdf (object 31 0, offset 861): unexpected 'endobj' or 'endstream' while reading object; giving up on reading object |
| 9 | -WARNING: issue-1503.pdf (object 31 0, offset 871): expected endobj | ||
| 10 | WARNING: issue-1503.pdf (object 38 0, offset 1126): unexpected 'endobj' or 'endstream' while reading object; giving up on reading object | 9 | WARNING: issue-1503.pdf (object 38 0, offset 1126): unexpected 'endobj' or 'endstream' while reading object; giving up on reading object |
| 11 | -WARNING: issue-1503.pdf (object 38 0, offset 1133): expected endobj | ||
| 12 | WARNING: issue-1503.pdf (object 40 0, offset 1195): unexpected array close token; giving up on reading object | 10 | WARNING: issue-1503.pdf (object 40 0, offset 1195): unexpected array close token; giving up on reading object |
| 13 | -WARNING: issue-1503.pdf (object 40 0, offset 1198): expected endobj | ||
| 14 | WARNING: issue-1503.pdf (object 41 0, offset 1359): stream dictionary lacks /Length key | 11 | WARNING: issue-1503.pdf (object 41 0, offset 1359): stream dictionary lacks /Length key |
| 15 | WARNING: issue-1503.pdf (object 41 0, offset 1411): attempting to recover stream length | 12 | WARNING: issue-1503.pdf (object 41 0, offset 1411): attempting to recover stream length |
| 16 | WARNING: issue-1503.pdf (object 41 0, offset 1411): recovered stream length: 54 | 13 | WARNING: issue-1503.pdf (object 41 0, offset 1411): recovered stream length: 54 |
| @@ -22,9 +19,7 @@ WARNING: issue-1503.pdf (object 44 0, offset 1814): name with stray # will not w | @@ -22,9 +19,7 @@ WARNING: issue-1503.pdf (object 44 0, offset 1814): name with stray # will not w | ||
| 22 | WARNING: issue-1503.pdf (object 44 0, offset 1821): unknown token while reading object; treating as null | 19 | WARNING: issue-1503.pdf (object 44 0, offset 1821): unknown token while reading object; treating as null |
| 23 | WARNING: issue-1503.pdf (object 44 0, offset 1826): unknown token while reading object; treating as null | 20 | WARNING: issue-1503.pdf (object 44 0, offset 1826): unknown token while reading object; treating as null |
| 24 | WARNING: issue-1503.pdf (object 44 0, offset 1826): too many errors; giving up on reading object | 21 | WARNING: issue-1503.pdf (object 44 0, offset 1826): too many errors; giving up on reading object |
| 25 | -WARNING: issue-1503.pdf (object 44 0, offset 1829): expected endobj | ||
| 26 | WARNING: issue-1503.pdf (object 46 0, offset 1923): unexpected array close token; giving up on reading object | 22 | WARNING: issue-1503.pdf (object 46 0, offset 1923): unexpected array close token; giving up on reading object |
| 27 | -WARNING: issue-1503.pdf (object 46 0, offset 1926): expected endobj | ||
| 28 | WARNING: issue-1503.pdf (object 47 0, offset 2087): stream dictionary lacks /Length key | 23 | WARNING: issue-1503.pdf (object 47 0, offset 2087): stream dictionary lacks /Length key |
| 29 | WARNING: issue-1503.pdf (object 47 0, offset 2139): attempting to recover stream length | 24 | WARNING: issue-1503.pdf (object 47 0, offset 2139): attempting to recover stream length |
| 30 | WARNING: issue-1503.pdf (object 47 0, offset 2139): recovered stream length: 54 | 25 | WARNING: issue-1503.pdf (object 47 0, offset 2139): recovered stream length: 54 |
| @@ -59,8 +54,6 @@ WARNING: issue-1503.pdf (object 151 0, offset 3836): unknown token while reading | @@ -59,8 +54,6 @@ WARNING: issue-1503.pdf (object 151 0, offset 3836): unknown token while reading | ||
| 59 | WARNING: issue-1503.pdf (object 151 0, offset 3958): unknown token while reading object; treating as null | 54 | WARNING: issue-1503.pdf (object 151 0, offset 3958): unknown token while reading object; treating as null |
| 60 | WARNING: issue-1503.pdf (object 152 0, offset 4088): parse error while reading object | 55 | WARNING: issue-1503.pdf (object 152 0, offset 4088): parse error while reading object |
| 61 | WARNING: issue-1503.pdf (object 152 0, offset 4088): unexpected EOF | 56 | WARNING: issue-1503.pdf (object 152 0, offset 4088): unexpected EOF |
| 62 | -WARNING: issue-1503.pdf (object 152 0, offset 4088): expected endobj | ||
| 63 | -WARNING: issue-1503.pdf (object 152 0, offset 4088): EOF after endobj | ||
| 64 | WARNING: issue-1503.pdf (object 155 0, offset 162): unknown token while reading object; treating as null | 57 | WARNING: issue-1503.pdf (object 155 0, offset 162): unknown token while reading object; treating as null |
| 65 | WARNING: issue-1503.pdf (object 155 0, offset 342): unknown token while reading object; treating as null | 58 | WARNING: issue-1503.pdf (object 155 0, offset 342): unknown token while reading object; treating as null |
| 66 | WARNING: issue-1503.pdf (object 155 0, offset 345): unknown token while reading object; treating as null | 59 | WARNING: issue-1503.pdf (object 155 0, offset 345): unknown token while reading object; treating as null |
qpdf/qtest/qpdf/issue-335a.out
| @@ -39,12 +39,14 @@ WARNING: issue-335a.pdf (trailer, offset 22844): expected dictionary keys but fo | @@ -39,12 +39,14 @@ WARNING: issue-335a.pdf (trailer, offset 22844): expected dictionary keys but fo | ||
| 39 | WARNING: issue-335a.pdf (trailer, offset 22880): stream keyword found in trailer | 39 | WARNING: issue-335a.pdf (trailer, offset 22880): stream keyword found in trailer |
| 40 | WARNING: issue-335a.pdf (trailer, offset 22840): recovered trailer has no /Root entry | 40 | WARNING: issue-335a.pdf (trailer, offset 22840): recovered trailer has no /Root entry |
| 41 | WARNING: issue-335a.pdf (trailer, offset 22702): unknown token while reading object; treating as null | 41 | WARNING: issue-335a.pdf (trailer, offset 22702): unknown token while reading object; treating as null |
| 42 | +WARNING: issue-335a.pdf (trailer, offset 22713): treating bad indirect reference (0 0 R) as null | ||
| 42 | WARNING: issue-335a.pdf (trailer, offset 22701): expected dictionary keys but found non-name objects; ignoring | 43 | WARNING: issue-335a.pdf (trailer, offset 22701): expected dictionary keys but found non-name objects; ignoring |
| 43 | WARNING: issue-335a.pdf (trailer, offset 22746): stream keyword found in trailer | 44 | WARNING: issue-335a.pdf (trailer, offset 22746): stream keyword found in trailer |
| 44 | WARNING: issue-335a.pdf (trailer, offset 22697): recovered trailer has no /Root entry | 45 | WARNING: issue-335a.pdf (trailer, offset 22697): recovered trailer has no /Root entry |
| 45 | WARNING: issue-335a.pdf (trailer, offset 22687): unknown token while reading object; treating as null | 46 | WARNING: issue-335a.pdf (trailer, offset 22687): unknown token while reading object; treating as null |
| 46 | WARNING: issue-335a.pdf (trailer, offset 22690): unknown token while reading object; treating as null | 47 | WARNING: issue-335a.pdf (trailer, offset 22690): unknown token while reading object; treating as null |
| 47 | WARNING: issue-335a.pdf (trailer, offset 22702): unknown token while reading object; treating as null | 48 | WARNING: issue-335a.pdf (trailer, offset 22702): unknown token while reading object; treating as null |
| 49 | +WARNING: issue-335a.pdf (trailer, offset 22713): treating bad indirect reference (0 0 R) as null | ||
| 48 | WARNING: issue-335a.pdf (trailer, offset 22701): expected dictionary keys but found non-name objects; ignoring | 50 | WARNING: issue-335a.pdf (trailer, offset 22701): expected dictionary keys but found non-name objects; ignoring |
| 49 | WARNING: issue-335a.pdf (trailer, offset 22740): unknown token while reading object; treating as null | 51 | WARNING: issue-335a.pdf (trailer, offset 22740): unknown token while reading object; treating as null |
| 50 | WARNING: issue-335a.pdf (trailer, offset 22748): unknown token while reading object; treating as null | 52 | WARNING: issue-335a.pdf (trailer, offset 22748): unknown token while reading object; treating as null |
| @@ -58,6 +60,7 @@ WARNING: issue-335a.pdf (trailer, offset 22675): unknown token while reading obj | @@ -58,6 +60,7 @@ WARNING: issue-335a.pdf (trailer, offset 22675): unknown token while reading obj | ||
| 58 | WARNING: issue-335a.pdf (trailer, offset 22687): unknown token while reading object; treating as null | 60 | WARNING: issue-335a.pdf (trailer, offset 22687): unknown token while reading object; treating as null |
| 59 | WARNING: issue-335a.pdf (trailer, offset 22690): unknown token while reading object; treating as null | 61 | WARNING: issue-335a.pdf (trailer, offset 22690): unknown token while reading object; treating as null |
| 60 | WARNING: issue-335a.pdf (trailer, offset 22702): unknown token while reading object; treating as null | 62 | WARNING: issue-335a.pdf (trailer, offset 22702): unknown token while reading object; treating as null |
| 63 | +WARNING: issue-335a.pdf (trailer, offset 22713): treating bad indirect reference (0 0 R) as null | ||
| 61 | WARNING: issue-335a.pdf (trailer, offset 22701): expected dictionary keys but found non-name objects; ignoring | 64 | WARNING: issue-335a.pdf (trailer, offset 22701): expected dictionary keys but found non-name objects; ignoring |
| 62 | WARNING: issue-335a.pdf (trailer, offset 22740): unknown token while reading object; treating as null | 65 | WARNING: issue-335a.pdf (trailer, offset 22740): unknown token while reading object; treating as null |
| 63 | WARNING: issue-335a.pdf (trailer, offset 22748): unknown token while reading object; treating as null | 66 | WARNING: issue-335a.pdf (trailer, offset 22748): unknown token while reading object; treating as null |
| @@ -66,6 +69,8 @@ WARNING: issue-335a.pdf (trailer, offset 22791): unknown token while reading obj | @@ -66,6 +69,8 @@ WARNING: issue-335a.pdf (trailer, offset 22791): unknown token while reading obj | ||
| 66 | WARNING: issue-335a.pdf (trailer, offset 22794): unexpected > | 69 | WARNING: issue-335a.pdf (trailer, offset 22794): unexpected > |
| 67 | WARNING: issue-335a.pdf (trailer, offset 22794): too many errors; giving up on reading object | 70 | WARNING: issue-335a.pdf (trailer, offset 22794): too many errors; giving up on reading object |
| 68 | WARNING: issue-335a.pdf (trailer, offset 22437): unknown token while reading object; treating as null | 71 | WARNING: issue-335a.pdf (trailer, offset 22437): unknown token while reading object; treating as null |
| 72 | +WARNING: issue-335a.pdf (trailer, offset 22448): treating bad indirect reference (0 0 R) as null | ||
| 73 | +WARNING: issue-335a.pdf (trailer, offset 22471): treating bad indirect reference (20 -1 R) as null | ||
| 69 | WARNING: issue-335a.pdf (trailer, offset 22436): expected dictionary keys but found non-name objects; ignoring | 74 | WARNING: issue-335a.pdf (trailer, offset 22436): expected dictionary keys but found non-name objects; ignoring |
| 70 | WARNING: issue-335a.pdf (trailer, offset 22482): stream keyword found in trailer | 75 | WARNING: issue-335a.pdf (trailer, offset 22482): stream keyword found in trailer |
| 71 | WARNING: issue-335a.pdf (trailer, offset 22432): recovered trailer has no /Root entry | 76 | WARNING: issue-335a.pdf (trailer, offset 22432): recovered trailer has no /Root entry |
| @@ -98,27 +103,30 @@ WARNING: issue-335a.pdf (trailer, offset 22134): stream keyword found in trailer | @@ -98,27 +103,30 @@ WARNING: issue-335a.pdf (trailer, offset 22134): stream keyword found in trailer | ||
| 98 | WARNING: issue-335a.pdf (trailer, offset 22083): recovered trailer has no /Root entry | 103 | WARNING: issue-335a.pdf (trailer, offset 22083): recovered trailer has no /Root entry |
| 99 | WARNING: issue-335a.pdf (trailer, offset 22000): invalid character (t) in hexstring | 104 | WARNING: issue-335a.pdf (trailer, offset 22000): invalid character (t) in hexstring |
| 100 | WARNING: issue-335a.pdf (trailer, offset 21937): unknown token while reading object; treating as null | 105 | WARNING: issue-335a.pdf (trailer, offset 21937): unknown token while reading object; treating as null |
| 106 | +WARNING: issue-335a.pdf (trailer, offset 21948): treating bad indirect reference (0 0 R) as null | ||
| 101 | WARNING: issue-335a.pdf (trailer, offset 21962): unknown token while reading object; treating as null | 107 | WARNING: issue-335a.pdf (trailer, offset 21962): unknown token while reading object; treating as null |
| 102 | WARNING: issue-335a.pdf (trailer, offset 21991): unknown token while reading object; treating as null | 108 | WARNING: issue-335a.pdf (trailer, offset 21991): unknown token while reading object; treating as null |
| 103 | WARNING: issue-335a.pdf (trailer, offset 22000): invalid character (t) in hexstring | 109 | WARNING: issue-335a.pdf (trailer, offset 22000): invalid character (t) in hexstring |
| 104 | WARNING: issue-335a.pdf (trailer, offset 22003): unknown token while reading object; treating as null | 110 | WARNING: issue-335a.pdf (trailer, offset 22003): unknown token while reading object; treating as null |
| 111 | +WARNING: issue-335a.pdf (trailer, offset 22026): treating bad indirect reference (-4 0 R) as null | ||
| 105 | WARNING: issue-335a.pdf (trailer, offset 21936): dictionary has duplicated key /Length; last occurrence overrides earlier ones | 112 | WARNING: issue-335a.pdf (trailer, offset 21936): dictionary has duplicated key /Length; last occurrence overrides earlier ones |
| 106 | WARNING: issue-335a.pdf (trailer, offset 22028): unexpected > | 113 | WARNING: issue-335a.pdf (trailer, offset 22028): unexpected > |
| 107 | WARNING: issue-335a.pdf (trailer, offset 22030): unknown token while reading object; treating as null | 114 | WARNING: issue-335a.pdf (trailer, offset 22030): unknown token while reading object; treating as null |
| 108 | -WARNING: issue-335a.pdf (trailer, offset 22038): unknown token while reading object; treating as null | ||
| 109 | -WARNING: issue-335a.pdf (trailer, offset 22038): too many errors; giving up on reading object | 115 | +WARNING: issue-335a.pdf (trailer, offset 22030): too many errors; giving up on reading object |
| 110 | WARNING: issue-335a.pdf (trailer, offset 21918): unknown token while reading object; treating as null | 116 | WARNING: issue-335a.pdf (trailer, offset 21918): unknown token while reading object; treating as null |
| 111 | WARNING: issue-335a.pdf (trailer, offset 21925): unknown token while reading object; treating as null | 117 | WARNING: issue-335a.pdf (trailer, offset 21925): unknown token while reading object; treating as null |
| 112 | WARNING: issue-335a.pdf (trailer, offset 21937): unknown token while reading object; treating as null | 118 | WARNING: issue-335a.pdf (trailer, offset 21937): unknown token while reading object; treating as null |
| 119 | +WARNING: issue-335a.pdf (trailer, offset 21948): treating bad indirect reference (0 0 R) as null | ||
| 113 | WARNING: issue-335a.pdf (trailer, offset 21962): unknown token while reading object; treating as null | 120 | WARNING: issue-335a.pdf (trailer, offset 21962): unknown token while reading object; treating as null |
| 114 | WARNING: issue-335a.pdf (trailer, offset 21991): unknown token while reading object; treating as null | 121 | WARNING: issue-335a.pdf (trailer, offset 21991): unknown token while reading object; treating as null |
| 115 | WARNING: issue-335a.pdf (trailer, offset 22000): invalid character (t) in hexstring | 122 | WARNING: issue-335a.pdf (trailer, offset 22000): invalid character (t) in hexstring |
| 116 | WARNING: issue-335a.pdf (trailer, offset 22003): unknown token while reading object; treating as null | 123 | WARNING: issue-335a.pdf (trailer, offset 22003): unknown token while reading object; treating as null |
| 124 | +WARNING: issue-335a.pdf (trailer, offset 22026): treating bad indirect reference (-4 0 R) as null | ||
| 117 | WARNING: issue-335a.pdf (trailer, offset 21936): dictionary has duplicated key /Length; last occurrence overrides earlier ones | 125 | WARNING: issue-335a.pdf (trailer, offset 21936): dictionary has duplicated key /Length; last occurrence overrides earlier ones |
| 118 | WARNING: issue-335a.pdf (trailer, offset 22028): unexpected > | 126 | WARNING: issue-335a.pdf (trailer, offset 22028): unexpected > |
| 119 | -WARNING: issue-335a.pdf (trailer, offset 22030): unknown token while reading object; treating as null | ||
| 120 | -WARNING: issue-335a.pdf (trailer, offset 22030): too many errors; giving up on reading object | 127 | +WARNING: issue-335a.pdf (trailer, offset 22028): too many errors; giving up on reading object |
| 121 | WARNING: issue-335a.pdf (trailer, offset 21837): unknown token while reading object; treating as null | 128 | WARNING: issue-335a.pdf (trailer, offset 21837): unknown token while reading object; treating as null |
| 129 | +WARNING: issue-335a.pdf (trailer, offset 21861): treating bad indirect reference (0 0 R) as null | ||
| 122 | WARNING: issue-335a.pdf (trailer, offset 21850): expected dictionary keys but found non-name objects; ignoring | 130 | WARNING: issue-335a.pdf (trailer, offset 21850): expected dictionary keys but found non-name objects; ignoring |
| 123 | WARNING: issue-335a.pdf (trailer, offset 21892): unknown token while reading object; treating as null | 131 | WARNING: issue-335a.pdf (trailer, offset 21892): unknown token while reading object; treating as null |
| 124 | WARNING: issue-335a.pdf (trailer, offset 21900): unknown token while reading object; treating as null | 132 | WARNING: issue-335a.pdf (trailer, offset 21900): unknown token while reading object; treating as null |
qpdf/qtest/qpdf/issue-51.out
| 1 | WARNING: issue-51.pdf: can't find PDF header | 1 | WARNING: issue-51.pdf: can't find PDF header |
| 2 | WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8) | 2 | WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8) |
| 3 | +WARNING: issue-51.pdf (object 7 0, offset 500): treating bad indirect reference (0 0 R) as null | ||
| 3 | WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones | 4 | WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones |
| 4 | WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj | 5 | WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj |
| 5 | issue-51.pdf: unable to find page tree | 6 | issue-51.pdf: unable to find page tree |
qpdf/qtest/qpdf/issue-99.out
| 1 | WARNING: issue-99.pdf: file is damaged | 1 | WARNING: issue-99.pdf: file is damaged |
| 2 | WARNING: issue-99.pdf (offset 3526): xref not found | 2 | WARNING: issue-99.pdf (offset 3526): xref not found |
| 3 | WARNING: issue-99.pdf: Attempting to reconstruct cross-reference table | 3 | WARNING: issue-99.pdf: Attempting to reconstruct cross-reference table |
| 4 | +WARNING: issue-99.pdf (trailer, offset 4635): treating bad indirect reference (0 0 R) as null | ||
| 4 | WARNING: issue-99.pdf (trailer, offset 4613): recovered trailer has no /Root entry | 5 | WARNING: issue-99.pdf (trailer, offset 4613): recovered trailer has no /Root entry |
| 5 | WARNING: issue-99.pdf (object 1 0, offset 775): unknown token while reading object; treating as null | 6 | WARNING: issue-99.pdf (object 1 0, offset 775): unknown token while reading object; treating as null |
| 6 | WARNING: issue-99.pdf (object 1 0, offset 795): unknown token while reading object; treating as null | 7 | WARNING: issue-99.pdf (object 1 0, offset 795): unknown token while reading object; treating as null |
| @@ -8,15 +9,13 @@ WARNING: issue-99.pdf (object 1 0, offset 815): unknown token while reading obje | @@ -8,15 +9,13 @@ WARNING: issue-99.pdf (object 1 0, offset 815): unknown token while reading obje | ||
| 8 | WARNING: issue-99.pdf (object 1 0, offset 835): unknown token while reading object; treating as null | 9 | WARNING: issue-99.pdf (object 1 0, offset 835): unknown token while reading object; treating as null |
| 9 | WARNING: issue-99.pdf (object 1 0, offset 855): unknown token while reading object; treating as null | 10 | WARNING: issue-99.pdf (object 1 0, offset 855): unknown token while reading object; treating as null |
| 10 | WARNING: issue-99.pdf (object 1 0, offset 855): too many errors; giving up on reading object | 11 | WARNING: issue-99.pdf (object 1 0, offset 855): too many errors; giving up on reading object |
| 11 | -WARNING: issue-99.pdf (object 1 0, offset 858): expected endobj | ||
| 12 | WARNING: issue-99.pdf (object 2 0, offset 64): expected endobj | 12 | WARNING: issue-99.pdf (object 2 0, offset 64): expected endobj |
| 13 | WARNING: issue-99.pdf (object 5 0, offset 2452): unknown token while reading object; treating as string | 13 | WARNING: issue-99.pdf (object 5 0, offset 2452): unknown token while reading object; treating as string |
| 14 | WARNING: issue-99.pdf (object 6 0, offset 2506): unexpected array close token; giving up on reading object | 14 | WARNING: issue-99.pdf (object 6 0, offset 2506): unexpected array close token; giving up on reading object |
| 15 | -WARNING: issue-99.pdf (object 6 0, offset 2507): expected endobj | 15 | +WARNING: issue-99.pdf (object 8 0, offset 4281): treating bad indirect reference (0 0 R) as null |
| 16 | WARNING: issue-99.pdf (object 10 0, offset 3708): expected dictionary keys but found non-name objects; ignoring | 16 | WARNING: issue-99.pdf (object 10 0, offset 3708): expected dictionary keys but found non-name objects; ignoring |
| 17 | WARNING: issue-99.pdf (object 11 0, offset 4485): unknown token while reading object; treating as null | 17 | WARNING: issue-99.pdf (object 11 0, offset 4485): unknown token while reading object; treating as null |
| 18 | WARNING: issue-99.pdf (object 11 0, offset 4497): unexpected array close token; giving up on reading object | 18 | WARNING: issue-99.pdf (object 11 0, offset 4497): unexpected array close token; giving up on reading object |
| 19 | -WARNING: issue-99.pdf (object 11 0, offset 4499): expected endobj | ||
| 20 | WARNING: issue-99.pdf: unable to find trailer dictionary while recovering damaged file | 19 | WARNING: issue-99.pdf: unable to find trailer dictionary while recovering damaged file |
| 21 | WARNING: object 1 0: Pages tree includes non-dictionary object; ignoring | 20 | WARNING: object 1 0: Pages tree includes non-dictionary object; ignoring |
| 22 | WARNING: object 1 0: operation for dictionary attempted on object of type null: ignoring key replacement request | 21 | WARNING: object 1 0: operation for dictionary attempted on object of type null: ignoring key replacement request |
qpdf/qtest/qpdf/parse-object.out
| @@ -6,6 +6,9 @@ WARNING: parsed object: treating unexpected brace token as null | @@ -6,6 +6,9 @@ WARNING: parsed object: treating unexpected brace token as null | ||
| 6 | WARNING: parsed object: treating unexpected brace token as null | 6 | WARNING: parsed object: treating unexpected brace token as null |
| 7 | WARNING: parsed object: unexpected dictionary close token | 7 | WARNING: parsed object: unexpected dictionary close token |
| 8 | WARNING: bad-parse.qdf (object 7 0, offset 1121): unexpected EOF | 8 | WARNING: bad-parse.qdf (object 7 0, offset 1121): unexpected EOF |
| 9 | -WARNING: bad-parse.qdf (object 7 0, offset 1121): expected endobj | ||
| 10 | -WARNING: bad-parse.qdf (object 7 0, offset 1121): EOF after endobj | 9 | +WARNING: parsed object (offset 5): treating bad indirect reference (0 0 R) as null |
| 10 | +WARNING: parsed object (offset 12): treating bad indirect reference (-1 0 R) as null | ||
| 11 | +WARNING: parsed object (offset 22): treating bad indirect reference (1 65535 R) as null | ||
| 12 | +WARNING: parsed object (offset 33): treating bad indirect reference (1 100000 R) as null | ||
| 13 | +WARNING: parsed object (offset 40): treating bad indirect reference (1 -1 R) as null | ||
| 11 | test 31 done | 14 | test 31 done |