Commit fc27221ab23431878c0a013f1204f2bda84bd389

Authored by m-holger
1 parent 4c23d2c0

Refactor `JSONReactor::dictionaryItem`: remove redundant `QTC::TC` calls, enhance assert usage.

libqpdf/QPDF_json.cc
@@ -460,104 +460,111 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) @@ -460,104 +460,111 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
460 next_state = st_ignore; 460 next_state = st_ignore;
461 auto state = stack.back().state; 461 auto state = stack.back().state;
462 if (state == st_ignore) { 462 if (state == st_ignore) {
463 - QTC::TC("qpdf", "QPDF_json ignoring in st_ignore");  
464 - // ignore  
465 - } else if (state == st_top) { 463 + return true; // ignore
  464 + }
  465 + if (state == st_top) {
466 if (key == "qpdf") { 466 if (key == "qpdf") {
467 - this->saw_qpdf = true; 467 + saw_qpdf = true;
468 if (!value.isArray()) { 468 if (!value.isArray()) {
469 error(value.getStart(), "\"qpdf\" must be an array"); 469 error(value.getStart(), "\"qpdf\" must be an array");
470 } else { 470 } else {
471 next_state = st_qpdf; 471 next_state = st_qpdf;
472 } 472 }
473 - } else {  
474 - // Ignore all other fields.  
475 - QTC::TC("qpdf", "QPDF_json ignoring unknown top-level key"); 473 + return true;
476 } 474 }
477 - } else if (state == st_qpdf_meta) { 475 + return true; // Ignore all other fields.
  476 + }
  477 +
  478 + if (state == st_qpdf_meta) {
478 if (key == "pdfversion") { 479 if (key == "pdfversion") {
479 - this->saw_pdf_version = true; 480 + saw_pdf_version = true;
480 std::string v; 481 std::string v;
481 - bool okay = false;  
482 if (value.getString(v)) { 482 if (value.getString(v)) {
483 std::string version; 483 std::string version;
484 char const* p = v.c_str(); 484 char const* p = v.c_str();
485 if (QPDF::validatePDFVersion(p, version) && (*p == '\0')) { 485 if (QPDF::validatePDFVersion(p, version) && (*p == '\0')) {
486 - this->pdf.m->pdf_version = version;  
487 - okay = true; 486 + pdf.m->pdf_version = version;
  487 + return true;
488 } 488 }
489 } 489 }
490 - if (!okay) {  
491 - error(value.getStart(), "invalid PDF version (must be \"x.y\")");  
492 - }  
493 - } else if (key == "jsonversion") {  
494 - this->saw_json_version = true; 490 + error(value.getStart(), "invalid PDF version (must be \"x.y\")");
  491 + return true;
  492 + }
  493 + if (key == "jsonversion") {
  494 + saw_json_version = true;
495 std::string v; 495 std::string v;
496 - bool okay = false;  
497 if (value.getNumber(v)) { 496 if (value.getNumber(v)) {
498 std::string version; 497 std::string version;
499 if (QUtil::string_to_int(v.c_str()) == 2) { 498 if (QUtil::string_to_int(v.c_str()) == 2) {
500 - okay = true; 499 + return true;
501 } 500 }
502 } 501 }
503 - if (!okay) {  
504 - error(value.getStart(), "invalid JSON version (must be numeric value 2)");  
505 - }  
506 - } else if (key == "pushedinheritedpageresources") { 502 + error(value.getStart(), "invalid JSON version (must be numeric value 2)");
  503 + return true;
  504 + }
  505 + if (key == "pushedinheritedpageresources") {
507 bool v; 506 bool v;
508 if (value.getBool(v)) { 507 if (value.getBool(v)) {
509 - if (!this->must_be_complete && v) {  
510 - this->pdf.pushInheritedAttributesToPage(); 508 + if (!must_be_complete && v) {
  509 + pdf.pushInheritedAttributesToPage();
511 } 510 }
512 - } else {  
513 - error(value.getStart(), "pushedinheritedpageresources must be a boolean"); 511 + return true;
514 } 512 }
515 - } else if (key == "calledgetallpages") { 513 + error(value.getStart(), "pushedinheritedpageresources must be a boolean");
  514 + return true;
  515 + }
  516 + if (key == "calledgetallpages") {
516 bool v; 517 bool v;
517 if (value.getBool(v)) { 518 if (value.getBool(v)) {
518 - if (!this->must_be_complete && v) { 519 + if (!must_be_complete && v) {
519 (void)pdf.doc().pages().all(); 520 (void)pdf.doc().pages().all();
520 } 521 }
521 - } else {  
522 - error(value.getStart(), "calledgetallpages must be a boolean"); 522 + return true;
523 } 523 }
524 - } else {  
525 - // ignore unknown keys for forward compatibility and to skip keys we don't care about  
526 - // like "maxobjectid".  
527 - QTC::TC("qpdf", "QPDF_json ignore second-level key"); 524 + error(value.getStart(), "calledgetallpages must be a boolean");
  525 + return true;
528 } 526 }
529 - } else if (state == st_objects) {  
530 - int obj = 0;  
531 - int gen = 0; 527 + // ignore unknown keys for forward compatibility and to skip keys we don't care about
  528 + // like "maxobjectid".
  529 + return true;
  530 + }
  531 +
  532 + if (state == st_objects) {
532 if (key == "trailer") { 533 if (key == "trailer") {
533 - this->saw_trailer = true;  
534 - this->cur_object = "trailer"; 534 + saw_trailer = true;
  535 + cur_object = "trailer";
535 setNextStateIfDictionary(key, value, st_trailer); 536 setNextStateIfDictionary(key, value, st_trailer);
536 - } else if (is_obj_key(key, obj, gen)) {  
537 - this->cur_object = key; 537 + return true;
  538 + }
  539 +
  540 + int obj = 0;
  541 + int gen = 0;
  542 + if (is_obj_key(key, obj, gen)) {
  543 + cur_object = key;
538 if (setNextStateIfDictionary(key, value, st_object_top)) { 544 if (setNextStateIfDictionary(key, value, st_object_top)) {
539 next_obj = objects.getObjectForJSON(obj, gen); 545 next_obj = objects.getObjectForJSON(obj, gen);
540 } 546 }
541 - } else {  
542 - error(value.getStart(), "object key should be \"trailer\" or \"obj:n n R\"");  
543 - }  
544 - } else if (state == st_object_top) {  
545 - if (stack.empty()) {  
546 - throw std::logic_error("stack empty in st_object_top"); 547 + return true;
547 } 548 }
  549 + error(value.getStart(), "object key should be \"trailer\" or \"obj:n n R\"");
  550 + return true;
  551 + }
  552 +
  553 + if (state == st_object_top) {
  554 + util::assertion(!stack.empty(), "QPDF_json: stack empty in st_object_top");
548 auto& tos = stack.back(); 555 auto& tos = stack.back();
549 - if (!tos.object) {  
550 - throw std::logic_error("current object uninitialized in st_object_top");  
551 - } 556 + util::assertion(!!tos.object, "current object uninitialized in st_object_top");
552 if (key == "value") { 557 if (key == "value") {
553 // Don't use setNextStateIfDictionary since this can have any type. 558 // Don't use setNextStateIfDictionary since this can have any type.
554 - this->saw_value = true; 559 + saw_value = true;
555 replaceObject(makeObject(value), value); 560 replaceObject(makeObject(value), value);
556 next_state = st_object; 561 next_state = st_object;
557 - } else if (key == "stream") {  
558 - this->saw_stream = true; 562 + return true;
  563 + }
  564 + if (key == "stream") {
  565 + saw_stream = true;
559 if (setNextStateIfDictionary(key, value, st_stream)) { 566 if (setNextStateIfDictionary(key, value, st_stream)) {
560 - this->this_stream_needs_data = false; 567 + this_stream_needs_data = false;
561 if (tos.object.isStream()) { 568 if (tos.object.isStream()) {
562 QTC::TC("qpdf", "QPDF_json updating existing stream"); 569 QTC::TC("qpdf", "QPDF_json updating existing stream");
563 } else { 570 } else {
@@ -568,95 +575,87 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) @@ -568,95 +575,87 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
568 value); 575 value);
569 } 576 }
570 next_obj = tos.object; 577 next_obj = tos.object;
571 - } else {  
572 - // Error message already given above  
573 - QTC::TC("qpdf", "QPDF_json stream not a dictionary"); 578 + return true;
574 } 579 }
575 - } else {  
576 - // Ignore unknown keys for forward compatibility  
577 - QTC::TC("qpdf", "QPDF_json ignore unknown key in object_top"); 580 + return true; // Error message already given above
578 } 581 }
579 - } else if (state == st_trailer) { 582 + return true; // Ignore unknown keys for forward compatibility
  583 + }
  584 +
  585 + if (state == st_trailer) {
580 if (key == "value") { 586 if (key == "value") {
581 - this->saw_value = true; 587 + saw_value = true;
582 // The trailer must be a dictionary, so we can use setNextStateIfDictionary. 588 // The trailer must be a dictionary, so we can use setNextStateIfDictionary.
583 if (setNextStateIfDictionary("trailer.value", value, st_object)) { 589 if (setNextStateIfDictionary("trailer.value", value, st_object)) {
584 - this->pdf.m->trailer = makeObject(value);  
585 - setObjectDescription(this->pdf.m->trailer, value); 590 + pdf.m->trailer = makeObject(value);
  591 + setObjectDescription(pdf.m->trailer, value);
586 } 592 }
587 - } else if (key == "stream") { 593 + return true;
  594 + }
  595 + if (key == "stream") {
588 // Don't need to set saw_stream here since there's already an error. 596 // Don't need to set saw_stream here since there's already an error.
589 error(value.getStart(), "the trailer may not be a stream"); 597 error(value.getStart(), "the trailer may not be a stream");
590 - } else {  
591 - // Ignore unknown keys for forward compatibility  
592 - QTC::TC("qpdf", "QPDF_json ignore unknown key in trailer");  
593 - }  
594 - } else if (state == st_stream) {  
595 - if (stack.empty()) {  
596 - throw std::logic_error("stack empty in st_stream"); 598 + return true;
597 } 599 }
  600 + return true; // Ignore unknown keys for forward compatibility
  601 + }
  602 +
  603 + if (state == st_stream) {
  604 + util::assertion(!stack.empty(), "stack empty in st_stream");
598 auto& tos = stack.back(); 605 auto& tos = stack.back();
599 - if (!tos.object.isStream()) {  
600 - throw std::logic_error("current object is not stream in st_stream");  
601 - } 606 + util::assertion(tos.object.isStream(), "current object is not stream in st_stream");
602 if (key == "dict") { 607 if (key == "dict") {
603 - this->saw_dict = true; 608 + saw_dict = true;
604 if (setNextStateIfDictionary("stream.dict", value, st_object)) { 609 if (setNextStateIfDictionary("stream.dict", value, st_object)) {
605 tos.object.replaceDict(makeObject(value)); 610 tos.object.replaceDict(makeObject(value));
606 - } else {  
607 - // An error had already been given by setNextStateIfDictionary  
608 - QTC::TC("qpdf", "QPDF_json stream dict not dict"); 611 + return true;
609 } 612 }
610 - } else if (key == "data") {  
611 - this->saw_data = true; 613 + return true; // An error had already been given by setNextStateIfDictionary
  614 + }
  615 + if (key == "data") {
  616 + saw_data = true;
612 std::string v; 617 std::string v;
613 if (!value.getString(v)) { 618 if (!value.getString(v)) {
614 error(value.getStart(), "\"stream.data\" must be a string"); 619 error(value.getStart(), "\"stream.data\" must be a string");
615 tos.object.replaceStreamData("", {}, {}); 620 tos.object.replaceStreamData("", {}, {});
616 - } else {  
617 - // The range includes the quotes.  
618 - auto start = value.getStart() + 1;  
619 - auto end = value.getEnd() - 1;  
620 - if (end < start) {  
621 - throw std::logic_error("QPDF_json: JSON string length < 0");  
622 - }  
623 - tos.object.replaceStreamData(provide_data(is, start, end), {}, {}); 621 + return true;
624 } 622 }
625 - } else if (key == "datafile") {  
626 - this->saw_datafile = true; 623 + // The range includes the quotes.
  624 + auto start = value.getStart() + 1;
  625 + auto end = value.getEnd() - 1;
  626 + util::assertion(end >= start, "QPDF_json: JSON string length < 0");
  627 + tos.object.replaceStreamData(provide_data(is, start, end), {}, {});
  628 + return true;
  629 + }
  630 + if (key == "datafile") {
  631 + saw_datafile = true;
627 std::string filename; 632 std::string filename;
628 if (!value.getString(filename)) { 633 if (!value.getString(filename)) {
629 - QTC::TC("qpdf", "QPDF_json stream datafile not string");  
630 error( 634 error(
631 value.getStart(), 635 value.getStart(),
632 "\"stream.datafile\" must be a string containing a file name"); 636 "\"stream.datafile\" must be a string containing a file name");
633 tos.object.replaceStreamData("", {}, {}); 637 tos.object.replaceStreamData("", {}, {});
634 - } else {  
635 - tos.object.replaceStreamData(QUtil::file_provider(filename), {}, {}); 638 + return true;
636 } 639 }
637 - } else {  
638 - // Ignore unknown keys for forward compatibility.  
639 - QTC::TC("qpdf", "QPDF_json ignore unknown key in stream");  
640 - }  
641 - } else if (state == st_object) {  
642 - if (stack.empty()) {  
643 - throw std::logic_error("stack empty in st_object"); 640 + tos.object.replaceStreamData(QUtil::file_provider(filename), {}, {});
  641 + return true;
644 } 642 }
645 - auto& tos = stack.back();  
646 - auto dict = tos.object;  
647 - if (dict.isStream()) {  
648 - dict = dict.getDict();  
649 - }  
650 - if (!dict.isDictionary()) {  
651 - throw std::logic_error(  
652 - "current object is not stream or dictionary in st_object dictionary item");  
653 - }  
654 - dict.replaceKey(  
655 - is_pdf_name(key) ? QPDFObjectHandle::parse(key.substr(2)).getName() : key,  
656 - makeObject(value));  
657 - } else {  
658 - throw std::logic_error("QPDF_json: unknown state " + std::to_string(state)); 643 + return true; // Ignore unknown keys for forward compatibility.
659 } 644 }
  645 +
  646 + util::assertion(state == st_object, "QPDF_json: unknown state " + std::to_string(state));
  647 + util::assertion(!stack.empty(), "stack empty in st_object");
  648 + auto& tos = stack.back();
  649 + auto dict = tos.object;
  650 + if (dict.isStream()) {
  651 + dict = dict.getDict();
  652 + }
  653 + util::assertion(
  654 + dict.isDictionary(),
  655 + "current object is not stream or dictionary in st_object dictionary item");
  656 + dict.replaceKey(
  657 + is_pdf_name(key) ? QPDFObjectHandle::parse(key.substr(2)).getName() : key,
  658 + makeObject(value));
660 return true; 659 return true;
661 } 660 }
662 661
qpdf/qpdf.testcov
@@ -423,8 +423,6 @@ QPDF_json top-level scalar 0 @@ -423,8 +423,6 @@ QPDF_json top-level scalar 0
423 QPDF_json top-level array 0 423 QPDF_json top-level array 0
424 QPDF_json missing trailer 0 424 QPDF_json missing trailer 0
425 QPDF_json missing objects 0 425 QPDF_json missing objects 0
426 -QPDF_json ignoring in st_ignore 0  
427 -QPDF_json stream dict not dict 0  
428 QPDF_json unrecognized string value 0 426 QPDF_json unrecognized string value 0
429 QPDF_json data datafile both or neither 0 427 QPDF_json data datafile both or neither 0
430 QPDF_json stream no dict 0 428 QPDF_json stream no dict 0
@@ -433,11 +431,6 @@ QPDF_json value stream both or neither 0 @@ -433,11 +431,6 @@ QPDF_json value stream both or neither 0
433 QPDFJob need json-stream-prefix for stdout 0 431 QPDFJob need json-stream-prefix for stdout 0
434 QPDFJob write json to stdout 0 432 QPDFJob write json to stdout 0
435 QPDFJob write json to file 0 433 QPDFJob write json to file 0
436 -QPDF_json ignoring unknown top-level key 0  
437 -QPDF_json ignore second-level key 0  
438 -QPDF_json ignore unknown key in object_top 0  
439 -QPDF_json ignore unknown key in trailer 0  
440 -QPDF_json ignore unknown key in stream 0  
441 QPDF_json data and datafile 0 434 QPDF_json data and datafile 0
442 QPDF_json no stream data in update mode 0 435 QPDF_json no stream data in update mode 0
443 QPDF_json updating existing stream 0 436 QPDF_json updating existing stream 0
@@ -448,5 +441,3 @@ QPDF skipping cache for known unchecked object 0 @@ -448,5 +441,3 @@ QPDF skipping cache for known unchecked object 0
448 QPDF recover xref stream 0 441 QPDF recover xref stream 0
449 QPDFJob json over/under no file 0 442 QPDFJob json over/under no file 0
450 QPDF_Array copy 1 443 QPDF_Array copy 1
451 -QPDF_json stream datafile not string 0  
452 -QPDF_json stream not a dictionary 0