_ZN10FuzzHelperC2EPKhm:
   24|  6.52k|{
   25|  6.52k|}
_ZN10FuzzHelper8doChecksEv:
   29|  6.52k|{
   30|  6.52k|    try {
   31|  6.52k|        JSON::parse(std::string(reinterpret_cast<char const*>(data), size));
   32|  6.52k|    } catch (std::runtime_error& e) {
   33|  6.24k|        std::cerr << "runtime_error parsing json: " << e.what() << std::endl;
   34|  6.24k|    }
   35|  6.52k|    QPDF q;
   36|  6.52k|    q.setMaxWarnings(1000);
   37|  6.52k|    Buffer buf(const_cast<unsigned char*>(data), size);
   38|  6.52k|    auto is = std::make_shared<BufferInputSource>("json", &buf);
   39|  6.52k|    q.createFromJSON(is);
   40|  6.52k|}
_ZN10FuzzHelper3runEv:
   44|  6.52k|{
   45|  6.52k|    try {
   46|  6.52k|        doChecks();
   47|  6.52k|    } catch (std::runtime_error const& e) {
   48|  6.51k|        std::cerr << "runtime_error: " << e.what() << std::endl;
   49|  6.51k|    }
   50|  6.52k|}
LLVMFuzzerTestOneInput:
   54|  6.52k|{
   55|  6.52k|    FuzzHelper f(data, size);
   56|  6.52k|    f.run();
   57|  6.52k|    return 0;
   58|  6.52k|}

_ZN11InputSourceC2Ev:
   37|  47.7k|    {
   38|  47.7k|    }
_ZN11InputSource10loadBufferEv:
  116|   114k|{
  117|   114k|    this->buf_idx = 0;
  118|   114k|    this->buf_len = qpdf_offset_t(read(this->buffer, this->buf_size));
  119|       |    // NB read sets last_offset
  120|   114k|    this->buf_start = this->last_offset;
  121|   114k|}
_ZN11InputSource8fastTellEv:
  125|   160k|{
  126|   160k|    if (this->buf_len == 0) {
  ------------------
  |  Branch (126:9): [True: 28.1k, False: 132k]
  ------------------
  127|  28.1k|        loadBuffer();
  128|   132k|    } else {
  129|   132k|        auto curr = tell();
  130|   132k|        if (curr < this->buf_start || curr >= (this->buf_start + this->buf_len)) {
  ------------------
  |  Branch (130:13): [True: 6.52k, False: 125k]
  |  Branch (130:39): [True: 80.1k, False: 45.6k]
  ------------------
  131|  86.6k|            loadBuffer();
  132|  86.6k|        } else {
  133|  45.6k|            this->last_offset = curr;
  134|  45.6k|            this->buf_idx = curr - this->buf_start;
  135|  45.6k|        }
  136|   132k|    }
  137|   160k|    return this->last_offset;
  138|   160k|}
_ZN11InputSource8fastReadERc:
  142|  8.49M|{
  143|       |    // Before calling fastRead, fastTell must be called to prepare the buffer. Once reading is
  144|       |    // complete, fastUnread must be called to set the correct file position.
  145|  8.49M|    if (this->buf_idx < this->buf_len) {
  ------------------
  |  Branch (145:9): [True: 8.40M, False: 98.7k]
  ------------------
  146|  8.40M|        ch = this->buffer[this->buf_idx];
  147|  8.40M|        ++(this->buf_idx);
  148|  8.40M|        ++(this->last_offset);
  149|  8.40M|        return true;
  150|       |
  151|  8.40M|    } else if (this->buf_len == 0) {
  ------------------
  |  Branch (151:16): [True: 18.5k, False: 80.1k]
  ------------------
  152|  18.5k|        return false;
  153|  80.1k|    } else {
  154|  80.1k|        seek(this->buf_start + this->buf_len, SEEK_SET);
  155|  80.1k|        fastTell();
  156|  80.1k|        return fastRead(ch);
  157|  80.1k|    }
  158|  8.49M|}
_ZN11InputSource10fastUnreadEb:
  162|  80.4k|{
  163|  80.4k|    this->last_offset -= back ? 1 : 0;
  ------------------
  |  Branch (163:26): [True: 48.7k, False: 31.6k]
  ------------------
  164|  80.4k|    seek(this->last_offset, SEEK_SET);
  165|  80.4k|}
_ZN11InputSourceD2Ev:
   40|  47.7k|    virtual ~InputSource() = default;
_ZN11InputSource6FinderC2Ev:
   46|  13.0k|        Finder() = default;
_ZN11InputSource6FinderD2Ev:
   48|  13.0k|        virtual ~Finder() = default;

_ZN4JSON10JSON_valueC2ENS_12value_type_eE:
  315|  6.82M|        {
  316|  6.82M|        }
_ZN4JSON15JSON_dictionaryC2Ev:
  325|   134k|        {
  326|   134k|        }
_ZN4JSON9JSON_nullC2Ev:
  361|  3.82k|        {
  362|  3.82k|        }
_ZN4JSON10JSON_arrayC2Ev:
  408|  60.5k|    {
  409|  60.5k|    }
_ZN4JSON10JSON_valueD2Ev:
  317|  6.82M|        virtual ~JSON_value() = default;
_ZN4JSONC2Ev:
   52|  14.4M|    JSON() = default;
_ZN4JSON15JSON_dictionaryD2Ev:
  327|   134k|        ~JSON_dictionary() override = default;
_ZN4JSON10JSON_arrayD2Ev:
  410|  60.5k|    ~JSON_array() override = default;
_ZN4JSON11JSON_stringD2Ev:
  336|   812k|        ~JSON_string() override = default;
_ZN4JSON11JSON_numberD2Ev:
  346|  5.80M|        ~JSON_number() override = default;
_ZN4JSON7MembersD2Ev:
  389|  6.82M|        ~Members() = default;
_ZN4JSON7ReactorD2Ev:
  220|  6.52k|        virtual ~Reactor() = default;

_ZN8PipelineD2Ev:
   53|      4|    virtual ~Pipeline() = default;

_ZN5QIntC9to_offsetImEExRKT_:
  221|   217k|    {
  222|   217k|        return IntConverter<T, qpdf_offset_t>::convert(i);
  223|   217k|    }
_ZN5QIntC12IntConverterImxLb0ELb1EE7convertERKm:
  146|   217k|        {
  147|       |            // From is unsigned, and to is signed. Convert To's max to the
  148|       |            // unsigned version of To and compare i against that.
  149|   217k|            auto maxval = static_cast<typename to_u<To>::type>(std::numeric_limits<To>::max());
  150|   217k|            if (i > maxval) {
  ------------------
  |  Branch (150:17): [True: 0, False: 217k]
  ------------------
  151|      0|                error(i);
  152|      0|            }
  153|   217k|            return static_cast<To>(i);
  154|   217k|        }
_ZN5QIntC11range_checkIxEEvRKT_S3_:
  273|  6.52k|    {
  274|  6.52k|        if ((delta > 0) != (cur > 0)) {
  ------------------
  |  Branch (274:13): [True: 6.52k, False: 0]
  ------------------
  275|  6.52k|            return;
  276|  6.52k|        }
  277|      0|        QIntC::range_check_error<T>(cur, delta);
  278|      0|    }
_ZN5QIntC7to_sizeIxEEmRKT_:
  214|   217k|    {
  215|   217k|        return IntConverter<T, size_t>::convert(i);
  216|   217k|    }
_ZN5QIntC12IntConverterIxmLb1ELb0EE7convertERKx:
  118|   217k|        {
  119|       |            // From is signed, and To is unsigned. If i > 0, it's safe to
  120|       |            // convert it to the corresponding unsigned type and to
  121|       |            // compare with To's max.
  122|   217k|            auto ii = static_cast<typename to_u<From>::type>(i);
  123|   217k|            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (123:17): [True: 0, False: 217k]
  |  Branch (123:28): [True: 0, False: 217k]
  ------------------
  124|      0|                error(i);
  125|      0|            }
  126|   217k|            return static_cast<To>(i);
  127|   217k|        }
_ZN5QIntC12IntConverterIimLb1ELb0EE7convertERKi:
  118|  1.35k|        {
  119|       |            // From is signed, and To is unsigned. If i > 0, it's safe to
  120|       |            // convert it to the corresponding unsigned type and to
  121|       |            // compare with To's max.
  122|  1.35k|            auto ii = static_cast<typename to_u<From>::type>(i);
  123|  1.35k|            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (123:17): [True: 0, False: 1.35k]
  |  Branch (123:28): [True: 0, False: 1.35k]
  ------------------
  124|      0|                error(i);
  125|      0|            }
  126|  1.35k|            return static_cast<To>(i);
  127|  1.35k|        }
_ZN5QIntC6to_intIlEEiRKT_:
  200|  6.52k|    {
  201|  6.52k|        return IntConverter<T, int>::convert(i);
  202|  6.52k|    }
_ZN5QIntC12IntConverterIliLb1ELb1EE7convertERKl:
   93|  6.52k|        {
   94|       |            // From and To are both signed.
   95|  6.52k|            if ((i < std::numeric_limits<To>::min()) || (i > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (95:17): [True: 0, False: 6.52k]
  |  Branch (95:57): [True: 0, False: 6.52k]
  ------------------
   96|      0|                error(i);
   97|      0|            }
   98|  6.52k|            return static_cast<To>(i);
   99|  6.52k|        }
_ZN5QIntC6to_intIxEEiRKT_:
  200|   714k|    {
  201|   714k|        return IntConverter<T, int>::convert(i);
  202|   714k|    }
_ZN5QIntC12IntConverterIxiLb1ELb1EE7convertERKx:
   93|   714k|        {
   94|       |            // From and To are both signed.
   95|   714k|            if ((i < std::numeric_limits<To>::min()) || (i > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (95:17): [True: 56, False: 713k]
  |  Branch (95:57): [True: 14, False: 713k]
  ------------------
   96|     70|                error(i);
   97|     70|            }
   98|   714k|            return static_cast<To>(i);
   99|   714k|        }
_ZN5QIntC12IntConverterIxiLb1ELb1EE5errorEx:
  103|     70|        {
  104|     70|            std::ostringstream msg;
  105|     70|            msg.imbue(std::locale::classic());
  106|     70|            msg << "integer out of range converting " << i << " from a " << sizeof(From)
  107|     70|                << "-byte signed type to a " << sizeof(To) << "-byte signed type";
  108|     70|            throw std::range_error(msg.str());
  109|     70|        }
_ZN5QIntC6to_intImEEiRKT_:
  200|  2.27M|    {
  201|  2.27M|        return IntConverter<T, int>::convert(i);
  202|  2.27M|    }
_ZN5QIntC12IntConverterImiLb0ELb1EE7convertERKm:
  146|  2.27M|        {
  147|       |            // From is unsigned, and to is signed. Convert To's max to the
  148|       |            // unsigned version of To and compare i against that.
  149|  2.27M|            auto maxval = static_cast<typename to_u<To>::type>(std::numeric_limits<To>::max());
  150|  2.27M|            if (i > maxval) {
  ------------------
  |  Branch (150:17): [True: 0, False: 2.27M]
  ------------------
  151|      0|                error(i);
  152|      0|            }
  153|  2.27M|            return static_cast<To>(i);
  154|  2.27M|        }
_ZN5QIntC7to_sizeIlEEmRKT_:
  214|  13.0k|    {
  215|  13.0k|        return IntConverter<T, size_t>::convert(i);
  216|  13.0k|    }
_ZN5QIntC12IntConverterIlmLb1ELb0EE7convertERKl:
  118|  13.0k|        {
  119|       |            // From is signed, and To is unsigned. If i > 0, it's safe to
  120|       |            // convert it to the corresponding unsigned type and to
  121|       |            // compare with To's max.
  122|  13.0k|            auto ii = static_cast<typename to_u<From>::type>(i);
  123|  13.0k|            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (123:17): [True: 0, False: 13.0k]
  |  Branch (123:28): [True: 0, False: 13.0k]
  ------------------
  124|      0|                error(i);
  125|      0|            }
  126|  13.0k|            return static_cast<To>(i);
  127|  13.0k|        }
_ZN5QIntC8to_ulongIcEEmRKT_:
  235|  7.67M|    {
  236|  7.67M|        return IntConverter<T, unsigned long>::convert(i);
  237|  7.67M|    }
_ZN5QIntC12IntConverterIcmLb1ELb0EE7convertERKc:
  118|  7.67M|        {
  119|       |            // From is signed, and To is unsigned. If i > 0, it's safe to
  120|       |            // convert it to the corresponding unsigned type and to
  121|       |            // compare with To's max.
  122|  7.67M|            auto ii = static_cast<typename to_u<From>::type>(i);
  123|  7.67M|            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (123:17): [True: 0, False: 7.67M]
  |  Branch (123:28): [True: 0, False: 7.67M]
  ------------------
  124|      0|                error(i);
  125|      0|            }
  126|  7.67M|            return static_cast<To>(i);
  127|  7.67M|        }
_ZN5QIntC8to_ulongIhEEmRKT_:
  235|  4.39k|    {
  236|  4.39k|        return IntConverter<T, unsigned long>::convert(i);
  237|  4.39k|    }
_ZN5QIntC12IntConverterIhmLb0ELb0EE7convertERKh:
   68|  4.39k|        {
   69|       |            // From and To are both unsigned.
   70|  4.39k|            if (i > std::numeric_limits<To>::max()) {
  ------------------
  |  Branch (70:17): [True: 0, False: 4.39k]
  ------------------
   71|      0|                error(i);
   72|      0|            }
   73|  4.39k|            return static_cast<To>(i);
   74|  4.39k|        }
_ZN5QIntC8to_ulongIiEEmRKT_:
  235|  1.35k|    {
  236|  1.35k|        return IntConverter<T, unsigned long>::convert(i);
  237|  1.35k|    }

_ZN4QPDF10ParseGuardC2EPS_:
  831|  28.1k|        {
  832|  28.1k|            if (qpdf) {
  ------------------
  |  Branch (832:17): [True: 6.52k, False: 21.6k]
  ------------------
  833|  6.52k|                qpdf->inParse(true);
  834|  6.52k|            }
  835|  28.1k|        }
_ZN4QPDF10ParseGuardD2Ev:
  844|  28.1k|        {
  845|  28.1k|            if (qpdf) {
  ------------------
  |  Branch (845:17): [True: 6.52k, False: 21.6k]
  ------------------
  846|  6.52k|                qpdf->inParse(false);
  847|  6.52k|            }
  848|  28.1k|        }
_ZN4QPDF8ObjCacheC2Ev:
  907|  18.1k|        {
  908|  18.1k|        }
_ZN4QPDF13PatternFinderC2ERS_MS_FbvE:
 1384|  13.0k|        {
 1385|  13.0k|        }
_ZN4QPDF13PatternFinder5checkEv:
 1389|  13.0k|        {
 1390|  13.0k|            return (this->qpdf.*checker)();
 1391|  13.0k|        }
_ZN4QPDF7MembersD2Ev:
 1500|  6.52k|        ~Members() = default;
_ZN4QPDF3toIIlEEiRKT_:
 1483|  6.52k|    {
 1484|  6.52k|        return QIntC::to_int(i);
 1485|  6.52k|    }
_ZN4QPDF3toIIxEEiRKT_:
 1483|  6.52k|    {
 1484|  6.52k|        return QIntC::to_int(i);
 1485|  6.52k|    }

_ZN7QPDFExcD2Ev:
   40|   128k|    ~QPDFExc() noexcept override = default;

_ZN10QPDFObjGenC2Ev:
   38|  4.87M|    {
   39|  4.87M|    }
_ZN10QPDFObjGenC2Eii:
   44|   359k|    {
   45|   359k|    }
_ZNK10QPDFObjGenltERKS_:
   49|  1.98M|    {
   50|  1.98M|        return (obj < rhs.obj) || ((obj == rhs.obj) && (gen < rhs.gen));
  ------------------
  |  Branch (50:16): [True: 843k, False: 1.14M]
  |  Branch (50:36): [True: 767k, False: 378k]
  |  Branch (50:56): [True: 40.6k, False: 726k]
  ------------------
   51|  1.98M|    }
_ZNK10QPDFObjGen6getObjEv:
   67|   165k|    {
   68|   165k|        return obj;
   69|   165k|    }
_ZNK10QPDFObjGen10isIndirectEv:
   79|  5.16M|    {
   80|  5.16M|        return obj != 0;
   81|  5.16M|    }

_ZN16QPDFObjectHandle16DisconnectAccess10disconnectES_:
 1271|  84.8k|        {
 1272|  84.8k|            o.disconnect();
 1273|  84.8k|        }
_ZN16QPDFObjectHandleC2ERKNSt3__110shared_ptrI10QPDFObjectEE:
 1337|  2.78M|    {
 1338|  2.78M|    }
_ZN16QPDFObjectHandle6getObjEv:
 1341|  11.0k|    {
 1342|  11.0k|        return obj;
 1343|  11.0k|    }
_ZNK16QPDFObjectHandle6getObjEv:
 1346|  2.57M|    {
 1347|  2.57M|        return obj;
 1348|  2.57M|    }
_ZN16QPDFObjectHandle12getObjectPtrEv:
 1351|  2.39M|    {
 1352|  2.39M|        return obj.get();
 1353|  2.39M|    }
_ZNK16QPDFObjectHandle12getObjectPtrEv:
 1356|  2.57M|    {
 1357|  2.57M|        return obj.get();
 1358|  2.57M|    }
_ZNK16QPDFObjectHandle11getObjectIDEv:
 1615|   159k|{
 1616|   159k|    return getObjGen().getObj();
 1617|   159k|}
_ZNK16QPDFObjectHandle10isIndirectEv:
 1627|   159k|{
 1628|   159k|    return (obj != nullptr) && (getObjectID() != 0);
  ------------------
  |  Branch (1628:12): [True: 159k, False: 0]
  |  Branch (1628:32): [True: 56.1k, False: 102k]
  ------------------
 1629|   159k|}
_ZNK16QPDFObjectHandle13isInitializedEv:
 1633|  3.31M|{
 1634|  3.31M|    return obj != nullptr;
 1635|  3.31M|}
_ZN16QPDFObjectHandleC2ERKS_:
  289|   469k|    QPDFObjectHandle(QPDFObjectHandle const&) = default;
_ZN16QPDFObjectHandleaSERKS_:
  291|   186k|    QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default;
_ZN16QPDFObjectHandleC2Ev:
  287|  2.96M|    QPDFObjectHandle() = default;
_ZN16QPDFObjectHandleaSEOS_:
  296|  2.81M|    QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default;
_ZN16QPDFObjectHandleC2EOS_:
  294|  85.9k|    QPDFObjectHandle(QPDFObjectHandle&&) = default;

_ZN13QPDFTokenizer5TokenC2Ev:
   63|  32.6k|        {
   64|  32.6k|        }
_ZN13QPDFTokenizer5TokenC2ENS_12token_type_eERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEES8_S8_:
   76|  32.6k|        {
   77|  32.6k|        }
_ZNK13QPDFTokenizer5Token7getTypeEv:
   80|  32.6k|        {
   81|  32.6k|            return this->type;
   82|  32.6k|        }
_ZNK13QPDFTokenizer5Token8getValueEv:
   85|  6.52k|        {
   86|  6.52k|            return this->value;
   87|  6.52k|        }
_ZNK13QPDFTokenizer5Token9isIntegerEv:
  107|  6.52k|        {
  108|  6.52k|            return this->type == tt_integer;
  109|  6.52k|        }
_ZNK13QPDFTokenizer5Token6isWordERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  117|  19.5k|        {
  118|  19.5k|            return this->type == tt_word && this->value == value;
  ------------------
  |  Branch (118:20): [True: 19.5k, False: 0]
  |  Branch (118:45): [True: 13.0k, False: 6.52k]
  ------------------
  119|  19.5k|        }
_ZNK13QPDFTokenizer7getTypeEv:
  300|  60.6k|{
  301|  60.6k|    return this->type;
  302|  60.6k|}
_ZNK13QPDFTokenizer8getValueEv:
  305|  34.5k|{
  306|  34.5k|    return (this->type == tt_name || this->type == tt_string) ? this->val : this->raw_val;
  ------------------
  |  Branch (306:13): [True: 28.0k, False: 6.52k]
  |  Branch (306:38): [True: 0, False: 6.52k]
  ------------------
  307|  34.5k|}
_ZNK13QPDFTokenizer15getErrorMessageEv:
  315|    188|{
  316|    188|    return this->error_message;
  317|    188|}

_ZN3QTC2TCEPKcS1_i:
   35|   155k|    {
   36|       |#ifndef QPDF_DISABLE_QTC
   37|       |        TC_real(scope, ccase, n);
   38|       |#endif // QPDF_DISABLE_QTC
   39|   155k|    }

_ZN5QUtil8is_spaceEc:
  499|   198k|{
  500|   198k|    return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\v';
  ------------------
  |  Branch (500:12): [True: 52.2k, False: 145k]
  |  Branch (500:25): [True: 32.6k, False: 113k]
  |  Branch (500:39): [True: 5, False: 113k]
  |  Branch (500:53): [True: 6, False: 113k]
  |  Branch (500:67): [True: 0, False: 113k]
  |  Branch (500:81): [True: 0, False: 113k]
  ------------------
  501|   198k|}
_ZN5QUtil15hex_decode_charEc:
  546|  1.82M|{
  547|  1.82M|    return digit <= '9' && digit >= '0'
  ------------------
  |  Branch (547:12): [True: 1.66M, False: 165k]
  |  Branch (547:28): [True: 1.63M, False: 25.3k]
  ------------------
  548|  1.82M|        ? char(digit - '0')
  549|  1.82M|        : (digit >= 'a' ? char(digit - 'a' + 10) : (digit >= 'A' ? char(digit - 'A' + 10) : '\20'));
  ------------------
  |  Branch (549:12): [True: 147k, False: 44.1k]
  |  Branch (549:53): [True: 18.1k, False: 26.0k]
  ------------------
  550|  1.82M|}
_ZN5QUtil12is_hex_digitEc:
  493|   875k|{
  494|   875k|    return hex_decode_char(ch) < '\20';
  495|   875k|}
_ZN5QUtil8is_digitEc:
  505|  2.75M|{
  506|  2.75M|    return ((ch >= '0') && (ch <= '9'));
  ------------------
  |  Branch (506:13): [True: 1.96M, False: 793k]
  |  Branch (506:28): [True: 1.93M, False: 30.3k]
  ------------------
  507|  2.75M|}

_ZN6Buffer7MembersC2EmPhb:
   22|  41.3k|{
   23|  41.3k|    if (own_memory) {
  ------------------
  |  Branch (23:9): [True: 28.3k, False: 13.0k]
  ------------------
   24|  28.3k|        this->buf = (size ? new unsigned char[size] : nullptr);
  ------------------
  |  Branch (24:22): [True: 28.1k, False: 122]
  ------------------
   25|  28.3k|    } else {
   26|  13.0k|        this->buf = buf;
   27|  13.0k|    }
   28|  41.3k|}
_ZN6Buffer7MembersD2Ev:
   39|  41.3k|{
   40|  41.3k|    if (this->own_memory) {
  ------------------
  |  Branch (40:9): [True: 28.3k, False: 13.0k]
  ------------------
   41|  28.3k|        delete[] this->buf;
   42|  28.3k|    }
   43|  41.3k|}
_ZN6BufferC2Em:
   52|  28.3k|{
   53|  28.3k|}
_ZN6BufferC2EPhm:
   62|  13.0k|{
   63|  13.0k|}
_ZNK6Buffer7getSizeEv:
  109|  41.3k|{
  110|  41.3k|    return m->size;
  111|  41.3k|}
_ZN6Buffer9getBufferEv:
  121|   210k|{
  122|   210k|    return m->buf;
  123|   210k|}

_ZN17BufferInputSourceC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEP6Bufferb:
   14|  13.0k|{
   15|  13.0k|}
_ZN17BufferInputSourceC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_:
   23|  28.1k|{
   24|  28.1k|    memcpy(buf->getBuffer(), contents.c_str(), contents.length());
   25|  28.1k|}
_ZN17BufferInputSourceD2Ev:
   28|  41.2k|{
   29|  41.2k|    if (this->own_memory) {
  ------------------
  |  Branch (29:9): [True: 34.7k, False: 6.52k]
  ------------------
   30|  34.7k|        delete this->buf;
   31|  34.7k|    }
   32|  41.2k|}
_ZN17BufferInputSource18findAndSkipNextEOLEv:
   36|  6.52k|{
   37|  6.52k|    if (this->cur_offset < 0) {
  ------------------
  |  Branch (37:9): [True: 0, False: 6.52k]
  ------------------
   38|      0|        throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
   39|      0|    }
   40|  6.52k|    qpdf_offset_t end_pos = this->max_offset;
   41|  6.52k|    if (this->cur_offset >= end_pos) {
  ------------------
  |  Branch (41:9): [True: 0, False: 6.52k]
  ------------------
   42|      0|        this->last_offset = end_pos;
   43|      0|        this->cur_offset = end_pos;
   44|      0|        return end_pos;
   45|      0|    }
   46|       |
   47|  6.52k|    qpdf_offset_t result = 0;
   48|  6.52k|    unsigned char const* buffer = this->buf->getBuffer();
   49|  6.52k|    unsigned char const* end = buffer + end_pos;
   50|  6.52k|    unsigned char const* p = buffer + this->cur_offset;
   51|       |
   52|  58.7k|    while ((p < end) && !((*p == '\r') || (*p == '\n'))) {
  ------------------
  |  Branch (52:12): [True: 58.7k, False: 0]
  |  Branch (52:27): [True: 0, False: 58.7k]
  |  Branch (52:43): [True: 6.52k, False: 52.2k]
  ------------------
   53|  52.2k|        ++p;
   54|  52.2k|    }
   55|  6.52k|    if (p < end) {
  ------------------
  |  Branch (55:9): [True: 6.52k, False: 0]
  ------------------
   56|  6.52k|        result = p - buffer;
   57|  6.52k|        this->cur_offset = result + 1;
   58|  6.52k|        ++p;
   59|  6.52k|        while ((this->cur_offset < end_pos) && ((*p == '\r') || (*p == '\n'))) {
  ------------------
  |  Branch (59:16): [True: 6.52k, False: 0]
  |  Branch (59:49): [True: 0, False: 6.52k]
  |  Branch (59:65): [True: 0, False: 6.52k]
  ------------------
   60|      0|            ++p;
   61|      0|            ++this->cur_offset;
   62|      0|        }
   63|  6.52k|    } else {
   64|      0|        this->cur_offset = end_pos;
   65|      0|        result = end_pos;
   66|      0|    }
   67|  6.52k|    return result;
   68|  6.52k|}
_ZNK17BufferInputSource7getNameEv:
   72|   170k|{
   73|   170k|    return this->description;
   74|   170k|}
_ZN17BufferInputSource4tellEv:
   78|   234k|{
   79|   234k|    return this->cur_offset;
   80|   234k|}
_ZN17BufferInputSource4seekExi:
   84|   238k|{
   85|   238k|    switch (whence) {
   86|   232k|    case SEEK_SET:
  ------------------
  |  Branch (86:5): [True: 232k, False: 6.52k]
  ------------------
   87|   232k|        this->cur_offset = offset;
   88|   232k|        break;
   89|       |
   90|  6.52k|    case SEEK_END:
  ------------------
  |  Branch (90:5): [True: 6.52k, False: 232k]
  ------------------
   91|  6.52k|        QIntC::range_check(this->max_offset, offset);
   92|  6.52k|        this->cur_offset = this->max_offset + offset;
   93|  6.52k|        break;
   94|       |
   95|      0|    case SEEK_CUR:
  ------------------
  |  Branch (95:5): [True: 0, False: 238k]
  ------------------
   96|      0|        QIntC::range_check(this->cur_offset, offset);
   97|      0|        this->cur_offset += offset;
   98|      0|        break;
   99|       |
  100|      0|    default:
  ------------------
  |  Branch (100:5): [True: 0, False: 238k]
  ------------------
  101|      0|        throw std::logic_error("INTERNAL ERROR: invalid argument to BufferInputSource::seek");
  102|      0|        break;
  103|   238k|    }
  104|       |
  105|   238k|    if (this->cur_offset < 0) {
  ------------------
  |  Branch (105:9): [True: 0, False: 238k]
  ------------------
  106|      0|        throw std::runtime_error(this->description + ": seek before beginning of buffer");
  107|      0|    }
  108|   238k|}
_ZN17BufferInputSource4readEPcm:
  118|   204k|{
  119|   204k|    if (this->cur_offset < 0) {
  ------------------
  |  Branch (119:9): [True: 0, False: 204k]
  ------------------
  120|      0|        throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
  121|      0|    }
  122|   204k|    qpdf_offset_t end_pos = this->max_offset;
  123|   204k|    if (this->cur_offset >= end_pos) {
  ------------------
  |  Branch (123:9): [True: 28.3k, False: 176k]
  ------------------
  124|  28.3k|        this->last_offset = end_pos;
  125|  28.3k|        return 0;
  126|  28.3k|    }
  127|       |
  128|   176k|    this->last_offset = this->cur_offset;
  129|   176k|    size_t len = std::min(QIntC::to_size(end_pos - this->cur_offset), length);
  130|   176k|    memcpy(buffer, this->buf->getBuffer() + this->cur_offset, len);
  131|   176k|    this->cur_offset += QIntC::to_offset(len);
  132|   176k|    return len;
  133|   204k|}
_ZN17BufferInputSource8unreadChEc:
  137|  6.52k|{
  138|  6.52k|    if (this->cur_offset > 0) {
  ------------------
  |  Branch (138:9): [True: 6.52k, False: 0]
  ------------------
  139|  6.52k|        --this->cur_offset;
  140|  6.52k|    }
  141|  6.52k|}

_ZN11InputSource13setLastOffsetEx:
   10|  86.9k|{
   11|  86.9k|    this->last_offset = offset;
   12|  86.9k|}
_ZNK11InputSource13getLastOffsetEv:
   16|  19.8k|{
   17|  19.8k|    return this->last_offset;
   18|  19.8k|}
_ZN11InputSource8readLineEm:
   22|  6.52k|{
   23|       |    // Return at most max_line_length characters from the next line. Lines are terminated by one or
   24|       |    // more \r or \n characters. Consume the trailing newline characters but don't return them.
   25|       |    // After this is called, the file will be positioned after a line terminator or at the end of
   26|       |    // the file, and last_offset will point to position the file had when this method was called.
   27|       |
   28|  6.52k|    qpdf_offset_t offset = this->tell();
   29|  6.52k|    auto bp = std::make_unique<char[]>(max_line_length + 1);
   30|  6.52k|    char* buf = bp.get();
   31|  6.52k|    memset(buf, '\0', max_line_length + 1);
   32|  6.52k|    this->read(buf, max_line_length);
   33|  6.52k|    this->seek(offset, SEEK_SET);
   34|  6.52k|    qpdf_offset_t eol = this->findAndSkipNextEOL();
   35|  6.52k|    this->last_offset = offset;
   36|  6.52k|    size_t line_length = QIntC::to_size(eol - offset);
   37|  6.52k|    if (line_length < max_line_length) {
  ------------------
  |  Branch (37:9): [True: 6.52k, False: 0]
  ------------------
   38|  6.52k|        buf[line_length] = '\0';
   39|  6.52k|    }
   40|  6.52k|    return {buf};
   41|  6.52k|}
_ZN11InputSource9findFirstEPKcxmRNS_6FinderE:
   45|  19.5k|{
   46|       |    // Basic approach: search for the first character of start_chars starting from offset but not
   47|       |    // going past len (if len != 0). Once the first character is found, see if it is the beginning
   48|       |    // of a sequence of characters matching start_chars. If so, call finder.check() to do
   49|       |    // caller-specific additional checks. If not, keep searching.
   50|       |
   51|       |    // This code is tricky and highly subject to off-by-one or other edge case logic errors. See
   52|       |    // comments throughout that explain how we're not missing any edge cases. There are also tests
   53|       |    // specifically constructed to make sure we caught the edge cases in testing.
   54|       |
   55|  19.5k|    char buf[1025]; // size known to input_source.cc in libtests
   56|       |    // To enable us to guarantee null-termination, save an extra byte so that buf[size] is valid
   57|       |    // memory.
   58|  19.5k|    size_t size = sizeof(buf) - 1;
   59|  19.5k|    if ((strlen(start_chars) < 1) || (strlen(start_chars) > size)) {
  ------------------
  |  Branch (59:9): [True: 0, False: 19.5k]
  |  Branch (59:38): [True: 0, False: 19.5k]
  ------------------
   60|      0|        throw std::logic_error("InputSource::findSource called with"
   61|      0|                               " too small or too large of a character sequence");
   62|      0|    }
   63|       |
   64|  19.5k|    char* p = nullptr;
   65|  19.5k|    qpdf_offset_t buf_offset = offset;
   66|  19.5k|    size_t bytes_read = 0;
   67|       |
   68|       |    // Guarantee that we return from this loop. Each time through, we either return, advance p, or
   69|       |    // restart the loop with a condition that will cause return on the next pass. Eventually we will
   70|       |    // either be out of range or hit EOF, either of which forces us to return.
   71|  19.5k|    while (true) {
  ------------------
  |  Branch (71:12): [Folded - Ignored]
  ------------------
   72|       |        // Do we need to read more data? Pretend size = 5, buf starts at 0, and start_chars has 3
   73|       |        // characters. buf[5] is valid and null. If p == 2, start_chars could be buf[2] through
   74|       |        // buf[4], so p + strlen(start_chars) == buf + size is okay. If p points to buf[size], since
   75|       |        // strlen(start_chars) is always >= 1, this overflow test will be correct for that case
   76|       |        // regardless of start_chars.
   77|  19.5k|        if ((p == nullptr) || ((p + strlen(start_chars)) > (buf + bytes_read))) {
  ------------------
  |  Branch (77:13): [True: 19.5k, False: 0]
  |  Branch (77:31): [True: 0, False: 0]
  ------------------
   78|  19.5k|            if (p) {
  ------------------
  |  Branch (78:17): [True: 0, False: 19.5k]
  ------------------
   79|      0|                QTC::TC(
   80|      0|                    "libtests", "InputSource read next block", ((p == buf + bytes_read) ? 0 : 1));
  ------------------
  |  Branch (80:65): [True: 0, False: 0]
  ------------------
   81|      0|                buf_offset += (p - buf);
   82|      0|            }
   83|  19.5k|            this->seek(buf_offset, SEEK_SET);
   84|       |            // Read into buffer and zero out the rest of the buffer including buf[size]. We
   85|       |            // allocated an extra byte so that we could guarantee null termination as an extra
   86|       |            // protection against overrun when using string functions.
   87|  19.5k|            bytes_read = this->read(buf, size);
   88|  19.5k|            if (bytes_read < strlen(start_chars)) {
  ------------------
  |  Branch (88:17): [True: 6.52k, False: 13.0k]
  ------------------
   89|  6.52k|                QTC::TC("libtests", "InputSource find EOF", bytes_read == 0 ? 0 : 1);
  ------------------
  |  Branch (89:61): [True: 0, False: 6.52k]
  ------------------
   90|  6.52k|                return false;
   91|  6.52k|            }
   92|  13.0k|            memset(buf + bytes_read, '\0', 1 + (size - bytes_read));
   93|  13.0k|            p = buf;
   94|  13.0k|        }
   95|       |
   96|       |        // Search for the first character.
   97|  13.0k|        if ((p = static_cast<char*>(
  ------------------
  |  Branch (97:13): [True: 13.0k, False: 0]
  ------------------
   98|       |                 // line-break
   99|  13.0k|                 memchr(p, start_chars[0], bytes_read - QIntC::to_size(p - buf)))) != nullptr) {
  100|  13.0k|            if (p == buf) {
  ------------------
  |  Branch (100:17): [True: 6.52k, False: 6.52k]
  ------------------
  101|  6.52k|                QTC::TC("libtests", "InputSource found match at buf[0]");
  102|  6.52k|            }
  103|       |            // Found first letter.
  104|  13.0k|            if (len != 0) {
  ------------------
  |  Branch (104:17): [True: 6.52k, False: 6.52k]
  ------------------
  105|       |                // Make sure it's in range.
  106|  6.52k|                size_t p_relative_offset = QIntC::to_size((p - buf) + (buf_offset - offset));
  107|  6.52k|                if (p_relative_offset >= len) {
  ------------------
  |  Branch (107:21): [True: 0, False: 6.52k]
  ------------------
  108|       |                    // out of range
  109|      0|                    QTC::TC("libtests", "InputSource out of range");
  110|      0|                    return false;
  111|      0|                }
  112|  6.52k|            }
  113|  13.0k|            if ((p + strlen(start_chars)) > (buf + bytes_read)) {
  ------------------
  |  Branch (113:17): [True: 0, False: 13.0k]
  ------------------
  114|       |                // If there are not enough bytes left in the file for start_chars, we will detect
  115|       |                // this on the next pass as EOF and return.
  116|      0|                QTC::TC("libtests", "InputSource not enough bytes");
  117|      0|                continue;
  118|      0|            }
  119|       |
  120|       |            // See if p points to a sequence matching start_chars. We already checked above to make
  121|       |            // sure we are not going to overrun memory.
  122|  13.0k|            if (strncmp(p, start_chars, strlen(start_chars)) == 0) {
  ------------------
  |  Branch (122:17): [True: 13.0k, False: 0]
  ------------------
  123|       |                // Call finder.check() with the input source positioned to the point of the match.
  124|  13.0k|                this->seek(buf_offset + (p - buf), SEEK_SET);
  125|  13.0k|                if (finder.check()) {
  ------------------
  |  Branch (125:21): [True: 13.0k, False: 0]
  ------------------
  126|  13.0k|                    return true;
  127|  13.0k|                } else {
  128|      0|                    QTC::TC("libtests", "InputSource start_chars matched but not check");
  129|      0|                }
  130|  13.0k|            } else {
  131|      0|                QTC::TC("libtests", "InputSource first char matched but not string");
  132|      0|            }
  133|       |            // This occurrence of the first character wasn't a match. Skip over it and keep
  134|       |            // searching.
  135|      0|            ++p;
  136|      0|        } else {
  137|       |            // Trigger reading the next block
  138|      0|            p = buf + bytes_read;
  139|      0|        }
  140|  13.0k|    }
  141|      0|    throw std::logic_error("InputSource after while (true)");
  142|  19.5k|}
_ZN11InputSource8findLastEPKcxmRNS_6FinderE:
  146|  6.52k|{
  147|  6.52k|    bool found = false;
  148|  6.52k|    qpdf_offset_t after_found_offset = 0;
  149|  6.52k|    qpdf_offset_t cur_offset = offset;
  150|  6.52k|    size_t cur_len = len;
  151|  13.0k|    while (this->findFirst(start_chars, cur_offset, cur_len, finder)) {
  ------------------
  |  Branch (151:12): [True: 6.52k, False: 6.52k]
  ------------------
  152|  6.52k|        if (found) {
  ------------------
  |  Branch (152:13): [True: 0, False: 6.52k]
  ------------------
  153|      0|            QTC::TC("libtests", "InputSource findLast found more than one");
  154|  6.52k|        } else {
  155|  6.52k|            found = true;
  156|  6.52k|        }
  157|  6.52k|        after_found_offset = this->tell();
  158|  6.52k|        cur_offset = after_found_offset;
  159|  6.52k|        cur_len = len - QIntC::to_size((cur_offset - offset));
  160|  6.52k|    }
  161|  6.52k|    if (found) {
  ------------------
  |  Branch (161:9): [True: 6.52k, False: 0]
  ------------------
  162|  6.52k|        this->seek(after_found_offset, SEEK_SET);
  163|  6.52k|    }
  164|  6.52k|    return found;
  165|  6.52k|}

_ZN4JSON7MembersC2ENSt3__110unique_ptrINS_10JSON_valueENS1_14default_deleteIS3_EEEE:
   16|  6.82M|{
   17|  6.82M|}
_ZN4JSONC2ENSt3__110unique_ptrINS_10JSON_valueENS0_14default_deleteIS2_EEEE:
   21|  6.82M|{
   22|  6.82M|}
_ZN4JSON11JSON_stringC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  125|   812k|{
  126|   812k|}
_ZN4JSON11JSON_numberC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  149|  5.80M|{
  150|  5.80M|}
_ZN4JSON9JSON_boolC2Eb:
  161|  1.91k|{
  162|  1.91k|}
_ZN4JSON6Writer13encode_stringERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  217|  1.00M|{
  218|  1.00M|    static auto constexpr hexchars = "0123456789abcdef";
  219|       |
  220|  1.00M|    auto begin = str.cbegin();
  221|  1.00M|    auto end = str.cend();
  222|  1.00M|    auto iter = begin;
  223|   136M|    while (iter != end) {
  ------------------
  |  Branch (223:12): [True: 135M, False: 996k]
  ------------------
  224|   135M|        auto c = static_cast<unsigned char>(*iter);
  225|   135M|        if ((c > 34 && c != '\\') || c == ' ' || c == 33) {
  ------------------
  |  Branch (225:14): [True: 76.7M, False: 58.9M]
  |  Branch (225:24): [True: 76.7M, False: 320]
  |  Branch (225:38): [True: 58.9M, False: 22.8k]
  |  Branch (225:50): [True: 18.5k, False: 4.34k]
  ------------------
  226|       |            // Optimistically check that no char in str requires escaping. Hopefully we can just
  227|       |            // return the input str.
  228|   135M|            ++iter;
  229|   135M|        } else {
  230|       |            // We found a char that requires escaping. Initialize result to the chars scanned so
  231|       |            // far, append/replace the rest of str one char at a time, and return the result.
  232|  4.34k|            std::string result{begin, iter};
  233|       |
  234|  1.55M|            for (; iter != end; ++iter) {
  ------------------
  |  Branch (234:20): [True: 1.55M, False: 4.34k]
  ------------------
  235|  1.55M|                auto ch = static_cast<unsigned char>(*iter);
  236|  1.55M|                if ((ch > 34 && ch != '\\') || ch == ' ' || ch == 33) {
  ------------------
  |  Branch (236:22): [True: 1.27M, False: 274k]
  |  Branch (236:33): [True: 1.27M, False: 814]
  |  Branch (236:48): [True: 268k, False: 7.68k]
  |  Branch (236:61): [True: 308, False: 7.37k]
  ------------------
  237|       |                    // Check for most common case first.
  238|  1.54M|                    result += *iter;
  239|  1.54M|                } else {
  240|  7.37k|                    switch (ch) {
  241|    814|                    case '\\':
  ------------------
  |  Branch (241:21): [True: 814, False: 6.55k]
  ------------------
  242|    814|                        result += "\\\\";
  243|    814|                        break;
  244|    270|                    case '\"':
  ------------------
  |  Branch (244:21): [True: 270, False: 7.10k]
  ------------------
  245|    270|                        result += "\\\"";
  246|    270|                        break;
  247|    545|                    case '\b':
  ------------------
  |  Branch (247:21): [True: 545, False: 6.82k]
  ------------------
  248|    545|                        result += "\\b";
  249|    545|                        break;
  250|    344|                    case '\f':
  ------------------
  |  Branch (250:21): [True: 344, False: 7.02k]
  ------------------
  251|    344|                        result += "\\f";
  252|    344|                        break;
  253|  2.51k|                    case '\n':
  ------------------
  |  Branch (253:21): [True: 2.51k, False: 4.85k]
  ------------------
  254|  2.51k|                        result += "\\n";
  255|  2.51k|                        break;
  256|    462|                    case '\r':
  ------------------
  |  Branch (256:21): [True: 462, False: 6.91k]
  ------------------
  257|    462|                        result += "\\r";
  258|    462|                        break;
  259|    483|                    case '\t':
  ------------------
  |  Branch (259:21): [True: 483, False: 6.89k]
  ------------------
  260|    483|                        result += "\\t";
  261|    483|                        break;
  262|  1.93k|                    default:
  ------------------
  |  Branch (262:21): [True: 1.93k, False: 5.43k]
  ------------------
  263|  1.93k|                        result += ch < 16 ? "\\u000" : "\\u001";
  ------------------
  |  Branch (263:35): [True: 944, False: 992]
  ------------------
  264|  1.93k|                        result += hexchars[ch % 16];
  265|  7.37k|                    }
  266|  7.37k|                }
  267|  1.55M|            }
  268|  4.34k|            return result;
  269|  4.34k|        }
  270|   135M|    }
  271|   996k|    return str;
  272|  1.00M|}
_ZN4JSON14makeDictionaryEv:
  276|   134k|{
  277|   134k|    return {std::make_unique<JSON_dictionary>()};
  278|   134k|}
_ZN4JSON19addDictionaryMemberERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKS_:
  282|   188k|{
  283|   188k|    if (auto* obj = m ? dynamic_cast<JSON_dictionary*>(m->value.get()) : nullptr) {
  ------------------
  |  Branch (283:15): [True: 188k, False: 0]
  ------------------
  284|   188k|        return obj->members[Writer::encode_string(key)] = val.m ? val : makeNull();
  ------------------
  |  Branch (284:59): [True: 188k, False: 0]
  ------------------
  285|   188k|    } else {
  286|      0|        throw std::runtime_error("JSON::addDictionaryMember called on non-dictionary");
  287|      0|    }
  288|   188k|}
_ZN4JSON22checkDictionaryKeySeenERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  292|   375k|{
  293|   375k|    if (auto* obj = m ? dynamic_cast<JSON_dictionary*>(m->value.get()) : nullptr) {
  ------------------
  |  Branch (293:15): [True: 375k, False: 0]
  ------------------
  294|   375k|        return !obj->parsed_keys.insert(key).second;
  295|   375k|    }
  296|      0|    throw std::logic_error("JSON::checkDictionaryKey called on non-dictionary");
  297|      0|    return false; // unreachable
  298|   375k|}
_ZN4JSON9makeArrayEv:
  302|  60.5k|{
  303|  60.5k|    return {std::make_unique<JSON_array>()};
  304|  60.5k|}
_ZN4JSON15addArrayElementERKS_:
  308|  3.30M|{
  309|  3.30M|    if (auto* arr = m ? dynamic_cast<JSON_array*>(m->value.get()) : nullptr) {
  ------------------
  |  Branch (309:15): [True: 3.30M, False: 0]
  ------------------
  310|  3.30M|        if (val.m) {
  ------------------
  |  Branch (310:13): [True: 3.30M, False: 0]
  ------------------
  311|  3.30M|            arr->elements.push_back(val);
  312|  3.30M|        } else {
  313|      0|            arr->elements.push_back(makeNull());
  314|      0|        }
  315|  3.30M|        return arr->elements.back();
  316|  3.30M|    }
  317|      0|    throw std::runtime_error("JSON::addArrayElement called on non-array");
  318|      0|    return {}; // unreachable
  319|  3.30M|}
_ZN4JSON10makeStringERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  323|   812k|{
  324|   812k|    return {std::make_unique<JSON_string>(utf8)};
  325|   812k|}
_ZN4JSON10makeNumberERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  341|  5.80M|{
  342|  5.80M|    return {std::make_unique<JSON_number>(encoded)};
  343|  5.80M|}
_ZN4JSON8makeBoolEb:
  347|  1.91k|{
  348|  1.91k|    return {std::make_unique<JSON_bool>(value)};
  349|  1.91k|}
_ZN4JSON8makeNullEv:
  353|  3.82k|{
  354|  3.82k|    return {std::make_unique<JSON_null>()};
  355|  3.82k|}
_ZNK4JSON7isArrayEv:
  365|  9.43M|{
  366|  9.43M|    return m ? m->value->type_code == vt_array : false;
  ------------------
  |  Branch (366:12): [True: 9.43M, False: 0]
  ------------------
  367|  9.43M|}
_ZNK4JSON12isDictionaryEv:
  371|  9.77M|{
  372|  9.77M|    return m && m->value->type_code == vt_dictionary;
  ------------------
  |  Branch (372:12): [True: 9.77M, False: 0]
  |  Branch (372:17): [True: 343k, False: 9.43M]
  ------------------
  373|  9.77M|}
_ZNK4JSON9getStringERNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  377|   401k|{
  378|   401k|    if (m && m->value->type_code == vt_string) {
  ------------------
  |  Branch (378:9): [True: 401k, False: 0]
  |  Branch (378:14): [True: 401k, False: 128]
  ------------------
  379|   401k|        auto v = dynamic_cast<JSON_string const*>(m->value.get());
  380|   401k|        utf8 = v->utf8;
  381|   401k|        return true;
  382|   401k|    }
  383|    128|    return false;
  384|   401k|}
_ZNK4JSON9getNumberERNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  388|  2.66M|{
  389|  2.66M|    if (m && m->value->type_code == vt_number) {
  ------------------
  |  Branch (389:9): [True: 2.66M, False: 0]
  |  Branch (389:14): [True: 2.27M, False: 397k]
  ------------------
  390|  2.27M|        auto v = dynamic_cast<JSON_number const*>(m->value.get());
  391|  2.27M|        value = v->encoded;
  392|  2.27M|        return true;
  393|  2.27M|    }
  394|   397k|    return false;
  395|  2.66M|}
_ZNK4JSON7getBoolERb:
  399|  2.66M|{
  400|  2.66M|    if (m && m->value->type_code == vt_bool) {
  ------------------
  |  Branch (400:9): [True: 2.66M, False: 0]
  |  Branch (400:14): [True: 476, False: 2.66M]
  ------------------
  401|    476|        auto v = dynamic_cast<JSON_bool const*>(m->value.get());
  402|    476|        value = v->value;
  403|    476|        return true;
  404|    476|    }
  405|  2.66M|    return false;
  406|  2.66M|}
_ZNK4JSON6isNullEv:
  410|  2.66M|{
  411|  2.66M|    return m && m->value->type_code == vt_null;
  ------------------
  |  Branch (411:12): [True: 2.66M, False: 0]
  |  Branch (411:17): [True: 1.30k, False: 2.66M]
  ------------------
  412|  2.66M|}
_ZN4JSON5parseER11InputSourcePNS_7ReactorE:
 1362|  6.52k|{
 1363|  6.52k|    JSONParser jp(is, reactor);
 1364|  6.52k|    return jp.parse();
 1365|  6.52k|}
_ZN4JSON5parseERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1369|  6.52k|{
 1370|  6.52k|    BufferInputSource bis("json input", s);
 1371|  6.52k|    JSONParser jp(bis, nullptr);
 1372|  6.52k|    return jp.parse();
 1373|  6.52k|}
_ZN4JSON8setStartEx:
 1377|  6.82M|{
 1378|  6.82M|    if (m) {
  ------------------
  |  Branch (1378:9): [True: 6.82M, False: 0]
  ------------------
 1379|  6.82M|        m->start = start;
 1380|  6.82M|    }
 1381|  6.82M|}
_ZN4JSON6setEndEx:
 1385|  6.88M|{
 1386|  6.88M|    if (m) {
  ------------------
  |  Branch (1386:9): [True: 6.88M, False: 0]
  ------------------
 1387|  6.88M|        m->end = end;
 1388|  6.88M|    }
 1389|  6.88M|}
_ZNK4JSON8getStartEv:
 1393|  2.43M|{
 1394|  2.43M|    return m ? m->start : 0;
  ------------------
  |  Branch (1394:12): [True: 2.43M, False: 0]
  ------------------
 1395|  2.43M|}
_ZNK4JSON6getEndEv:
 1399|  3.60k|{
 1400|  3.60k|    return m ? m->end : 0;
  ------------------
  |  Branch (1400:12): [True: 3.60k, False: 0]
  ------------------
 1401|  3.60k|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParserC2ER11InputSourcePN4JSON7ReactorE:
  602|  13.0k|        {
  603|  13.0k|        }
JSON.cc:_ZN12_GLOBAL__N_110JSONParser5parseEv:
 1344|  13.0k|{
 1345|  14.2M|    while (!done) {
  ------------------
  |  Branch (1345:12): [True: 14.2M, False: 13.0k]
  ------------------
 1346|  14.2M|        getToken();
 1347|  14.2M|        handleToken();
 1348|  14.2M|    }
 1349|  13.0k|    if (parser_state != ps_done) {
  ------------------
  |  Branch (1349:9): [True: 7.82k, False: 5.23k]
  ------------------
 1350|  7.82k|        QTC::TC("libtests", "JSON parse premature EOF");
 1351|  7.82k|        throw std::runtime_error("JSON: premature end of input");
 1352|  7.82k|    }
 1353|  5.23k|    auto const& tos = stack.back().item;
 1354|  5.23k|    if (reactor && !(tos.isArray() || tos.isDictionary())) {
  ------------------
  |  Branch (1354:9): [True: 273, False: 4.95k]
  |  Branch (1354:22): [True: 0, False: 273]
  |  Branch (1354:39): [True: 35, False: 238]
  ------------------
 1355|    238|        reactor->topLevelScalar();
 1356|    238|    }
 1357|  5.23k|    return tos;
 1358|  13.0k|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser8getTokenEv:
  829|  14.2M|{
  830|  14.2M|    token.clear();
  831|       |
  832|       |    // Keep track of UTF-16 surrogate pairs.
  833|  14.2M|    unsigned long high_surrogate = 0;
  834|  14.2M|    qpdf_offset_t high_offset = 0;
  835|       |
  836|   256M|    while (true) {
  ------------------
  |  Branch (836:12): [Folded - Ignored]
  ------------------
  837|   256M|        if (p == (buf + bytes)) {
  ------------------
  |  Branch (837:13): [True: 37.4k, False: 256M]
  ------------------
  838|  37.4k|            p = buf;
  839|  37.4k|            bytes = is.read(buf, sizeof(buf));
  840|  37.4k|            if (bytes == 0) {
  ------------------
  |  Branch (840:17): [True: 9.79k, False: 27.6k]
  ------------------
  841|  9.79k|                done = true;
  842|  9.79k|                break;
  843|  9.79k|            }
  844|  37.4k|        }
  845|       |
  846|   256M|        if ((*p < 32 && *p >= 0)) {
  ------------------
  |  Branch (846:14): [True: 34.1M, False: 221M]
  |  Branch (846:25): [True: 414k, False: 33.6M]
  ------------------
  847|   414k|            if (*p == '\t' || *p == '\n' || *p == '\r') {
  ------------------
  |  Branch (847:17): [True: 375, False: 414k]
  |  Branch (847:31): [True: 412k, False: 1.93k]
  |  Branch (847:45): [True: 1.76k, False: 165]
  ------------------
  848|       |                // Legal white space not permitted in strings. This will always end the current
  849|       |                // token (unless we are still before the start of the token).
  850|   414k|                if (lex_state == ls_top) {
  ------------------
  |  Branch (850:21): [True: 392k, False: 22.0k]
  ------------------
  851|   392k|                    ignore();
  852|   392k|                } else {
  853|  22.0k|                    break;
  854|  22.0k|                }
  855|       |
  856|   414k|            } else {
  857|    165|                QTC::TC("libtests", "JSON parse null character");
  858|    165|                throw std::runtime_error(
  859|    165|                    "JSON: control or null character at offset " + std::to_string(offset));
  860|    165|            }
  861|   255M|        } else if (*p == ',') {
  ------------------
  |  Branch (861:20): [True: 15.5M, False: 240M]
  ------------------
  862|  15.5M|            if (lex_state == ls_top) {
  ------------------
  |  Branch (862:17): [True: 6.62M, False: 8.95M]
  ------------------
  863|  6.62M|                ignore(ls_comma);
  864|  6.62M|                return;
  865|  8.95M|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (865:24): [True: 3.16M, False: 5.78M]
  ------------------
  866|  3.16M|                append();
  867|  5.78M|            } else {
  868|  5.78M|                break;
  869|  5.78M|            }
  870|   240M|        } else if (*p == ':') {
  ------------------
  |  Branch (870:20): [True: 496k, False: 239M]
  ------------------
  871|   496k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (871:17): [True: 376k, False: 120k]
  ------------------
  872|   376k|                ignore(ls_colon);
  873|   376k|                return;
  874|   376k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (874:24): [True: 120k, False: 78]
  ------------------
  875|   120k|                append();
  876|   120k|            } else {
  877|     78|                break;
  878|     78|            }
  879|   239M|        } else if (*p == ' ') {
  ------------------
  |  Branch (879:20): [True: 94.8M, False: 144M]
  ------------------
  880|  94.8M|            if (lex_state == ls_top) {
  ------------------
  |  Branch (880:17): [True: 4.93M, False: 89.9M]
  ------------------
  881|  4.93M|                ignore();
  882|  89.9M|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (882:24): [True: 89.9M, False: 569]
  ------------------
  883|  89.9M|                append();
  884|  89.9M|            } else {
  885|    569|                break;
  886|    569|            }
  887|   144M|        } else if (*p == '{') {
  ------------------
  |  Branch (887:20): [True: 136k, False: 144M]
  ------------------
  888|   136k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (888:17): [True: 134k, False: 1.14k]
  ------------------
  889|   134k|                token_start = offset;
  890|   134k|                ignore(ls_begin_dict);
  891|   134k|                return;
  892|   134k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (892:24): [True: 1.08k, False: 60]
  ------------------
  893|  1.08k|                append();
  894|  1.08k|            } else {
  895|     60|                break;
  896|     60|            }
  897|   144M|        } else if (*p == '}') {
  ------------------
  |  Branch (897:20): [True: 77.3k, False: 144M]
  ------------------
  898|  77.3k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (898:17): [True: 56.7k, False: 20.5k]
  ------------------
  899|  56.7k|                ignore(ls_end_dict);
  900|  56.7k|                return;
  901|  56.7k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (901:24): [True: 20.0k, False: 484]
  ------------------
  902|  20.0k|                append();
  903|  20.0k|            } else {
  904|    484|                break;
  905|    484|            }
  906|   144M|        } else if (*p == '[') {
  ------------------
  |  Branch (906:20): [True: 84.1k, False: 144M]
  ------------------
  907|  84.1k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (907:17): [True: 60.5k, False: 23.6k]
  ------------------
  908|  60.5k|                token_start = offset;
  909|  60.5k|                ignore(ls_begin_array);
  910|  60.5k|                return;
  911|  60.5k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (911:24): [True: 23.6k, False: 24]
  ------------------
  912|  23.6k|                append();
  913|  23.6k|            } else {
  914|     24|                break;
  915|     24|            }
  916|   144M|        } else if (*p == ']') {
  ------------------
  |  Branch (916:20): [True: 18.0k, False: 144M]
  ------------------
  917|  18.0k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (917:17): [True: 5.49k, False: 12.5k]
  ------------------
  918|  5.49k|                ignore(ls_end_array);
  919|  5.49k|                return;
  920|  12.5k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (920:24): [True: 11.7k, False: 838]
  ------------------
  921|  11.7k|                append();
  922|  11.7k|            } else {
  923|    838|                break;
  924|    838|            }
  925|   144M|        } else {
  926|   144M|            switch (lex_state) {
  927|  7.00M|            case ls_top:
  ------------------
  |  Branch (927:13): [True: 7.00M, False: 137M]
  ------------------
  928|  7.00M|                token_start = offset;
  929|  7.00M|                if (*p == '"') {
  ------------------
  |  Branch (929:21): [True: 1.18M, False: 5.81M]
  ------------------
  930|  1.18M|                    ignore(ls_string);
  931|  5.81M|                } else if ((*p >= 'a') && (*p <= 'z')) {
  ------------------
  |  Branch (931:28): [True: 6.29k, False: 5.80M]
  |  Branch (931:43): [True: 6.28k, False: 11]
  ------------------
  932|  6.28k|                    append(ls_alpha);
  933|  5.80M|                } else if (*p == '-') {
  ------------------
  |  Branch (933:28): [True: 8.99k, False: 5.79M]
  ------------------
  934|  8.99k|                    append(ls_number_minus);
  935|  5.79M|                } else if ((*p >= '1') && (*p <= '9')) {
  ------------------
  |  Branch (935:28): [True: 1.71M, False: 4.08M]
  |  Branch (935:43): [True: 1.71M, False: 171]
  ------------------
  936|  1.71M|                    append(ls_number_before_point);
  937|  4.08M|                } else if (*p == '0') {
  ------------------
  |  Branch (937:28): [True: 4.08M, False: 658]
  ------------------
  938|  4.08M|                    append(ls_number_leading_zero);
  939|  4.08M|                } else {
  940|    658|                    QTC::TC("libtests", "JSON parse bad character");
  941|    658|                    throw std::runtime_error(
  942|    658|                        "JSON: offset " + std::to_string(offset) + ": unexpected character " +
  943|    658|                        std::string(p, 1));
  944|    658|                }
  945|  7.00M|                break;
  946|       |
  947|  7.00M|            case ls_number_minus:
  ------------------
  |  Branch (947:13): [True: 8.94k, False: 144M]
  ------------------
  948|  8.94k|                if ((*p >= '1') && (*p <= '9')) {
  ------------------
  |  Branch (948:21): [True: 6.99k, False: 1.95k]
  |  Branch (948:36): [True: 6.98k, False: 11]
  ------------------
  949|  6.98k|                    append(ls_number_before_point);
  950|  6.98k|                } else if (*p == '0') {
  ------------------
  |  Branch (950:28): [True: 1.93k, False: 25]
  ------------------
  951|  1.93k|                    append(ls_number_leading_zero);
  952|  1.93k|                } else {
  953|     25|                    QTC::TC("libtests", "JSON parse number minus no digits");
  954|     25|                    throw std::runtime_error(
  955|     25|                        "JSON: offset " + std::to_string(offset) +
  956|     25|                        ": numeric literal: no digit after minus sign");
  957|     25|                }
  958|  8.92k|                break;
  959|       |
  960|  8.92k|            case ls_number_leading_zero:
  ------------------
  |  Branch (960:13): [True: 1.26k, False: 144M]
  ------------------
  961|  1.26k|                if (*p == '.') {
  ------------------
  |  Branch (961:21): [True: 709, False: 555]
  ------------------
  962|    709|                    append(ls_number_point);
  963|    709|                } else if (*p == 'e' || *p == 'E') {
  ------------------
  |  Branch (963:28): [True: 262, False: 293]
  |  Branch (963:41): [True: 235, False: 58]
  ------------------
  964|    497|                    append(ls_number_e);
  965|    497|                } else {
  966|     58|                    QTC::TC("libtests", "JSON parse leading zero");
  967|     58|                    throw std::runtime_error(
  968|     58|                        "JSON: offset " + std::to_string(offset) + ": number with leading zero");
  969|     58|                }
  970|  1.20k|                break;
  971|       |
  972|  1.65M|            case ls_number_before_point:
  ------------------
  |  Branch (972:13): [True: 1.65M, False: 142M]
  ------------------
  973|  1.65M|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (973:21): [True: 1.64M, False: 3.34k]
  |  Branch (973:36): [True: 1.64M, False: 5.92k]
  ------------------
  974|  1.64M|                    append();
  975|  1.64M|                } else if (*p == '.') {
  ------------------
  |  Branch (975:28): [True: 3.28k, False: 5.98k]
  ------------------
  976|  3.28k|                    append(ls_number_point);
  977|  5.98k|                } else if (*p == 'e' || *p == 'E') {
  ------------------
  |  Branch (977:28): [True: 2.42k, False: 3.56k]
  |  Branch (977:41): [True: 3.45k, False: 101]
  ------------------
  978|  5.87k|                    append(ls_number_e);
  979|  5.87k|                } else {
  980|    101|                    tokenError();
  981|    101|                }
  982|  1.65M|                break;
  983|       |
  984|  3.95k|            case ls_number_point:
  ------------------
  |  Branch (984:13): [True: 3.95k, False: 144M]
  ------------------
  985|  3.95k|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (985:21): [True: 3.95k, False: 7]
  |  Branch (985:36): [True: 3.93k, False: 13]
  ------------------
  986|  3.93k|                    append(ls_number_after_point);
  987|  3.93k|                } else {
  988|     20|                    tokenError();
  989|     20|                }
  990|  3.95k|                break;
  991|       |
  992|  2.57M|            case ls_number_after_point:
  ------------------
  |  Branch (992:13): [True: 2.57M, False: 141M]
  ------------------
  993|  2.57M|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (993:21): [True: 2.57M, False: 21]
  |  Branch (993:36): [True: 2.57M, False: 434]
  ------------------
  994|  2.57M|                    append();
  995|  2.57M|                } else if (*p == 'e' || *p == 'E') {
  ------------------
  |  Branch (995:28): [True: 212, False: 243]
  |  Branch (995:41): [True: 214, False: 29]
  ------------------
  996|    426|                    append(ls_number_e);
  997|    426|                } else {
  998|     29|                    tokenError();
  999|     29|                }
 1000|  2.57M|                break;
 1001|       |
 1002|  6.71k|            case ls_number_e:
  ------------------
  |  Branch (1002:13): [True: 6.71k, False: 144M]
  ------------------
 1003|  6.71k|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (1003:21): [True: 5.57k, False: 1.14k]
  |  Branch (1003:36): [True: 5.56k, False: 9]
  ------------------
 1004|  5.56k|                    append(ls_number);
 1005|  5.56k|                } else if ((*p == '+') || (*p == '-')) {
  ------------------
  |  Branch (1005:28): [True: 434, False: 716]
  |  Branch (1005:43): [True: 682, False: 34]
  ------------------
 1006|  1.11k|                    append(ls_number_e_sign);
 1007|  1.11k|                } else {
 1008|     34|                    tokenError();
 1009|     34|                }
 1010|  6.71k|                break;
 1011|       |
 1012|  1.09k|            case ls_number_e_sign:
  ------------------
  |  Branch (1012:13): [True: 1.09k, False: 144M]
  ------------------
 1013|  1.09k|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (1013:21): [True: 1.08k, False: 11]
  |  Branch (1013:36): [True: 1.07k, False: 11]
  ------------------
 1014|  1.07k|                    append(ls_number);
 1015|  1.07k|                } else {
 1016|     22|                    tokenError();
 1017|     22|                }
 1018|  1.09k|                break;
 1019|       |
 1020|  15.9M|            case ls_number:
  ------------------
  |  Branch (1020:13): [True: 15.9M, False: 128M]
  ------------------
 1021|       |                // We only get here after we have seen an exponent.
 1022|  15.9M|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (1022:21): [True: 15.9M, False: 29]
  |  Branch (1022:36): [True: 15.9M, False: 7]
  ------------------
 1023|  15.9M|                    append();
 1024|  15.9M|                } else {
 1025|     36|                    tokenError();
 1026|     36|                }
 1027|  15.9M|                break;
 1028|       |
 1029|   589k|            case ls_alpha:
  ------------------
  |  Branch (1029:13): [True: 589k, False: 143M]
  ------------------
 1030|   589k|                if ((*p >= 'a') && (*p <= 'z')) {
  ------------------
  |  Branch (1030:21): [True: 589k, False: 179]
  |  Branch (1030:36): [True: 589k, False: 3]
  ------------------
 1031|   589k|                    append();
 1032|   589k|                } else {
 1033|    182|                    tokenError();
 1034|    182|                }
 1035|   589k|                break;
 1036|       |
 1037|   116M|            case ls_string:
  ------------------
  |  Branch (1037:13): [True: 116M, False: 27.8M]
  ------------------
 1038|   116M|                if (*p == '"') {
  ------------------
  |  Branch (1038:21): [True: 1.18M, False: 115M]
  ------------------
 1039|  1.18M|                    if (high_offset) {
  ------------------
  |  Branch (1039:25): [True: 9, False: 1.18M]
  ------------------
 1040|      9|                        QTC::TC("libtests", "JSON 16 dangling high");
 1041|      9|                        throw std::runtime_error(
 1042|      9|                            "JSON: offset " + std::to_string(high_offset) +
 1043|      9|                            ": UTF-16 high surrogate not followed by low surrogate");
 1044|      9|                    }
 1045|  1.18M|                    ignore(ls_after_string);
 1046|  1.18M|                    return;
 1047|   115M|                } else if (*p == '\\') {
  ------------------
  |  Branch (1047:28): [True: 20.3k, False: 115M]
  ------------------
 1048|  20.3k|                    ignore(ls_backslash);
 1049|   115M|                } else {
 1050|   115M|                    append();
 1051|   115M|                }
 1052|   115M|                break;
 1053|       |
 1054|   115M|            case ls_backslash:
  ------------------
  |  Branch (1054:13): [True: 20.2k, False: 144M]
  ------------------
 1055|  20.2k|                lex_state = ls_string;
 1056|  20.2k|                switch (*p) {
 1057|  1.22k|                case '\\':
  ------------------
  |  Branch (1057:17): [True: 1.22k, False: 19.0k]
  ------------------
 1058|  2.24k|                case '\"':
  ------------------
  |  Branch (1058:17): [True: 1.02k, False: 19.2k]
  ------------------
 1059|  2.59k|                case '/':
  ------------------
  |  Branch (1059:17): [True: 352, False: 19.9k]
  ------------------
 1060|       |                    // \/ is allowed in json input, but so is /, so we don't map / to \/ in output.
 1061|  2.59k|                    token += *p;
 1062|  2.59k|                    break;
 1063|    802|                case 'b':
  ------------------
  |  Branch (1063:17): [True: 802, False: 19.4k]
  ------------------
 1064|    802|                    token += '\b';
 1065|    802|                    break;
 1066|    632|                case 'f':
  ------------------
  |  Branch (1066:17): [True: 632, False: 19.6k]
  ------------------
 1067|    632|                    token += '\f';
 1068|    632|                    break;
 1069|  5.46k|                case 'n':
  ------------------
  |  Branch (1069:17): [True: 5.46k, False: 14.8k]
  ------------------
 1070|  5.46k|                    token += '\n';
 1071|  5.46k|                    break;
 1072|    770|                case 'r':
  ------------------
  |  Branch (1072:17): [True: 770, False: 19.5k]
  ------------------
 1073|    770|                    token += '\r';
 1074|    770|                    break;
 1075|    853|                case 't':
  ------------------
  |  Branch (1075:17): [True: 853, False: 19.4k]
  ------------------
 1076|    853|                    token += '\t';
 1077|    853|                    break;
 1078|  9.16k|                case 'u':
  ------------------
  |  Branch (1078:17): [True: 9.16k, False: 11.1k]
  ------------------
 1079|  9.16k|                    lex_state = ls_u4;
 1080|  9.16k|                    u_count = 0;
 1081|  9.16k|                    u_value = 0;
 1082|  9.16k|                    break;
 1083|      5|                default:
  ------------------
  |  Branch (1083:17): [True: 5, False: 20.2k]
  ------------------
 1084|      5|                    lex_state = ls_backslash;
 1085|      5|                    tokenError();
 1086|  20.2k|                }
 1087|  20.2k|                ignore();
 1088|  20.2k|                break;
 1089|       |
 1090|  36.4k|            case ls_u4:
  ------------------
  |  Branch (1090:13): [True: 36.4k, False: 144M]
  ------------------
 1091|  36.4k|                using ui = unsigned int;
 1092|  36.4k|                if (ui val = ui(QUtil::hex_decode_char(*p)); val < 16) {
  ------------------
  |  Branch (1092:62): [True: 36.3k, False: 36]
  ------------------
 1093|  36.3k|                    u_value = 16 * u_value + val;
 1094|  36.3k|                } else {
 1095|     36|                    tokenError();
 1096|     36|                }
 1097|  36.4k|                if (++u_count == 4) {
  ------------------
  |  Branch (1097:21): [True: 9.08k, False: 27.3k]
  ------------------
 1098|  9.08k|                    handle_u_code(u_value, offset - 5, high_surrogate, high_offset, token);
 1099|  9.08k|                    lex_state = ls_string;
 1100|  9.08k|                }
 1101|  36.4k|                ignore();
 1102|  36.4k|                break;
 1103|       |
 1104|      0|            default:
  ------------------
  |  Branch (1104:13): [True: 0, False: 144M]
  ------------------
 1105|      0|                throw std::logic_error("JSONParser::getToken : trying to handle delimiter state");
 1106|   144M|            }
 1107|   144M|        }
 1108|   256M|    }
 1109|       |
 1110|       |    // We only get here if on end of input or if the last character was a control character or other
 1111|       |    // delimiter.
 1112|       |
 1113|  5.81M|    if (!token.empty()) {
  ------------------
  |  Branch (1113:9): [True: 5.81M, False: 6.25k]
  ------------------
 1114|  5.81M|        switch (lex_state) {
 1115|      0|        case ls_top:
  ------------------
  |  Branch (1115:9): [True: 0, False: 5.81M]
  ------------------
 1116|       |            // Can't happen
 1117|      0|            throw std::logic_error("tok_start set in ls_top while parsing");
 1118|      0|            break;
 1119|       |
 1120|  4.08M|        case ls_number_leading_zero:
  ------------------
  |  Branch (1120:9): [True: 4.08M, False: 1.72M]
  ------------------
 1121|  5.79M|        case ls_number_before_point:
  ------------------
  |  Branch (1121:9): [True: 1.70M, False: 4.10M]
  ------------------
 1122|  5.79M|        case ls_number_after_point:
  ------------------
  |  Branch (1122:9): [True: 3.48k, False: 5.80M]
  ------------------
 1123|  5.79M|            lex_state = ls_number;
 1124|  5.79M|            break;
 1125|       |
 1126|  6.59k|        case ls_number:
  ------------------
  |  Branch (1126:9): [True: 6.59k, False: 5.80M]
  ------------------
 1127|  12.7k|        case ls_alpha:
  ------------------
  |  Branch (1127:9): [True: 6.10k, False: 5.80M]
  ------------------
 1128|       |            // terminal state
 1129|  12.7k|            break;
 1130|       |
 1131|    953|        default:
  ------------------
  |  Branch (1131:9): [True: 953, False: 5.81M]
  ------------------
 1132|    953|            tokenError();
 1133|  5.81M|        }
 1134|  5.81M|    }
 1135|  5.81M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser6ignoreEv:
  812|  5.38M|{
  813|  5.38M|    ++p;
  814|  5.38M|    ++offset;
  815|  5.38M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser6ignoreENS0_11lex_state_eE:
  821|  9.65M|{
  822|  9.65M|    lex_state = next;
  823|  9.65M|    ++p;
  824|  9.65M|    ++offset;
  825|  9.65M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser6appendEv:
  792|   229M|{
  793|   229M|    token += *p;
  794|   229M|    ++p;
  795|   229M|    ++offset;
  796|   229M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser6appendENS0_11lex_state_eE:
  802|  5.84M|{
  803|  5.84M|    lex_state = next;
  804|  5.84M|    token += *p;
  805|  5.84M|    ++p;
  806|  5.84M|    ++offset;
  807|  5.84M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser10tokenErrorEv:
  727|  1.41k|{
  728|  1.41k|    if (done) {
  ------------------
  |  Branch (728:9): [True: 851, False: 567]
  ------------------
  729|    851|        QTC::TC("libtests", "JSON parse ls premature end of input");
  730|    851|        throw std::runtime_error("JSON: premature end of input");
  731|    851|    }
  732|       |
  733|    567|    if (lex_state == ls_u4) {
  ------------------
  |  Branch (733:9): [True: 36, False: 531]
  ------------------
  734|     36|        QTC::TC("libtests", "JSON parse bad hex after u");
  735|     36|        throw std::runtime_error(
  736|     36|            "JSON: offset " + std::to_string(offset - u_count - 1) +
  737|     36|            ": \\u must be followed by four hex digits");
  738|    531|    } else if (lex_state == ls_alpha) {
  ------------------
  |  Branch (738:16): [True: 182, False: 349]
  ------------------
  739|    182|        QTC::TC("libtests", "JSON parse keyword bad character");
  740|    182|        throw std::runtime_error(
  741|    182|            "JSON: offset " + std::to_string(offset) + ": keyword: unexpected character " +
  742|    182|            std::string(p, 1));
  743|    349|    } else if (lex_state == ls_string) {
  ------------------
  |  Branch (743:16): [True: 33, False: 316]
  ------------------
  744|     33|        QTC::TC("libtests", "JSON parse control char in string");
  745|     33|        throw std::runtime_error(
  746|     33|            "JSON: offset " + std::to_string(offset) +
  747|     33|            ": control character in string (missing \"?)");
  748|    316|    } else if (lex_state == ls_backslash) {
  ------------------
  |  Branch (748:16): [True: 5, False: 311]
  ------------------
  749|      5|        QTC::TC("libtests", "JSON parse backslash bad character");
  750|      5|        throw std::runtime_error(
  751|      5|            "JSON: offset " + std::to_string(offset) +
  752|      5|            ": invalid character after backslash: " + std::string(p, 1));
  753|      5|    }
  754|       |
  755|    311|    if (*p == '.') {
  ------------------
  |  Branch (755:9): [True: 17, False: 294]
  ------------------
  756|     17|        if (lex_state == ls_number || lex_state == ls_number_e || lex_state == ls_number_e_sign) {
  ------------------
  |  Branch (756:13): [True: 3, False: 14]
  |  Branch (756:39): [True: 5, False: 9]
  |  Branch (756:67): [True: 3, False: 6]
  ------------------
  757|     11|            QTC::TC("libtests", "JSON parse point after e");
  758|     11|            throw std::runtime_error(
  759|     11|                "JSON: offset " + std::to_string(offset) +
  760|     11|                ": numeric literal: decimal point after e");
  761|     11|        } else {
  762|      6|            QTC::TC("libtests", "JSON parse duplicate point");
  763|      6|            throw std::runtime_error(
  764|      6|                "JSON: offset " + std::to_string(offset) +
  765|      6|                ": numeric literal: decimal point already seen");
  766|      6|        }
  767|    294|    } else if (*p == 'e' || *p == 'E') {
  ------------------
  |  Branch (767:16): [True: 8, False: 286]
  |  Branch (767:29): [True: 10, False: 276]
  ------------------
  768|     18|        QTC::TC("libtests", "JSON parse duplicate e");
  769|     18|        throw std::runtime_error(
  770|     18|            "JSON: offset " + std::to_string(offset) + ": numeric literal: e already seen");
  771|    276|    } else if ((*p == '+') || (*p == '-')) {
  ------------------
  |  Branch (771:16): [True: 7, False: 269]
  |  Branch (771:31): [True: 19, False: 250]
  ------------------
  772|     26|        QTC::TC("libtests", "JSON parse unexpected sign");
  773|     26|        throw std::runtime_error(
  774|     26|            "JSON: offset " + std::to_string(offset) + ": numeric literal: unexpected sign");
  775|    250|    } else if (QUtil::is_space(*p) || strchr("{}[]:,", *p)) {
  ------------------
  |  Branch (775:16): [True: 29, False: 221]
  |  Branch (775:39): [True: 40, False: 181]
  ------------------
  776|     69|        QTC::TC("libtests", "JSON parse incomplete number");
  777|     69|        throw std::runtime_error(
  778|     69|            "JSON: offset " + std::to_string(offset) + ": numeric literal: incomplete number");
  779|       |
  780|    181|    } else {
  781|    181|        QTC::TC("libtests", "JSON parse numeric bad character");
  782|    181|        throw std::runtime_error(
  783|    181|            "JSON: offset " + std::to_string(offset) + ": numeric literal: unexpected character " +
  784|    181|            std::string(p, 1));
  785|    181|    }
  786|      0|    throw std::logic_error("JSON::tokenError : unhandled error");
  787|    311|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser13handle_u_codeEmxRmRxRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  696|  9.08k|{
  697|  9.08k|    if ((codepoint & 0xFC00) == 0xD800) {
  ------------------
  |  Branch (697:9): [True: 428, False: 8.65k]
  ------------------
  698|       |        // high surrogate
  699|    428|        qpdf_offset_t new_high_offset = offset;
  700|    428|        if (high_offset) {
  ------------------
  |  Branch (700:13): [True: 19, False: 409]
  ------------------
  701|     19|            QTC::TC("libtests", "JSON 16 high high");
  702|     19|            throw std::runtime_error(
  703|     19|                "JSON: offset " + std::to_string(new_high_offset) +
  704|     19|                ": UTF-16 high surrogate found after previous high surrogate at offset " +
  705|     19|                std::to_string(high_offset));
  706|     19|        }
  707|    409|        high_offset = new_high_offset;
  708|    409|        high_surrogate = codepoint;
  709|  8.65k|    } else if ((codepoint & 0xFC00) == 0xDC00) {
  ------------------
  |  Branch (709:16): [True: 394, False: 8.26k]
  ------------------
  710|       |        // low surrogate
  711|    394|        if (offset != (high_offset + 6)) {
  ------------------
  |  Branch (711:13): [True: 32, False: 362]
  ------------------
  712|     32|            QTC::TC("libtests", "JSON 16 low not after high");
  713|     32|            throw std::runtime_error(
  714|     32|                "JSON: offset " + std::to_string(offset) +
  715|     32|                ": UTF-16 low surrogate found not immediately after high surrogate");
  716|     32|        }
  717|    362|        high_offset = 0;
  718|    362|        codepoint = 0x10000U + ((high_surrogate & 0x3FFU) << 10U) + (codepoint & 0x3FF);
  719|    362|        result += QUtil::toUTF8(codepoint);
  720|  8.26k|    } else {
  721|  8.26k|        result += QUtil::toUTF8(codepoint);
  722|  8.26k|    }
  723|  9.08k|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser11handleTokenEv:
 1139|  14.2M|{
 1140|  14.2M|    if (lex_state == ls_top) {
  ------------------
  |  Branch (1140:9): [True: 6.10k, False: 14.2M]
  ------------------
 1141|  6.10k|        return;
 1142|  6.10k|    }
 1143|       |
 1144|  14.2M|    if (parser_state == ps_done) {
  ------------------
  |  Branch (1144:9): [True: 61, False: 14.2M]
  ------------------
 1145|     61|        QTC::TC("libtests", "JSON parse junk after object");
 1146|     61|        throw std::runtime_error(
 1147|     61|            "JSON: offset " + std::to_string(offset) +
 1148|     61|            ": material follows end of object: " + token);
 1149|     61|    }
 1150|       |
 1151|  14.2M|    const static JSON null_item = JSON::makeNull();
 1152|  14.2M|    JSON item;
 1153|  14.2M|    auto tos = stack.empty() ? null_item : stack.back().item;
  ------------------
  |  Branch (1153:16): [True: 12.2k, False: 14.2M]
  ------------------
 1154|  14.2M|    auto ls = lex_state;
 1155|  14.2M|    lex_state = ls_top;
 1156|       |
 1157|  14.2M|    switch (ls) {
 1158|   134k|    case ls_begin_dict:
  ------------------
  |  Branch (1158:5): [True: 134k, False: 14.1M]
  ------------------
 1159|   134k|        item = JSON::makeDictionary();
 1160|   134k|        break;
 1161|       |
 1162|  60.5k|    case ls_begin_array:
  ------------------
  |  Branch (1162:5): [True: 60.5k, False: 14.2M]
  ------------------
 1163|  60.5k|        item = JSON::makeArray();
 1164|  60.5k|        break;
 1165|       |
 1166|   376k|    case ls_colon:
  ------------------
  |  Branch (1166:5): [True: 376k, False: 13.8M]
  ------------------
 1167|   376k|        if (parser_state != ps_dict_after_key) {
  ------------------
  |  Branch (1167:13): [True: 326, False: 375k]
  ------------------
 1168|    326|            QTC::TC("libtests", "JSON parse unexpected :");
 1169|    326|            throw std::runtime_error(
 1170|    326|                "JSON: offset " + std::to_string(offset) + ": unexpected colon");
 1171|    326|        }
 1172|   375k|        parser_state = ps_dict_after_colon;
 1173|   375k|        return;
 1174|       |
 1175|  6.62M|    case ls_comma:
  ------------------
  |  Branch (1175:5): [True: 6.62M, False: 7.63M]
  ------------------
 1176|  6.62M|        if (!((parser_state == ps_dict_after_item) || (parser_state == ps_array_after_item))) {
  ------------------
  |  Branch (1176:15): [True: 252k, False: 6.37M]
  |  Branch (1176:55): [True: 6.37M, False: 97]
  ------------------
 1177|     97|            QTC::TC("libtests", "JSON parse unexpected ,");
 1178|     97|            throw std::runtime_error(
 1179|     97|                "JSON: offset " + std::to_string(offset) + ": unexpected comma");
 1180|     97|        }
 1181|  6.62M|        if (parser_state == ps_dict_after_item) {
  ------------------
  |  Branch (1181:13): [True: 252k, False: 6.37M]
  ------------------
 1182|   252k|            parser_state = ps_dict_after_comma;
 1183|  6.37M|        } else if (parser_state == ps_array_after_item) {
  ------------------
  |  Branch (1183:20): [True: 6.37M, False: 0]
  ------------------
 1184|  6.37M|            parser_state = ps_array_after_comma;
 1185|  6.37M|        } else {
 1186|      0|            throw std::logic_error("JSONParser::handleToken: unexpected parser state for comma");
 1187|      0|        }
 1188|  6.62M|        return;
 1189|       |
 1190|  6.62M|    case ls_end_array:
  ------------------
  |  Branch (1190:5): [True: 5.49k, False: 14.2M]
  ------------------
 1191|  5.49k|        if (!(parser_state == ps_array_begin || parser_state == ps_array_after_item)) {
  ------------------
  |  Branch (1191:15): [True: 810, False: 4.68k]
  |  Branch (1191:49): [True: 4.65k, False: 26]
  ------------------
 1192|     26|            QTC::TC("libtests", "JSON parse unexpected ]");
 1193|     26|            throw std::runtime_error(
 1194|     26|                "JSON: offset " + std::to_string(offset) + ": unexpected array end delimiter");
 1195|     26|        }
 1196|  5.46k|        parser_state = stack.back().state;
 1197|  5.46k|        tos.setEnd(offset);
 1198|  5.46k|        if (reactor) {
  ------------------
  |  Branch (1198:13): [True: 2.62k, False: 2.84k]
  ------------------
 1199|  2.62k|            reactor->containerEnd(tos);
 1200|  2.62k|        }
 1201|  5.46k|        if (parser_state != ps_done) {
  ------------------
  |  Branch (1201:13): [True: 5.45k, False: 17]
  ------------------
 1202|  5.45k|            stack.pop_back();
 1203|  5.45k|        }
 1204|  5.46k|        return;
 1205|       |
 1206|  56.7k|    case ls_end_dict:
  ------------------
  |  Branch (1206:5): [True: 56.7k, False: 14.2M]
  ------------------
 1207|  56.7k|        if (!((parser_state == ps_dict_begin) || (parser_state == ps_dict_after_item))) {
  ------------------
  |  Branch (1207:15): [True: 9.19k, False: 47.5k]
  |  Branch (1207:50): [True: 47.5k, False: 15]
  ------------------
 1208|     15|            QTC::TC("libtests", "JSON parse unexpected }");
 1209|     15|            throw std::runtime_error(
 1210|     15|                "JSON: offset " + std::to_string(offset) + ": unexpected dictionary end delimiter");
 1211|     15|        }
 1212|  56.7k|        parser_state = stack.back().state;
 1213|  56.7k|        tos.setEnd(offset);
 1214|  56.7k|        if (reactor) {
  ------------------
  |  Branch (1214:13): [True: 28.3k, False: 28.3k]
  ------------------
 1215|  28.3k|            reactor->containerEnd(tos);
 1216|  28.3k|        }
 1217|  56.7k|        if (parser_state != ps_done) {
  ------------------
  |  Branch (1217:13): [True: 56.6k, False: 83]
  ------------------
 1218|  56.6k|            stack.pop_back();
 1219|  56.6k|        }
 1220|  56.7k|        return;
 1221|       |
 1222|  5.80M|    case ls_number:
  ------------------
  |  Branch (1222:5): [True: 5.80M, False: 8.45M]
  ------------------
 1223|  5.80M|        item = JSON::makeNumber(token);
 1224|  5.80M|        break;
 1225|       |
 1226|  6.10k|    case ls_alpha:
  ------------------
  |  Branch (1226:5): [True: 6.10k, False: 14.2M]
  ------------------
 1227|  6.10k|        if (token == "true") {
  ------------------
  |  Branch (1227:13): [True: 562, False: 5.53k]
  ------------------
 1228|    562|            item = JSON::makeBool(true);
 1229|  5.53k|        } else if (token == "false") {
  ------------------
  |  Branch (1229:20): [True: 1.35k, False: 4.18k]
  ------------------
 1230|  1.35k|            item = JSON::makeBool(false);
 1231|  4.18k|        } else if (token == "null") {
  ------------------
  |  Branch (1231:20): [True: 3.82k, False: 361]
  ------------------
 1232|  3.82k|            item = JSON::makeNull();
 1233|  3.82k|        } else {
 1234|    361|            QTC::TC("libtests", "JSON parse invalid keyword");
 1235|    361|            throw std::runtime_error(
 1236|    361|                "JSON: offset " + std::to_string(offset) + ": invalid keyword " + token);
 1237|    361|        }
 1238|  5.74k|        break;
 1239|       |
 1240|  1.18M|    case ls_after_string:
  ------------------
  |  Branch (1240:5): [True: 1.18M, False: 13.0M]
  ------------------
 1241|  1.18M|        if (parser_state == ps_dict_begin || parser_state == ps_dict_after_comma) {
  ------------------
  |  Branch (1241:13): [True: 124k, False: 1.06M]
  |  Branch (1241:46): [True: 251k, False: 812k]
  ------------------
 1242|   376k|            dict_key = token;
 1243|   376k|            dict_key_offset = token_start;
 1244|   376k|            parser_state = ps_dict_after_key;
 1245|   376k|            return;
 1246|   812k|        } else {
 1247|   812k|            item = JSON::makeString(token);
 1248|   812k|        }
 1249|   812k|        break;
 1250|       |
 1251|   812k|    default:
  ------------------
  |  Branch (1251:5): [True: 153, False: 14.2M]
  ------------------
 1252|    153|        throw std::runtime_error(
 1253|    153|            "JSON: offset " + std::to_string(offset) + ": premature end of input");
 1254|      0|        break;
 1255|  14.2M|    }
 1256|       |
 1257|  6.82M|    item.setStart(token_start);
 1258|  6.82M|    item.setEnd(offset);
 1259|       |
 1260|  6.82M|    switch (parser_state) {
  ------------------
  |  Branch (1260:13): [True: 0, False: 6.82M]
  ------------------
 1261|     50|    case ps_dict_begin:
  ------------------
  |  Branch (1261:5): [True: 50, False: 6.81M]
  ------------------
 1262|    103|    case ps_dict_after_comma:
  ------------------
  |  Branch (1262:5): [True: 53, False: 6.81M]
  ------------------
 1263|    103|        QTC::TC("libtests", "JSON parse string as dict key");
 1264|    103|        throw std::runtime_error(
 1265|    103|            "JSON: offset " + std::to_string(offset) + ": expect string as dictionary key");
 1266|      0|        break;
 1267|       |
 1268|   375k|    case ps_dict_after_colon:
  ------------------
  |  Branch (1268:5): [True: 375k, False: 6.44M]
  ------------------
 1269|   375k|        if (tos.checkDictionaryKeySeen(dict_key)) {
  ------------------
  |  Branch (1269:13): [True: 49, False: 375k]
  ------------------
 1270|     49|            QTC::TC("libtests", "JSON parse duplicate key");
 1271|     49|            throw std::runtime_error(
 1272|     49|                "JSON: offset " + std::to_string(dict_key_offset) + ": duplicated dictionary key");
 1273|     49|        }
 1274|   375k|        if (!reactor || !reactor->dictionaryItem(dict_key, item)) {
  ------------------
  |  Branch (1274:13): [True: 188k, False: 187k]
  |  Branch (1274:25): [True: 307, False: 187k]
  ------------------
 1275|   188k|            tos.addDictionaryMember(dict_key, item);
 1276|   188k|        }
 1277|   375k|        parser_state = ps_dict_after_item;
 1278|   375k|        break;
 1279|       |
 1280|  58.4k|    case ps_array_begin:
  ------------------
  |  Branch (1280:5): [True: 58.4k, False: 6.76M]
  ------------------
 1281|  6.43M|    case ps_array_after_comma:
  ------------------
  |  Branch (1281:5): [True: 6.37M, False: 446k]
  ------------------
 1282|  6.43M|        if (!reactor || !reactor->arrayItem(item)) {
  ------------------
  |  Branch (1282:13): [True: 3.30M, False: 3.12M]
  |  Branch (1282:25): [True: 26, False: 3.12M]
  ------------------
 1283|  3.30M|            tos.addArrayElement(item);
 1284|  3.30M|        }
 1285|  6.43M|        parser_state = ps_array_after_item;
 1286|  6.43M|        break;
 1287|       |
 1288|  12.0k|    case ps_top:
  ------------------
  |  Branch (1288:5): [True: 12.0k, False: 6.80M]
  ------------------
 1289|  12.0k|        if (!(item.isDictionary() || item.isArray())) {
  ------------------
  |  Branch (1289:15): [True: 10.7k, False: 1.36k]
  |  Branch (1289:38): [True: 814, False: 548]
  ------------------
 1290|    548|            stack.emplace_back(ps_done, item);
 1291|    548|            parser_state = ps_done;
 1292|    548|            return;
 1293|    548|        }
 1294|  11.5k|        parser_state = ps_done;
 1295|  11.5k|        break;
 1296|       |
 1297|     41|    case ps_dict_after_key:
  ------------------
  |  Branch (1297:5): [True: 41, False: 6.81M]
  ------------------
 1298|     41|        QTC::TC("libtests", "JSON parse expected colon");
 1299|     41|        throw std::runtime_error("JSON: offset " + std::to_string(offset) + ": expected ':'");
 1300|      0|        break;
 1301|       |
 1302|    160|    case ps_dict_after_item:
  ------------------
  |  Branch (1302:5): [True: 160, False: 6.81M]
  ------------------
 1303|    160|        QTC::TC("libtests", "JSON parse expected , or }");
 1304|    160|        throw std::runtime_error(
 1305|    160|            "JSON: offset " + std::to_string(offset) + ": expected ',' or '}'");
 1306|      0|        break;
 1307|       |
 1308|    151|    case ps_array_after_item:
  ------------------
  |  Branch (1308:5): [True: 151, False: 6.81M]
  ------------------
 1309|    151|        QTC::TC("libtests", "JSON parse expected, or ]");
 1310|    151|        throw std::runtime_error(
 1311|    151|            "JSON: offset " + std::to_string(offset) + ": expected ',' or ']'");
 1312|      0|        break;
 1313|       |
 1314|      0|    case ps_done:
  ------------------
  |  Branch (1314:5): [True: 0, False: 6.82M]
  ------------------
 1315|      0|        throw std::logic_error("JSONParser::handleToken: unexpected parser state");
 1316|  6.82M|    }
 1317|       |
 1318|  6.81M|    if (item.isDictionary() || item.isArray()) {
  ------------------
  |  Branch (1318:9): [True: 134k, False: 6.68M]
  |  Branch (1318:32): [True: 60.4k, False: 6.62M]
  ------------------
 1319|   195k|        stack.emplace_back(parser_state, item);
 1320|       |        // Calling container start method is postponed until after adding the containers to their
 1321|       |        // parent containers, if any. This makes it much easier to keep track of the current nesting
 1322|       |        // level.
 1323|   195k|        if (item.isDictionary()) {
  ------------------
  |  Branch (1323:13): [True: 134k, False: 60.4k]
  ------------------
 1324|   134k|            if (reactor) {
  ------------------
  |  Branch (1324:17): [True: 67.3k, False: 67.4k]
  ------------------
 1325|  67.3k|                reactor->dictionaryStart();
 1326|  67.3k|            }
 1327|   134k|            parser_state = ps_dict_begin;
 1328|   134k|        } else if (item.isArray()) {
  ------------------
  |  Branch (1328:20): [True: 60.4k, False: 0]
  ------------------
 1329|  60.4k|            if (reactor) {
  ------------------
  |  Branch (1329:17): [True: 27.4k, False: 33.0k]
  ------------------
 1330|  27.4k|                reactor->arrayStart();
 1331|  27.4k|            }
 1332|  60.4k|            parser_state = ps_array_begin;
 1333|  60.4k|        }
 1334|       |
 1335|   195k|        if (stack.size() > 500) {
  ------------------
  |  Branch (1335:13): [True: 5, False: 195k]
  ------------------
 1336|      5|            throw std::runtime_error(
 1337|      5|                "JSON: offset " + std::to_string(offset) + ": maximum object depth exceeded");
 1338|      5|        }
 1339|   195k|    }
 1340|  6.81M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser10StackFrameC2ENS0_14parser_state_eER4JSON:
  649|   195k|            {
  650|   195k|            }

_ZN8PipelineC2EPKcPS_:
    9|      4|{
   10|      4|}
_ZN8Pipeline7getNextEb:
   14|      1|{
   15|      1|    if ((this->next == nullptr) && (!allow_null)) {
  ------------------
  |  Branch (15:9): [True: 0, False: 1]
  |  Branch (15:36): [True: 0, False: 0]
  ------------------
   16|      0|        throw std::logic_error(
   17|      0|            this->identifier + ": Pipeline::getNext() called on pipeline with no next");
   18|      0|    }
   19|      1|    return this->next;
   20|      1|}
_ZN8Pipeline9writeCStrEPKc:
   30|   118k|{
   31|   118k|    this->write(cstr, strlen(cstr));
   32|   118k|}
_ZN8PipelinelsEPKc:
   42|   118k|{
   43|   118k|    this->writeCStr(cstr);
   44|   118k|    return *this;
   45|   118k|}
_ZN8Pipeline5writeEPKcm:
  112|   118k|{
  113|   118k|    this->write(reinterpret_cast<unsigned char const*>(data), len);
  114|   118k|}

_ZN10Pl_DiscardC2Ev:
    7|      1|{
    8|      1|}
_ZN10Pl_DiscardD2Ev:
   11|      1|{
   12|       |    // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
   13|      1|}

_ZN10Pl_OStream7MembersC2ERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE:
    7|      2|{
    8|      2|}
_ZN10Pl_OStreamC2EPKcRNSt3__113basic_ostreamIcNS2_11char_traitsIcEEEE:
   13|      2|{
   14|      2|}
_ZN10Pl_OStreamD2Ev:
   17|      2|{
   18|       |    // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
   19|      2|}
_ZN10Pl_OStream5writeEPKhm:
   23|   118k|{
   24|   118k|    m->os.write(reinterpret_cast<char const*>(buf), static_cast<std::streamsize>(len));
   25|   118k|}
_ZN10Pl_OStream6finishEv:
   29|      2|{
   30|      2|    m->os.flush();
   31|      2|}

_ZN4QPDF20EncryptionParametersC2Ev:
  196|  6.52k|{
  197|  6.52k|}
_ZN4QPDF7MembersC2Ev:
  203|  6.52k|{
  204|  6.52k|}
_ZN4QPDFC2Ev:
  208|  6.52k|{
  209|  6.52k|    m->tokenizer.allowEOF();
  210|       |    // Generate a unique ID. It just has to be unique among all QPDF objects allocated throughout
  211|       |    // the lifetime of this running application.
  212|  6.52k|    static std::atomic<unsigned long long> unique_id{0};
  213|  6.52k|    m->unique_id = unique_id.fetch_add(1ULL);
  214|  6.52k|}
_ZN4QPDFD2Ev:
  217|  6.52k|{
  218|       |    // If two objects are mutually referential (through each object having an array or dictionary
  219|       |    // that contains an indirect reference to the other), the circular references in the
  220|       |    // std::shared_ptr objects will prevent the objects from being deleted. Walk through all objects
  221|       |    // in the object cache, which is those objects that we read from the file, and break all
  222|       |    // resolved indirect references by replacing them with an internal object type representing that
  223|       |    // they have been destroyed. Note that we can't break references like this at any time when the
  224|       |    // QPDF object is active. The call to reset also causes all direct QPDFObjectHandle objects that
  225|       |    // are reachable from this object to release their association with this QPDF. Direct objects
  226|       |    // are not destroyed since they can be moved to other QPDF objects safely.
  227|       |
  228|       |    // At this point, obviously no one is still using the QPDF object, but we'll explicitly clear
  229|       |    // the xref table anyway just to prevent any possibility of resolve() succeeding.
  230|  6.52k|    m->xref_table.clear();
  231|  18.1k|    for (auto const& iter: m->obj_cache) {
  ------------------
  |  Branch (231:26): [True: 18.1k, False: 6.52k]
  ------------------
  232|  18.1k|        iter.second.object->disconnect();
  233|  18.1k|        if (iter.second.object->getTypeCode() != ::ot_null) {
  ------------------
  |  Branch (233:13): [True: 10.7k, False: 7.36k]
  ------------------
  234|  10.7k|            iter.second.object->destroy();
  235|  10.7k|        }
  236|  18.1k|    }
  237|  6.52k|}
_ZN4QPDF17processMemoryFileEPKcS1_mS1_:
  262|  6.52k|{
  263|  6.52k|    processInputSource(
  264|  6.52k|        std::shared_ptr<InputSource>(
  265|       |            // line-break
  266|  6.52k|            new BufferInputSource(
  267|  6.52k|                description, new Buffer(QUtil::unsigned_char_pointer(buf), length), true)),
  268|  6.52k|        password);
  269|  6.52k|}
_ZN4QPDF18processInputSourceENSt3__110shared_ptrI11InputSourceEEPKc:
  273|  6.52k|{
  274|  6.52k|    m->file = source;
  275|  6.52k|    parse(password);
  276|  6.52k|}
_ZN4QPDF14setMaxWarningsEm:
  336|  6.52k|{
  337|  6.52k|    m->max_warnings = val;
  338|  6.52k|}
_ZN4QPDF18validatePDFVersionERPKcRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  374|  6.71k|{
  375|  6.71k|    bool valid = QUtil::is_digit(*p);
  376|  6.71k|    if (valid) {
  ------------------
  |  Branch (376:9): [True: 6.70k, False: 10]
  ------------------
  377|  13.5k|        while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (377:16): [True: 6.89k, False: 6.70k]
  ------------------
  378|  6.89k|            version.append(1, *p++);
  379|  6.89k|        }
  380|  6.70k|        if ((*p == '.') && QUtil::is_digit(*(p + 1))) {
  ------------------
  |  Branch (380:13): [True: 6.68k, False: 21]
  |  Branch (380:28): [True: 6.67k, False: 11]
  ------------------
  381|  6.67k|            version.append(1, *p++);
  382|  13.5k|            while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (382:20): [True: 6.89k, False: 6.67k]
  ------------------
  383|  6.89k|                version.append(1, *p++);
  384|  6.89k|            }
  385|  6.67k|        } else {
  386|     32|            valid = false;
  387|     32|        }
  388|  6.70k|    }
  389|  6.71k|    return valid;
  390|  6.71k|}
_ZN4QPDF10findHeaderEv:
  394|  6.52k|{
  395|  6.52k|    qpdf_offset_t global_offset = m->file->tell();
  396|  6.52k|    std::string line = m->file->readLine(1024);
  397|  6.52k|    char const* p = line.c_str();
  398|  6.52k|    if (strncmp(p, "%PDF-", 5) != 0) {
  ------------------
  |  Branch (398:9): [True: 0, False: 6.52k]
  ------------------
  399|      0|        throw std::logic_error("findHeader is not looking at %PDF-");
  400|      0|    }
  401|  6.52k|    p += 5;
  402|  6.52k|    std::string version;
  403|       |    // Note: The string returned by line.c_str() is always null-terminated. The code below never
  404|       |    // overruns the buffer because a null character always short-circuits further advancement.
  405|  6.52k|    bool valid = validatePDFVersion(p, version);
  406|  6.52k|    if (valid) {
  ------------------
  |  Branch (406:9): [True: 6.52k, False: 0]
  ------------------
  407|  6.52k|        m->pdf_version = version;
  408|  6.52k|        if (global_offset != 0) {
  ------------------
  |  Branch (408:13): [True: 0, False: 6.52k]
  ------------------
  409|       |            // Empirical evidence strongly suggests that when there is leading material prior to the
  410|       |            // PDF header, all explicit offsets in the file are such that 0 points to the beginning
  411|       |            // of the header.
  412|      0|            QTC::TC("qpdf", "QPDF global offset");
  413|      0|            m->file = std::shared_ptr<InputSource>(new OffsetInputSource(m->file, global_offset));
  414|      0|        }
  415|  6.52k|    }
  416|  6.52k|    return valid;
  417|  6.52k|}
_ZN4QPDF13findStartxrefEv:
  421|  6.52k|{
  422|  6.52k|    if (readToken(m->file).isWord("startxref") && readToken(m->file).isInteger()) {
  ------------------
  |  Branch (422:9): [True: 6.52k, False: 0]
  |  Branch (422:9): [True: 6.52k, False: 0]
  |  Branch (422:51): [True: 6.52k, False: 0]
  ------------------
  423|       |        // Position in front of offset token
  424|  6.52k|        m->file->seek(m->file->getLastOffset(), SEEK_SET);
  425|  6.52k|        return true;
  426|  6.52k|    }
  427|      0|    return false;
  428|  6.52k|}
_ZN4QPDF5parseEPKc:
  432|  6.52k|{
  433|  6.52k|    if (password) {
  ------------------
  |  Branch (433:9): [True: 0, False: 6.52k]
  ------------------
  434|      0|        m->encp->provided_password = password;
  435|      0|    }
  436|       |
  437|       |    // Find the header anywhere in the first 1024 bytes of the file.
  438|  6.52k|    PatternFinder hf(*this, &QPDF::findHeader);
  439|  6.52k|    if (!m->file->findFirst("%PDF-", 0, 1024, hf)) {
  ------------------
  |  Branch (439:9): [True: 0, False: 6.52k]
  ------------------
  440|      0|        QTC::TC("qpdf", "QPDF not a pdf file");
  441|      0|        warn(damagedPDF("", 0, "can't find PDF header"));
  442|       |        // QPDFWriter writes files that usually require at least version 1.2 for /FlateDecode
  443|      0|        m->pdf_version = "1.2";
  444|      0|    }
  445|       |
  446|       |    // PDF spec says %%EOF must be found within the last 1024 bytes of/ the file.  We add an extra
  447|       |    // 30 characters to leave room for the startxref stuff.
  448|  6.52k|    m->file->seek(0, SEEK_END);
  449|  6.52k|    qpdf_offset_t end_offset = m->file->tell();
  450|  6.52k|    m->xref_table_max_offset = end_offset;
  451|       |    // Sanity check on object ids. All objects must appear in xref table / stream. In all realistic
  452|       |    // scenarios at least 3 bytes are required.
  453|  6.52k|    if (m->xref_table_max_id > m->xref_table_max_offset / 3) {
  ------------------
  |  Branch (453:9): [True: 6.52k, False: 0]
  ------------------
  454|  6.52k|        m->xref_table_max_id = static_cast<int>(m->xref_table_max_offset / 3);
  455|  6.52k|    }
  456|  6.52k|    qpdf_offset_t start_offset = (end_offset > 1054 ? end_offset - 1054 : 0);
  ------------------
  |  Branch (456:35): [True: 0, False: 6.52k]
  ------------------
  457|  6.52k|    PatternFinder sf(*this, &QPDF::findStartxref);
  458|  6.52k|    qpdf_offset_t xref_offset = 0;
  459|  6.52k|    if (m->file->findLast("startxref", start_offset, 0, sf)) {
  ------------------
  |  Branch (459:9): [True: 6.52k, False: 0]
  ------------------
  460|  6.52k|        xref_offset = QUtil::string_to_ll(readToken(m->file).getValue().c_str());
  461|  6.52k|    }
  462|       |
  463|  6.52k|    try {
  464|  6.52k|        if (xref_offset == 0) {
  ------------------
  |  Branch (464:13): [True: 0, False: 6.52k]
  ------------------
  465|      0|            QTC::TC("qpdf", "QPDF can't find startxref");
  466|      0|            throw damagedPDF("", 0, "can't find startxref");
  467|      0|        }
  468|  6.52k|        try {
  469|  6.52k|            read_xref(xref_offset);
  470|  6.52k|        } catch (QPDFExc&) {
  471|      0|            throw;
  472|      0|        } catch (std::exception& e) {
  473|      0|            throw damagedPDF("", 0, std::string("error reading xref: ") + e.what());
  474|      0|        }
  475|  6.52k|    } catch (QPDFExc& e) {
  476|      0|        if (m->attempt_recovery) {
  ------------------
  |  Branch (476:13): [True: 0, False: 0]
  ------------------
  477|      0|            reconstruct_xref(e);
  478|      0|            QTC::TC("qpdf", "QPDF reconstructed xref table");
  479|      0|        } else {
  480|      0|            throw;
  481|      0|        }
  482|      0|    }
  483|       |
  484|  6.52k|    initializeEncryption();
  485|  6.52k|    m->parsed = true;
  486|  6.52k|    if (m->xref_table.size() > 0 && !getRoot().getKey("/Pages").isDictionary()) {
  ------------------
  |  Branch (486:9): [True: 0, False: 6.52k]
  |  Branch (486:9): [True: 0, False: 6.52k]
  |  Branch (486:37): [True: 0, False: 0]
  ------------------
  487|       |        // QPDFs created from JSON have an empty xref table and no root object yet.
  488|      0|        throw damagedPDF("", 0, "unable to find page tree");
  489|      0|    }
  490|  6.52k|}
_ZN4QPDF7inParseEb:
  494|  13.0k|{
  495|  13.0k|    if (m->in_parse == v) {
  ------------------
  |  Branch (495:9): [True: 0, False: 13.0k]
  ------------------
  496|       |        // This happens if QPDFParser::parse tries to resolve an indirect object while it is
  497|       |        // parsing.
  498|      0|        throw std::logic_error("QPDF: re-entrant parsing detected. This is a qpdf bug."
  499|      0|                               " Please report at https://github.com/qpdf/qpdf/issues.");
  500|      0|    }
  501|  13.0k|    m->in_parse = v;
  502|  13.0k|}
_ZN4QPDF4warnERK7QPDFExc:
  506|  39.6k|{
  507|  39.6k|    if (m->max_warnings > 0 && m->warnings.size() >= m->max_warnings) {
  ------------------
  |  Branch (507:9): [True: 39.6k, False: 0]
  |  Branch (507:32): [True: 9, False: 39.5k]
  ------------------
  508|      9|        stopOnError("Too many warnings - file is too badly damaged");
  509|      9|    }
  510|  39.6k|    m->warnings.push_back(e);
  511|  39.6k|    if (!m->suppress_warnings) {
  ------------------
  |  Branch (511:9): [True: 39.5k, False: 9]
  ------------------
  512|  39.5k|        *m->log->getWarn() << "WARNING: " << m->warnings.back().what() << "\n";
  513|  39.5k|    }
  514|  39.6k|}
_ZN4QPDF4warnE17qpdf_error_code_eRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEExS9_:
  522|  39.6k|{
  523|  39.6k|    warn(QPDFExc(error_code, getFilename(), object, offset, message));
  524|  39.6k|}
_ZN4QPDF10setTrailerE16QPDFObjectHandle:
  528|  6.52k|{
  529|  6.52k|    if (m->trailer.isInitialized()) {
  ------------------
  |  Branch (529:9): [True: 0, False: 6.52k]
  ------------------
  530|      0|        return;
  531|      0|    }
  532|  6.52k|    m->trailer = obj;
  533|  6.52k|}
_ZN4QPDF9read_xrefEx:
  674|  6.52k|{
  675|  6.52k|    std::map<int, int> free_table;
  676|  6.52k|    std::set<qpdf_offset_t> visited;
  677|  13.0k|    while (xref_offset) {
  ------------------
  |  Branch (677:12): [True: 6.52k, False: 6.52k]
  ------------------
  678|  6.52k|        visited.insert(xref_offset);
  679|  6.52k|        char buf[7];
  680|  6.52k|        memset(buf, 0, sizeof(buf));
  681|  6.52k|        m->file->seek(xref_offset, SEEK_SET);
  682|       |        // Some files miss the mark a little with startxref. We could do a better job of searching
  683|       |        // in the neighborhood for something that looks like either an xref table or stream, but the
  684|       |        // simple heuristic of skipping whitespace can help with the xref table case and is harmless
  685|       |        // with the stream case.
  686|  6.52k|        bool done = false;
  687|  6.52k|        bool skipped_space = false;
  688|  13.0k|        while (!done) {
  ------------------
  |  Branch (688:16): [True: 6.52k, False: 6.52k]
  ------------------
  689|  6.52k|            char ch;
  690|  6.52k|            if (1 == m->file->read(&ch, 1)) {
  ------------------
  |  Branch (690:17): [True: 6.52k, False: 0]
  ------------------
  691|  6.52k|                if (QUtil::is_space(ch)) {
  ------------------
  |  Branch (691:21): [True: 0, False: 6.52k]
  ------------------
  692|      0|                    skipped_space = true;
  693|  6.52k|                } else {
  694|  6.52k|                    m->file->unreadCh(ch);
  695|  6.52k|                    done = true;
  696|  6.52k|                }
  697|  6.52k|            } else {
  698|      0|                QTC::TC("qpdf", "QPDF eof skipping spaces before xref", skipped_space ? 0 : 1);
  ------------------
  |  Branch (698:73): [True: 0, False: 0]
  ------------------
  699|      0|                done = true;
  700|      0|            }
  701|  6.52k|        }
  702|       |
  703|  6.52k|        m->file->read(buf, sizeof(buf) - 1);
  704|       |        // The PDF spec says xref must be followed by a line terminator, but files exist in the wild
  705|       |        // where it is terminated by arbitrary whitespace.
  706|  6.52k|        if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) {
  ------------------
  |  Branch (706:13): [True: 6.52k, False: 0]
  |  Branch (706:47): [True: 6.52k, False: 0]
  ------------------
  707|  6.52k|            if (skipped_space) {
  ------------------
  |  Branch (707:17): [True: 0, False: 6.52k]
  ------------------
  708|      0|                QTC::TC("qpdf", "QPDF xref skipped space");
  709|      0|                warn(damagedPDF("", 0, "extraneous whitespace seen before xref"));
  710|      0|            }
  711|  6.52k|            QTC::TC(
  712|  6.52k|                "qpdf",
  713|  6.52k|                "QPDF xref space",
  714|  6.52k|                ((buf[4] == '\n')       ? 0
  ------------------
  |  Branch (714:18): [True: 6.52k, False: 0]
  ------------------
  715|  6.52k|                     : (buf[4] == '\r') ? 1
  ------------------
  |  Branch (715:24): [True: 0, False: 0]
  ------------------
  716|      0|                     : (buf[4] == ' ')  ? 2
  ------------------
  |  Branch (716:24): [True: 0, False: 0]
  ------------------
  717|      0|                                        : 9999));
  718|  6.52k|            int skip = 4;
  719|       |            // buf is null-terminated, and QUtil::is_space('\0') is false, so this won't overrun.
  720|  13.0k|            while (QUtil::is_space(buf[skip])) {
  ------------------
  |  Branch (720:20): [True: 6.52k, False: 6.52k]
  ------------------
  721|  6.52k|                ++skip;
  722|  6.52k|            }
  723|  6.52k|            xref_offset = read_xrefTable(xref_offset + skip);
  724|  6.52k|        } else {
  725|      0|            xref_offset = read_xrefStream(xref_offset);
  726|      0|        }
  727|  6.52k|        if (visited.count(xref_offset) != 0) {
  ------------------
  |  Branch (727:13): [True: 0, False: 6.52k]
  ------------------
  728|      0|            QTC::TC("qpdf", "QPDF xref loop");
  729|      0|            throw damagedPDF("", 0, "loop detected following xref tables");
  730|      0|        }
  731|  6.52k|    }
  732|       |
  733|  6.52k|    if (!m->trailer.isInitialized()) {
  ------------------
  |  Branch (733:9): [True: 0, False: 6.52k]
  ------------------
  734|      0|        throw damagedPDF("", 0, "unable to find trailer while reading xref");
  735|      0|    }
  736|  6.52k|    int size = m->trailer.getKey("/Size").getIntValueAsInt();
  737|  6.52k|    int max_obj = 0;
  738|  6.52k|    if (!m->xref_table.empty()) {
  ------------------
  |  Branch (738:9): [True: 0, False: 6.52k]
  ------------------
  739|      0|        max_obj = m->xref_table.rbegin()->first.getObj();
  740|      0|    }
  741|  6.52k|    if (!m->deleted_objects.empty()) {
  ------------------
  |  Branch (741:9): [True: 6.52k, False: 0]
  ------------------
  742|  6.52k|        max_obj = std::max(max_obj, *(m->deleted_objects.rbegin()));
  743|  6.52k|    }
  744|  6.52k|    if ((size < 1) || (size - 1 != max_obj)) {
  ------------------
  |  Branch (744:9): [True: 0, False: 6.52k]
  |  Branch (744:23): [True: 0, False: 6.52k]
  ------------------
  745|      0|        QTC::TC("qpdf", "QPDF xref size mismatch");
  746|      0|        warn(damagedPDF(
  747|      0|            "",
  748|      0|            0,
  749|      0|            ("reported number of objects (" + std::to_string(size) +
  750|      0|             ") is not one plus the highest object number (" + std::to_string(max_obj) + ")")));
  751|      0|    }
  752|       |
  753|       |    // We no longer need the deleted_objects table, so go ahead and clear it out to make sure we
  754|       |    // never depend on its being set.
  755|  6.52k|    m->deleted_objects.clear();
  756|       |
  757|       |    // Make sure we keep only the highest generation for any object.
  758|  6.52k|    QPDFObjGen last_og{-1, 0};
  759|  6.52k|    for (auto const& item: m->xref_table) {
  ------------------
  |  Branch (759:26): [True: 0, False: 6.52k]
  ------------------
  760|      0|        auto id = item.first.getObj();
  761|      0|        if (id == last_og.getObj() && id > 0) {
  ------------------
  |  Branch (761:13): [True: 0, False: 0]
  |  Branch (761:39): [True: 0, False: 0]
  ------------------
  762|      0|            removeObject(last_og);
  763|      0|        }
  764|      0|        last_og = item.first;
  765|      0|    }
  766|  6.52k|}
_ZN4QPDF15parse_xrefFirstERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERiS9_S9_:
  770|  6.52k|{
  771|       |    // is_space and is_digit both return false on '\0', so this will not overrun the null-terminated
  772|       |    // buffer.
  773|  6.52k|    char const* p = line.c_str();
  774|  6.52k|    char const* start = line.c_str();
  775|       |
  776|       |    // Skip zero or more spaces
  777|  6.52k|    while (QUtil::is_space(*p)) {
  ------------------
  |  Branch (777:12): [True: 0, False: 6.52k]
  ------------------
  778|      0|        ++p;
  779|      0|    }
  780|       |    // Require digit
  781|  6.52k|    if (!QUtil::is_digit(*p)) {
  ------------------
  |  Branch (781:9): [True: 0, False: 6.52k]
  ------------------
  782|      0|        return false;
  783|      0|    }
  784|       |    // Gather digits
  785|  6.52k|    std::string obj_str;
  786|  13.0k|    while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (786:12): [True: 6.52k, False: 6.52k]
  ------------------
  787|  6.52k|        obj_str.append(1, *p++);
  788|  6.52k|    }
  789|       |    // Require space
  790|  6.52k|    if (!QUtil::is_space(*p)) {
  ------------------
  |  Branch (790:9): [True: 0, False: 6.52k]
  ------------------
  791|      0|        return false;
  792|      0|    }
  793|       |    // Skip spaces
  794|  13.0k|    while (QUtil::is_space(*p)) {
  ------------------
  |  Branch (794:12): [True: 6.52k, False: 6.52k]
  ------------------
  795|  6.52k|        ++p;
  796|  6.52k|    }
  797|       |    // Require digit
  798|  6.52k|    if (!QUtil::is_digit(*p)) {
  ------------------
  |  Branch (798:9): [True: 0, False: 6.52k]
  ------------------
  799|      0|        return false;
  800|      0|    }
  801|       |    // Gather digits
  802|  6.52k|    std::string num_str;
  803|  13.0k|    while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (803:12): [True: 6.52k, False: 6.52k]
  ------------------
  804|  6.52k|        num_str.append(1, *p++);
  805|  6.52k|    }
  806|       |    // Skip any space including line terminators
  807|  13.0k|    while (QUtil::is_space(*p)) {
  ------------------
  |  Branch (807:12): [True: 6.52k, False: 6.52k]
  ------------------
  808|  6.52k|        ++p;
  809|  6.52k|    }
  810|  6.52k|    bytes = toI(p - start);
  811|  6.52k|    obj = QUtil::string_to_int(obj_str.c_str());
  812|  6.52k|    num = QUtil::string_to_int(num_str.c_str());
  813|  6.52k|    return true;
  814|  6.52k|}
_ZN4QPDF14read_xrefEntryERxRiRc:
  900|  6.52k|{
  901|  6.52k|    std::array<char, 21> line;
  902|  6.52k|    if (m->file->read(line.data(), 20) != 20) {
  ------------------
  |  Branch (902:9): [True: 0, False: 6.52k]
  ------------------
  903|       |        // C++20: [[unlikely]]
  904|      0|        return false;
  905|      0|    }
  906|  6.52k|    line[20] = '\0';
  907|  6.52k|    char const* p = line.data();
  908|       |
  909|  6.52k|    int f1_len = 0;
  910|  6.52k|    int f2_len = 0;
  911|       |
  912|       |    // is_space and is_digit both return false on '\0', so this will not overrun the null-terminated
  913|       |    // buffer.
  914|       |
  915|       |    // Gather f1 digits. NB No risk of overflow as 9'999'999'999 < max long long.
  916|  71.7k|    while (*p == '0') {
  ------------------
  |  Branch (916:12): [True: 65.2k, False: 6.52k]
  ------------------
  917|  65.2k|        ++f1_len;
  918|  65.2k|        ++p;
  919|  65.2k|    }
  920|  6.52k|    while (QUtil::is_digit(*p) && f1_len++ < 10) {
  ------------------
  |  Branch (920:12): [True: 0, False: 6.52k]
  |  Branch (920:35): [True: 0, False: 0]
  ------------------
  921|      0|        f1 *= 10;
  922|      0|        f1 += *p++ - '0';
  923|      0|    }
  924|       |    // Require space
  925|  6.52k|    if (!QUtil::is_space(*p++)) {
  ------------------
  |  Branch (925:9): [True: 0, False: 6.52k]
  ------------------
  926|       |        // Entry doesn't start with space or digit.
  927|       |        // C++20: [[unlikely]]
  928|      0|        return false;
  929|      0|    }
  930|       |    // Gather digits. NB No risk of overflow as 99'999 < max int.
  931|  6.52k|    while (*p == '0') {
  ------------------
  |  Branch (931:12): [True: 0, False: 6.52k]
  ------------------
  932|      0|        ++f2_len;
  933|      0|        ++p;
  934|      0|    }
  935|  39.1k|    while (QUtil::is_digit(*p) && f2_len++ < 5) {
  ------------------
  |  Branch (935:12): [True: 32.6k, False: 6.52k]
  |  Branch (935:35): [True: 32.6k, False: 0]
  ------------------
  936|  32.6k|        f2 *= 10;
  937|  32.6k|        f2 += static_cast<int>(*p++ - '0');
  938|  32.6k|    }
  939|  6.52k|    if (QUtil::is_space(*p++) && (*p == 'f' || *p == 'n')) {
  ------------------
  |  Branch (939:9): [True: 6.52k, False: 0]
  |  Branch (939:35): [True: 6.52k, False: 0]
  |  Branch (939:48): [True: 0, False: 0]
  ------------------
  940|       |        // C++20: [[likely]]
  941|  6.52k|        type = *p;
  942|       |        // No test for valid line[19].
  943|  6.52k|        if (*(++p) && *(++p) && (*p == '\n' || *p == '\r') && f1_len == 10 && f2_len == 5) {
  ------------------
  |  Branch (943:13): [True: 6.52k, False: 0]
  |  Branch (943:23): [True: 6.52k, False: 0]
  |  Branch (943:34): [True: 6.52k, False: 0]
  |  Branch (943:48): [True: 0, False: 0]
  |  Branch (943:63): [True: 6.52k, False: 0]
  |  Branch (943:79): [True: 6.52k, False: 0]
  ------------------
  944|       |            // C++20: [[likely]]
  945|  6.52k|            return true;
  946|  6.52k|        }
  947|  6.52k|    }
  948|      0|    return read_bad_xrefEntry(f1, f2, type);
  949|  6.52k|}
_ZN4QPDF14read_xrefTableEx:
  954|  6.52k|{
  955|  6.52k|    std::vector<QPDFObjGen> deleted_items;
  956|       |
  957|  6.52k|    m->file->seek(xref_offset, SEEK_SET);
  958|  6.52k|    std::string line;
  959|  6.52k|    while (true) {
  ------------------
  |  Branch (959:12): [Folded - Ignored]
  ------------------
  960|  6.52k|        line.assign(50, '\0');
  961|  6.52k|        m->file->read(line.data(), line.size());
  962|  6.52k|        int obj = 0;
  963|  6.52k|        int num = 0;
  964|  6.52k|        int bytes = 0;
  965|  6.52k|        if (!parse_xrefFirst(line, obj, num, bytes)) {
  ------------------
  |  Branch (965:13): [True: 0, False: 6.52k]
  ------------------
  966|      0|            QTC::TC("qpdf", "QPDF invalid xref");
  967|      0|            throw damagedPDF("xref table", "xref syntax invalid");
  968|      0|        }
  969|  6.52k|        m->file->seek(m->file->getLastOffset() + bytes, SEEK_SET);
  970|  13.0k|        for (qpdf_offset_t i = obj; i - num < obj; ++i) {
  ------------------
  |  Branch (970:37): [True: 6.52k, False: 6.52k]
  ------------------
  971|  6.52k|            if (i == 0) {
  ------------------
  |  Branch (971:17): [True: 6.52k, False: 0]
  ------------------
  972|       |                // This is needed by checkLinearization()
  973|  6.52k|                m->first_xref_item_offset = m->file->tell();
  974|  6.52k|            }
  975|       |            // For xref_table, these will always be small enough to be ints
  976|  6.52k|            qpdf_offset_t f1 = 0;
  977|  6.52k|            int f2 = 0;
  978|  6.52k|            char type = '\0';
  979|  6.52k|            if (!read_xrefEntry(f1, f2, type)) {
  ------------------
  |  Branch (979:17): [True: 0, False: 6.52k]
  ------------------
  980|      0|                QTC::TC("qpdf", "QPDF invalid xref entry");
  981|      0|                throw damagedPDF(
  982|      0|                    "xref table", "invalid xref entry (obj=" + std::to_string(i) + ")");
  983|      0|            }
  984|  6.52k|            if (type == 'f') {
  ------------------
  |  Branch (984:17): [True: 6.52k, False: 0]
  ------------------
  985|       |                // Save deleted items until after we've checked the XRefStm, if any.
  986|  6.52k|                deleted_items.emplace_back(toI(i), f2);
  987|  6.52k|            } else {
  988|      0|                insertXrefEntry(toI(i), 1, f1, f2);
  989|      0|            }
  990|  6.52k|        }
  991|  6.52k|        qpdf_offset_t pos = m->file->tell();
  992|  6.52k|        if (readToken(m->file).isWord("trailer")) {
  ------------------
  |  Branch (992:13): [True: 6.52k, False: 0]
  ------------------
  993|  6.52k|            break;
  994|  6.52k|        } else {
  995|      0|            m->file->seek(pos, SEEK_SET);
  996|      0|        }
  997|  6.52k|    }
  998|       |
  999|       |    // Set offset to previous xref table if any
 1000|  6.52k|    QPDFObjectHandle cur_trailer = readTrailer();
 1001|  6.52k|    if (!cur_trailer.isDictionary()) {
  ------------------
  |  Branch (1001:9): [True: 0, False: 6.52k]
  ------------------
 1002|      0|        QTC::TC("qpdf", "QPDF missing trailer");
 1003|      0|        throw damagedPDF("", "expected trailer dictionary");
 1004|      0|    }
 1005|       |
 1006|  6.52k|    if (!m->trailer.isInitialized()) {
  ------------------
  |  Branch (1006:9): [True: 6.52k, False: 0]
  ------------------
 1007|  6.52k|        setTrailer(cur_trailer);
 1008|       |
 1009|  6.52k|        if (!m->trailer.hasKey("/Size")) {
  ------------------
  |  Branch (1009:13): [True: 0, False: 6.52k]
  ------------------
 1010|      0|            QTC::TC("qpdf", "QPDF trailer lacks size");
 1011|      0|            throw damagedPDF("trailer", "trailer dictionary lacks /Size key");
 1012|      0|        }
 1013|  6.52k|        if (!m->trailer.getKey("/Size").isInteger()) {
  ------------------
  |  Branch (1013:13): [True: 0, False: 6.52k]
  ------------------
 1014|      0|            QTC::TC("qpdf", "QPDF trailer size not integer");
 1015|      0|            throw damagedPDF("trailer", "/Size key in trailer dictionary is not an integer");
 1016|      0|        }
 1017|  6.52k|    }
 1018|       |
 1019|  6.52k|    if (cur_trailer.hasKey("/XRefStm")) {
  ------------------
  |  Branch (1019:9): [True: 0, False: 6.52k]
  ------------------
 1020|      0|        if (m->ignore_xref_streams) {
  ------------------
  |  Branch (1020:13): [True: 0, False: 0]
  ------------------
 1021|      0|            QTC::TC("qpdf", "QPDF ignoring XRefStm in trailer");
 1022|      0|        } else {
 1023|      0|            if (cur_trailer.getKey("/XRefStm").isInteger()) {
  ------------------
  |  Branch (1023:17): [True: 0, False: 0]
  ------------------
 1024|       |                // Read the xref stream but disregard any return value -- we'll use our trailer's
 1025|       |                // /Prev key instead of the xref stream's.
 1026|      0|                (void)read_xrefStream(cur_trailer.getKey("/XRefStm").getIntValue());
 1027|      0|            } else {
 1028|      0|                throw damagedPDF("xref stream", xref_offset, "invalid /XRefStm");
 1029|      0|            }
 1030|      0|        }
 1031|      0|    }
 1032|       |
 1033|       |    // Handle any deleted items now that we've read the /XRefStm.
 1034|  6.52k|    for (auto const& og: deleted_items) {
  ------------------
  |  Branch (1034:24): [True: 6.52k, False: 6.52k]
  ------------------
 1035|  6.52k|        insertFreeXrefEntry(og);
 1036|  6.52k|    }
 1037|       |
 1038|  6.52k|    if (cur_trailer.hasKey("/Prev")) {
  ------------------
  |  Branch (1038:9): [True: 0, False: 6.52k]
  ------------------
 1039|      0|        if (!cur_trailer.getKey("/Prev").isInteger()) {
  ------------------
  |  Branch (1039:13): [True: 0, False: 0]
  ------------------
 1040|      0|            QTC::TC("qpdf", "QPDF trailer prev not integer");
 1041|      0|            throw damagedPDF("trailer", "/Prev key in trailer dictionary is not an integer");
 1042|      0|        }
 1043|      0|        QTC::TC("qpdf", "QPDF prev key in trailer dictionary");
 1044|      0|        xref_offset = cur_trailer.getKey("/Prev").getIntValue();
 1045|  6.52k|    } else {
 1046|  6.52k|        xref_offset = 0;
 1047|  6.52k|    }
 1048|       |
 1049|  6.52k|    return xref_offset;
 1050|  6.52k|}
_ZN4QPDF19insertFreeXrefEntryE10QPDFObjGen:
 1337|  6.52k|{
 1338|  6.52k|    if (!m->xref_table.count(og)) {
  ------------------
  |  Branch (1338:9): [True: 6.52k, False: 0]
  ------------------
 1339|  6.52k|        m->deleted_objects.insert(og.getObj());
 1340|  6.52k|    }
 1341|  6.52k|}
_ZN4QPDF11readTrailerEv:
 1464|  6.52k|{
 1465|  6.52k|    qpdf_offset_t offset = m->file->tell();
 1466|  6.52k|    bool empty = false;
 1467|  6.52k|    auto object =
 1468|  6.52k|        QPDFParser(m->file, "trailer", m->tokenizer, nullptr, this, true).parse(empty, false);
 1469|  6.52k|    if (empty) {
  ------------------
  |  Branch (1469:9): [True: 0, False: 6.52k]
  ------------------
 1470|       |        // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in
 1471|       |        // actual PDF files and Adobe Reader appears to ignore them.
 1472|      0|        warn(damagedPDF("trailer", "empty object treated as null"));
 1473|  6.52k|    } else if (object.isDictionary() && readToken(m->file).isWord("stream")) {
  ------------------
  |  Branch (1473:16): [True: 6.52k, False: 0]
  |  Branch (1473:16): [True: 0, False: 6.52k]
  |  Branch (1473:41): [True: 0, False: 6.52k]
  ------------------
 1474|      0|        warn(damagedPDF("trailer", m->file->tell(), "stream keyword found in trailer"));
 1475|      0|    }
 1476|       |    // Override last_offset so that it points to the beginning of the object we just read
 1477|  6.52k|    m->file->setLastOffset(offset);
 1478|  6.52k|    return object;
 1479|  6.52k|}
_ZN4QPDF9readTokenENSt3__110shared_ptrI11InputSourceEEm:
 1689|  32.6k|{
 1690|  32.6k|    return m->tokenizer.readToken(input, m->last_object_description, true, max_len);
 1691|  32.6k|}
_ZN4QPDF11updateCacheERK10QPDFObjGenRKNSt3__110shared_ptrI10QPDFObjectEExx:
 2018|  11.0k|{
 2019|  11.0k|    object->setObjGen(this, og);
 2020|  11.0k|    if (isCached(og)) {
  ------------------
  |  Branch (2020:9): [True: 11.0k, False: 0]
  ------------------
 2021|  11.0k|        auto& cache = m->obj_cache[og];
 2022|  11.0k|        cache.object->assign(object);
 2023|  11.0k|        cache.end_before_space = end_before_space;
 2024|  11.0k|        cache.end_after_space = end_after_space;
 2025|  11.0k|    } else {
 2026|      0|        m->obj_cache[og] = ObjCache(object, end_before_space, end_after_space);
 2027|      0|    }
 2028|  11.0k|}
_ZN4QPDF8isCachedERK10QPDFObjGen:
 2032|  11.0k|{
 2033|  11.0k|    return m->obj_cache.count(og) != 0;
 2034|  11.0k|}
_ZN4QPDF13reserveStreamERK10QPDFObjGen:
 2106|  4.07k|{
 2107|  4.07k|    return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)};
 2108|  4.07k|}
_ZN4QPDF16getObjectForJSONEii:
 2129|   346k|{
 2130|   346k|    auto og = QPDFObjGen(id, gen);
 2131|   346k|    auto [it, inserted] = m->obj_cache.try_emplace(og);
 2132|   346k|    auto& obj = it->second.object;
 2133|   346k|    if (inserted) {
  ------------------
  |  Branch (2133:9): [True: 18.1k, False: 328k]
  ------------------
 2134|  18.1k|        obj = (m->parsed && !m->xref_table.count(og)) ? QPDF_Null::create(this, og)
  ------------------
  |  Branch (2134:16): [True: 18.1k, False: 0]
  |  Branch (2134:29): [True: 18.1k, False: 0]
  ------------------
 2135|  18.1k|                                                      : QPDF_Unresolved::create(this, og);
 2136|  18.1k|    }
 2137|   346k|    return obj;
 2138|   346k|}
_ZN4QPDF9getObjectERK10QPDFObjGen:
 2142|  11.0k|{
 2143|  11.0k|    if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
  ------------------
  |  Branch (2143:42): [True: 11.0k, False: 0]
  ------------------
 2144|  11.0k|        return {it->second.object};
 2145|  11.0k|    } else if (m->parsed && !m->xref_table.count(og)) {
  ------------------
  |  Branch (2145:16): [True: 0, False: 0]
  |  Branch (2145:29): [True: 0, False: 0]
  ------------------
 2146|      0|        return QPDF_Null::create();
 2147|      0|    } else {
 2148|      0|        auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1);
 2149|      0|        return {result.first->second.object};
 2150|      0|    }
 2151|  11.0k|}
_ZN4QPDF13replaceObjectERK10QPDFObjGen16QPDFObjectHandle:
 2179|  11.0k|{
 2180|  11.0k|    if (oh.isIndirect() || !oh.isInitialized()) {
  ------------------
  |  Branch (2180:9): [True: 0, False: 11.0k]
  |  Branch (2180:28): [True: 0, False: 11.0k]
  ------------------
 2181|      0|        QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
 2182|      0|        throw std::logic_error("QPDF::replaceObject called with indirect object handle");
 2183|      0|    }
 2184|  11.0k|    updateCache(og, oh.getObj(), -1, -1);
 2185|  11.0k|}
_ZNK4QPDF11getFilenameEv:
 2493|  83.2k|{
 2494|  83.2k|    return m->file->getName();
 2495|  83.2k|}
_ZN4QPDF11stopOnErrorERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2821|      9|{
 2822|      9|    throw damagedPDF("", message);
 2823|      9|}
_ZN4QPDF10damagedPDFERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEExS8_:
 2848|      9|{
 2849|      9|    return {qpdf_e_damaged_pdf, m->file->getName(), object, offset, message};
 2850|      9|}
_ZN4QPDF10damagedPDFERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_:
 2856|      9|{
 2857|      9|    return damagedPDF(object, m->file->getLastOffset(), message);
 2858|      9|}

_ZN7QPDFExcC2E17qpdf_error_code_eRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_xS9_:
   15|  39.8k|{
   16|  39.8k|}
_ZN7QPDFExc10createWhatERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_xS8_:
   24|  39.8k|{
   25|  39.8k|    std::string result;
   26|  39.8k|    if (!filename.empty()) {
  ------------------
  |  Branch (26:9): [True: 39.8k, False: 0]
  ------------------
   27|  39.8k|        result += filename;
   28|  39.8k|    }
   29|  39.8k|    if (!(object.empty() && offset == 0)) {
  ------------------
  |  Branch (29:11): [True: 12.8k, False: 27.0k]
  |  Branch (29:29): [True: 287, False: 12.5k]
  ------------------
   30|  39.5k|        if (!filename.empty()) {
  ------------------
  |  Branch (30:13): [True: 39.5k, False: 0]
  ------------------
   31|  39.5k|            result += " (";
   32|  39.5k|        }
   33|  39.5k|        if (!object.empty()) {
  ------------------
  |  Branch (33:13): [True: 27.0k, False: 12.5k]
  ------------------
   34|  27.0k|            result += object;
   35|  27.0k|            if (offset > 0) {
  ------------------
  |  Branch (35:17): [True: 26.9k, False: 127]
  ------------------
   36|  26.9k|                result += ", ";
   37|  26.9k|            }
   38|  27.0k|        }
   39|  39.5k|        if (offset > 0) {
  ------------------
  |  Branch (39:13): [True: 39.4k, False: 127]
  ------------------
   40|  39.4k|            result += "offset " + std::to_string(offset);
   41|  39.4k|        }
   42|  39.5k|        if (!filename.empty()) {
  ------------------
  |  Branch (42:13): [True: 39.5k, False: 0]
  ------------------
   43|  39.5k|            result += ")";
   44|  39.5k|        }
   45|  39.5k|    }
   46|  39.8k|    if (!result.empty()) {
  ------------------
  |  Branch (46:9): [True: 39.8k, False: 0]
  ------------------
   47|  39.8k|        result += ": ";
   48|  39.8k|    }
   49|  39.8k|    result += message;
   50|  39.8k|    return result;
   51|  39.8k|}

_ZN10QPDFLogger7MembersC2Ev:
   52|      1|{
   53|      1|}
_ZN10QPDFLogger7MembersD2Ev:
   56|      1|{
   57|      1|    p_stdout->finish();
   58|      1|    p_stderr->finish();
   59|      1|}
_ZN10QPDFLoggerC2Ev:
   63|      1|{
   64|      1|}
_ZN10QPDFLogger6createEv:
   68|      1|{
   69|      1|    return std::shared_ptr<QPDFLogger>(new QPDFLogger);
   70|      1|}
_ZN10QPDFLogger13defaultLoggerEv:
   74|  6.52k|{
   75|  6.52k|    static auto l = create();
   76|  6.52k|    return l;
   77|  6.52k|}
_ZN10QPDFLogger7getWarnEb:
  111|  39.5k|{
  112|  39.5k|    if (m->p_warn) {
  ------------------
  |  Branch (112:9): [True: 0, False: 39.5k]
  ------------------
  113|      0|        return m->p_warn;
  114|      0|    }
  115|  39.5k|    return getError(null_okay);
  116|  39.5k|}
_ZN10QPDFLogger8getErrorEb:
  132|  39.5k|{
  133|  39.5k|    return throwIfNull(m->p_error, null_okay);
  134|  39.5k|}
_ZN10QPDFLogger11throwIfNullENSt3__110shared_ptrI8PipelineEEb:
  250|  39.5k|{
  251|  39.5k|    if (!(null_okay || p)) {
  ------------------
  |  Branch (251:11): [True: 0, False: 39.5k]
  |  Branch (251:24): [True: 39.5k, False: 0]
  ------------------
  252|      0|        throw std::logic_error("QPDFLogger: requested a null pipeline without null_okay == true");
  253|      0|    }
  254|  39.5k|    return p;
  255|  39.5k|}
QPDFLogger.cc:_ZN12_GLOBAL__N_18Pl_TrackC2EPKcP8Pipeline:
   16|      1|        {
   17|      1|        }
QPDFLogger.cc:_ZN12_GLOBAL__N_18Pl_Track6finishEv:
   28|      1|        {
   29|      1|            getNext()->finish();
   30|      1|        }

_ZNK10QPDFObjGen7unparseEc:
   20|  4.07k|{
   21|  4.07k|    return std::to_string(obj) + separator + std::to_string(gen);
   22|  4.07k|}

_ZN10QPDFObject7destroyEv:
    8|  10.7k|{
    9|  10.7k|    value = QPDF_Destroyed::getInstance();
   10|  10.7k|}

_ZN16QPDFObjectHandle18StreamDataProviderC2Eb:
   51|  3.78k|{
   52|  3.78k|}
_ZN16QPDFObjectHandle18StreamDataProviderD2Ev:
   55|  3.78k|{
   56|       |    // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
   57|  3.78k|}
_ZN16QPDFObjectHandle10disconnectEv:
  239|  84.8k|{
  240|       |    // Recursively remove association with any QPDF object. This method may only be called during
  241|       |    // final destruction. QPDF::~QPDF() calls it for indirect objects using the object pointer
  242|       |    // itself, so we don't do that here. Other objects call it through this method.
  243|  84.8k|    if (obj && !isIndirect()) {
  ------------------
  |  Branch (243:9): [True: 84.8k, False: 0]
  |  Branch (243:16): [True: 65.2k, False: 19.6k]
  ------------------
  244|  65.2k|        this->obj->disconnect();
  245|  65.2k|    }
  246|  84.8k|}
_ZNK16QPDFObjectHandle7asArrayEv:
  288|  2.57M|{
  289|  2.57M|    return obj ? obj->as<QPDF_Array>() : nullptr;
  ------------------
  |  Branch (289:12): [True: 2.57M, False: 0]
  ------------------
  290|  2.57M|}
_ZNK16QPDFObjectHandle12asDictionaryEv:
  300|   178k|{
  301|   178k|    return obj ? obj->as<QPDF_Dictionary>() : nullptr;
  ------------------
  |  Branch (301:12): [True: 178k, False: 0]
  ------------------
  302|   178k|}
_ZNK16QPDFObjectHandle9asIntegerEv:
  312|  6.52k|{
  313|  6.52k|    return obj ? obj->as<QPDF_Integer>() : nullptr;
  ------------------
  |  Branch (313:12): [True: 6.52k, False: 0]
  ------------------
  314|  6.52k|}
_ZNK16QPDFObjectHandle8asStreamEv:
  348|  7.34k|{
  349|  7.34k|    return obj ? obj->as<QPDF_Stream>() : nullptr;
  ------------------
  |  Branch (349:12): [True: 7.34k, False: 0]
  ------------------
  350|  7.34k|}
_ZNK16QPDFObjectHandle18asStreamWithAssertEv:
  354|  7.34k|{
  355|  7.34k|    auto stream = asStream();
  356|  7.34k|    assertType("stream", stream);
  357|  7.34k|    return stream;
  358|  7.34k|}
_ZNK16QPDFObjectHandle6isNullEv:
  403|   142k|{
  404|   142k|    return obj && obj->getResolvedTypeCode() == ::ot_null;
  ------------------
  |  Branch (404:12): [True: 142k, False: 0]
  |  Branch (404:19): [True: 52.0k, False: 90.2k]
  ------------------
  405|   142k|}
_ZNK16QPDFObjectHandle9isIntegerEv:
  414|  6.52k|{
  415|  6.52k|    return obj && obj->getResolvedTypeCode() == ::ot_integer;
  ------------------
  |  Branch (415:12): [True: 6.52k, False: 0]
  |  Branch (415:19): [True: 6.52k, False: 0]
  ------------------
  416|  6.52k|}
_ZNK16QPDFObjectHandle6isNameEv:
  481|  15.3k|{
  482|  15.3k|    return obj && obj->getResolvedTypeCode() == ::ot_name;
  ------------------
  |  Branch (482:12): [True: 15.3k, False: 0]
  |  Branch (482:19): [True: 15.3k, False: 0]
  ------------------
  483|  15.3k|}
_ZNK16QPDFObjectHandle12isDictionaryEv:
  536|   152k|{
  537|   152k|    return obj && obj->getResolvedTypeCode() == ::ot_dictionary;
  ------------------
  |  Branch (537:12): [True: 152k, False: 0]
  |  Branch (537:19): [True: 152k, False: 0]
  ------------------
  538|   152k|}
_ZNK16QPDFObjectHandle8isStreamEv:
  547|   147k|{
  548|   147k|    return obj && obj->getResolvedTypeCode() == ::ot_stream;
  ------------------
  |  Branch (548:12): [True: 147k, False: 0]
  |  Branch (548:19): [True: 7.95k, False: 139k]
  ------------------
  549|   147k|}
_ZNK16QPDFObjectHandle11getIntValueEv:
  652|  6.52k|{
  653|  6.52k|    auto integer = asInteger();
  654|  6.52k|    if (integer) {
  ------------------
  |  Branch (654:9): [True: 6.52k, False: 0]
  ------------------
  655|  6.52k|        return integer->getVal();
  656|  6.52k|    } else {
  657|      0|        typeWarning("integer", "returning 0");
  658|      0|        QTC::TC("qpdf", "QPDFObjectHandle integer returning 0");
  659|      0|        return 0;
  660|      0|    }
  661|  6.52k|}
_ZNK16QPDFObjectHandle16getIntValueAsIntEv:
  686|  6.52k|{
  687|  6.52k|    int result = 0;
  688|  6.52k|    long long v = getIntValue();
  689|  6.52k|    if (v < INT_MIN) {
  ------------------
  |  Branch (689:9): [True: 0, False: 6.52k]
  ------------------
  690|      0|        QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MIN");
  691|      0|        warnIfPossible("requested value of integer is too small; returning INT_MIN");
  692|      0|        result = INT_MIN;
  693|  6.52k|    } else if (v > INT_MAX) {
  ------------------
  |  Branch (693:16): [True: 0, False: 6.52k]
  ------------------
  694|      0|        QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MAX");
  695|      0|        warnIfPossible("requested value of integer is too big; returning INT_MAX");
  696|      0|        result = INT_MAX;
  697|  6.52k|    } else {
  698|  6.52k|        result = static_cast<int>(v);
  699|  6.52k|    }
  700|  6.52k|    return result;
  701|  6.52k|}
_ZNK16QPDFObjectHandle7getNameEv:
  831|  15.3k|{
  832|  15.3k|    if (isName()) {
  ------------------
  |  Branch (832:9): [True: 15.3k, False: 0]
  ------------------
  833|  15.3k|        return obj->getStringValue();
  834|  15.3k|    } else {
  835|      0|        typeWarning("name", "returning dummy name");
  836|      0|        QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name");
  837|      0|        return "/QPDFFakeName";
  838|      0|    }
  839|  15.3k|}
_ZN16QPDFObjectHandle10appendItemERKS_:
 1193|  2.57M|{
 1194|  2.57M|    if (auto array = asArray()) {
  ------------------
  |  Branch (1194:14): [True: 2.57M, False: 0]
  ------------------
 1195|  2.57M|        array->push_back(item);
 1196|  2.57M|    } else {
 1197|      0|        typeWarning("array", "ignoring attempt to append item");
 1198|      0|        QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item");
 1199|      0|    }
 1200|  2.57M|}
_ZNK16QPDFObjectHandle6hasKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1247|  26.1k|{
 1248|  26.1k|    auto dict = asDictionary();
 1249|  26.1k|    if (dict) {
  ------------------
  |  Branch (1249:9): [True: 26.1k, False: 0]
  ------------------
 1250|  26.1k|        return dict->hasKey(key);
 1251|  26.1k|    } else {
 1252|      0|        typeWarning("dictionary", "returning false for a key containment request");
 1253|      0|        QTC::TC("qpdf", "QPDFObjectHandle dictionary false for hasKey");
 1254|      0|        return false;
 1255|      0|    }
 1256|  26.1k|}
_ZNK16QPDFObjectHandle6getKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1265|  13.0k|{
 1266|  13.0k|    if (auto dict = asDictionary()) {
  ------------------
  |  Branch (1266:14): [True: 13.0k, False: 0]
  ------------------
 1267|  13.0k|        return dict->getKey(key);
 1268|  13.0k|    } else {
 1269|      0|        typeWarning("dictionary", "returning null for attempted key retrieval");
 1270|      0|        QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey");
 1271|      0|        static auto constexpr msg = " -> null returned from getting key $VD from non-Dictionary"sv;
 1272|      0|        return QPDF_Null::create(obj, msg, "");
 1273|      0|    }
 1274|  13.0k|}
_ZN16QPDFObjectHandle10replaceKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKS_:
 1517|   135k|{
 1518|   135k|    auto dict = asDictionary();
 1519|   135k|    if (dict) {
  ------------------
  |  Branch (1519:9): [True: 135k, False: 0]
  ------------------
 1520|   135k|        checkOwnership(value);
 1521|   135k|        dict->replaceKey(key, value);
 1522|   135k|    } else {
 1523|      0|        typeWarning("dictionary", "ignoring key replacement request");
 1524|      0|        QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey");
 1525|      0|    }
 1526|   135k|}
_ZN16QPDFObjectHandle9removeKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1545|  3.90k|{
 1546|  3.90k|    auto dict = asDictionary();
 1547|  3.90k|    if (dict) {
  ------------------
  |  Branch (1547:9): [True: 3.90k, False: 0]
  ------------------
 1548|  3.90k|        dict->removeKey(key);
 1549|  3.90k|    } else {
 1550|      0|        typeWarning("dictionary", "ignoring key removal request");
 1551|      0|        QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey");
 1552|      0|    }
 1553|  3.90k|}
_ZN16QPDFObjectHandle11replaceDictERKS_:
 1605|  3.44k|{
 1606|  3.44k|    asStreamWithAssert()->replaceDict(new_dict);
 1607|  3.44k|}
_ZN16QPDFObjectHandle17replaceStreamDataERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKS_SA_:
 1677|    122|{
 1678|    122|    auto b = std::make_shared<Buffer>(data.length());
 1679|    122|    unsigned char* bp = b->getBuffer();
 1680|    122|    if (bp) {
  ------------------
  |  Branch (1680:9): [True: 0, False: 122]
  ------------------
 1681|      0|        memcpy(bp, data.c_str(), data.length());
 1682|      0|    }
 1683|    122|    asStreamWithAssert()->replaceStreamData(b, filter, decode_parms);
 1684|    122|}
_ZN16QPDFObjectHandle17replaceStreamDataENSt3__18functionIFvP8PipelineEEERKS_S7_:
 1737|  3.78k|{
 1738|  3.78k|    auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
 1739|  3.78k|    asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
 1740|  3.78k|}
_ZN16QPDFObjectHandle5parseERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_:
 2027|  21.6k|{
 2028|  21.6k|    return parse(nullptr, object_str, object_description);
 2029|  21.6k|}
_ZN16QPDFObjectHandle5parseEP4QPDFRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_:
 2034|  21.6k|{
 2035|  21.6k|    auto input = std::shared_ptr<InputSource>(new BufferInputSource("parsed object", object_str));
 2036|  21.6k|    QPDFTokenizer tokenizer;
 2037|  21.6k|    bool empty = false;
 2038|  21.6k|    QPDFObjectHandle result = parse(input, object_description, tokenizer, empty, nullptr, context);
 2039|  21.6k|    size_t offset = QIntC::to_size(input->tell());
 2040|   879k|    while (offset < object_str.length()) {
  ------------------
  |  Branch (2040:12): [True: 858k, False: 21.6k]
  ------------------
 2041|   858k|        if (!isspace(object_str.at(offset))) {
  ------------------
  |  Branch (2041:13): [True: 58, False: 858k]
  ------------------
 2042|     58|            QTC::TC("qpdf", "QPDFObjectHandle trailing data in parse");
 2043|     58|            throw QPDFExc(
 2044|     58|                qpdf_e_damaged_pdf,
 2045|     58|                input->getName(),
 2046|     58|                object_description,
 2047|     58|                input->getLastOffset(),
 2048|     58|                "trailing data found parsing object from string");
 2049|     58|        }
 2050|   858k|        ++offset;
 2051|   858k|    }
 2052|  21.6k|    return result;
 2053|  21.6k|}
_ZN16QPDFObjectHandle5parseENSt3__110shared_ptrI11InputSourceEERKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEER13QPDFTokenizerRbPNS_15StringDecrypterEP4QPDF:
 2225|  21.6k|{
 2226|  21.6k|    return QPDFParser(input, object_description, tokenizer, decrypter, context, false)
 2227|  21.6k|        .parse(empty, false);
 2228|  21.6k|}
_ZNK16QPDFObjectHandle15getParsedOffsetEv:
 2237|    116|{
 2238|    116|    return obj ? obj->getParsedOffset() : -1;
  ------------------
  |  Branch (2238:12): [True: 116, False: 0]
  ------------------
 2239|    116|}
_ZN16QPDFObjectHandle7newBoolEb:
 2243|    391|{
 2244|    391|    return {QPDF_Bool::create(value)};
 2245|    391|}
_ZN16QPDFObjectHandle7newNullEv:
 2249|  26.7k|{
 2250|  26.7k|    return {QPDF_Null::create()};
 2251|  26.7k|}
_ZN16QPDFObjectHandle10newIntegerEx:
 2255|  2.26M|{
 2256|  2.26M|    return {QPDF_Integer::create(value)};
 2257|  2.26M|}
_ZN16QPDFObjectHandle7newRealERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2261|  5.21k|{
 2262|  5.21k|    return {QPDF_Real::create(value)};
 2263|  5.21k|}
_ZN16QPDFObjectHandle7newNameERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2273|  22.1k|{
 2274|  22.1k|    return {QPDF_Name::create(name)};
 2275|  22.1k|}
_ZN16QPDFObjectHandle9newStringERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2279|  1.85k|{
 2280|  1.85k|    return {QPDF_String::create(str)};
 2281|  1.85k|}
_ZN16QPDFObjectHandle16newUnicodeStringERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2285|  6.55k|{
 2286|  6.55k|    return {QPDF_String::create_utf16(utf8_str)};
 2287|  6.55k|}
_ZN16QPDFObjectHandle8newArrayEv:
 2303|  18.5k|{
 2304|  18.5k|    return newArray(std::vector<QPDFObjectHandle>());
 2305|  18.5k|}
_ZN16QPDFObjectHandle8newArrayERKNSt3__16vectorIS_NS0_9allocatorIS_EEEE:
 2309|  18.5k|{
 2310|  18.5k|    return {QPDF_Array::create(items)};
 2311|  18.5k|}
_ZN16QPDFObjectHandle13newDictionaryEv:
 2363|  37.8k|{
 2364|  37.8k|    return newDictionary(std::map<std::string, QPDFObjectHandle>());
 2365|  37.8k|}
_ZN16QPDFObjectHandle13newDictionaryERKNSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES_NS0_4lessIS7_EENS5_INS0_4pairIKS7_S_EEEEEE:
 2369|  37.8k|{
 2370|  37.8k|    return {QPDF_Dictionary::create(items)};
 2371|  37.8k|}
_ZN16QPDFObjectHandle20setObjectDescriptionEP4QPDFRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
 2414|  4.07k|{
 2415|  4.07k|    if (obj) {
  ------------------
  |  Branch (2415:9): [True: 4.07k, False: 0]
  ------------------
 2416|  4.07k|        auto descr = std::make_shared<QPDFValue::Description>(object_description);
 2417|  4.07k|        obj->setDescription(owning_qpdf, descr);
 2418|  4.07k|    }
 2419|  4.07k|}
_ZNK16QPDFObjectHandle20hasObjectDescriptionEv:
 2428|  2.73M|{
 2429|  2.73M|    return obj && obj->hasDescription();
  ------------------
  |  Branch (2429:12): [True: 2.73M, False: 0]
  |  Branch (2429:19): [True: 348k, False: 2.38M]
  ------------------
 2430|  2.73M|}
_ZNK16QPDFObjectHandle10assertTypeEPKcb:
 2581|  7.34k|{
 2582|  7.34k|    if (!istype) {
  ------------------
  |  Branch (2582:9): [True: 0, False: 7.34k]
  ------------------
 2583|      0|        throw std::runtime_error(
 2584|      0|            std::string("operation for ") + type_name + " attempted on object of type " +
 2585|      0|            QPDFObjectHandle(*this).getTypeName());
 2586|      0|    }
 2587|  7.34k|}
_ZNK16QPDFObjectHandle14checkOwnershipERKS_:
 2817|   135k|{
 2818|   135k|    auto qpdf = getOwningQPDF();
 2819|   135k|    auto item_qpdf = item.getOwningQPDF();
 2820|   135k|    if ((qpdf != nullptr) && (item_qpdf != nullptr) && (qpdf != item_qpdf)) {
  ------------------
  |  Branch (2820:9): [True: 135k, False: 0]
  |  Branch (2820:30): [True: 135k, False: 235]
  |  Branch (2820:56): [True: 0, False: 135k]
  ------------------
 2821|      0|        QTC::TC("qpdf", "QPDFObjectHandle check ownership");
 2822|      0|        throw std::logic_error("Attempting to add an object from a different QPDF. Use "
 2823|      0|                               "QPDF::copyForeignObject to add objects from another file.");
 2824|      0|    }
 2825|   135k|}
_ZNK16QPDFObjectHandle9getObjGenEv:
 3020|   174k|{
 3021|   174k|    return isInitialized() ? obj->getObjGen() : QPDFObjGen();
  ------------------
  |  Branch (3021:12): [True: 174k, False: 0]
  ------------------
 3022|   174k|}
_ZNK16QPDFObjectHandle13getOwningQPDFEv:
 3027|   271k|{
 3028|   271k|    return isInitialized() ? this->obj->getQPDF() : nullptr;
  ------------------
  |  Branch (3028:12): [True: 271k, False: 0]
  ------------------
 3029|   271k|}
QPDFObjectHandle.cc:_ZN12_GLOBAL__N_116FunctionProviderC2ENSt3__18functionIFvP8PipelineEEE:
 1704|  3.78k|        {
 1705|  3.78k|        }

_ZN10QPDFParser5parseERbb:
   28|  28.1k|{
   29|       |    // This method must take care not to resolve any objects. Don't check the type of any object
   30|       |    // without first ensuring that it is a direct object. Otherwise, doing so may have the side
   31|       |    // effect of reading the object and changing the file pointer. If you do this, it will cause a
   32|       |    // logic error to be thrown from QPDF::inParse().
   33|       |
   34|  28.1k|    QPDF::ParseGuard pg(context);
   35|  28.1k|    empty = false;
   36|  28.1k|    start = input->tell();
   37|       |
   38|  28.1k|    if (!tokenizer.nextToken(*input, object_description)) {
  ------------------
  |  Branch (38:9): [True: 188, False: 28.0k]
  ------------------
   39|    188|        warn(tokenizer.getErrorMessage());
   40|    188|    }
   41|       |
   42|  28.1k|    switch (tokenizer.getType()) {
   43|      0|    case QPDFTokenizer::tt_eof:
  ------------------
  |  Branch (43:5): [True: 0, False: 28.1k]
  ------------------
   44|      0|        if (content_stream) {
  ------------------
  |  Branch (44:13): [True: 0, False: 0]
  ------------------
   45|       |            // In content stream mode, leave object uninitialized to indicate EOF
   46|      0|            return {};
   47|      0|        }
   48|      0|        QTC::TC("qpdf", "QPDFParser eof in parse");
   49|      0|        warn("unexpected EOF");
   50|      0|        return {QPDF_Null::create()};
   51|       |
   52|      0|    case QPDFTokenizer::tt_bad:
  ------------------
  |  Branch (52:5): [True: 0, False: 28.1k]
  ------------------
   53|      0|        QTC::TC("qpdf", "QPDFParser bad token in parse");
   54|      0|        return {QPDF_Null::create()};
   55|       |
   56|      0|    case QPDFTokenizer::tt_brace_open:
  ------------------
  |  Branch (56:5): [True: 0, False: 28.1k]
  ------------------
   57|      0|    case QPDFTokenizer::tt_brace_close:
  ------------------
  |  Branch (57:5): [True: 0, False: 28.1k]
  ------------------
   58|      0|        QTC::TC("qpdf", "QPDFParser bad brace");
   59|      0|        warn("treating unexpected brace token as null");
   60|      0|        return {QPDF_Null::create()};
   61|       |
   62|      0|    case QPDFTokenizer::tt_array_close:
  ------------------
  |  Branch (62:5): [True: 0, False: 28.1k]
  ------------------
   63|      0|        QTC::TC("qpdf", "QPDFParser bad array close");
   64|      0|        warn("treating unexpected array close token as null");
   65|      0|        return {QPDF_Null::create()};
   66|       |
   67|      0|    case QPDFTokenizer::tt_dict_close:
  ------------------
  |  Branch (67:5): [True: 0, False: 28.1k]
  ------------------
   68|      0|        QTC::TC("qpdf", "QPDFParser bad dictionary close");
   69|      0|        warn("unexpected dictionary close token");
   70|      0|        return {QPDF_Null::create()};
   71|       |
   72|      0|    case QPDFTokenizer::tt_array_open:
  ------------------
  |  Branch (72:5): [True: 0, False: 28.1k]
  ------------------
   73|  6.52k|    case QPDFTokenizer::tt_dict_open:
  ------------------
  |  Branch (73:5): [True: 6.52k, False: 21.6k]
  ------------------
   74|  6.52k|        stack.clear();
   75|  6.52k|        stack.emplace_back(
   76|  6.52k|            input,
   77|  6.52k|            (tokenizer.getType() == QPDFTokenizer::tt_array_open) ? st_array : st_dictionary_key);
  ------------------
  |  Branch (77:13): [True: 0, False: 6.52k]
  ------------------
   78|  6.52k|        frame = &stack.back();
   79|  6.52k|        return parseRemainder(content_stream);
   80|       |
   81|      0|    case QPDFTokenizer::tt_bool:
  ------------------
  |  Branch (81:5): [True: 0, False: 28.1k]
  ------------------
   82|      0|        return withDescription<QPDF_Bool>(tokenizer.getValue() == "true");
   83|       |
   84|      0|    case QPDFTokenizer::tt_null:
  ------------------
  |  Branch (84:5): [True: 0, False: 28.1k]
  ------------------
   85|      0|        return {QPDF_Null::create()};
   86|       |
   87|      0|    case QPDFTokenizer::tt_integer:
  ------------------
  |  Branch (87:5): [True: 0, False: 28.1k]
  ------------------
   88|      0|        return withDescription<QPDF_Integer>(QUtil::string_to_ll(tokenizer.getValue().c_str()));
   89|       |
   90|      0|    case QPDFTokenizer::tt_real:
  ------------------
  |  Branch (90:5): [True: 0, False: 28.1k]
  ------------------
   91|      0|        return withDescription<QPDF_Real>(tokenizer.getValue());
   92|       |
   93|  21.4k|    case QPDFTokenizer::tt_name:
  ------------------
  |  Branch (93:5): [True: 21.4k, False: 6.71k]
  ------------------
   94|  21.4k|        return withDescription<QPDF_Name>(tokenizer.getValue());
   95|       |
   96|      0|    case QPDFTokenizer::tt_word:
  ------------------
  |  Branch (96:5): [True: 0, False: 28.1k]
  ------------------
   97|      0|        {
   98|      0|            auto const& value = tokenizer.getValue();
   99|      0|            if (content_stream) {
  ------------------
  |  Branch (99:17): [True: 0, False: 0]
  ------------------
  100|      0|                return withDescription<QPDF_Operator>(value);
  101|      0|            } else if (value == "endobj") {
  ------------------
  |  Branch (101:24): [True: 0, False: 0]
  ------------------
  102|       |                // We just saw endobj without having read anything.  Treat this as a null and do
  103|       |                // not move the input source's offset.
  104|      0|                input->seek(input->getLastOffset(), SEEK_SET);
  105|      0|                empty = true;
  106|      0|                return {QPDF_Null::create()};
  107|      0|            } else {
  108|      0|                QTC::TC("qpdf", "QPDFParser treat word as string");
  109|      0|                warn("unknown token while reading object; treating as string");
  110|      0|                return withDescription<QPDF_String>(value);
  111|      0|            }
  112|      0|        }
  113|       |
  114|      0|    case QPDFTokenizer::tt_string:
  ------------------
  |  Branch (114:5): [True: 0, False: 28.1k]
  ------------------
  115|      0|        if (decrypter) {
  ------------------
  |  Branch (115:13): [True: 0, False: 0]
  ------------------
  116|      0|            std::string s{tokenizer.getValue()};
  117|      0|            decrypter->decryptString(s);
  118|      0|            return withDescription<QPDF_String>(s);
  119|      0|        } else {
  120|      0|            return withDescription<QPDF_String>(tokenizer.getValue());
  121|      0|        }
  122|       |
  123|      0|    default:
  ------------------
  |  Branch (123:5): [True: 0, False: 28.1k]
  ------------------
  124|      0|        warn("treating unknown token type as null while reading object");
  125|      0|        return {QPDF_Null::create()};
  126|  28.1k|    }
  127|  28.1k|}
_ZN10QPDFParser14parseRemainderEb:
  131|  6.52k|{
  132|       |    // This method must take care not to resolve any objects. Don't check the type of any object
  133|       |    // without first ensuring that it is a direct object. Otherwise, doing so may have the side
  134|       |    // effect of reading the object and changing the file pointer. If you do this, it will cause a
  135|       |    // logic error to be thrown from QPDF::inParse().
  136|       |
  137|  6.52k|    bad_count = 0;
  138|  6.52k|    bool b_contents = false;
  139|       |
  140|  19.5k|    while (true) {
  ------------------
  |  Branch (140:12): [Folded - Ignored]
  ------------------
  141|  19.5k|        if (!tokenizer.nextToken(*input, object_description)) {
  ------------------
  |  Branch (141:13): [True: 0, False: 19.5k]
  ------------------
  142|      0|            warn(tokenizer.getErrorMessage());
  143|      0|        }
  144|  19.5k|        ++good_count; // optimistically
  145|       |
  146|  19.5k|        if (int_count != 0) {
  ------------------
  |  Branch (146:13): [True: 6.52k, False: 13.0k]
  ------------------
  147|       |            // Special handling of indirect references. Treat integer tokens as part of an indirect
  148|       |            // reference until proven otherwise.
  149|  6.52k|            if (tokenizer.getType() == QPDFTokenizer::tt_integer) {
  ------------------
  |  Branch (149:17): [True: 0, False: 6.52k]
  ------------------
  150|      0|                if (++int_count > 2) {
  ------------------
  |  Branch (150:21): [True: 0, False: 0]
  ------------------
  151|       |                    // Process the oldest buffered integer.
  152|      0|                    addInt(int_count);
  153|      0|                }
  154|      0|                last_offset_buffer[int_count % 2] = input->getLastOffset();
  155|      0|                int_buffer[int_count % 2] = QUtil::string_to_ll(tokenizer.getValue().c_str());
  156|      0|                continue;
  157|       |
  158|  6.52k|            } else if (
  159|  6.52k|                int_count >= 2 && tokenizer.getType() == QPDFTokenizer::tt_word &&
  ------------------
  |  Branch (159:17): [True: 0, False: 6.52k]
  |  Branch (159:35): [True: 0, False: 0]
  ------------------
  160|  6.52k|                tokenizer.getValue() == "R") {
  ------------------
  |  Branch (160:17): [True: 0, False: 0]
  ------------------
  161|      0|                if (context == nullptr) {
  ------------------
  |  Branch (161:21): [True: 0, False: 0]
  ------------------
  162|      0|                    QTC::TC("qpdf", "QPDFParser indirect without context");
  163|      0|                    throw std::logic_error("QPDFParser::parse called without context on an object "
  164|      0|                                           "with indirect references");
  165|      0|                }
  166|      0|                auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]);
  167|      0|                auto gen = QIntC::to_int(int_buffer[(int_count) % 2]);
  168|      0|                if (!(id < 1 || gen < 0 || gen >= 65535)) {
  ------------------
  |  Branch (168:23): [True: 0, False: 0]
  |  Branch (168:33): [True: 0, False: 0]
  |  Branch (168:44): [True: 0, False: 0]
  ------------------
  169|      0|                    add(QPDF::ParseGuard::getObject(context, id, gen, parse_pdf));
  170|      0|                } else {
  171|      0|                    QTC::TC("qpdf", "QPDFParser invalid objgen");
  172|      0|                    addNull();
  173|      0|                }
  174|      0|                int_count = 0;
  175|      0|                continue;
  176|       |
  177|  6.52k|            } else if (int_count > 0) {
  ------------------
  |  Branch (177:24): [True: 6.52k, False: 0]
  ------------------
  178|       |                // Process the buffered integers before processing the current token.
  179|  6.52k|                if (int_count > 1) {
  ------------------
  |  Branch (179:21): [True: 0, False: 6.52k]
  ------------------
  180|      0|                    addInt(int_count - 1);
  181|      0|                }
  182|  6.52k|                addInt(int_count);
  183|  6.52k|                int_count = 0;
  184|  6.52k|            }
  185|  6.52k|        }
  186|       |
  187|  19.5k|        switch (tokenizer.getType()) {
  188|      0|        case QPDFTokenizer::tt_eof:
  ------------------
  |  Branch (188:9): [True: 0, False: 19.5k]
  ------------------
  189|      0|            warn("parse error while reading object");
  190|      0|            if (content_stream) {
  ------------------
  |  Branch (190:17): [True: 0, False: 0]
  ------------------
  191|       |                // In content stream mode, leave object uninitialized to indicate EOF
  192|      0|                return {};
  193|      0|            }
  194|      0|            QTC::TC("qpdf", "QPDFParser eof in parseRemainder");
  195|      0|            warn("unexpected EOF");
  196|      0|            return {QPDF_Null::create()};
  197|       |
  198|      0|        case QPDFTokenizer::tt_bad:
  ------------------
  |  Branch (198:9): [True: 0, False: 19.5k]
  ------------------
  199|      0|            QTC::TC("qpdf", "QPDFParser bad token in parseRemainder");
  200|      0|            if (tooManyBadTokens()) {
  ------------------
  |  Branch (200:17): [True: 0, False: 0]
  ------------------
  201|      0|                return {QPDF_Null::create()};
  202|      0|            }
  203|      0|            addNull();
  204|      0|            continue;
  205|       |
  206|      0|        case QPDFTokenizer::tt_brace_open:
  ------------------
  |  Branch (206:9): [True: 0, False: 19.5k]
  ------------------
  207|      0|        case QPDFTokenizer::tt_brace_close:
  ------------------
  |  Branch (207:9): [True: 0, False: 19.5k]
  ------------------
  208|      0|            QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder");
  209|      0|            warn("treating unexpected brace token as null");
  210|      0|            if (tooManyBadTokens()) {
  ------------------
  |  Branch (210:17): [True: 0, False: 0]
  ------------------
  211|      0|                return {QPDF_Null::create()};
  212|      0|            }
  213|      0|            addNull();
  214|      0|            continue;
  215|       |
  216|      0|        case QPDFTokenizer::tt_array_close:
  ------------------
  |  Branch (216:9): [True: 0, False: 19.5k]
  ------------------
  217|      0|            if (frame->state == st_array) {
  ------------------
  |  Branch (217:17): [True: 0, False: 0]
  ------------------
  218|      0|                auto object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100);
  219|      0|                setDescription(object, frame->offset - 1);
  220|       |                // The `offset` points to the next of "[".  Set the rewind offset to point to the
  221|       |                // beginning of "[". This has been explicitly tested with whitespace surrounding the
  222|       |                // array start delimiter. getLastOffset points to the array end token and therefore
  223|       |                // can't be used here.
  224|      0|                if (stack.size() <= 1) {
  ------------------
  |  Branch (224:21): [True: 0, False: 0]
  ------------------
  225|      0|                    return object;
  226|      0|                }
  227|      0|                stack.pop_back();
  228|      0|                frame = &stack.back();
  229|      0|                add(std::move(object));
  230|      0|            } else {
  231|      0|                QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder");
  232|      0|                warn("treating unexpected array close token as null");
  233|      0|                if (tooManyBadTokens()) {
  ------------------
  |  Branch (233:21): [True: 0, False: 0]
  ------------------
  234|      0|                    return {QPDF_Null::create()};
  235|      0|                }
  236|      0|                addNull();
  237|      0|            }
  238|      0|            continue;
  239|       |
  240|  6.52k|        case QPDFTokenizer::tt_dict_close:
  ------------------
  |  Branch (240:9): [True: 6.52k, False: 13.0k]
  ------------------
  241|  6.52k|            if (frame->state <= st_dictionary_value) {
  ------------------
  |  Branch (241:17): [True: 6.52k, False: 0]
  ------------------
  242|       |                // Attempt to recover more or less gracefully from invalid dictionaries.
  243|  6.52k|                auto& dict = frame->dict;
  244|       |
  245|  6.52k|                if (frame->state == st_dictionary_value) {
  ------------------
  |  Branch (245:21): [True: 0, False: 6.52k]
  ------------------
  246|      0|                    QTC::TC("qpdf", "QPDFParser no val for last key");
  247|      0|                    warn(
  248|      0|                        frame->offset,
  249|      0|                        "dictionary ended prematurely; using null as value for last key");
  250|      0|                    dict[frame->key] = QPDF_Null::create();
  251|      0|                }
  252|       |
  253|  6.52k|                if (!frame->olist.empty()) {
  ------------------
  |  Branch (253:21): [True: 0, False: 6.52k]
  ------------------
  254|      0|                    fixMissingKeys();
  255|      0|                }
  256|       |
  257|  6.52k|                if (!frame->contents_string.empty() && dict.count("/Type") &&
  ------------------
  |  Branch (257:21): [True: 0, False: 6.52k]
  |  Branch (257:21): [True: 0, False: 6.52k]
  |  Branch (257:56): [True: 0, False: 0]
  ------------------
  258|  6.52k|                    dict["/Type"].isNameAndEquals("/Sig") && dict.count("/ByteRange") &&
  ------------------
  |  Branch (258:21): [True: 0, False: 0]
  |  Branch (258:62): [True: 0, False: 0]
  ------------------
  259|  6.52k|                    dict.count("/Contents") && dict["/Contents"].isString()) {
  ------------------
  |  Branch (259:21): [True: 0, False: 0]
  |  Branch (259:48): [True: 0, False: 0]
  ------------------
  260|      0|                    dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string);
  261|      0|                    dict["/Contents"].setParsedOffset(frame->contents_offset);
  262|      0|                }
  263|  6.52k|                auto object = QPDF_Dictionary::create(std::move(dict));
  264|  6.52k|                setDescription(object, frame->offset - 2);
  265|       |                // The `offset` points to the next of "<<". Set the rewind offset to point to the
  266|       |                // beginning of "<<". This has been explicitly tested with whitespace surrounding
  267|       |                // the dictionary start delimiter. getLastOffset points to the dictionary end token
  268|       |                // and therefore can't be used here.
  269|  6.52k|                if (stack.size() <= 1) {
  ------------------
  |  Branch (269:21): [True: 6.52k, False: 0]
  ------------------
  270|  6.52k|                    return object;
  271|  6.52k|                }
  272|      0|                stack.pop_back();
  273|      0|                frame = &stack.back();
  274|      0|                add(std::move(object));
  275|      0|            } else {
  276|      0|                QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder");
  277|      0|                warn("unexpected dictionary close token");
  278|      0|                if (tooManyBadTokens()) {
  ------------------
  |  Branch (278:21): [True: 0, False: 0]
  ------------------
  279|      0|                    return {QPDF_Null::create()};
  280|      0|                }
  281|      0|                addNull();
  282|      0|            }
  283|      0|            continue;
  284|       |
  285|      0|        case QPDFTokenizer::tt_array_open:
  ------------------
  |  Branch (285:9): [True: 0, False: 19.5k]
  ------------------
  286|      0|        case QPDFTokenizer::tt_dict_open:
  ------------------
  |  Branch (286:9): [True: 0, False: 19.5k]
  ------------------
  287|      0|            if (stack.size() > 499) {
  ------------------
  |  Branch (287:17): [True: 0, False: 0]
  ------------------
  288|      0|                QTC::TC("qpdf", "QPDFParser too deep");
  289|      0|                warn("ignoring excessively deeply nested data structure");
  290|      0|                return {QPDF_Null::create()};
  291|      0|            } else {
  292|      0|                b_contents = false;
  293|      0|                stack.emplace_back(
  294|      0|                    input,
  295|      0|                    (tokenizer.getType() == QPDFTokenizer::tt_array_open) ? st_array
  ------------------
  |  Branch (295:21): [True: 0, False: 0]
  ------------------
  296|      0|                                                                          : st_dictionary_key);
  297|      0|                frame = &stack.back();
  298|      0|                continue;
  299|      0|            }
  300|       |
  301|      0|        case QPDFTokenizer::tt_bool:
  ------------------
  |  Branch (301:9): [True: 0, False: 19.5k]
  ------------------
  302|      0|            addScalar<QPDF_Bool>(tokenizer.getValue() == "true");
  303|      0|            continue;
  304|       |
  305|      0|        case QPDFTokenizer::tt_null:
  ------------------
  |  Branch (305:9): [True: 0, False: 19.5k]
  ------------------
  306|      0|            addNull();
  307|      0|            continue;
  308|       |
  309|  6.52k|        case QPDFTokenizer::tt_integer:
  ------------------
  |  Branch (309:9): [True: 6.52k, False: 13.0k]
  ------------------
  310|  6.52k|            if (!content_stream) {
  ------------------
  |  Branch (310:17): [True: 6.52k, False: 0]
  ------------------
  311|       |                // Buffer token in case it is part of an indirect reference.
  312|  6.52k|                last_offset_buffer[1] = input->getLastOffset();
  313|  6.52k|                int_buffer[1] = QUtil::string_to_ll(tokenizer.getValue().c_str());
  314|  6.52k|                int_count = 1;
  315|  6.52k|            } else {
  316|      0|                addScalar<QPDF_Integer>(QUtil::string_to_ll(tokenizer.getValue().c_str()));
  317|      0|            }
  318|  6.52k|            continue;
  319|       |
  320|      0|        case QPDFTokenizer::tt_real:
  ------------------
  |  Branch (320:9): [True: 0, False: 19.5k]
  ------------------
  321|      0|            addScalar<QPDF_Real>(tokenizer.getValue());
  322|      0|            continue;
  323|       |
  324|  6.52k|        case QPDFTokenizer::tt_name:
  ------------------
  |  Branch (324:9): [True: 6.52k, False: 13.0k]
  ------------------
  325|  6.52k|            if (frame->state == st_dictionary_key) {
  ------------------
  |  Branch (325:17): [True: 6.52k, False: 0]
  ------------------
  326|  6.52k|                frame->key = tokenizer.getValue();
  327|  6.52k|                frame->state = st_dictionary_value;
  328|  6.52k|                b_contents = decrypter && frame->key == "/Contents";
  ------------------
  |  Branch (328:30): [True: 0, False: 6.52k]
  |  Branch (328:43): [True: 0, False: 0]
  ------------------
  329|  6.52k|                continue;
  330|  6.52k|            } else {
  331|      0|                addScalar<QPDF_Name>(tokenizer.getValue());
  332|      0|            }
  333|      0|            continue;
  334|       |
  335|      0|        case QPDFTokenizer::tt_word:
  ------------------
  |  Branch (335:9): [True: 0, False: 19.5k]
  ------------------
  336|      0|            if (content_stream) {
  ------------------
  |  Branch (336:17): [True: 0, False: 0]
  ------------------
  337|      0|                addScalar<QPDF_Operator>(tokenizer.getValue());
  338|      0|            } else {
  339|      0|                QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder");
  340|      0|                warn("unknown token while reading object; treating as string");
  341|      0|                if (tooManyBadTokens()) {
  ------------------
  |  Branch (341:21): [True: 0, False: 0]
  ------------------
  342|      0|                    return {QPDF_Null::create()};
  343|      0|                }
  344|      0|                addScalar<QPDF_String>(tokenizer.getValue());
  345|      0|            }
  346|      0|            continue;
  347|       |
  348|      0|        case QPDFTokenizer::tt_string:
  ------------------
  |  Branch (348:9): [True: 0, False: 19.5k]
  ------------------
  349|      0|            {
  350|      0|                auto const& val = tokenizer.getValue();
  351|      0|                if (decrypter) {
  ------------------
  |  Branch (351:21): [True: 0, False: 0]
  ------------------
  352|      0|                    if (b_contents) {
  ------------------
  |  Branch (352:25): [True: 0, False: 0]
  ------------------
  353|      0|                        frame->contents_string = val;
  354|      0|                        frame->contents_offset = input->getLastOffset();
  355|      0|                        b_contents = false;
  356|      0|                    }
  357|      0|                    std::string s{val};
  358|      0|                    decrypter->decryptString(s);
  359|      0|                    addScalar<QPDF_String>(s);
  360|      0|                } else {
  361|      0|                    addScalar<QPDF_String>(val);
  362|      0|                }
  363|      0|            }
  364|      0|            continue;
  365|       |
  366|      0|        default:
  ------------------
  |  Branch (366:9): [True: 0, False: 19.5k]
  ------------------
  367|      0|            warn("treating unknown token type as null while reading object");
  368|      0|            if (tooManyBadTokens()) {
  ------------------
  |  Branch (368:17): [True: 0, False: 0]
  ------------------
  369|      0|                return {QPDF_Null::create()};
  370|      0|            }
  371|      0|            addNull();
  372|  19.5k|        }
  373|  19.5k|    }
  374|  6.52k|}
_ZN10QPDFParser3addEONSt3__110shared_ptrI10QPDFObjectEE:
  378|  6.52k|{
  379|  6.52k|    if (frame->state != st_dictionary_value) {
  ------------------
  |  Branch (379:9): [True: 0, False: 6.52k]
  ------------------
  380|       |        // If state is st_dictionary_key then there is a missing key. Push onto olist for
  381|       |        // processing once the tt_dict_close token has been found.
  382|      0|        frame->olist.emplace_back(std::move(obj));
  383|  6.52k|    } else {
  384|  6.52k|        if (auto res = frame->dict.insert_or_assign(frame->key, std::move(obj)); !res.second) {
  ------------------
  |  Branch (384:82): [True: 0, False: 6.52k]
  ------------------
  385|      0|            warnDuplicateKey();
  386|      0|        }
  387|  6.52k|        frame->state = st_dictionary_key;
  388|  6.52k|    }
  389|  6.52k|}
_ZN10QPDFParser6addIntEi:
  411|  6.52k|{
  412|  6.52k|    auto obj = QPDF_Integer::create(int_buffer[count % 2]);
  413|  6.52k|    obj->setDescription(context, description, last_offset_buffer[count % 2]);
  414|  6.52k|    add(std::move(obj));
  415|  6.52k|}
_ZN10QPDFParser14setDescriptionERNSt3__110shared_ptrI10QPDFObjectEEx:
  437|  6.52k|{
  438|  6.52k|    if (obj) {
  ------------------
  |  Branch (438:9): [True: 6.52k, False: 0]
  ------------------
  439|  6.52k|        obj->setDescription(context, description, parsed_offset);
  440|  6.52k|    }
  441|  6.52k|}
_ZNK10QPDFParser4warnERK7QPDFExc:
  486|    188|{
  487|       |    // If parsing on behalf of a QPDF object and want to give a warning, we can warn through the
  488|       |    // object. If parsing for some other reason, such as an explicit creation of an object from a
  489|       |    // string, then just throw the exception.
  490|    188|    if (context) {
  ------------------
  |  Branch (490:9): [True: 0, False: 188]
  ------------------
  491|      0|        context->warn(e);
  492|    188|    } else {
  493|    188|        throw e;
  494|    188|    }
  495|    188|}
_ZNK10QPDFParser4warnExRKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  508|    188|{
  509|    188|    warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(), object_description, offset, msg));
  510|    188|}
_ZNK10QPDFParser4warnERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  514|    188|{
  515|    188|    warn(input->getLastOffset(), msg);
  516|    188|}
_ZN10QPDFParser15withDescriptionI9QPDF_NameJRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEEE16QPDFObjectHandleDpOT0_:
  429|  21.4k|{
  430|  21.4k|    auto obj = T::create(args...);
  431|  21.4k|    obj->setDescription(context, description, start);
  432|  21.4k|    return {obj};
  433|  21.4k|}

_ZN13QPDFTokenizer5resetEv:
   78|   141k|{
   79|   141k|    state = st_before_token;
   80|   141k|    type = tt_bad;
   81|   141k|    val.clear();
   82|   141k|    raw_val.clear();
   83|   141k|    error_message = "";
   84|   141k|    before_token = true;
   85|   141k|    in_token = false;
   86|   141k|    char_to_unread = '\0';
   87|   141k|    inline_image_bytes = 0;
   88|   141k|    string_depth = 0;
   89|   141k|    bad = false;
   90|   141k|}
_ZN13QPDFTokenizerC2Ev:
  107|  28.1k|{
  108|  28.1k|    reset();
  109|  28.1k|}
_ZN13QPDFTokenizer8allowEOFEv:
  113|  6.52k|{
  114|  6.52k|    this->allow_eof = true;
  115|  6.52k|}
_ZN13QPDFTokenizer7isSpaceEc:
  125|   119k|{
  126|   119k|    return ((ch == '\0') || QUtil::is_space(ch));
  ------------------
  |  Branch (126:13): [True: 0, False: 119k]
  |  Branch (126:29): [True: 39.1k, False: 80.4k]
  ------------------
  127|   119k|}
_ZN13QPDFTokenizer11isDelimiterEc:
  131|  8.24M|{
  132|  8.24M|    return is_delimiter(ch);
  133|  8.24M|}
_ZN13QPDFTokenizer16presentCharacterEc:
  137|  18.5k|{
  138|  18.5k|    handleCharacter(ch);
  139|       |
  140|  18.5k|    if (this->in_token) {
  ------------------
  |  Branch (140:9): [True: 0, False: 18.5k]
  ------------------
  141|      0|        this->raw_val += ch;
  142|      0|    }
  143|  18.5k|}
_ZN13QPDFTokenizer15handleCharacterEc:
  147|  8.41M|{
  148|       |    // In some cases, functions called below may call a second handler. This happens whenever you
  149|       |    // have to use a character from the next token to detect the end of the current token.
  150|       |
  151|  8.41M|    switch (this->state) {
  152|      0|    case st_top:
  ------------------
  |  Branch (152:5): [True: 0, False: 8.41M]
  ------------------
  153|      0|        inTop(ch);
  154|      0|        return;
  155|       |
  156|      0|    case st_in_space:
  ------------------
  |  Branch (156:5): [True: 0, False: 8.41M]
  ------------------
  157|      0|        inSpace(ch);
  158|      0|        return;
  159|       |
  160|      0|    case st_in_comment:
  ------------------
  |  Branch (160:5): [True: 0, False: 8.41M]
  ------------------
  161|      0|        inComment(ch);
  162|      0|        return;
  163|       |
  164|  6.52k|    case st_lt:
  ------------------
  |  Branch (164:5): [True: 6.52k, False: 8.41M]
  ------------------
  165|  6.52k|        inLt(ch);
  166|  6.52k|        return;
  167|       |
  168|  6.52k|    case st_gt:
  ------------------
  |  Branch (168:5): [True: 6.52k, False: 8.41M]
  ------------------
  169|  6.52k|        inGt(ch);
  170|  6.52k|        return;
  171|       |
  172|      0|    case st_in_string:
  ------------------
  |  Branch (172:5): [True: 0, False: 8.41M]
  ------------------
  173|      0|        inString(ch);
  174|      0|        return;
  175|       |
  176|  8.02M|    case st_name:
  ------------------
  |  Branch (176:5): [True: 8.02M, False: 395k]
  ------------------
  177|  8.02M|        inName(ch);
  178|  8.02M|        return;
  179|       |
  180|  19.5k|    case st_number:
  ------------------
  |  Branch (180:5): [True: 19.5k, False: 8.39M]
  ------------------
  181|  19.5k|        inNumber(ch);
  182|  19.5k|        return;
  183|       |
  184|      0|    case st_real:
  ------------------
  |  Branch (184:5): [True: 0, False: 8.41M]
  ------------------
  185|      0|        inReal(ch);
  186|      0|        return;
  187|       |
  188|      0|    case st_string_after_cr:
  ------------------
  |  Branch (188:5): [True: 0, False: 8.41M]
  ------------------
  189|      0|        inStringAfterCR(ch);
  190|      0|        return;
  191|       |
  192|      0|    case st_string_escape:
  ------------------
  |  Branch (192:5): [True: 0, False: 8.41M]
  ------------------
  193|      0|        inStringEscape(ch);
  194|      0|        return;
  195|       |
  196|      0|    case st_char_code:
  ------------------
  |  Branch (196:5): [True: 0, False: 8.41M]
  ------------------
  197|      0|        inCharCode(ch);
  198|      0|        return;
  199|       |
  200|   163k|    case st_literal:
  ------------------
  |  Branch (200:5): [True: 163k, False: 8.25M]
  ------------------
  201|   163k|        inLiteral(ch);
  202|   163k|        return;
  203|       |
  204|      0|    case st_inline_image:
  ------------------
  |  Branch (204:5): [True: 0, False: 8.41M]
  ------------------
  205|      0|        inInlineImage(ch);
  206|      0|        return;
  207|       |
  208|      0|    case st_in_hexstring:
  ------------------
  |  Branch (208:5): [True: 0, False: 8.41M]
  ------------------
  209|      0|        inHexstring(ch);
  210|      0|        return;
  211|       |
  212|      0|    case st_in_hexstring_2nd:
  ------------------
  |  Branch (212:5): [True: 0, False: 8.41M]
  ------------------
  213|      0|        inHexstring2nd(ch);
  214|      0|        return;
  215|       |
  216|  54.7k|    case st_name_hex1:
  ------------------
  |  Branch (216:5): [True: 54.7k, False: 8.36M]
  ------------------
  217|  54.7k|        inNameHex1(ch);
  218|  54.7k|        return;
  219|       |
  220|  24.8k|    case st_name_hex2:
  ------------------
  |  Branch (220:5): [True: 24.8k, False: 8.39M]
  ------------------
  221|  24.8k|        inNameHex2(ch);
  222|  24.8k|        return;
  223|       |
  224|      0|    case st_sign:
  ------------------
  |  Branch (224:5): [True: 0, False: 8.41M]
  ------------------
  225|      0|        inSign(ch);
  226|      0|        return;
  227|       |
  228|      0|    case st_decimal:
  ------------------
  |  Branch (228:5): [True: 0, False: 8.41M]
  ------------------
  229|      0|        inDecimal(ch);
  230|      0|        return;
  231|       |
  232|   119k|    case (st_before_token):
  ------------------
  |  Branch (232:5): [True: 119k, False: 8.29M]
  ------------------
  233|   119k|        inBeforeToken(ch);
  234|   119k|        return;
  235|       |
  236|      0|    case (st_token_ready):
  ------------------
  |  Branch (236:5): [True: 0, False: 8.41M]
  ------------------
  237|      0|        inTokenReady(ch);
  238|      0|        return;
  239|       |
  240|      0|    default:
  ------------------
  |  Branch (240:5): [True: 0, False: 8.41M]
  ------------------
  241|      0|        throw std::logic_error("INTERNAL ERROR: invalid state while reading token");
  242|  8.41M|    }
  243|  8.41M|}
_ZN13QPDFTokenizer13inBeforeTokenEc:
  254|   119k|{
  255|       |    // Note: we specifically do not use ctype here.  It is locale-dependent.
  256|   119k|    if (isSpace(ch)) {
  ------------------
  |  Branch (256:9): [True: 39.1k, False: 80.4k]
  ------------------
  257|  39.1k|        this->before_token = !this->include_ignorable;
  258|  39.1k|        this->in_token = this->include_ignorable;
  259|  39.1k|        if (this->include_ignorable) {
  ------------------
  |  Branch (259:13): [True: 0, False: 39.1k]
  ------------------
  260|      0|            this->state = st_in_space;
  261|      0|        }
  262|  80.4k|    } else if (ch == '%') {
  ------------------
  |  Branch (262:16): [True: 0, False: 80.4k]
  ------------------
  263|      0|        this->before_token = !this->include_ignorable;
  264|      0|        this->in_token = this->include_ignorable;
  265|      0|        this->state = st_in_comment;
  266|  80.4k|    } else {
  267|  80.4k|        this->before_token = false;
  268|  80.4k|        this->in_token = true;
  269|  80.4k|        inTop(ch);
  270|  80.4k|    }
  271|   119k|}
_ZN13QPDFTokenizer5inTopEc:
  275|  80.4k|{
  276|  80.4k|    switch (ch) {
  277|      0|    case '(':
  ------------------
  |  Branch (277:5): [True: 0, False: 80.4k]
  ------------------
  278|      0|        this->string_depth = 1;
  279|      0|        this->state = st_in_string;
  280|      0|        return;
  281|       |
  282|  6.52k|    case '<':
  ------------------
  |  Branch (282:5): [True: 6.52k, False: 73.8k]
  ------------------
  283|  6.52k|        this->state = st_lt;
  284|  6.52k|        return;
  285|       |
  286|  6.52k|    case '>':
  ------------------
  |  Branch (286:5): [True: 6.52k, False: 73.8k]
  ------------------
  287|  6.52k|        this->state = st_gt;
  288|  6.52k|        return;
  289|       |
  290|      0|    case (')'):
  ------------------
  |  Branch (290:5): [True: 0, False: 80.4k]
  ------------------
  291|      0|        this->type = tt_bad;
  292|      0|        QTC::TC("qpdf", "QPDFTokenizer bad )");
  293|      0|        this->error_message = "unexpected )";
  294|      0|        this->state = st_token_ready;
  295|      0|        return;
  296|       |
  297|      0|    case '[':
  ------------------
  |  Branch (297:5): [True: 0, False: 80.4k]
  ------------------
  298|      0|        this->type = tt_array_open;
  299|      0|        this->state = st_token_ready;
  300|      0|        return;
  301|       |
  302|      0|    case ']':
  ------------------
  |  Branch (302:5): [True: 0, False: 80.4k]
  ------------------
  303|      0|        this->type = tt_array_close;
  304|      0|        this->state = st_token_ready;
  305|      0|        return;
  306|       |
  307|      0|    case '{':
  ------------------
  |  Branch (307:5): [True: 0, False: 80.4k]
  ------------------
  308|      0|        this->type = tt_brace_open;
  309|      0|        this->state = st_token_ready;
  310|      0|        return;
  311|       |
  312|      0|    case '}':
  ------------------
  |  Branch (312:5): [True: 0, False: 80.4k]
  ------------------
  313|      0|        this->type = tt_brace_close;
  314|      0|        this->state = st_token_ready;
  315|      0|        return;
  316|       |
  317|  28.1k|    case '/':
  ------------------
  |  Branch (317:5): [True: 28.1k, False: 52.2k]
  ------------------
  318|  28.1k|        this->state = st_name;
  319|  28.1k|        this->val += ch;
  320|  28.1k|        return;
  321|       |
  322|      0|    case '0':
  ------------------
  |  Branch (322:5): [True: 0, False: 80.4k]
  ------------------
  323|  6.52k|    case '1':
  ------------------
  |  Branch (323:5): [True: 6.52k, False: 73.8k]
  ------------------
  324|  6.52k|    case '2':
  ------------------
  |  Branch (324:5): [True: 0, False: 80.4k]
  ------------------
  325|  6.52k|    case '3':
  ------------------
  |  Branch (325:5): [True: 0, False: 80.4k]
  ------------------
  326|  6.52k|    case '4':
  ------------------
  |  Branch (326:5): [True: 0, False: 80.4k]
  ------------------
  327|  6.52k|    case '5':
  ------------------
  |  Branch (327:5): [True: 0, False: 80.4k]
  ------------------
  328|  6.52k|    case '6':
  ------------------
  |  Branch (328:5): [True: 0, False: 80.4k]
  ------------------
  329|  6.52k|    case '7':
  ------------------
  |  Branch (329:5): [True: 0, False: 80.4k]
  ------------------
  330|  6.52k|    case '8':
  ------------------
  |  Branch (330:5): [True: 0, False: 80.4k]
  ------------------
  331|  19.5k|    case '9':
  ------------------
  |  Branch (331:5): [True: 13.0k, False: 67.3k]
  ------------------
  332|  19.5k|        this->state = st_number;
  333|  19.5k|        return;
  334|       |
  335|      0|    case '+':
  ------------------
  |  Branch (335:5): [True: 0, False: 80.4k]
  ------------------
  336|      0|    case '-':
  ------------------
  |  Branch (336:5): [True: 0, False: 80.4k]
  ------------------
  337|      0|        this->state = st_sign;
  338|      0|        return;
  339|       |
  340|      0|    case '.':
  ------------------
  |  Branch (340:5): [True: 0, False: 80.4k]
  ------------------
  341|      0|        this->state = st_decimal;
  342|      0|        return;
  343|       |
  344|  19.5k|    default:
  ------------------
  |  Branch (344:5): [True: 19.5k, False: 60.8k]
  ------------------
  345|  19.5k|        this->state = st_literal;
  346|  19.5k|        return;
  347|  80.4k|    }
  348|  80.4k|}
_ZN13QPDFTokenizer6inNameEc:
  418|  8.06M|{
  419|  8.06M|    if (isDelimiter(ch)) {
  ------------------
  |  Branch (419:9): [True: 28.1k, False: 8.03M]
  ------------------
  420|       |        // A C-locale whitespace character or delimiter terminates token.  It is important to unread
  421|       |        // the whitespace character even though it is ignored since it may be the newline after a
  422|       |        // stream keyword.  Removing it here could make the stream-reading code break on some files,
  423|       |        // though not on any files in the test suite as of this
  424|       |        // writing.
  425|       |
  426|  28.1k|        this->type = this->bad ? tt_bad : tt_name;
  ------------------
  |  Branch (426:22): [True: 54, False: 28.1k]
  ------------------
  427|  28.1k|        this->in_token = false;
  428|  28.1k|        this->char_to_unread = ch;
  429|  28.1k|        this->state = st_token_ready;
  430|  8.03M|    } else if (ch == '#') {
  ------------------
  |  Branch (430:16): [True: 54.7k, False: 7.98M]
  ------------------
  431|  54.7k|        this->char_code = 0;
  432|  54.7k|        this->state = st_name_hex1;
  433|  7.98M|    } else {
  434|  7.98M|        this->val += ch;
  435|  7.98M|    }
  436|  8.06M|}
_ZN13QPDFTokenizer10inNameHex1Ec:
  440|  54.7k|{
  441|  54.7k|    this->hex_char = ch;
  442|       |
  443|  54.7k|    if (char hval = QUtil::hex_decode_char(ch); hval < '\20') {
  ------------------
  |  Branch (443:49): [True: 24.8k, False: 29.9k]
  ------------------
  444|  24.8k|        this->char_code = int(hval) << 4;
  445|  24.8k|        this->state = st_name_hex2;
  446|  29.9k|    } else {
  447|  29.9k|        QTC::TC("qpdf", "QPDFTokenizer bad name 1");
  448|  29.9k|        this->error_message = "name with stray # will not work with PDF >= 1.2";
  449|       |        // Use null to encode a bad # -- this is reversed in QPDF_Name::normalizeName.
  450|  29.9k|        this->val += '\0';
  451|  29.9k|        this->state = st_name;
  452|  29.9k|        inName(ch);
  453|  29.9k|    }
  454|  54.7k|}
_ZN13QPDFTokenizer10inNameHex2Ec:
  458|  24.8k|{
  459|  24.8k|    if (char hval = QUtil::hex_decode_char(ch); hval < '\20') {
  ------------------
  |  Branch (459:49): [True: 14.3k, False: 10.4k]
  ------------------
  460|  14.3k|        this->char_code |= int(hval);
  461|  14.3k|    } else {
  462|  10.4k|        QTC::TC("qpdf", "QPDFTokenizer bad name 2");
  463|  10.4k|        this->error_message = "name with stray # will not work with PDF >= 1.2";
  464|       |        // Use null to encode a bad # -- this is reversed in QPDF_Name::normalizeName.
  465|  10.4k|        this->val += '\0';
  466|  10.4k|        this->val += this->hex_char;
  467|  10.4k|        this->state = st_name;
  468|  10.4k|        inName(ch);
  469|  10.4k|        return;
  470|  10.4k|    }
  471|  14.3k|    if (this->char_code == 0) {
  ------------------
  |  Branch (471:9): [True: 11.3k, False: 2.96k]
  ------------------
  472|  11.3k|        QTC::TC("qpdf", "QPDFTokenizer null in name");
  473|  11.3k|        this->error_message = "null character not allowed in name token";
  474|  11.3k|        this->val += "#00";
  475|  11.3k|        this->state = st_name;
  476|  11.3k|        this->bad = true;
  477|  11.3k|    } else {
  478|  2.96k|        this->val += char(this->char_code);
  479|  2.96k|        this->state = st_name;
  480|  2.96k|    }
  481|  14.3k|}
_ZN13QPDFTokenizer8inNumberEc:
  509|  19.5k|{
  510|  19.5k|    if (QUtil::is_digit(ch)) {
  ------------------
  |  Branch (510:9): [True: 0, False: 19.5k]
  ------------------
  511|  19.5k|    } else if (ch == '.') {
  ------------------
  |  Branch (511:16): [True: 0, False: 19.5k]
  ------------------
  512|      0|        this->state = st_real;
  513|  19.5k|    } else if (isDelimiter(ch)) {
  ------------------
  |  Branch (513:16): [True: 19.5k, False: 0]
  ------------------
  514|  19.5k|        this->type = tt_integer;
  515|  19.5k|        this->state = st_token_ready;
  516|  19.5k|        this->in_token = false;
  517|  19.5k|        this->char_to_unread = ch;
  518|  19.5k|    } else {
  519|      0|        this->state = st_literal;
  520|      0|    }
  521|  19.5k|}
_ZN13QPDFTokenizer4inLtEc:
  600|  6.52k|{
  601|  6.52k|    if (ch == '<') {
  ------------------
  |  Branch (601:9): [True: 6.52k, False: 0]
  ------------------
  602|  6.52k|        this->type = tt_dict_open;
  603|  6.52k|        this->state = st_token_ready;
  604|  6.52k|        return;
  605|  6.52k|    }
  606|       |
  607|      0|    this->state = st_in_hexstring;
  608|      0|    inHexstring(ch);
  609|      0|}
_ZN13QPDFTokenizer4inGtEc:
  613|  6.52k|{
  614|  6.52k|    if (ch == '>') {
  ------------------
  |  Branch (614:9): [True: 6.52k, False: 0]
  ------------------
  615|  6.52k|        this->type = tt_dict_close;
  616|  6.52k|        this->state = st_token_ready;
  617|  6.52k|    } else {
  618|      0|        this->type = tt_bad;
  619|      0|        QTC::TC("qpdf", "QPDFTokenizer bad >");
  620|      0|        this->error_message = "unexpected >";
  621|      0|        this->in_token = false;
  622|      0|        this->char_to_unread = ch;
  623|      0|        this->state = st_token_ready;
  624|      0|    }
  625|  6.52k|}
_ZN13QPDFTokenizer9inLiteralEc:
  629|   163k|{
  630|   163k|    if (isDelimiter(ch)) {
  ------------------
  |  Branch (630:9): [True: 19.5k, False: 143k]
  ------------------
  631|       |        // A C-locale whitespace character or delimiter terminates token.  It is important to unread
  632|       |        // the whitespace character even though it is ignored since it may be the newline after a
  633|       |        // stream keyword.  Removing it here could make the stream-reading code break on some files,
  634|       |        // though not on any files in the test suite as of this writing.
  635|       |
  636|  19.5k|        this->in_token = false;
  637|  19.5k|        this->char_to_unread = ch;
  638|  19.5k|        this->state = st_token_ready;
  639|  19.5k|        this->type = (this->raw_val == "true") || (this->raw_val == "false")
  ------------------
  |  Branch (639:22): [True: 0, False: 19.5k]
  |  Branch (639:51): [True: 0, False: 19.5k]
  ------------------
  640|  19.5k|            ? tt_bool
  641|  19.5k|            : (this->raw_val == "null" ? tt_null : tt_word);
  ------------------
  |  Branch (641:16): [True: 0, False: 19.5k]
  ------------------
  642|  19.5k|    }
  643|   163k|}
_ZN13QPDFTokenizer10presentEOFEv:
  724|  18.5k|{
  725|  18.5k|    switch (this->state) {
  726|  18.5k|    case st_name:
  ------------------
  |  Branch (726:5): [True: 18.5k, False: 37]
  ------------------
  727|  18.5k|    case st_name_hex1:
  ------------------
  |  Branch (727:5): [True: 19, False: 18.5k]
  ------------------
  728|  18.5k|    case st_name_hex2:
  ------------------
  |  Branch (728:5): [True: 18, False: 18.5k]
  ------------------
  729|  18.5k|    case st_number:
  ------------------
  |  Branch (729:5): [True: 0, False: 18.5k]
  ------------------
  730|  18.5k|    case st_real:
  ------------------
  |  Branch (730:5): [True: 0, False: 18.5k]
  ------------------
  731|  18.5k|    case st_sign:
  ------------------
  |  Branch (731:5): [True: 0, False: 18.5k]
  ------------------
  732|  18.5k|    case st_decimal:
  ------------------
  |  Branch (732:5): [True: 0, False: 18.5k]
  ------------------
  733|  18.5k|    case st_literal:
  ------------------
  |  Branch (733:5): [True: 0, False: 18.5k]
  ------------------
  734|  18.5k|        QTC::TC("qpdf", "QPDFTokenizer EOF reading appendable token");
  735|       |        // Push any delimiter to the state machine to finish off the final token.
  736|  18.5k|        presentCharacter('\f');
  737|  18.5k|        this->in_token = true;
  738|  18.5k|        break;
  739|       |
  740|      0|    case st_top:
  ------------------
  |  Branch (740:5): [True: 0, False: 18.5k]
  ------------------
  741|      0|    case st_before_token:
  ------------------
  |  Branch (741:5): [True: 0, False: 18.5k]
  ------------------
  742|      0|        this->type = tt_eof;
  743|      0|        break;
  744|       |
  745|      0|    case st_in_space:
  ------------------
  |  Branch (745:5): [True: 0, False: 18.5k]
  ------------------
  746|      0|        this->type = this->include_ignorable ? tt_space : tt_eof;
  ------------------
  |  Branch (746:22): [True: 0, False: 0]
  ------------------
  747|      0|        break;
  748|       |
  749|      0|    case st_in_comment:
  ------------------
  |  Branch (749:5): [True: 0, False: 18.5k]
  ------------------
  750|      0|        this->type = this->include_ignorable ? tt_comment : tt_bad;
  ------------------
  |  Branch (750:22): [True: 0, False: 0]
  ------------------
  751|      0|        break;
  752|       |
  753|      0|    case st_token_ready:
  ------------------
  |  Branch (753:5): [True: 0, False: 18.5k]
  ------------------
  754|      0|        break;
  755|       |
  756|      0|    default:
  ------------------
  |  Branch (756:5): [True: 0, False: 18.5k]
  ------------------
  757|      0|        QTC::TC("qpdf", "QPDFTokenizer EOF reading token");
  758|      0|        this->type = tt_bad;
  759|      0|        this->error_message = "EOF while reading token";
  760|  18.5k|    }
  761|  18.5k|    this->state = st_token_ready;
  762|  18.5k|}
_ZN13QPDFTokenizer8getTokenERNS_5TokenERbRc:
  869|  32.6k|{
  870|  32.6k|    bool ready = (this->state == st_token_ready);
  871|  32.6k|    unread_char = !this->in_token && !this->before_token;
  ------------------
  |  Branch (871:19): [True: 32.6k, False: 0]
  |  Branch (871:38): [True: 32.6k, False: 0]
  ------------------
  872|  32.6k|    ch = this->char_to_unread;
  873|  32.6k|    if (ready) {
  ------------------
  |  Branch (873:9): [True: 32.6k, False: 0]
  ------------------
  874|  32.6k|        token = (!(this->type == tt_name || this->type == tt_string))
  ------------------
  |  Branch (874:20): [True: 0, False: 32.6k]
  |  Branch (874:45): [True: 0, False: 32.6k]
  ------------------
  875|  32.6k|            ? Token(this->type, this->raw_val, this->raw_val, this->error_message)
  876|  32.6k|            : Token(this->type, this->val, this->raw_val, this->error_message);
  877|       |
  878|  32.6k|        this->reset();
  879|  32.6k|    }
  880|  32.6k|    return ready;
  881|  32.6k|}
_ZN13QPDFTokenizer9readTokenER11InputSourceRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbm:
  892|  32.6k|{
  893|  32.6k|    nextToken(input, context, max_len);
  894|       |
  895|  32.6k|    Token token;
  896|  32.6k|    bool unread_char;
  897|  32.6k|    char char_to_unread;
  898|  32.6k|    getToken(token, unread_char, char_to_unread);
  899|       |
  900|  32.6k|    if (token.getType() == tt_bad) {
  ------------------
  |  Branch (900:9): [True: 0, False: 32.6k]
  ------------------
  901|      0|        if (allow_bad) {
  ------------------
  |  Branch (901:13): [True: 0, False: 0]
  ------------------
  902|      0|            QTC::TC("qpdf", "QPDFTokenizer allowing bad token");
  903|      0|        } else {
  904|      0|            throw QPDFExc(
  905|      0|                qpdf_e_damaged_pdf,
  906|      0|                input.getName(),
  907|      0|                context.empty() ? "offset " + std::to_string(input.getLastOffset()) : context,
  ------------------
  |  Branch (907:17): [True: 0, False: 0]
  ------------------
  908|      0|                input.getLastOffset(),
  909|      0|                token.getErrorMessage());
  910|      0|        }
  911|      0|    }
  912|  32.6k|    return token;
  913|  32.6k|}
_ZN13QPDFTokenizer9readTokenENSt3__110shared_ptrI11InputSourceEERKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEbm:
  918|  32.6k|{
  919|  32.6k|    return readToken(*input, context, allow_bad, max_len);
  920|  32.6k|}
_ZN13QPDFTokenizer9nextTokenER11InputSourceRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEm:
  924|  80.4k|{
  925|  80.4k|    if (this->state != st_inline_image) {
  ------------------
  |  Branch (925:9): [True: 80.4k, False: 0]
  ------------------
  926|  80.4k|        reset();
  927|  80.4k|    }
  928|  80.4k|    qpdf_offset_t offset = input.fastTell();
  929|       |
  930|  8.49M|    while (this->state != st_token_ready) {
  ------------------
  |  Branch (930:12): [True: 8.41M, False: 80.4k]
  ------------------
  931|  8.41M|        char ch;
  932|  8.41M|        if (!input.fastRead(ch)) {
  ------------------
  |  Branch (932:13): [True: 18.5k, False: 8.40M]
  ------------------
  933|  18.5k|            presentEOF();
  934|       |
  935|  18.5k|            if ((this->type == tt_eof) && (!this->allow_eof)) {
  ------------------
  |  Branch (935:17): [True: 0, False: 18.5k]
  |  Branch (935:43): [True: 0, False: 0]
  ------------------
  936|       |                // Nothing in the qpdf library calls readToken without allowEOF anymore, so this
  937|       |                // case is not exercised.
  938|      0|                this->type = tt_bad;
  939|      0|                this->error_message = "unexpected EOF";
  940|      0|                offset = input.getLastOffset();
  941|      0|            }
  942|  8.40M|        } else {
  943|  8.40M|            handleCharacter(ch);
  944|  8.40M|            if (this->before_token) {
  ------------------
  |  Branch (944:17): [True: 39.1k, False: 8.36M]
  ------------------
  945|  39.1k|                ++offset;
  946|  39.1k|            }
  947|  8.40M|            if (this->in_token) {
  ------------------
  |  Branch (947:17): [True: 8.31M, False: 87.9k]
  ------------------
  948|  8.31M|                this->raw_val += ch;
  949|  8.31M|            }
  950|  8.40M|            if (max_len && (this->raw_val.length() >= max_len) && (this->state != st_token_ready)) {
  ------------------
  |  Branch (950:17): [True: 0, False: 8.40M]
  |  Branch (950:28): [True: 0, False: 0]
  |  Branch (950:67): [True: 0, False: 0]
  ------------------
  951|       |                // terminate this token now
  952|      0|                QTC::TC("qpdf", "QPDFTokenizer block long token");
  953|      0|                this->type = tt_bad;
  954|      0|                this->state = st_token_ready;
  955|      0|                this->error_message = "exceeded allowable length while reading token";
  956|      0|            }
  957|  8.40M|        }
  958|  8.41M|    }
  959|       |
  960|  80.4k|    input.fastUnread(!this->in_token && !this->before_token);
  ------------------
  |  Branch (960:22): [True: 48.7k, False: 31.6k]
  |  Branch (960:41): [True: 48.7k, False: 0]
  ------------------
  961|       |
  962|  80.4k|    if (this->type != tt_eof) {
  ------------------
  |  Branch (962:9): [True: 80.4k, False: 0]
  ------------------
  963|  80.4k|        input.setLastOffset(offset);
  964|  80.4k|    }
  965|       |
  966|  80.4k|    return this->error_message.empty();
  967|  80.4k|}
QPDFTokenizer.cc:_ZL12is_delimiterc:
   18|  8.24M|{
   19|  8.24M|    return (
   20|  8.24M|        ch == ' ' || ch == '\n' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
  ------------------
  |  Branch (20:9): [True: 20.0k, False: 8.22M]
  |  Branch (20:22): [True: 28.1k, False: 8.19M]
  |  Branch (20:36): [True: 30, False: 8.19M]
  |  Branch (20:49): [True: 7, False: 8.19M]
  |  Branch (20:62): [True: 6, False: 8.19M]
  |  Branch (20:75): [True: 5, False: 8.19M]
  |  Branch (20:88): [True: 3, False: 8.19M]
  ------------------
   21|  8.24M|        ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch == '\t' || ch == '\r' ||
  ------------------
  |  Branch (21:9): [True: 1, False: 8.19M]
  |  Branch (21:22): [True: 6, False: 8.19M]
  |  Branch (21:35): [True: 6, False: 8.19M]
  |  Branch (21:48): [True: 5, False: 8.19M]
  |  Branch (21:61): [True: 3, False: 8.19M]
  |  Branch (21:74): [True: 200, False: 8.19M]
  |  Branch (21:88): [True: 198, False: 8.19M]
  ------------------
   22|  8.24M|        ch == '\v' || ch == '\f' || ch == 0);
  ------------------
  |  Branch (22:9): [True: 196, False: 8.19M]
  |  Branch (22:23): [True: 18.5k, False: 8.17M]
  |  Branch (22:37): [True: 1, False: 8.17M]
  ------------------
   23|  8.24M|}

_ZN9QPDFValue9do_createEPS_:
    7|  2.44M|{
    8|  2.44M|    std::shared_ptr<QPDFObject> obj(new QPDFObject());
    9|  2.44M|    obj->value = std::shared_ptr<QPDFValue>(object);
   10|  2.44M|    return obj;
   11|  2.44M|}
_ZN9QPDFValue14getDescriptionEv:
   15|  4.07k|{
   16|  4.07k|    if (object_description) {
  ------------------
  |  Branch (16:9): [True: 4.07k, False: 0]
  ------------------
   17|  4.07k|        switch (object_description->index()) {
  ------------------
  |  Branch (17:17): [True: 0, False: 4.07k]
  ------------------
   18|  4.07k|        case 0:
  ------------------
  |  Branch (18:9): [True: 4.07k, False: 0]
  ------------------
   19|  4.07k|            {
   20|       |                // Simple template string
   21|  4.07k|                auto description = std::get<0>(*object_description);
   22|       |
   23|  4.07k|                if (auto pos = description.find("$OG"); pos != std::string::npos) {
  ------------------
  |  Branch (23:57): [True: 0, False: 4.07k]
  ------------------
   24|      0|                    description.replace(pos, 3, og.unparse(' '));
   25|      0|                }
   26|  4.07k|                if (auto pos = description.find("$PO"); pos != std::string::npos) {
  ------------------
  |  Branch (26:57): [True: 0, False: 4.07k]
  ------------------
   27|      0|                    qpdf_offset_t shift = (type_code == ::ot_dictionary) ? 2
  ------------------
  |  Branch (27:43): [True: 0, False: 0]
  ------------------
   28|      0|                        : (type_code == ::ot_array)                      ? 1
  ------------------
  |  Branch (28:27): [True: 0, False: 0]
  ------------------
   29|      0|                                                                         : 0;
   30|       |
   31|      0|                    description.replace(pos, 3, std::to_string(parsed_offset + shift));
   32|      0|                }
   33|  4.07k|                return description;
   34|      0|            }
   35|      0|        case 1:
  ------------------
  |  Branch (35:9): [True: 0, False: 4.07k]
  ------------------
   36|      0|            {
   37|       |                // QPDF::JSONReactor generated description
   38|      0|                auto j_descr = std::get<1>(*object_description);
   39|      0|                return (
   40|      0|                    *j_descr.input + (j_descr.object.empty() ? "" : ", " + j_descr.object) +
  ------------------
  |  Branch (40:39): [True: 0, False: 0]
  ------------------
   41|      0|                    " at offset " + std::to_string(parsed_offset));
   42|      0|            }
   43|      0|        case 2:
  ------------------
  |  Branch (43:9): [True: 0, False: 4.07k]
  ------------------
   44|      0|            {
   45|       |                // Child object description
   46|      0|                auto j_descr = std::get<2>(*object_description);
   47|      0|                std::string result;
   48|      0|                if (auto p = j_descr.parent.lock()) {
  ------------------
  |  Branch (48:26): [True: 0, False: 0]
  ------------------
   49|      0|                    result = p->getDescription();
   50|      0|                }
   51|      0|                result += j_descr.static_descr;
   52|      0|                if (auto pos = result.find("$VD"); pos != std::string::npos) {
  ------------------
  |  Branch (52:52): [True: 0, False: 0]
  ------------------
   53|      0|                    result.replace(pos, 3, j_descr.var_descr);
   54|      0|                }
   55|      0|                return result;
   56|      0|            }
   57|  4.07k|        }
   58|  4.07k|    } else if (og.isIndirect()) {
  ------------------
  |  Branch (58:16): [True: 0, False: 0]
  ------------------
   59|      0|        return "object " + og.unparse(' ');
   60|      0|    }
   61|      0|    return {};
   62|  4.07k|}

_ZN10QPDF_ArrayC2ERKNSt3__16vectorI16QPDFObjectHandleNS0_9allocatorIS2_EEEE:
   41|  18.5k|{
   42|  18.5k|    setFromVector(v);
   43|  18.5k|}
_ZN10QPDF_Array6createERKNSt3__16vectorI16QPDFObjectHandleNS0_9allocatorIS2_EEEE:
   63|  18.5k|{
   64|  18.5k|    return do_create(new QPDF_Array(items));
   65|  18.5k|}
_ZN10QPDF_Array10disconnectEv:
  105|  13.5k|{
  106|  13.5k|    if (sp) {
  ------------------
  |  Branch (106:9): [True: 0, False: 13.5k]
  ------------------
  107|      0|        for (auto& item: sp->elements) {
  ------------------
  |  Branch (107:24): [True: 0, False: 0]
  ------------------
  108|      0|            auto& obj = item.second;
  109|      0|            if (!obj->getObjGen().isIndirect()) {
  ------------------
  |  Branch (109:17): [True: 0, False: 0]
  ------------------
  110|      0|                obj->disconnect();
  111|      0|            }
  112|      0|        }
  113|  13.5k|    } else {
  114|  2.50M|        for (auto& obj: elements) {
  ------------------
  |  Branch (114:23): [True: 2.50M, False: 13.5k]
  ------------------
  115|  2.50M|            if (!obj->getObjGen().isIndirect()) {
  ------------------
  |  Branch (115:17): [True: 2.36M, False: 146k]
  ------------------
  116|  2.36M|                obj->disconnect();
  117|  2.36M|            }
  118|  2.50M|        }
  119|  13.5k|    }
  120|  13.5k|}
_ZN10QPDF_Array13setFromVectorERKNSt3__16vectorI16QPDFObjectHandleNS0_9allocatorIS2_EEEE:
  234|  18.5k|{
  235|  18.5k|    elements.resize(0);
  236|  18.5k|    elements.reserve(v.size());
  237|  18.5k|    for (auto const& item: v) {
  ------------------
  |  Branch (237:26): [True: 0, False: 18.5k]
  ------------------
  238|      0|        checkOwnership(item);
  239|      0|        elements.push_back(item.getObj());
  240|      0|    }
  241|  18.5k|}
_ZN10QPDF_Array9push_backERK16QPDFObjectHandle:
  277|  2.57M|{
  278|  2.57M|    checkOwnership(item);
  279|  2.57M|    if (sp) {
  ------------------
  |  Branch (279:9): [True: 0, False: 2.57M]
  ------------------
  280|      0|        sp->elements[(sp->size)++] = item.getObj();
  281|  2.57M|    } else {
  282|  2.57M|        elements.push_back(item.getObj());
  283|  2.57M|    }
  284|  2.57M|}
_ZNK10QPDF_Array14checkOwnershipERK16QPDFObjectHandle:
   12|  2.57M|{
   13|  2.57M|    if (auto obj = item.getObjectPtr()) {
  ------------------
  |  Branch (13:14): [True: 2.57M, False: 0]
  ------------------
   14|  2.57M|        if (qpdf) {
  ------------------
  |  Branch (14:13): [True: 2.57M, False: 0]
  ------------------
   15|  2.57M|            if (auto item_qpdf = obj->getQPDF()) {
  ------------------
  |  Branch (15:22): [True: 2.56M, False: 5.81k]
  ------------------
   16|  2.56M|                if (qpdf != item_qpdf) {
  ------------------
  |  Branch (16:21): [True: 0, False: 2.56M]
  ------------------
   17|      0|                    throw std::logic_error(
   18|      0|                        "Attempting to add an object from a different QPDF. Use "
   19|      0|                        "QPDF::copyForeignObject to add objects from another file.");
   20|      0|                }
   21|  2.56M|            }
   22|  2.57M|        }
   23|  2.57M|    } else {
   24|      0|        throw std::logic_error("Attempting to add an uninitialized object to a QPDF_Array.");
   25|      0|    }
   26|  2.57M|}

_ZN9QPDF_BoolC2Eb:
    8|    391|{
    9|    391|}
_ZN9QPDF_Bool6createEb:
   13|    391|{
   14|    391|    return do_create(new QPDF_Bool(value));
   15|    391|}

_ZN14QPDF_DestroyedC2Ev:
    7|      1|{
    8|      1|}
_ZN14QPDF_Destroyed11getInstanceEv:
   12|  10.7k|{
   13|  10.7k|    static std::shared_ptr<QPDFValue> instance(new QPDF_Destroyed());
   14|  10.7k|    return instance;
   15|  10.7k|}

_ZN15QPDF_DictionaryC2ERKNSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE16QPDFObjectHandleNS0_4lessIS7_EENS5_INS0_4pairIKS7_S8_EEEEEE:
   14|  44.3k|{
   15|  44.3k|}
_ZN15QPDF_Dictionary6createERKNSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE16QPDFObjectHandleNS0_4lessIS7_EENS5_INS0_4pairIKS7_S8_EEEEEE:
   25|  37.8k|{
   26|  37.8k|    return do_create(new QPDF_Dictionary(items));
   27|  37.8k|}
_ZN15QPDF_Dictionary6createEONSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE16QPDFObjectHandleNS0_4lessIS7_EENS5_INS0_4pairIKS7_S8_EEEEEE:
   31|  6.52k|{
   32|  6.52k|    return do_create(new QPDF_Dictionary(items));
   33|  6.52k|}
_ZN15QPDF_Dictionary10disconnectEv:
   52|  21.5k|{
   53|  80.8k|    for (auto& iter: this->items) {
  ------------------
  |  Branch (53:20): [True: 80.8k, False: 21.5k]
  ------------------
   54|  80.8k|        QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
   55|  80.8k|    }
   56|  21.5k|}
_ZN15QPDF_Dictionary6hasKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   99|  26.1k|{
  100|  26.1k|    return ((this->items.count(key) > 0) && (!this->items[key].isNull()));
  ------------------
  |  Branch (100:13): [True: 6.52k, False: 19.5k]
  |  Branch (100:45): [True: 6.52k, False: 0]
  ------------------
  101|  26.1k|}
_ZN15QPDF_Dictionary6getKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  105|  13.0k|{
  106|       |    // PDF spec says fetching a non-existent key from a dictionary returns the null object.
  107|  13.0k|    auto item = this->items.find(key);
  108|  13.0k|    if (item != this->items.end()) {
  ------------------
  |  Branch (108:9): [True: 13.0k, False: 0]
  ------------------
  109|       |        // May be a null object
  110|  13.0k|        return item->second;
  111|  13.0k|    } else {
  112|      0|        static auto constexpr msg = " -> dictionary key $VD"sv;
  113|      0|        return QPDF_Null::create(shared_from_this(), msg, key);
  114|      0|    }
  115|  13.0k|}
_ZN15QPDF_Dictionary10replaceKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE16QPDFObjectHandle:
  137|   135k|{
  138|   135k|    if (value.isNull() && !value.isIndirect()) {
  ------------------
  |  Branch (138:9): [True: 52.0k, False: 83.7k]
  |  Branch (138:27): [True: 15.5k, False: 36.4k]
  ------------------
  139|       |        // The PDF spec doesn't distinguish between keys with null values and missing keys. Allow
  140|       |        // indirect nulls which are equivalent to a dangling reference, which is permitted by the
  141|       |        // spec.
  142|  15.5k|        removeKey(key);
  143|   120k|    } else {
  144|       |        // add or replace value
  145|   120k|        this->items[key] = value;
  146|   120k|    }
  147|   135k|}
_ZN15QPDF_Dictionary9removeKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  151|  19.4k|{
  152|       |    // no-op if key does not exist
  153|  19.4k|    this->items.erase(key);
  154|  19.4k|}

_ZN12QPDF_IntegerC2Ex:
    9|  2.27M|{
   10|  2.27M|}
_ZN12QPDF_Integer6createEx:
   14|  2.27M|{
   15|  2.27M|    return do_create(new QPDF_Integer(value));
   16|  2.27M|}
_ZNK12QPDF_Integer6getValEv:
   38|  6.52k|{
   39|  6.52k|    return this->val;
   40|  6.52k|}

_ZN9QPDF_NameC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
    9|  43.6k|{
   10|  43.6k|}
_ZN9QPDF_Name6createERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   14|  43.6k|{
   15|  43.6k|    return do_create(new QPDF_Name(name));
   16|  43.6k|}

_ZN9QPDF_NullC2EP4QPDF10QPDFObjGen:
    8|  44.9k|{
    9|  44.9k|}
_ZN9QPDF_Null6createEP4QPDF10QPDFObjGen:
   13|  44.9k|{
   14|  44.9k|    return do_create(new QPDF_Null(qpdf, og));
   15|  44.9k|}

_ZN9QPDF_RealC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
    9|  5.21k|{
   10|  5.21k|}
_ZN9QPDF_Real6createERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   20|  5.21k|{
   21|  5.21k|    return do_create(new QPDF_Real(val));
   22|  5.21k|}

_ZN11QPDF_StreamC2EP4QPDFRK10QPDFObjGen16QPDFObjectHandlexm:
  119|  4.07k|{
  120|  4.07k|    if (!stream_dict.isDictionary()) {
  ------------------
  |  Branch (120:9): [True: 0, False: 4.07k]
  ------------------
  121|      0|        throw std::logic_error(
  122|      0|            "stream object instantiated with non-dictionary object for dictionary");
  123|      0|    }
  124|  4.07k|    auto descr = std::make_shared<QPDFValue::Description>(
  125|  4.07k|        qpdf->getFilename() + ", stream object " + og.unparse(' '));
  126|  4.07k|    setDescription(qpdf, descr, offset);
  127|  4.07k|}
_ZN11QPDF_Stream6createEP4QPDFRK10QPDFObjGen16QPDFObjectHandlexm:
  136|  4.07k|{
  137|  4.07k|    return do_create(new QPDF_Stream(qpdf, og, stream_dict, offset, length));
  138|  4.07k|}
_ZN11QPDF_Stream10disconnectEv:
  168|  4.04k|{
  169|  4.04k|    this->stream_provider = nullptr;
  170|  4.04k|    QPDFObjectHandle::DisconnectAccess::disconnect(this->stream_dict);
  171|  4.04k|}
_ZN11QPDF_Stream14setDescriptionEP4QPDFRNSt3__110shared_ptrINS2_7variantIJNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEN9QPDFValue10JSON_DescrENSB_10ChildDescrEEEEEEx:
  301|  8.14k|{
  302|  8.14k|    this->QPDFValue::setDescription(qpdf, description, offset);
  303|  8.14k|    setDictDescription();
  304|  8.14k|}
_ZN11QPDF_Stream18setDictDescriptionEv:
  308|  11.5k|{
  309|  11.5k|    if (!this->stream_dict.hasObjectDescription()) {
  ------------------
  |  Branch (309:9): [True: 4.07k, False: 7.51k]
  ------------------
  310|  4.07k|        this->stream_dict.setObjectDescription(qpdf, getDescription() + " -> stream dictionary");
  311|  4.07k|    }
  312|  11.5k|}
_ZN11QPDF_Stream17replaceStreamDataENSt3__110shared_ptrI6BufferEERK16QPDFObjectHandleS6_:
  645|    122|{
  646|    122|    this->stream_data = data;
  647|    122|    this->stream_provider = nullptr;
  648|    122|    replaceFilterData(filter, decode_parms, data->getSize());
  649|    122|}
_ZN11QPDF_Stream17replaceStreamDataENSt3__110shared_ptrIN16QPDFObjectHandle18StreamDataProviderEEERKS2_S6_:
  656|  3.78k|{
  657|  3.78k|    this->stream_provider = provider;
  658|  3.78k|    this->stream_data = nullptr;
  659|  3.78k|    replaceFilterData(filter, decode_parms, 0);
  660|  3.78k|}
_ZN11QPDF_Stream17replaceFilterDataERK16QPDFObjectHandleS2_m:
  671|  3.90k|{
  672|  3.90k|    if (filter.isInitialized()) {
  ------------------
  |  Branch (672:9): [True: 0, False: 3.90k]
  ------------------
  673|      0|        this->stream_dict.replaceKey("/Filter", filter);
  674|      0|    }
  675|  3.90k|    if (decode_parms.isInitialized()) {
  ------------------
  |  Branch (675:9): [True: 0, False: 3.90k]
  ------------------
  676|      0|        this->stream_dict.replaceKey("/DecodeParms", decode_parms);
  677|      0|    }
  678|  3.90k|    if (length == 0) {
  ------------------
  |  Branch (678:9): [True: 3.90k, False: 0]
  ------------------
  679|  3.90k|        QTC::TC("qpdf", "QPDF_Stream unknown stream length");
  680|  3.90k|        this->stream_dict.removeKey("/Length");
  681|  3.90k|    } else {
  682|      0|        this->stream_dict.replaceKey(
  683|      0|            "/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length)));
  684|      0|    }
  685|  3.90k|}
_ZN11QPDF_Stream11replaceDictERK16QPDFObjectHandle:
  689|  3.44k|{
  690|  3.44k|    this->stream_dict = new_dict;
  691|  3.44k|    setDictDescription();
  692|  3.44k|}

_ZN11QPDF_StringC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   18|  8.40k|{
   19|  8.40k|}
_ZN11QPDF_String6createERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   23|  1.85k|{
   24|  1.85k|    return do_create(new QPDF_String(val));
   25|  1.85k|}
_ZN11QPDF_String12create_utf16ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   29|  6.55k|{
   30|  6.55k|    std::string result;
   31|  6.55k|    if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) {
  ------------------
  |  Branch (31:9): [True: 4.14k, False: 2.40k]
  ------------------
   32|  4.14k|        result = QUtil::utf8_to_utf16(utf8_val);
   33|  4.14k|    }
   34|  6.55k|    return do_create(new QPDF_String(result));
   35|  6.55k|}

_ZN4QPDF20initializeEncryptionEv:
  720|  6.52k|{
  721|  6.52k|    if (m->encp->encryption_initialized) {
  ------------------
  |  Branch (721:9): [True: 0, False: 6.52k]
  ------------------
  722|      0|        return;
  723|      0|    }
  724|  6.52k|    m->encp->encryption_initialized = true;
  725|       |
  726|       |    // After we initialize encryption parameters, we must use stored key information and never look
  727|       |    // at /Encrypt again.  Otherwise, things could go wrong if someone mutates the encryption
  728|       |    // dictionary.
  729|       |
  730|  6.52k|    if (!m->trailer.hasKey("/Encrypt")) {
  ------------------
  |  Branch (730:9): [True: 6.52k, False: 0]
  ------------------
  731|  6.52k|        return;
  732|  6.52k|    }
  733|       |
  734|       |    // Go ahead and set m->encrypted here.  That way, isEncrypted will return true even if there
  735|       |    // were errors reading the encryption dictionary.
  736|      0|    m->encp->encrypted = true;
  737|       |
  738|      0|    std::string id1;
  739|      0|    QPDFObjectHandle id_obj = m->trailer.getKey("/ID");
  740|      0|    if ((id_obj.isArray() && (id_obj.getArrayNItems() == 2) && id_obj.getArrayItem(0).isString())) {
  ------------------
  |  Branch (740:9): [True: 0, False: 0]
  |  Branch (740:10): [True: 0, False: 0]
  |  Branch (740:30): [True: 0, False: 0]
  |  Branch (740:64): [True: 0, False: 0]
  ------------------
  741|      0|        id1 = id_obj.getArrayItem(0).getStringValue();
  742|      0|    } else {
  743|       |        // Treating a missing ID as the empty string enables qpdf to decrypt some invalid encrypted
  744|       |        // files with no /ID that poppler can read but Adobe Reader can't.
  745|      0|        warn(damagedPDF("trailer", "invalid /ID in trailer dictionary"));
  746|      0|    }
  747|       |
  748|      0|    QPDFObjectHandle encryption_dict = m->trailer.getKey("/Encrypt");
  749|      0|    if (!encryption_dict.isDictionary()) {
  ------------------
  |  Branch (749:9): [True: 0, False: 0]
  ------------------
  750|      0|        throw damagedPDF("/Encrypt in trailer dictionary is not a dictionary");
  751|      0|    }
  752|       |
  753|      0|    if (!(encryption_dict.getKey("/Filter").isName() &&
  ------------------
  |  Branch (753:9): [True: 0, False: 0]
  |  Branch (753:11): [True: 0, False: 0]
  ------------------
  754|      0|          (encryption_dict.getKey("/Filter").getName() == "/Standard"))) {
  ------------------
  |  Branch (754:11): [True: 0, False: 0]
  ------------------
  755|      0|        throw QPDFExc(
  756|      0|            qpdf_e_unsupported,
  757|      0|            m->file->getName(),
  758|      0|            "encryption dictionary",
  759|      0|            m->file->getLastOffset(),
  760|      0|            "unsupported encryption filter");
  761|      0|    }
  762|      0|    if (!encryption_dict.getKey("/SubFilter").isNull()) {
  ------------------
  |  Branch (762:9): [True: 0, False: 0]
  ------------------
  763|      0|        warn(
  764|      0|            qpdf_e_unsupported,
  765|      0|            "encryption dictionary",
  766|      0|            m->file->getLastOffset(),
  767|      0|            "file uses encryption SubFilters, which qpdf does not support");
  768|      0|    }
  769|       |
  770|      0|    if (!(encryption_dict.getKey("/V").isInteger() && encryption_dict.getKey("/R").isInteger() &&
  ------------------
  |  Branch (770:9): [True: 0, False: 0]
  |  Branch (770:11): [True: 0, False: 0]
  |  Branch (770:55): [True: 0, False: 0]
  ------------------
  771|      0|          encryption_dict.getKey("/O").isString() && encryption_dict.getKey("/U").isString() &&
  ------------------
  |  Branch (771:11): [True: 0, False: 0]
  |  Branch (771:54): [True: 0, False: 0]
  ------------------
  772|      0|          encryption_dict.getKey("/P").isInteger())) {
  ------------------
  |  Branch (772:11): [True: 0, False: 0]
  ------------------
  773|      0|        throw damagedPDF(
  774|      0|            "encryption dictionary",
  775|      0|            "some encryption dictionary parameters are missing or the wrong "
  776|      0|            "type");
  777|      0|    }
  778|       |
  779|      0|    int V = encryption_dict.getKey("/V").getIntValueAsInt();
  780|      0|    int R = encryption_dict.getKey("/R").getIntValueAsInt();
  781|      0|    std::string O = encryption_dict.getKey("/O").getStringValue();
  782|      0|    std::string U = encryption_dict.getKey("/U").getStringValue();
  783|      0|    int P = static_cast<int>(encryption_dict.getKey("/P").getIntValue());
  784|       |
  785|       |    // If supporting new encryption R/V values, remember to update error message inside this if
  786|       |    // statement.
  787|      0|    if (!(((R >= 2) && (R <= 6)) && ((V == 1) || (V == 2) || (V == 4) || (V == 5)))) {
  ------------------
  |  Branch (787:12): [True: 0, False: 0]
  |  Branch (787:24): [True: 0, False: 0]
  |  Branch (787:38): [True: 0, False: 0]
  |  Branch (787:50): [True: 0, False: 0]
  |  Branch (787:62): [True: 0, False: 0]
  |  Branch (787:74): [True: 0, False: 0]
  ------------------
  788|      0|        throw QPDFExc(
  789|      0|            qpdf_e_unsupported,
  790|      0|            m->file->getName(),
  791|      0|            "encryption dictionary",
  792|      0|            m->file->getLastOffset(),
  793|      0|            "Unsupported /R or /V in encryption dictionary; R = " + std::to_string(R) +
  794|      0|                " (max 6), V = " + std::to_string(V) + " (max 5)");
  795|      0|    }
  796|       |
  797|      0|    m->encp->encryption_V = V;
  798|      0|    m->encp->encryption_R = R;
  799|       |
  800|       |    // OE, UE, and Perms are only present if V >= 5.
  801|      0|    std::string OE;
  802|      0|    std::string UE;
  803|      0|    std::string Perms;
  804|       |
  805|      0|    if (V < 5) {
  ------------------
  |  Branch (805:9): [True: 0, False: 0]
  ------------------
  806|       |        // These must be exactly the right number of bytes.
  807|      0|        pad_short_parameter(O, key_bytes);
  808|      0|        pad_short_parameter(U, key_bytes);
  809|      0|        if (!((O.length() == key_bytes) && (U.length() == key_bytes))) {
  ------------------
  |  Branch (809:15): [True: 0, False: 0]
  |  Branch (809:44): [True: 0, False: 0]
  ------------------
  810|      0|            throw damagedPDF(
  811|      0|                "encryption dictionary",
  812|      0|                "incorrect length for /O and/or /U in encryption dictionary");
  813|      0|        }
  814|      0|    } else {
  815|      0|        if (!(encryption_dict.getKey("/OE").isString() &&
  ------------------
  |  Branch (815:13): [True: 0, False: 0]
  |  Branch (815:15): [True: 0, False: 0]
  ------------------
  816|      0|              encryption_dict.getKey("/UE").isString() &&
  ------------------
  |  Branch (816:15): [True: 0, False: 0]
  ------------------
  817|      0|              encryption_dict.getKey("/Perms").isString())) {
  ------------------
  |  Branch (817:15): [True: 0, False: 0]
  ------------------
  818|      0|            throw damagedPDF(
  819|      0|                "encryption dictionary",
  820|      0|                "some V=5 encryption dictionary parameters are missing or the "
  821|      0|                "wrong type");
  822|      0|        }
  823|      0|        OE = encryption_dict.getKey("/OE").getStringValue();
  824|      0|        UE = encryption_dict.getKey("/UE").getStringValue();
  825|      0|        Perms = encryption_dict.getKey("/Perms").getStringValue();
  826|       |
  827|       |        // These may be longer than the minimum number of bytes.
  828|      0|        pad_short_parameter(O, OU_key_bytes_V5);
  829|      0|        pad_short_parameter(U, OU_key_bytes_V5);
  830|      0|        pad_short_parameter(OE, OUE_key_bytes_V5);
  831|      0|        pad_short_parameter(UE, OUE_key_bytes_V5);
  832|      0|        pad_short_parameter(Perms, Perms_key_bytes_V5);
  833|      0|    }
  834|       |
  835|      0|    int Length = 0;
  836|      0|    if (V <= 1) {
  ------------------
  |  Branch (836:9): [True: 0, False: 0]
  ------------------
  837|      0|        Length = 40;
  838|      0|    } else if (V == 4) {
  ------------------
  |  Branch (838:16): [True: 0, False: 0]
  ------------------
  839|      0|        Length = 128;
  840|      0|    } else if (V == 5) {
  ------------------
  |  Branch (840:16): [True: 0, False: 0]
  ------------------
  841|      0|        Length = 256;
  842|      0|    } else {
  843|      0|        if (encryption_dict.getKey("/Length").isInteger()) {
  ------------------
  |  Branch (843:13): [True: 0, False: 0]
  ------------------
  844|      0|            Length = encryption_dict.getKey("/Length").getIntValueAsInt();
  845|      0|            if ((Length % 8) || (Length < 40) || (Length > 128)) {
  ------------------
  |  Branch (845:17): [True: 0, False: 0]
  |  Branch (845:33): [True: 0, False: 0]
  |  Branch (845:50): [True: 0, False: 0]
  ------------------
  846|      0|                Length = 0;
  847|      0|            }
  848|      0|        }
  849|      0|    }
  850|      0|    if (Length == 0) {
  ------------------
  |  Branch (850:9): [True: 0, False: 0]
  ------------------
  851|       |        // Still no Length? Just take a guess.
  852|      0|        Length = 128;
  853|      0|    }
  854|       |
  855|      0|    m->encp->encrypt_metadata = true;
  856|      0|    if ((V >= 4) && (encryption_dict.getKey("/EncryptMetadata").isBool())) {
  ------------------
  |  Branch (856:9): [True: 0, False: 0]
  |  Branch (856:9): [True: 0, False: 0]
  |  Branch (856:21): [True: 0, False: 0]
  ------------------
  857|      0|        m->encp->encrypt_metadata = encryption_dict.getKey("/EncryptMetadata").getBoolValue();
  858|      0|    }
  859|       |
  860|      0|    if ((V == 4) || (V == 5)) {
  ------------------
  |  Branch (860:9): [True: 0, False: 0]
  |  Branch (860:21): [True: 0, False: 0]
  ------------------
  861|      0|        QPDFObjectHandle CF = encryption_dict.getKey("/CF");
  862|      0|        for (auto const& filter: CF.getKeys()) {
  ------------------
  |  Branch (862:32): [True: 0, False: 0]
  ------------------
  863|      0|            QPDFObjectHandle cdict = CF.getKey(filter);
  864|      0|            if (cdict.isDictionary()) {
  ------------------
  |  Branch (864:17): [True: 0, False: 0]
  ------------------
  865|      0|                encryption_method_e method = e_none;
  866|      0|                if (cdict.getKey("/CFM").isName()) {
  ------------------
  |  Branch (866:21): [True: 0, False: 0]
  ------------------
  867|      0|                    std::string method_name = cdict.getKey("/CFM").getName();
  868|      0|                    if (method_name == "/V2") {
  ------------------
  |  Branch (868:25): [True: 0, False: 0]
  ------------------
  869|      0|                        QTC::TC("qpdf", "QPDF_encryption CFM V2");
  870|      0|                        method = e_rc4;
  871|      0|                    } else if (method_name == "/AESV2") {
  ------------------
  |  Branch (871:32): [True: 0, False: 0]
  ------------------
  872|      0|                        QTC::TC("qpdf", "QPDF_encryption CFM AESV2");
  873|      0|                        method = e_aes;
  874|      0|                    } else if (method_name == "/AESV3") {
  ------------------
  |  Branch (874:32): [True: 0, False: 0]
  ------------------
  875|      0|                        QTC::TC("qpdf", "QPDF_encryption CFM AESV3");
  876|      0|                        method = e_aesv3;
  877|      0|                    } else {
  878|       |                        // Don't complain now -- maybe we won't need to reference this type.
  879|      0|                        method = e_unknown;
  880|      0|                    }
  881|      0|                }
  882|      0|                m->encp->crypt_filters[filter] = method;
  883|      0|            }
  884|      0|        }
  885|       |
  886|      0|        QPDFObjectHandle StmF = encryption_dict.getKey("/StmF");
  887|      0|        QPDFObjectHandle StrF = encryption_dict.getKey("/StrF");
  888|      0|        QPDFObjectHandle EFF = encryption_dict.getKey("/EFF");
  889|      0|        m->encp->cf_stream = interpretCF(m->encp, StmF);
  890|      0|        m->encp->cf_string = interpretCF(m->encp, StrF);
  891|      0|        if (EFF.isName()) {
  ------------------
  |  Branch (891:13): [True: 0, False: 0]
  ------------------
  892|       |            // qpdf does not use this for anything other than informational purposes. This is
  893|       |            // intended to instruct conforming writers on which crypt filter should be used when new
  894|       |            // file attachments are added to a PDF file, but qpdf never generates encrypted files
  895|       |            // with non-default crypt filters. Prior to 10.2, I was under the mistaken impression
  896|       |            // that this was supposed to be used for decrypting attachments, but the code was wrong
  897|       |            // in a way that turns out not to have mattered because no writers were generating files
  898|       |            // the way I was imagining. Still, providing this information could be useful when
  899|       |            // looking at a file generated by something else, such as Acrobat when specifying that
  900|       |            // only attachments should be encrypted.
  901|      0|            m->encp->cf_file = interpretCF(m->encp, EFF);
  902|      0|        } else {
  903|      0|            m->encp->cf_file = m->encp->cf_stream;
  904|      0|        }
  905|      0|    }
  906|       |
  907|      0|    EncryptionData data(V, R, Length / 8, P, O, U, OE, UE, Perms, id1, m->encp->encrypt_metadata);
  908|      0|    if (m->provided_password_is_hex_key) {
  ------------------
  |  Branch (908:9): [True: 0, False: 0]
  ------------------
  909|       |        // ignore passwords in file
  910|      0|    } else {
  911|      0|        m->encp->owner_password_matched =
  912|      0|            check_owner_password(m->encp->user_password, m->encp->provided_password, data);
  913|      0|        if (m->encp->owner_password_matched && (V < 5)) {
  ------------------
  |  Branch (913:13): [True: 0, False: 0]
  |  Branch (913:48): [True: 0, False: 0]
  ------------------
  914|       |            // password supplied was owner password; user_password has been initialized for V < 5
  915|      0|            if (getTrimmedUserPassword() == m->encp->provided_password) {
  ------------------
  |  Branch (915:17): [True: 0, False: 0]
  ------------------
  916|      0|                m->encp->user_password_matched = true;
  917|      0|                QTC::TC("qpdf", "QPDF_encryption user matches owner V < 5");
  918|      0|            }
  919|      0|        } else {
  920|      0|            m->encp->user_password_matched = check_user_password(m->encp->provided_password, data);
  921|      0|            if (m->encp->user_password_matched) {
  ------------------
  |  Branch (921:17): [True: 0, False: 0]
  ------------------
  922|      0|                m->encp->user_password = m->encp->provided_password;
  923|      0|            }
  924|      0|        }
  925|      0|        if (m->encp->user_password_matched && m->encp->owner_password_matched) {
  ------------------
  |  Branch (925:13): [True: 0, False: 0]
  |  Branch (925:47): [True: 0, False: 0]
  ------------------
  926|      0|            QTC::TC("qpdf", "QPDF_encryption same password", (V < 5) ? 0 : 1);
  ------------------
  |  Branch (926:62): [True: 0, False: 0]
  ------------------
  927|      0|        }
  928|      0|        if (!(m->encp->owner_password_matched || m->encp->user_password_matched)) {
  ------------------
  |  Branch (928:15): [True: 0, False: 0]
  |  Branch (928:50): [True: 0, False: 0]
  ------------------
  929|      0|            throw QPDFExc(qpdf_e_password, m->file->getName(), "", 0, "invalid password");
  930|      0|        }
  931|      0|    }
  932|       |
  933|      0|    if (m->provided_password_is_hex_key) {
  ------------------
  |  Branch (933:9): [True: 0, False: 0]
  ------------------
  934|      0|        m->encp->encryption_key = QUtil::hex_decode(m->encp->provided_password);
  935|      0|    } else if (V < 5) {
  ------------------
  |  Branch (935:16): [True: 0, False: 0]
  ------------------
  936|       |        // For V < 5, the user password is encrypted with the owner password, and the user password
  937|       |        // is always used for computing the encryption key.
  938|      0|        m->encp->encryption_key = compute_encryption_key(m->encp->user_password, data);
  939|      0|    } else {
  940|       |        // For V >= 5, either password can be used independently to compute the encryption key, and
  941|       |        // neither password can be used to recover the other.
  942|      0|        bool perms_valid;
  943|      0|        m->encp->encryption_key =
  944|      0|            recover_encryption_key_with_password(m->encp->provided_password, data, perms_valid);
  945|      0|        if (!perms_valid) {
  ------------------
  |  Branch (945:13): [True: 0, False: 0]
  ------------------
  946|      0|            warn(damagedPDF(
  947|      0|                "encryption dictionary",
  948|      0|                "/Perms field in encryption dictionary doesn't match expected "
  949|      0|                "value"));
  950|      0|        }
  951|      0|    }
  952|      0|}

_ZN4QPDF11JSONReactor5errorExRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  310|  39.6k|{
  311|  39.6k|    errors = true;
  312|  39.6k|    std::string object = this->cur_object;
  313|  39.6k|    if (is->getName() != pdf.getFilename()) {
  ------------------
  |  Branch (313:9): [True: 0, False: 39.6k]
  ------------------
  314|      0|        object += " from " + is->getName();
  315|      0|    }
  316|  39.6k|    pdf.warn(qpdf_e_json, object, offset, msg);
  317|  39.6k|}
_ZNK4QPDF11JSONReactor9anyErrorsEv:
  321|     35|{
  322|     35|    return errors;
  323|     35|}
_ZN4QPDF11JSONReactor14containerStartEv:
  327|  94.3k|{
  328|  94.3k|    if (next_obj.isInitialized()) {
  ------------------
  |  Branch (328:9): [True: 68.3k, False: 26.0k]
  ------------------
  329|  68.3k|        stack.emplace_back(next_state, std::move(next_obj));
  330|  68.3k|        next_obj = QPDFObjectHandle();
  331|  68.3k|    } else {
  332|  26.0k|        stack.emplace_back(next_state);
  333|  26.0k|    }
  334|  94.3k|}
_ZN4QPDF11JSONReactor15dictionaryStartEv:
  338|  67.3k|{
  339|  67.3k|    containerStart();
  340|  67.3k|}
_ZN4QPDF11JSONReactor10arrayStartEv:
  344|  27.4k|{
  345|  27.4k|    if (stack.empty()) {
  ------------------
  |  Branch (345:9): [True: 407, False: 27.0k]
  ------------------
  346|    407|        QTC::TC("qpdf", "QPDF_json top-level array");
  347|    407|        throw std::runtime_error("QPDF JSON must be a dictionary");
  348|    407|    }
  349|  27.0k|    containerStart();
  350|  27.0k|}
_ZN4QPDF11JSONReactor12containerEndERK4JSON:
  354|  30.9k|{
  355|  30.9k|    auto from_state = stack.back().state;
  356|  30.9k|    stack.pop_back();
  357|  30.9k|    if (stack.empty()) {
  ------------------
  |  Branch (357:9): [True: 41, False: 30.9k]
  ------------------
  358|     41|        if (!this->saw_qpdf) {
  ------------------
  |  Branch (358:13): [True: 17, False: 24]
  ------------------
  359|     17|            QTC::TC("qpdf", "QPDF_json missing qpdf");
  360|     17|            error(0, "\"qpdf\" object was not seen");
  361|     24|        } else {
  362|     24|            if (!this->saw_json_version) {
  ------------------
  |  Branch (362:17): [True: 12, False: 12]
  ------------------
  363|     12|                QTC::TC("qpdf", "QPDF_json missing json version");
  364|     12|                error(0, "\"qpdf[0].jsonversion\" was not seen");
  365|     12|            }
  366|     24|            if (must_be_complete && !this->saw_pdf_version) {
  ------------------
  |  Branch (366:17): [True: 24, False: 0]
  |  Branch (366:37): [True: 12, False: 12]
  ------------------
  367|     12|                QTC::TC("qpdf", "QPDF_json missing pdf version");
  368|     12|                error(0, "\"qpdf[0].pdfversion\" was not seen");
  369|     12|            }
  370|     24|            if (!this->saw_objects) {
  ------------------
  |  Branch (370:17): [True: 4, False: 20]
  ------------------
  371|      4|                QTC::TC("qpdf", "QPDF_json missing objects");
  372|      4|                error(0, "\"qpdf[1]\" was not seen");
  373|     20|            } else {
  374|     20|                if (must_be_complete && !this->saw_trailer) {
  ------------------
  |  Branch (374:21): [True: 20, False: 0]
  |  Branch (374:41): [True: 7, False: 13]
  ------------------
  375|      7|                    QTC::TC("qpdf", "QPDF_json missing trailer");
  376|      7|                    error(0, "\"qpdf[1].trailer\" was not seen");
  377|      7|                }
  378|     20|            }
  379|     24|        }
  380|  30.9k|    } else if (from_state == st_trailer) {
  ------------------
  |  Branch (380:16): [True: 28, False: 30.9k]
  ------------------
  381|     28|        if (!saw_value) {
  ------------------
  |  Branch (381:13): [True: 3, False: 25]
  ------------------
  382|      3|            QTC::TC("qpdf", "QPDF_json trailer no value");
  383|      3|            error(value.getStart(), "\"trailer\" is missing \"value\"");
  384|      3|        }
  385|  30.9k|    } else if (from_state == st_object_top) {
  ------------------
  |  Branch (385:16): [True: 9.43k, False: 21.4k]
  ------------------
  386|  9.43k|        if (saw_value == saw_stream) {
  ------------------
  |  Branch (386:13): [True: 310, False: 9.12k]
  ------------------
  387|    310|            QTC::TC("qpdf", "QPDF_json value stream both or neither");
  388|    310|            error(value.getStart(), "object must have exactly one of \"value\" or \"stream\"");
  389|    310|        }
  390|  9.43k|        if (saw_stream) {
  ------------------
  |  Branch (390:13): [True: 3.95k, False: 5.47k]
  ------------------
  391|  3.95k|            if (!saw_dict) {
  ------------------
  |  Branch (391:17): [True: 518, False: 3.43k]
  ------------------
  392|    518|                QTC::TC("qpdf", "QPDF_json stream no dict");
  393|    518|                error(value.getStart(), "\"stream\" is missing \"dict\"");
  394|    518|            }
  395|  3.95k|            if (saw_data == saw_datafile) {
  ------------------
  |  Branch (395:17): [True: 368, False: 3.58k]
  ------------------
  396|    368|                if (this_stream_needs_data) {
  ------------------
  |  Branch (396:21): [True: 305, False: 63]
  ------------------
  397|    305|                    QTC::TC("qpdf", "QPDF_json data datafile both or neither");
  398|    305|                    error(
  399|    305|                        value.getStart(),
  400|    305|                        "new \"stream\" must have exactly one of \"data\" or "
  401|    305|                        "\"datafile\"");
  402|    305|                } else if (saw_datafile) {
  ------------------
  |  Branch (402:28): [True: 41, False: 22]
  ------------------
  403|     41|                    QTC::TC("qpdf", "QPDF_json data and datafile");
  404|     41|                    error(
  405|     41|                        value.getStart(),
  406|     41|                        "existing \"stream\" may at most one of \"data\" or "
  407|     41|                        "\"datafile\"");
  408|     41|                } else {
  409|     22|                    QTC::TC("qpdf", "QPDF_json no stream data in update mode");
  410|     22|                }
  411|    368|            }
  412|  3.95k|        }
  413|  9.43k|    }
  414|  30.9k|    if (!stack.empty()) {
  ------------------
  |  Branch (414:9): [True: 30.9k, False: 41]
  ------------------
  415|  30.9k|        auto state = stack.back().state;
  416|  30.9k|        if (state == st_objects) {
  ------------------
  |  Branch (416:13): [True: 9.64k, False: 21.2k]
  ------------------
  417|  9.64k|            this->cur_object = "";
  418|  9.64k|            this->saw_dict = false;
  419|  9.64k|            this->saw_data = false;
  420|  9.64k|            this->saw_datafile = false;
  421|  9.64k|            this->saw_value = false;
  422|  9.64k|            this->saw_stream = false;
  423|  9.64k|        }
  424|  30.9k|    }
  425|  30.9k|}
_ZN4QPDF11JSONReactor13replaceObjectEO16QPDFObjectHandleRK4JSON:
  429|  11.1k|{
  430|  11.1k|    if (replacement.isIndirect()) {
  ------------------
  |  Branch (430:9): [True: 116, False: 11.0k]
  ------------------
  431|    116|        error(
  432|    116|            replacement.getParsedOffset(),
  433|    116|            "the value of an object may not be an indirect object reference");
  434|    116|        return;
  435|    116|    }
  436|  11.0k|    auto& tos = stack.back();
  437|  11.0k|    auto og = tos.object.getObjGen();
  438|  11.0k|    this->pdf.replaceObject(og, replacement);
  439|  11.0k|    next_obj = pdf.getObject(og);
  440|  11.0k|    setObjectDescription(tos.object, value);
  441|  11.0k|}
_ZN4QPDF11JSONReactor14topLevelScalarEv:
  445|    238|{
  446|    238|    QTC::TC("qpdf", "QPDF_json top-level scalar");
  447|    238|    throw std::runtime_error("QPDF JSON must be a dictionary");
  448|    238|}
_ZN4QPDF11JSONReactor24setNextStateIfDictionaryERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERK4JSONNS0_7state_eE:
  452|  31.0k|{
  453|       |    // Use this method when the next state is for processing a nested dictionary.
  454|  31.0k|    if (value.isDictionary()) {
  ------------------
  |  Branch (454:9): [True: 29.0k, False: 2.06k]
  ------------------
  455|  29.0k|        this->next_state = next;
  456|  29.0k|        return true;
  457|  29.0k|    }
  458|  2.06k|    error(value.getStart(), "\"" + key + "\" must be a dictionary");
  459|  2.06k|    return false;
  460|  31.0k|}
_ZN4QPDF11JSONReactor14dictionaryItemERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERK4JSON:
  464|   187k|{
  465|   187k|    if (stack.empty()) {
  ------------------
  |  Branch (465:9): [True: 0, False: 187k]
  ------------------
  466|      0|        throw std::logic_error("stack is empty in dictionaryItem");
  467|      0|    }
  468|   187k|    next_state = st_ignore;
  469|   187k|    auto state = stack.back().state;
  470|   187k|    if (state == st_ignore) {
  ------------------
  |  Branch (470:9): [True: 6.67k, False: 181k]
  ------------------
  471|  6.67k|        QTC::TC("qpdf", "QPDF_json ignoring in st_ignore");
  472|       |        // ignore
  473|   181k|    } else if (state == st_top) {
  ------------------
  |  Branch (473:16): [True: 6.74k, False: 174k]
  ------------------
  474|  6.74k|        if (key == "qpdf") {
  ------------------
  |  Branch (474:13): [True: 4.64k, False: 2.10k]
  ------------------
  475|  4.64k|            this->saw_qpdf = true;
  476|  4.64k|            if (!value.isArray()) {
  ------------------
  |  Branch (476:17): [True: 6, False: 4.63k]
  ------------------
  477|      6|                QTC::TC("qpdf", "QPDF_json qpdf not array");
  478|      6|                error(value.getStart(), "\"qpdf\" must be an array");
  479|  4.63k|            } else {
  480|  4.63k|                next_state = st_qpdf;
  481|  4.63k|            }
  482|  4.64k|        } else {
  483|       |            // Ignore all other fields.
  484|  2.10k|            QTC::TC("qpdf", "QPDF_json ignoring unknown top-level key");
  485|  2.10k|        }
  486|   174k|    } else if (state == st_qpdf_meta) {
  ------------------
  |  Branch (486:16): [True: 1.97k, False: 172k]
  ------------------
  487|  1.97k|        if (key == "pdfversion") {
  ------------------
  |  Branch (487:13): [True: 193, False: 1.78k]
  ------------------
  488|    193|            this->saw_pdf_version = true;
  489|    193|            std::string v;
  490|    193|            bool okay = false;
  491|    193|            if (value.getString(v)) {
  ------------------
  |  Branch (491:17): [True: 187, False: 6]
  ------------------
  492|    187|                std::string version;
  493|    187|                char const* p = v.c_str();
  494|    187|                if (QPDF::validatePDFVersion(p, version) && (*p == '\0')) {
  ------------------
  |  Branch (494:21): [True: 145, False: 42]
  |  Branch (494:61): [True: 132, False: 13]
  ------------------
  495|    132|                    this->pdf.m->pdf_version = version;
  496|    132|                    okay = true;
  497|    132|                }
  498|    187|            }
  499|    193|            if (!okay) {
  ------------------
  |  Branch (499:17): [True: 61, False: 132]
  ------------------
  500|     61|                QTC::TC("qpdf", "QPDF_json bad pdf version");
  501|     61|                error(value.getStart(), "invalid PDF version (must be \"x.y\")");
  502|     61|            }
  503|  1.78k|        } else if (key == "jsonversion") {
  ------------------
  |  Branch (503:20): [True: 252, False: 1.52k]
  ------------------
  504|    252|            this->saw_json_version = true;
  505|    252|            std::string v;
  506|    252|            bool okay = false;
  507|    252|            if (value.getNumber(v)) {
  ------------------
  |  Branch (507:17): [True: 249, False: 3]
  ------------------
  508|    249|                std::string version;
  509|    249|                if (QUtil::string_to_int(v.c_str()) == 2) {
  ------------------
  |  Branch (509:21): [True: 94, False: 155]
  ------------------
  510|     94|                    okay = true;
  511|     94|                }
  512|    249|            }
  513|    252|            if (!okay) {
  ------------------
  |  Branch (513:17): [True: 98, False: 154]
  ------------------
  514|     98|                QTC::TC("qpdf", "QPDF_json bad json version");
  515|     98|                error(value.getStart(), "invalid JSON version (must be numeric value 2)");
  516|     98|            }
  517|  1.52k|        } else if (key == "pushedinheritedpageresources") {
  ------------------
  |  Branch (517:20): [True: 41, False: 1.48k]
  ------------------
  518|     41|            bool v;
  519|     41|            if (value.getBool(v)) {
  ------------------
  |  Branch (519:17): [True: 40, False: 1]
  ------------------
  520|     40|                if (!this->must_be_complete && v) {
  ------------------
  |  Branch (520:21): [True: 0, False: 40]
  |  Branch (520:48): [True: 0, False: 0]
  ------------------
  521|      0|                    this->pdf.pushInheritedAttributesToPage();
  522|      0|                }
  523|     40|            } else {
  524|      1|                QTC::TC("qpdf", "QPDF_json bad pushedinheritedpageresources");
  525|      1|                error(value.getStart(), "pushedinheritedpageresources must be a boolean");
  526|      1|            }
  527|  1.48k|        } else if (key == "calledgetallpages") {
  ------------------
  |  Branch (527:20): [True: 49, False: 1.43k]
  ------------------
  528|     49|            bool v;
  529|     49|            if (value.getBool(v)) {
  ------------------
  |  Branch (529:17): [True: 45, False: 4]
  ------------------
  530|     45|                if (!this->must_be_complete && v) {
  ------------------
  |  Branch (530:21): [True: 0, False: 45]
  |  Branch (530:48): [True: 0, False: 0]
  ------------------
  531|      0|                    this->pdf.getAllPages();
  532|      0|                }
  533|     45|            } else {
  534|      4|                QTC::TC("qpdf", "QPDF_json bad calledgetallpages");
  535|      4|                error(value.getStart(), "calledgetallpages must be a boolean");
  536|      4|            }
  537|  1.43k|        } else {
  538|       |            // ignore unknown keys for forward compatibility and to skip keys we don't care about
  539|       |            // like "maxobjectid".
  540|  1.43k|            QTC::TC("qpdf", "QPDF_json ignore second-level key");
  541|  1.43k|        }
  542|   172k|    } else if (state == st_objects) {
  ------------------
  |  Branch (542:16): [True: 14.6k, False: 157k]
  ------------------
  543|  14.6k|        int obj = 0;
  544|  14.6k|        int gen = 0;
  545|  14.6k|        if (key == "trailer") {
  ------------------
  |  Branch (545:13): [True: 1.34k, False: 13.2k]
  ------------------
  546|  1.34k|            this->saw_trailer = true;
  547|  1.34k|            this->cur_object = "trailer";
  548|  1.34k|            setNextStateIfDictionary(key, value, st_trailer);
  549|  13.2k|        } else if (is_obj_key(key, obj, gen)) {
  ------------------
  |  Branch (549:20): [True: 11.9k, False: 1.34k]
  ------------------
  550|  11.9k|            this->cur_object = key;
  551|  11.9k|            if (setNextStateIfDictionary(key, value, st_object_top)) {
  ------------------
  |  Branch (551:17): [True: 11.7k, False: 132]
  ------------------
  552|  11.7k|                next_obj = pdf.getObjectForJSON(obj, gen);
  553|  11.7k|            }
  554|  11.9k|        } else {
  555|  1.34k|            QTC::TC("qpdf", "QPDF_json bad object key");
  556|  1.34k|            error(value.getStart(), "object key should be \"trailer\" or \"obj:n n R\"");
  557|  1.34k|        }
  558|   157k|    } else if (state == st_object_top) {
  ------------------
  |  Branch (558:16): [True: 12.3k, False: 145k]
  ------------------
  559|  12.3k|        if (stack.empty()) {
  ------------------
  |  Branch (559:13): [True: 0, False: 12.3k]
  ------------------
  560|      0|            throw std::logic_error("stack empty in st_object_top");
  561|      0|        }
  562|  12.3k|        auto& tos = stack.back();
  563|  12.3k|        if (!tos.object.isInitialized()) {
  ------------------
  |  Branch (563:13): [True: 0, False: 12.3k]
  ------------------
  564|      0|            throw std::logic_error("current object uninitialized in st_object_top");
  565|      0|        }
  566|  12.3k|        if (key == "value") {
  ------------------
  |  Branch (566:13): [True: 7.25k, False: 5.08k]
  ------------------
  567|       |            // Don't use setNextStateIfDictionary since this can have any type.
  568|  7.25k|            this->saw_value = true;
  569|  7.25k|            replaceObject(makeObject(value), value);
  570|  7.25k|            next_state = st_object;
  571|  7.25k|        } else if (key == "stream") {
  ------------------
  |  Branch (571:20): [True: 4.20k, False: 882]
  ------------------
  572|  4.20k|            this->saw_stream = true;
  573|  4.20k|            if (setNextStateIfDictionary(key, value, st_stream)) {
  ------------------
  |  Branch (573:17): [True: 4.19k, False: 11]
  ------------------
  574|  4.19k|                this->this_stream_needs_data = false;
  575|  4.19k|                if (tos.object.isStream()) {
  ------------------
  |  Branch (575:21): [True: 126, False: 4.07k]
  ------------------
  576|    126|                    QTC::TC("qpdf", "QPDF_json updating existing stream");
  577|  4.07k|                } else {
  578|  4.07k|                    this->this_stream_needs_data = true;
  579|  4.07k|                    replaceObject(pdf.reserveStream(tos.object.getObjGen()), value);
  580|  4.07k|                }
  581|  4.19k|                next_obj = tos.object;
  582|  4.19k|            } else {
  583|       |                // Error message already given above
  584|     11|                QTC::TC("qpdf", "QPDF_json stream not a dictionary");
  585|     11|            }
  586|  4.20k|        } else {
  587|       |            // Ignore unknown keys for forward compatibility
  588|    882|            QTC::TC("qpdf", "QPDF_json ignore unknown key in object_top");
  589|    882|        }
  590|   145k|    } else if (state == st_trailer) {
  ------------------
  |  Branch (590:16): [True: 1.78k, False: 143k]
  ------------------
  591|  1.78k|        if (key == "value") {
  ------------------
  |  Branch (591:13): [True: 1.31k, False: 468]
  ------------------
  592|  1.31k|            this->saw_value = true;
  593|       |            // The trailer must be a dictionary, so we can use setNextStateIfDictionary.
  594|  1.31k|            if (setNextStateIfDictionary("trailer.value", value, st_object)) {
  ------------------
  |  Branch (594:17): [True: 1.31k, False: 2]
  ------------------
  595|  1.31k|                this->pdf.m->trailer = makeObject(value);
  596|  1.31k|                setObjectDescription(this->pdf.m->trailer, value);
  597|  1.31k|            }
  598|  1.31k|        } else if (key == "stream") {
  ------------------
  |  Branch (598:20): [True: 1, False: 467]
  ------------------
  599|       |            // Don't need to set saw_stream here since there's already an error.
  600|      1|            QTC::TC("qpdf", "QPDF_json trailer stream");
  601|      1|            error(value.getStart(), "the trailer may not be a stream");
  602|    467|        } else {
  603|       |            // Ignore unknown keys for forward compatibility
  604|    467|            QTC::TC("qpdf", "QPDF_json ignore unknown key in trailer");
  605|    467|        }
  606|   143k|    } else if (state == st_stream) {
  ------------------
  |  Branch (606:16): [True: 7.82k, False: 135k]
  ------------------
  607|  7.82k|        if (stack.empty()) {
  ------------------
  |  Branch (607:13): [True: 0, False: 7.82k]
  ------------------
  608|      0|            throw std::logic_error("stack empty in st_stream");
  609|      0|        }
  610|  7.82k|        auto& tos = stack.back();
  611|  7.82k|        if (!tos.object.isStream()) {
  ------------------
  |  Branch (611:13): [True: 0, False: 7.82k]
  ------------------
  612|      0|            throw std::logic_error("current object is not stream in st_stream");
  613|      0|        }
  614|  7.82k|        auto uninitialized = QPDFObjectHandle();
  615|  7.82k|        if (key == "dict") {
  ------------------
  |  Branch (615:13): [True: 3.45k, False: 4.37k]
  ------------------
  616|  3.45k|            this->saw_dict = true;
  617|  3.45k|            if (setNextStateIfDictionary("stream.dict", value, st_object)) {
  ------------------
  |  Branch (617:17): [True: 3.44k, False: 13]
  ------------------
  618|  3.44k|                tos.object.replaceDict(makeObject(value));
  619|  3.44k|            } else {
  620|       |                // An error had already been given by setNextStateIfDictionary
  621|     13|                QTC::TC("qpdf", "QPDF_json stream dict not dict");
  622|     13|            }
  623|  4.37k|        } else if (key == "data") {
  ------------------
  |  Branch (623:20): [True: 3.68k, False: 690]
  ------------------
  624|  3.68k|            this->saw_data = true;
  625|  3.68k|            std::string v;
  626|  3.68k|            if (!value.getString(v)) {
  ------------------
  |  Branch (626:17): [True: 81, False: 3.60k]
  ------------------
  627|     81|                QTC::TC("qpdf", "QPDF_json stream data not string");
  628|     81|                error(value.getStart(), "\"stream.data\" must be a string");
  629|     81|                tos.object.replaceStreamData("", uninitialized, uninitialized);
  630|  3.60k|            } else {
  631|       |                // The range includes the quotes.
  632|  3.60k|                auto start = value.getStart() + 1;
  633|  3.60k|                auto end = value.getEnd() - 1;
  634|  3.60k|                if (end < start) {
  ------------------
  |  Branch (634:21): [True: 0, False: 3.60k]
  ------------------
  635|      0|                    throw std::logic_error("QPDF_json: JSON string length < 0");
  636|      0|                }
  637|  3.60k|                tos.object.replaceStreamData(
  638|  3.60k|                    provide_data(is, start, end), uninitialized, uninitialized);
  639|  3.60k|            }
  640|  3.68k|        } else if (key == "datafile") {
  ------------------
  |  Branch (640:20): [True: 222, False: 468]
  ------------------
  641|    222|            this->saw_datafile = true;
  642|    222|            std::string filename;
  643|    222|            if (!value.getString(filename)) {
  ------------------
  |  Branch (643:17): [True: 41, False: 181]
  ------------------
  644|     41|                QTC::TC("qpdf", "QPDF_json stream datafile not string");
  645|     41|                error(
  646|     41|                    value.getStart(),
  647|     41|                    "\"stream.datafile\" must be a string containing a file name");
  648|     41|                tos.object.replaceStreamData("", uninitialized, uninitialized);
  649|    181|            } else {
  650|    181|                tos.object.replaceStreamData(
  651|    181|                    QUtil::file_provider(filename), uninitialized, uninitialized);
  652|    181|            }
  653|    468|        } else {
  654|       |            // Ignore unknown keys for forward compatibility.
  655|    468|            QTC::TC("qpdf", "QPDF_json ignore unknown key in stream");
  656|    468|        }
  657|   135k|    } else if (state == st_object) {
  ------------------
  |  Branch (657:16): [True: 135k, False: 0]
  ------------------
  658|   135k|        if (stack.empty()) {
  ------------------
  |  Branch (658:13): [True: 0, False: 135k]
  ------------------
  659|      0|            throw std::logic_error("stack empty in st_object");
  660|      0|        }
  661|   135k|        auto& tos = stack.back();
  662|   135k|        auto dict = tos.object;
  663|   135k|        if (dict.isStream()) {
  ------------------
  |  Branch (663:13): [True: 0, False: 135k]
  ------------------
  664|      0|            dict = dict.getDict();
  665|      0|        }
  666|   135k|        if (!dict.isDictionary()) {
  ------------------
  |  Branch (666:13): [True: 0, False: 135k]
  ------------------
  667|      0|            throw std::logic_error(
  668|      0|                "current object is not stream or dictionary in st_object dictionary item");
  669|      0|        }
  670|   135k|        dict.replaceKey(
  671|   135k|            is_pdf_name(key) ? QPDFObjectHandle::parse(key.substr(2)).getName() : key,
  ------------------
  |  Branch (671:13): [True: 15.3k, False: 120k]
  ------------------
  672|   135k|            makeObject(value));
  673|   135k|    } else {
  674|      0|        throw std::logic_error("QPDF_json: unknown state " + std::to_string(state));
  675|      0|    }
  676|   187k|    return true;
  677|   187k|}
_ZN4QPDF11JSONReactor9arrayItemERK4JSON:
  681|  3.12M|{
  682|  3.12M|    if (stack.empty()) {
  ------------------
  |  Branch (682:9): [True: 0, False: 3.12M]
  ------------------
  683|      0|        throw std::logic_error("stack is empty in arrayItem");
  684|      0|    }
  685|  3.12M|    next_state = st_ignore;
  686|  3.12M|    auto state = stack.back().state;
  687|  3.12M|    if (state == st_qpdf) {
  ------------------
  |  Branch (687:9): [True: 17.9k, False: 3.10M]
  ------------------
  688|  17.9k|        if (!this->saw_qpdf_meta) {
  ------------------
  |  Branch (688:13): [True: 4.63k, False: 13.3k]
  ------------------
  689|  4.63k|            this->saw_qpdf_meta = true;
  690|  4.63k|            setNextStateIfDictionary("qpdf[0]", value, st_qpdf_meta);
  691|  13.3k|        } else if (!this->saw_objects) {
  ------------------
  |  Branch (691:20): [True: 4.21k, False: 9.11k]
  ------------------
  692|  4.21k|            this->saw_objects = true;
  693|  4.21k|            setNextStateIfDictionary("qpdf[1]", value, st_objects);
  694|  9.11k|        } else {
  695|  9.11k|            QTC::TC("qpdf", "QPDF_json more than two qpdf elements");
  696|  9.11k|            error(value.getStart(), "\"qpdf\" must have two elements");
  697|  9.11k|        }
  698|  3.10M|    } else if (state == st_object) {
  ------------------
  |  Branch (698:16): [True: 2.57M, False: 531k]
  ------------------
  699|  2.57M|        stack.back().object.appendItem(makeObject(value));
  700|  2.57M|    }
  701|  3.12M|    return true;
  702|  3.12M|}
_ZN4QPDF11JSONReactor20setObjectDescriptionER16QPDFObjectHandleRK4JSON:
  706|  2.39M|{
  707|  2.39M|    auto j_descr = std::get<QPDFValue::JSON_Descr>(*descr);
  708|  2.39M|    if (j_descr.object != cur_object) {
  ------------------
  |  Branch (708:9): [True: 12.3k, False: 2.38M]
  ------------------
  709|  12.3k|        descr = std::make_shared<QPDFValue::Description>(
  710|  12.3k|            QPDFValue::JSON_Descr(j_descr.input, cur_object));
  711|  12.3k|    }
  712|       |
  713|  2.39M|    oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart());
  714|  2.39M|}
_ZN4QPDF11JSONReactor10makeObjectERK4JSON:
  718|  2.72M|{
  719|  2.72M|    QPDFObjectHandle result;
  720|  2.72M|    std::string str_v;
  721|  2.72M|    bool bool_v = false;
  722|  2.72M|    if (value.isDictionary()) {
  ------------------
  |  Branch (722:9): [True: 33.7k, False: 2.68M]
  ------------------
  723|  33.7k|        result = QPDFObjectHandle::newDictionary();
  724|  33.7k|        next_obj = result;
  725|  33.7k|        next_state = st_object;
  726|  2.68M|    } else if (value.isArray()) {
  ------------------
  |  Branch (726:16): [True: 18.5k, False: 2.66M]
  ------------------
  727|  18.5k|        result = QPDFObjectHandle::newArray();
  728|  18.5k|        next_obj = result;
  729|  18.5k|        next_state = st_object;
  730|  2.66M|    } else if (value.isNull()) {
  ------------------
  |  Branch (730:16): [True: 1.30k, False: 2.66M]
  ------------------
  731|  1.30k|        result = QPDFObjectHandle::newNull();
  732|  2.66M|    } else if (value.getBool(bool_v)) {
  ------------------
  |  Branch (732:16): [True: 391, False: 2.66M]
  ------------------
  733|    391|        result = QPDFObjectHandle::newBool(bool_v);
  734|  2.66M|    } else if (value.getNumber(str_v)) {
  ------------------
  |  Branch (734:16): [True: 2.27M, False: 397k]
  ------------------
  735|  2.27M|        if (QUtil::is_long_long(str_v.c_str())) {
  ------------------
  |  Branch (735:13): [True: 2.26M, False: 5.21k]
  ------------------
  736|  2.26M|            result = QPDFObjectHandle::newInteger(QUtil::string_to_ll(str_v.c_str()));
  737|  2.26M|        } else {
  738|       |            // JSON allows scientific notation, but PDF does not.
  739|  5.21k|            if (str_v.find('e') != std::string::npos || str_v.find('E') != std::string::npos) {
  ------------------
  |  Branch (739:17): [True: 938, False: 4.27k]
  |  Branch (739:57): [True: 1.42k, False: 2.85k]
  ------------------
  740|  2.36k|                try {
  741|  2.36k|                    auto v = std::stod(str_v);
  742|  2.36k|                    str_v = QUtil::double_to_string(v);
  743|  2.36k|                } catch (std::exception&) {
  744|       |                    // Keep it as it was
  745|    264|                }
  746|  2.36k|            }
  747|  5.21k|            result = QPDFObjectHandle::newReal(str_v);
  748|  5.21k|        }
  749|  2.27M|    } else if (value.getString(str_v)) {
  ------------------
  |  Branch (749:16): [True: 397k, False: 0]
  ------------------
  750|   397k|        int obj = 0;
  751|   397k|        int gen = 0;
  752|   397k|        std::string str;
  753|   397k|        if (is_indirect_object(str_v, obj, gen)) {
  ------------------
  |  Branch (753:13): [True: 334k, False: 62.3k]
  ------------------
  754|   334k|            result = pdf.getObjectForJSON(obj, gen);
  755|   334k|        } else if (is_unicode_string(str_v, str)) {
  ------------------
  |  Branch (755:20): [True: 6.55k, False: 55.7k]
  ------------------
  756|  6.55k|            result = QPDFObjectHandle::newUnicodeString(str);
  757|  55.7k|        } else if (is_binary_string(str_v, str)) {
  ------------------
  |  Branch (757:20): [True: 1.85k, False: 53.9k]
  ------------------
  758|  1.85k|            result = QPDFObjectHandle::newString(QUtil::hex_decode(str));
  759|  53.9k|        } else if (is_name(str_v)) {
  ------------------
  |  Branch (759:20): [True: 22.1k, False: 31.7k]
  ------------------
  760|  22.1k|            result = QPDFObjectHandle::newName(str_v);
  761|  31.7k|        } else if (is_pdf_name(str_v)) {
  ------------------
  |  Branch (761:20): [True: 6.32k, False: 25.4k]
  ------------------
  762|  6.32k|            result = QPDFObjectHandle::parse(str_v.substr(2));
  763|  25.4k|        } else {
  764|  25.4k|            QTC::TC("qpdf", "QPDF_json unrecognized string value");
  765|  25.4k|            error(value.getStart(), "unrecognized string value");
  766|  25.4k|            result = QPDFObjectHandle::newNull();
  767|  25.4k|        }
  768|   397k|    }
  769|  2.72M|    if (!result.isInitialized()) {
  ------------------
  |  Branch (769:9): [True: 0, False: 2.72M]
  ------------------
  770|      0|        throw std::logic_error("JSONReactor::makeObject didn't initialize the object");
  771|      0|    }
  772|       |
  773|  2.72M|    if (!result.hasObjectDescription()) {
  ------------------
  |  Branch (773:9): [True: 2.38M, False: 341k]
  ------------------
  774|  2.38M|        setObjectDescription(result, value);
  775|  2.38M|    }
  776|  2.72M|    return result;
  777|  2.72M|}
_ZN4QPDF14createFromJSONENSt3__110shared_ptrI11InputSourceEE:
  787|  6.52k|{
  788|  6.52k|    processMemoryFile(is->getName().c_str(), JSON_PDF, strlen(JSON_PDF));
  789|  6.52k|    importJSON(is, true);
  790|  6.52k|}
_ZN4QPDF10importJSONENSt3__110shared_ptrI11InputSourceEEb:
  806|  6.52k|{
  807|  6.52k|    JSONReactor reactor(*this, is, must_be_complete);
  808|  6.52k|    try {
  809|  6.52k|        JSON::parse(*is, &reactor);
  810|  6.52k|    } catch (std::runtime_error& e) {
  811|  6.49k|        throw std::runtime_error(is->getName() + ": " + e.what());
  812|  6.49k|    }
  813|     35|    if (reactor.anyErrors()) {
  ------------------
  |  Branch (813:9): [True: 27, False: 8]
  ------------------
  814|     27|        throw std::runtime_error(is->getName() + ": errors found in JSON");
  815|     27|    }
  816|     35|}
QPDF_json.cc:_ZL18is_indirect_objectRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERiS8_:
   68|   409k|{
   69|   409k|    char const* p = v.c_str();
   70|   409k|    std::string o_str;
   71|   409k|    std::string g_str;
   72|   409k|    if (!QUtil::is_digit(*p)) {
  ------------------
  |  Branch (72:9): [True: 51.3k, False: 358k]
  ------------------
   73|  51.3k|        return false;
   74|  51.3k|    }
   75|   816k|    while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (75:12): [True: 457k, False: 358k]
  ------------------
   76|   457k|        o_str.append(1, *p++);
   77|   457k|    }
   78|   358k|    if (*p != ' ') {
  ------------------
  |  Branch (78:9): [True: 3.05k, False: 355k]
  ------------------
   79|  3.05k|        return false;
   80|  3.05k|    }
   81|  15.5M|    while (*p == ' ') {
  ------------------
  |  Branch (81:12): [True: 15.1M, False: 355k]
  ------------------
   82|  15.1M|        ++p;
   83|  15.1M|    }
   84|   355k|    if (!QUtil::is_digit(*p)) {
  ------------------
  |  Branch (84:9): [True: 5.82k, False: 349k]
  ------------------
   85|  5.82k|        return false;
   86|  5.82k|    }
   87|  1.03M|    while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (87:12): [True: 683k, False: 349k]
  ------------------
   88|   683k|        g_str.append(1, *p++);
   89|   683k|    }
   90|   349k|    if (*p != ' ') {
  ------------------
  |  Branch (90:9): [True: 553, False: 348k]
  ------------------
   91|    553|        return false;
   92|    553|    }
   93|  2.16M|    while (*p == ' ') {
  ------------------
  |  Branch (93:12): [True: 1.81M, False: 348k]
  ------------------
   94|  1.81M|        ++p;
   95|  1.81M|    }
   96|   348k|    if (*p++ != 'R') {
  ------------------
  |  Branch (96:9): [True: 1.20k, False: 347k]
  ------------------
   97|  1.20k|        return false;
   98|  1.20k|    }
   99|   347k|    if (*p) {
  ------------------
  |  Branch (99:9): [True: 536, False: 347k]
  ------------------
  100|    536|        return false;
  101|    536|    }
  102|   347k|    obj = QUtil::string_to_int(o_str.c_str());
  103|   347k|    gen = QUtil::string_to_int(g_str.c_str());
  104|   347k|    return obj > 0;
  105|   347k|}
QPDF_json.cc:_ZL10is_obj_keyRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERiS8_:
  109|  13.2k|{
  110|  13.2k|    if (v.substr(0, 4) != "obj:") {
  ------------------
  |  Branch (110:9): [True: 929, False: 12.3k]
  ------------------
  111|    929|        return false;
  112|    929|    }
  113|  12.3k|    return is_indirect_object(v.substr(4), obj, gen);
  114|  13.2k|}
QPDF_json.cc:_ZL17is_unicode_stringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERS5_:
  118|  62.3k|{
  119|  62.3k|    if (v.substr(0, 2) == "u:") {
  ------------------
  |  Branch (119:9): [True: 6.55k, False: 55.7k]
  ------------------
  120|  6.55k|        str = v.substr(2);
  121|  6.55k|        return true;
  122|  6.55k|    }
  123|  55.7k|    return false;
  124|  62.3k|}
QPDF_json.cc:_ZL16is_binary_stringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERS5_:
  128|  55.7k|{
  129|  55.7k|    if (v.substr(0, 2) == "b:") {
  ------------------
  |  Branch (129:9): [True: 4.91k, False: 50.8k]
  ------------------
  130|  4.91k|        str = v.substr(2);
  131|  4.91k|        int count = 0;
  132|   875k|        for (char c: str) {
  ------------------
  |  Branch (132:20): [True: 875k, False: 2.18k]
  ------------------
  133|   875k|            if (!QUtil::is_hex_digit(c)) {
  ------------------
  |  Branch (133:17): [True: 2.73k, False: 873k]
  ------------------
  134|  2.73k|                return false;
  135|  2.73k|            }
  136|   873k|            ++count;
  137|   873k|        }
  138|  2.18k|        return (count % 2 == 0);
  139|  4.91k|    }
  140|  50.8k|    return false;
  141|  55.7k|}
QPDF_json.cc:_ZL7is_nameRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
  145|  53.9k|{
  146|  53.9k|    return ((v.length() > 1) && (v.at(0) == '/'));
  ------------------
  |  Branch (146:13): [True: 45.0k, False: 8.81k]
  |  Branch (146:33): [True: 22.1k, False: 22.9k]
  ------------------
  147|  53.9k|}
QPDF_json.cc:_ZL12provide_dataNSt3__110shared_ptrI11InputSourceEExx:
  214|  3.60k|{
  215|  3.60k|    return [is, start, end](Pipeline* p) {
  216|  3.60k|        Pl_Base64 decode("base64-decode", p, Pl_Base64::a_decode);
  217|  3.60k|        p = &decode;
  218|  3.60k|        size_t bytes = QIntC::to_size(end - start);
  219|  3.60k|        char buf[8192];
  220|  3.60k|        is->seek(start, SEEK_SET);
  221|  3.60k|        size_t len = 0;
  222|  3.60k|        while ((len = is->read(buf, std::min(bytes, sizeof(buf)))) > 0) {
  223|  3.60k|            p->write(buf, len);
  224|  3.60k|            bytes -= len;
  225|  3.60k|            if (bytes == 0) {
  226|  3.60k|                break;
  227|  3.60k|            }
  228|  3.60k|        }
  229|  3.60k|        decode.finish();
  230|  3.60k|    };
  231|  3.60k|}
QPDF_json.cc:_ZL11is_pdf_nameRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
  151|   167k|{
  152|   167k|    return ((v.length() > 3) && (v.substr(0, 3) == "n:/"));
  ------------------
  |  Branch (152:13): [True: 125k, False: 41.9k]
  |  Branch (152:33): [True: 21.6k, False: 103k]
  ------------------
  153|   167k|}
_ZN4QPDF11JSONReactorC2ERS_NSt3__110shared_ptrI11InputSourceEEb:
  242|  6.52k|    {
  243|  6.52k|    }
_ZN4QPDF11JSONReactorD2Ev:
  244|  6.52k|    ~JSONReactor() override = default;
_ZN4QPDF11JSONReactor10StackFrameC2ENS0_7state_eEO16QPDFObjectHandle:
  273|  68.3k|            object(object) {};
_ZN4QPDF11JSONReactor10StackFrameC2ENS0_7state_eE:
  270|  26.0k|            state(state) {};

_ZN5QUtil13int_to_stringExi:
  326|  2.27M|{
  327|  2.27M|    return int_to_string_base(num, 10, length);
  328|  2.27M|}
_ZN5QUtil18int_to_string_baseExii:
  338|  2.27M|{
  339|  2.27M|    return int_to_string_base_internal(num, base, length);
  340|  2.27M|}
_ZN5QUtil16double_to_stringEdib:
  350|  2.09k|{
  351|       |    // Backward compatibility -- this code used to use sprintf and treated decimal_places <= 0 to
  352|       |    // mean to use the default, which was six decimal places. Starting in 10.2, we trim trailing
  353|       |    // zeroes by default.
  354|  2.09k|    if (decimal_places <= 0) {
  ------------------
  |  Branch (354:9): [True: 2.09k, False: 0]
  ------------------
  355|  2.09k|        decimal_places = 6;
  356|  2.09k|    }
  357|  2.09k|    std::ostringstream buf;
  358|  2.09k|    buf.imbue(std::locale::classic());
  359|  2.09k|    buf << std::setprecision(decimal_places) << std::fixed << num;
  360|  2.09k|    std::string result = buf.str();
  361|  2.09k|    if (trim_trailing_zeroes) {
  ------------------
  |  Branch (361:9): [True: 2.09k, False: 0]
  ------------------
  362|  14.1k|        while ((result.length() > 1) && (result.back() == '0')) {
  ------------------
  |  Branch (362:16): [True: 14.1k, False: 0]
  |  Branch (362:41): [True: 12.0k, False: 2.09k]
  ------------------
  363|  12.0k|            result.pop_back();
  364|  12.0k|        }
  365|  2.09k|        if ((result.length() > 1) && (result.back() == '.')) {
  ------------------
  |  Branch (365:13): [True: 2.09k, False: 0]
  |  Branch (365:38): [True: 1.88k, False: 216]
  ------------------
  366|  1.88k|            result.pop_back();
  367|  1.88k|        }
  368|  2.09k|    }
  369|  2.09k|    return result;
  370|  2.09k|}
_ZN5QUtil12string_to_llEPKc:
  374|  5.25M|{
  375|  5.25M|    errno = 0;
  376|       |#ifdef _MSC_VER
  377|       |    long long result = _strtoi64(str, 0, 10);
  378|       |#else
  379|  5.25M|    long long result = strtoll(str, nullptr, 10);
  380|  5.25M|#endif
  381|  5.25M|    if (errno == ERANGE) {
  ------------------
  |  Branch (381:9): [True: 622, False: 5.25M]
  ------------------
  382|    622|        throw std::range_error(
  383|    622|            std::string("overflow/underflow converting ") + str + " to 64-bit integer");
  384|    622|    }
  385|  5.25M|    return result;
  386|  5.25M|}
_ZN5QUtil13string_to_intEPKc:
  390|   707k|{
  391|       |    // QIntC::to_int does range checking
  392|   707k|    return QIntC::to_int(string_to_ll(str));
  393|   707k|}
_ZN5QUtil12is_long_longEPKc:
  429|  2.27M|{
  430|  2.27M|    try {
  431|  2.27M|        auto i1 = string_to_ll(str);
  432|  2.27M|        std::string s1 = int_to_string(i1);
  433|  2.27M|        return str == s1;
  434|  2.27M|    } catch (std::exception&) {
  435|       |        // overflow or other error
  436|    614|    }
  437|    614|    return false;
  438|  2.27M|}
_ZN5QUtil21unsigned_char_pointerEPKc:
  448|  6.52k|{
  449|  6.52k|    return reinterpret_cast<unsigned char*>(const_cast<char*>(str));
  450|  6.52k|}
_ZN5QUtil13file_providerERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  661|    181|{
  662|    181|    return [filename](Pipeline* p) { pipe_file(filename.c_str(), p); };
  663|    181|}
_ZN5QUtil10hex_decodeERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  735|  1.85k|{
  736|  1.85k|    std::string result;
  737|       |    // We know result.size() <= 0.5 * input.size() + 1. However, reserving string space for this
  738|       |    // upper bound has a negative impact.
  739|  1.85k|    bool first = true;
  740|  1.85k|    char decoded;
  741|   837k|    for (auto ch: input) {
  ------------------
  |  Branch (741:17): [True: 837k, False: 1.85k]
  ------------------
  742|   837k|        ch = hex_decode_char(ch);
  743|   837k|        if (ch < '\20') {
  ------------------
  |  Branch (743:13): [True: 837k, False: 0]
  ------------------
  744|   837k|            if (first) {
  ------------------
  |  Branch (744:17): [True: 418k, False: 418k]
  ------------------
  745|   418k|                decoded = static_cast<char>(ch << 4);
  746|   418k|                first = false;
  747|   418k|            } else {
  748|   418k|                result.push_back(decoded | ch);
  749|   418k|                first = true;
  750|   418k|            }
  751|   837k|        }
  752|   837k|    }
  753|  1.85k|    if (!first) {
  ------------------
  |  Branch (753:9): [True: 0, False: 1.85k]
  ------------------
  754|      0|        result.push_back(decoded);
  755|      0|    }
  756|  1.85k|    return result;
  757|  1.85k|}
_ZN5QUtil6toUTF8Em:
  998|  8.62k|{
  999|  8.62k|    std::string result;
 1000|       |
 1001|       |    // A UTF-8 encoding of a Unicode value is a single byte for Unicode values <= 127.  For larger
 1002|       |    // values, the first byte of the UTF-8 encoding has '1' as each of its n highest bits and '0'
 1003|       |    // for its (n+1)th highest bit where n is the total number of bytes required.  Subsequent bytes
 1004|       |    // start with '10' and have the remaining 6 bits free for encoding.  For example, an 11-bit
 1005|       |    // Unicode value can be stored in two bytes where the first is 110zzzzz, the second is 10zzzzzz,
 1006|       |    // and the z's represent the remaining bits.
 1007|       |
 1008|  8.62k|    if (uval > 0x7fffffff) {
  ------------------
  |  Branch (1008:9): [True: 0, False: 8.62k]
  ------------------
 1009|      0|        throw std::runtime_error("bounds error in QUtil::toUTF8");
 1010|  8.62k|    } else if (uval < 128) {
  ------------------
  |  Branch (1010:16): [True: 7.27k, False: 1.35k]
  ------------------
 1011|  7.27k|        result += static_cast<char>(uval);
 1012|  7.27k|    } else {
 1013|  1.35k|        unsigned char bytes[7];
 1014|  1.35k|        bytes[6] = '\0';
 1015|  1.35k|        unsigned char* cur_byte = &bytes[5];
 1016|       |
 1017|       |        // maximum value that will fit in the current number of bytes
 1018|  1.35k|        unsigned char maxval = 0x3f; // six bits
 1019|       |
 1020|  4.39k|        while (uval > QIntC::to_ulong(maxval)) {
  ------------------
  |  Branch (1020:16): [True: 3.04k, False: 1.35k]
  ------------------
 1021|       |            // Assign low six bits plus 10000000 to lowest unused byte position, then shift
 1022|  3.04k|            *cur_byte = static_cast<unsigned char>(0x80 + (uval & 0x3f));
 1023|  3.04k|            uval >>= 6;
 1024|       |            // Maximum that will fit in high byte now shrinks by one bit
 1025|  3.04k|            maxval = static_cast<unsigned char>(maxval >> 1);
 1026|       |            // Slide to the left one byte
 1027|  3.04k|            if (cur_byte <= bytes) {
  ------------------
  |  Branch (1027:17): [True: 0, False: 3.04k]
  ------------------
 1028|      0|                throw std::logic_error("QUtil::toUTF8: overflow error");
 1029|      0|            }
 1030|  3.04k|            --cur_byte;
 1031|  3.04k|        }
 1032|       |        // If maxval is k bits long, the high (7 - k) bits of the resulting byte must be high.
 1033|  1.35k|        *cur_byte = static_cast<unsigned char>(QIntC::to_ulong(0xff - (1 + (maxval << 1))) + uval);
 1034|       |
 1035|  1.35k|        result += reinterpret_cast<char*>(cur_byte);
 1036|  1.35k|    }
 1037|       |
 1038|  8.62k|    return result;
 1039|  8.62k|}
_ZN5QUtil7toUTF16Em:
 1043|  7.68M|{
 1044|  7.68M|    std::string result;
 1045|  7.68M|    if ((uval >= 0xd800) && (uval <= 0xdfff)) {
  ------------------
  |  Branch (1045:9): [True: 1.93k, False: 7.68M]
  |  Branch (1045:29): [True: 429, False: 1.50k]
  ------------------
 1046|    429|        result = "\xff\xfd";
 1047|  7.68M|    } else if (uval <= 0xffff) {
  ------------------
  |  Branch (1047:16): [True: 7.68M, False: 1.48k]
  ------------------
 1048|  7.68M|        char out[2];
 1049|  7.68M|        out[0] = static_cast<char>((uval & 0xff00) >> 8);
 1050|  7.68M|        out[1] = static_cast<char>(uval & 0xff);
 1051|  7.68M|        result = std::string(out, 2);
 1052|  7.68M|    } else if (uval <= 0x10ffff) {
  ------------------
  |  Branch (1052:16): [True: 537, False: 949]
  ------------------
 1053|    537|        char out[4];
 1054|    537|        uval -= 0x10000;
 1055|    537|        unsigned short high = static_cast<unsigned short>(((uval & 0xffc00) >> 10) + 0xd800);
 1056|    537|        unsigned short low = static_cast<unsigned short>((uval & 0x3ff) + 0xdc00);
 1057|    537|        out[0] = static_cast<char>((high & 0xff00) >> 8);
 1058|    537|        out[1] = static_cast<char>(high & 0xff);
 1059|    537|        out[2] = static_cast<char>((low & 0xff00) >> 8);
 1060|    537|        out[3] = static_cast<char>(low & 0xff);
 1061|    537|        result = std::string(out, 4);
 1062|    949|    } else {
 1063|    949|        result = "\xff\xfd";
 1064|    949|    }
 1065|       |
 1066|  7.68M|    return result;
 1067|  7.68M|}
_ZN5QUtil23get_next_utf8_codepointERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERmRb:
 1465|  22.5M|{
 1466|  22.5M|    auto o_pos = pos;
 1467|  22.5M|    size_t len = utf8_val.length();
 1468|  22.5M|    unsigned char ch = static_cast<unsigned char>(utf8_val.at(pos++));
 1469|  22.5M|    error = false;
 1470|  22.5M|    if (ch < 128) {
  ------------------
  |  Branch (1470:9): [True: 15.3M, False: 7.17M]
  ------------------
 1471|  15.3M|        return static_cast<unsigned long>(ch);
 1472|  15.3M|    }
 1473|       |
 1474|  7.17M|    size_t bytes_needed = 0;
 1475|  7.17M|    unsigned bit_check = 0x40;
 1476|  7.17M|    unsigned char to_clear = 0x80;
 1477|  20.7M|    while (ch & bit_check) {
  ------------------
  |  Branch (1477:12): [True: 13.5M, False: 7.17M]
  ------------------
 1478|  13.5M|        ++bytes_needed;
 1479|  13.5M|        to_clear = static_cast<unsigned char>(to_clear | bit_check);
 1480|  13.5M|        bit_check >>= 1;
 1481|  13.5M|    }
 1482|  7.17M|    if (((bytes_needed > 5) || (bytes_needed < 1)) || ((pos + bytes_needed) > len)) {
  ------------------
  |  Branch (1482:10): [True: 114k, False: 7.05M]
  |  Branch (1482:32): [True: 2.80M, False: 4.25M]
  |  Branch (1482:55): [True: 3.86k, False: 4.24M]
  ------------------
 1483|  2.92M|        error = true;
 1484|  2.92M|        return 0xfffd;
 1485|  2.92M|    }
 1486|       |
 1487|  4.24M|    auto codepoint = static_cast<unsigned long>(ch & ~to_clear);
 1488|  4.27M|    while (bytes_needed > 0) {
  ------------------
  |  Branch (1488:12): [True: 4.25M, False: 14.5k]
  ------------------
 1489|  4.25M|        --bytes_needed;
 1490|  4.25M|        ch = static_cast<unsigned char>(utf8_val.at(pos++));
 1491|  4.25M|        if ((ch & 0xc0) != 0x80) {
  ------------------
  |  Branch (1491:13): [True: 4.23M, False: 24.3k]
  ------------------
 1492|  4.23M|            --pos;
 1493|  4.23M|            error = true;
 1494|  4.23M|            return 0xfffd;
 1495|  4.23M|        }
 1496|  24.3k|        codepoint <<= 6;
 1497|  24.3k|        codepoint += (ch & 0x3f);
 1498|  24.3k|    }
 1499|  14.5k|    unsigned long lower_bound = 0;
 1500|  14.5k|    switch (pos - o_pos) {
 1501|  10.5k|    case 2:
  ------------------
  |  Branch (1501:5): [True: 10.5k, False: 4.01k]
  ------------------
 1502|  10.5k|        lower_bound = 1 << 7;
 1503|  10.5k|        break;
 1504|  1.03k|    case 3:
  ------------------
  |  Branch (1504:5): [True: 1.03k, False: 13.5k]
  ------------------
 1505|  1.03k|        lower_bound = 1 << 11;
 1506|  1.03k|        break;
 1507|  1.88k|    case 4:
  ------------------
  |  Branch (1507:5): [True: 1.88k, False: 12.6k]
  ------------------
 1508|  1.88k|        lower_bound = 1 << 16;
 1509|  1.88k|        break;
 1510|    638|    case 5:
  ------------------
  |  Branch (1510:5): [True: 638, False: 13.9k]
  ------------------
 1511|    638|        lower_bound = 1 << 12;
 1512|    638|        break;
 1513|    460|    case 6:
  ------------------
  |  Branch (1513:5): [True: 460, False: 14.1k]
  ------------------
 1514|    460|        lower_bound = 1 << 26;
 1515|    460|        break;
 1516|      0|    default:
  ------------------
  |  Branch (1516:5): [True: 0, False: 14.5k]
  ------------------
 1517|      0|        lower_bound = 0;
 1518|  14.5k|    }
 1519|       |
 1520|  14.5k|    if (lower_bound > 0 && codepoint < lower_bound) {
  ------------------
  |  Branch (1520:9): [True: 14.5k, False: 0]
  |  Branch (1520:28): [True: 246, False: 14.3k]
  ------------------
 1521|       |        // Too many bytes were used, but return whatever character was encoded.
 1522|    246|        error = true;
 1523|    246|    }
 1524|  14.5k|    return codepoint;
 1525|  14.5k|}
_ZN5QUtil13utf8_to_utf16ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1623|  4.14k|{
 1624|  4.14k|    return transcode_utf8(utf8, e_utf16, 0);
 1625|  4.14k|}
_ZN5QUtil15utf8_to_pdf_docERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERS6_c:
 1671|  6.55k|{
 1672|  6.55k|    return transcode_utf8(utf8, pdfdoc, e_pdfdoc, unknown_char);
 1673|  6.55k|}
QUtil.cc:_ZL14transcode_utf8RKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE10encoding_ec:
 1615|  4.14k|{
 1616|  4.14k|    std::string result;
 1617|  4.14k|    transcode_utf8(utf8_val, result, encoding, unknown);
 1618|  4.14k|    return result;
 1619|  4.14k|}
QUtil.cc:_ZL14transcode_utf8RKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERS5_10encoding_ec:
 1529|  10.6k|{
 1530|  10.6k|    bool okay = true;
 1531|  10.6k|    result.clear();
 1532|  10.6k|    size_t len = utf8_val.length();
 1533|  10.6k|    switch (encoding) {
 1534|  4.14k|    case e_utf16:
  ------------------
  |  Branch (1534:5): [True: 4.14k, False: 6.55k]
  ------------------
 1535|  4.14k|        result += "\xfe\xff";
 1536|  4.14k|        break;
 1537|  6.55k|    case e_pdfdoc:
  ------------------
  |  Branch (1537:5): [True: 6.55k, False: 4.14k]
  ------------------
 1538|       |        // We need to avoid having the result start with something that will be interpreted as
 1539|       |        // UTF-16 or UTF-8, meaning we can't end up with a string that starts with "fe ff",
 1540|       |        // (UTF-16-BE) "ff fe" (UTF-16-LE, not officially part of the PDF spec, but recognized by
 1541|       |        // most readers including qpdf), or "ef bb bf" (UTF-8). It's more efficient to check the
 1542|       |        // input string to see if it will map to one of those sequences than to check the output
 1543|       |        // string since all cases start with the same starting character.
 1544|  6.55k|        if ((len >= 4) && (utf8_val[0] == '\xc3')) {
  ------------------
  |  Branch (1544:13): [True: 4.88k, False: 1.66k]
  |  Branch (1544:27): [True: 3.19k, False: 1.69k]
  ------------------
 1545|  3.19k|            static std::string fe_ff("\xbe\xc3\xbf");
 1546|  3.19k|            static std::string ff_fe("\xbf\xc3\xbe");
 1547|  3.19k|            static std::string ef_bb_bf("\xaf\xc2\xbb\xc2\xbf");
 1548|       |            // C++-20 has starts_with, but when this was written, qpdf had a minimum supported
 1549|       |            // version of C++-17.
 1550|  3.19k|            if ((utf8_val.compare(1, 3, fe_ff) == 0) || (utf8_val.compare(1, 3, ff_fe) == 0) ||
  ------------------
  |  Branch (1550:17): [True: 195, False: 3.00k]
  |  Branch (1550:57): [True: 196, False: 2.80k]
  ------------------
 1551|  3.19k|                (utf8_val.compare(1, 5, ef_bb_bf) == 0)) {
  ------------------
  |  Branch (1551:17): [True: 217, False: 2.59k]
  ------------------
 1552|    608|                result += unknown;
 1553|    608|                okay = false;
 1554|    608|            }
 1555|  3.19k|        }
 1556|  6.55k|        break;
 1557|      0|    default:
  ------------------
  |  Branch (1557:5): [True: 0, False: 10.6k]
  ------------------
 1558|      0|        break;
 1559|  10.6k|    }
 1560|  10.6k|    size_t pos = 0;
 1561|  22.5M|    while (pos < len) {
  ------------------
  |  Branch (1561:12): [True: 22.5M, False: 10.6k]
  ------------------
 1562|  22.5M|        bool error = false;
 1563|  22.5M|        unsigned long codepoint = QUtil::get_next_utf8_codepoint(utf8_val, pos, error);
 1564|  22.5M|        if (error) {
  ------------------
  |  Branch (1564:13): [True: 7.15M, False: 15.3M]
  ------------------
 1565|  7.15M|            okay = false;
 1566|  7.15M|            if (encoding == e_utf16) {
  ------------------
  |  Branch (1566:17): [True: 3.57M, False: 3.57M]
  ------------------
 1567|  3.57M|                result += "\xff\xfd";
 1568|  3.57M|            } else {
 1569|  3.57M|                result.append(1, unknown);
 1570|  3.57M|            }
 1571|  15.3M|        } else if (codepoint < 128) {
  ------------------
  |  Branch (1571:20): [True: 15.3M, False: 14.3k]
  ------------------
 1572|  15.3M|            char ch = static_cast<char>(codepoint);
 1573|  15.3M|            if (encoding == e_utf16) {
  ------------------
  |  Branch (1573:17): [True: 7.67M, False: 7.69M]
  ------------------
 1574|  7.67M|                result += QUtil::toUTF16(QIntC::to_ulong(ch));
 1575|  7.69M|            } else if ((encoding == e_pdfdoc) && (((ch >= 0x18) && (ch <= 0x1f)) || (ch == 127))) {
  ------------------
  |  Branch (1575:24): [True: 7.69M, False: 0]
  |  Branch (1575:52): [True: 7.69M, False: 199]
  |  Branch (1575:68): [True: 194, False: 7.69M]
  |  Branch (1575:85): [True: 2.09k, False: 7.69M]
  ------------------
 1576|       |                // PDFDocEncoding maps some low characters to Unicode, so if we encounter those
 1577|       |                // invalid UTF-8 code points, map them to unknown so reversing the mapping doesn't
 1578|       |                // change them into other characters.
 1579|  2.28k|                okay = false;
 1580|  2.28k|                result.append(1, unknown);
 1581|  7.69M|            } else {
 1582|  7.69M|                result.append(1, ch);
 1583|  7.69M|            }
 1584|  15.3M|        } else if (encoding == e_utf16) {
  ------------------
  |  Branch (1584:20): [True: 6.77k, False: 7.55k]
  ------------------
 1585|  6.77k|            result += QUtil::toUTF16(codepoint);
 1586|  7.55k|        } else if ((codepoint == 0xad) && (encoding == e_pdfdoc)) {
  ------------------
  |  Branch (1586:20): [True: 208, False: 7.34k]
  |  Branch (1586:43): [True: 208, False: 0]
  ------------------
 1587|       |            // PDFDocEncoding omits 0x00ad (soft hyphen).
 1588|    208|            okay = false;
 1589|    208|            result.append(1, unknown);
 1590|  7.34k|        } else if (
 1591|  7.34k|            (codepoint > 160) && (codepoint < 256) &&
  ------------------
  |  Branch (1591:13): [True: 7.11k, False: 236]
  |  Branch (1591:34): [True: 4.21k, False: 2.89k]
  ------------------
 1592|  7.34k|            ((encoding == e_winansi) || (encoding == e_pdfdoc))) {
  ------------------
  |  Branch (1592:14): [True: 0, False: 4.21k]
  |  Branch (1592:41): [True: 4.21k, False: 0]
  ------------------
 1593|  4.21k|            result.append(1, static_cast<char>(codepoint & 0xff));
 1594|  4.21k|        } else {
 1595|  3.13k|            unsigned char ch = '\0';
 1596|  3.13k|            if (encoding == e_winansi) {
  ------------------
  |  Branch (1596:17): [True: 0, False: 3.13k]
  ------------------
 1597|      0|                ch = encode_winansi(codepoint);
 1598|  3.13k|            } else if (encoding == e_macroman) {
  ------------------
  |  Branch (1598:24): [True: 0, False: 3.13k]
  ------------------
 1599|      0|                ch = encode_macroman(codepoint);
 1600|  3.13k|            } else if (encoding == e_pdfdoc) {
  ------------------
  |  Branch (1600:24): [True: 3.13k, False: 0]
  ------------------
 1601|  3.13k|                ch = encode_pdfdoc(codepoint);
 1602|  3.13k|            }
 1603|  3.13k|            if (ch == '\0') {
  ------------------
  |  Branch (1603:17): [True: 2.74k, False: 385]
  ------------------
 1604|  2.74k|                okay = false;
 1605|  2.74k|                ch = static_cast<unsigned char>(unknown);
 1606|  2.74k|            }
 1607|  3.13k|            result.append(1, static_cast<char>(ch));
 1608|  3.13k|        }
 1609|  22.5M|    }
 1610|  10.6k|    return okay;
 1611|  10.6k|}
QUtil.cc:_ZL13encode_pdfdocm:
 1455|  3.13k|{
 1456|  3.13k|    auto i = unicode_to_pdf_doc.find(codepoint);
 1457|  3.13k|    if (i != unicode_to_pdf_doc.end()) {
  ------------------
  |  Branch (1457:9): [True: 385, False: 2.74k]
  ------------------
 1458|    385|        return i->second;
 1459|    385|    }
 1460|  2.74k|    return '\0';
 1461|  3.13k|}
QUtil.cc:_ZL27int_to_string_base_internalIxENSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEET_ii:
  295|  2.27M|{
  296|       |    // Backward compatibility -- int_to_string, which calls this function, used to use sprintf with
  297|       |    // %0*d, so we interpret length such that a negative value appends spaces and a positive value
  298|       |    // prepends zeroes.
  299|  2.27M|    if (!((base == 8) || (base == 10) || (base == 16))) {
  ------------------
  |  Branch (299:11): [True: 0, False: 2.27M]
  |  Branch (299:26): [True: 2.27M, False: 0]
  |  Branch (299:42): [True: 0, False: 0]
  ------------------
  300|      0|        throw std::logic_error("int_to_string_base called with unsupported base");
  301|      0|    }
  302|  2.27M|    std::string cvt;
  303|  2.27M|    if (base == 10) {
  ------------------
  |  Branch (303:9): [True: 2.27M, False: 0]
  ------------------
  304|       |        // Use the more efficient std::to_string when possible
  305|  2.27M|        cvt = std::to_string(num);
  306|  2.27M|    } else {
  307|      0|        std::ostringstream buf;
  308|      0|        buf.imbue(std::locale::classic());
  309|      0|        buf << std::setbase(base) << std::nouppercase << num;
  310|      0|        cvt = buf.str();
  311|      0|    }
  312|  2.27M|    std::string result;
  313|  2.27M|    int str_length = QIntC::to_int(cvt.length());
  314|  2.27M|    if ((length > 0) && (str_length < length)) {
  ------------------
  |  Branch (314:9): [True: 0, False: 2.27M]
  |  Branch (314:25): [True: 0, False: 0]
  ------------------
  315|      0|        result.append(QIntC::to_size(length - str_length), '0');
  316|      0|    }
  317|  2.27M|    result += cvt;
  318|  2.27M|    if ((length < 0) && (str_length < -length)) {
  ------------------
  |  Branch (318:9): [True: 0, False: 2.27M]
  |  Branch (318:25): [True: 0, False: 0]
  ------------------
  319|      0|        result.append(QIntC::to_size(-length - str_length), ' ');
  320|      0|    }
  321|  2.27M|    return result;
  322|  2.27M|}

_ZN10QPDFObject10disconnectEv:
  148|  2.44M|    {
  149|       |        // Disconnect an object from its owning QPDF. This is called by QPDF's destructor.
  150|  2.44M|        value->disconnect();
  151|  2.44M|        value->qpdf = nullptr;
  152|  2.44M|        value->og = QPDFObjGen();
  153|  2.44M|    }
_ZNK10QPDFObject11getTypeCodeEv:
   58|  18.1k|    {
   59|  18.1k|        return value->type_code;
   60|  18.1k|    }
_ZN10QPDFObject9setObjGenEP4QPDFRK10QPDFObjGen:
  142|  11.0k|    {
  143|  11.0k|        value->qpdf = qpdf;
  144|  11.0k|        value->og = og;
  145|  11.0k|    }
_ZN10QPDFObject6assignENSt3__110shared_ptrIS_EE:
  120|  11.0k|    {
  121|  11.0k|        value = o->value;
  122|  11.0k|    }
_ZNK10QPDFObject2asI11QPDF_StreamEEPT_v:
  171|  7.34k|    {
  172|  7.34k|        if (auto result = dynamic_cast<T*>(value.get())) {
  ------------------
  |  Branch (172:18): [True: 7.34k, False: 0]
  ------------------
  173|  7.34k|            return result;
  174|  7.34k|        } else {
  175|      0|            return isUnresolved()
  ------------------
  |  Branch (175:20): [True: 0, False: 0]
  ------------------
  176|      0|                ? dynamic_cast<T*>(QPDF::Resolver::resolved(value->qpdf, value->og)->value.get())
  177|      0|                : nullptr;
  178|      0|        }
  179|  7.34k|    }
_ZNK10QPDFObject14getStringValueEv:
   43|  15.3k|    {
   44|  15.3k|        return value->getStringValue();
   45|  15.3k|    }
_ZNK10QPDFObject19getResolvedTypeCodeEv:
   49|   464k|    {
   50|   464k|        auto tc = value->type_code;
   51|   464k|        return tc == ::ot_unresolved
  ------------------
  |  Branch (51:16): [True: 0, False: 464k]
  ------------------
   52|   464k|            ? QPDF::Resolver::resolved(value->qpdf, value->og)->value->type_code
   53|   464k|            : tc;
   54|   464k|    }
_ZNK10QPDFObject7getQPDFEv:
   64|  2.84M|    {
   65|  2.84M|        return value->qpdf;
   66|  2.84M|    }
_ZNK10QPDFObject9getObjGenEv:
   69|  2.68M|    {
   70|  2.68M|        return value->og;
   71|  2.68M|    }
_ZN10QPDFObject14setDescriptionEP4QPDFRNSt3__110shared_ptrINS2_7variantIJNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEN9QPDFValue10JSON_DescrENSB_10ChildDescrEEEEEEx:
   75|  2.43M|    {
   76|  2.43M|        return value->setDescription(qpdf, description, offset);
   77|  2.43M|    }
_ZN10QPDFObject14hasDescriptionEv:
  105|  2.73M|    {
  106|  2.73M|        return value->hasDescription();
  107|  2.73M|    }
_ZN10QPDFObject15getParsedOffsetEv:
  115|    116|    {
  116|    116|        return value->getParsedOffset();
  117|    116|    }
_ZNK10QPDFObject2asI10QPDF_ArrayEEPT_v:
  171|  2.57M|    {
  172|  2.57M|        if (auto result = dynamic_cast<T*>(value.get())) {
  ------------------
  |  Branch (172:18): [True: 2.57M, False: 0]
  ------------------
  173|  2.57M|            return result;
  174|  2.57M|        } else {
  175|      0|            return isUnresolved()
  ------------------
  |  Branch (175:20): [True: 0, False: 0]
  ------------------
  176|      0|                ? dynamic_cast<T*>(QPDF::Resolver::resolved(value->qpdf, value->og)->value.get())
  177|      0|                : nullptr;
  178|      0|        }
  179|  2.57M|    }
_ZNK10QPDFObject2asI15QPDF_DictionaryEEPT_v:
  171|   178k|    {
  172|   178k|        if (auto result = dynamic_cast<T*>(value.get())) {
  ------------------
  |  Branch (172:18): [True: 178k, False: 0]
  ------------------
  173|   178k|            return result;
  174|   178k|        } else {
  175|      0|            return isUnresolved()
  ------------------
  |  Branch (175:20): [True: 0, False: 0]
  ------------------
  176|      0|                ? dynamic_cast<T*>(QPDF::Resolver::resolved(value->qpdf, value->og)->value.get())
  177|      0|                : nullptr;
  178|      0|        }
  179|   178k|    }
_ZNK10QPDFObject2asI12QPDF_IntegerEEPT_v:
  171|  6.52k|    {
  172|  6.52k|        if (auto result = dynamic_cast<T*>(value.get())) {
  ------------------
  |  Branch (172:18): [True: 6.52k, False: 0]
  ------------------
  173|  6.52k|            return result;
  174|  6.52k|        } else {
  175|      0|            return isUnresolved()
  ------------------
  |  Branch (175:20): [True: 0, False: 0]
  ------------------
  176|      0|                ? dynamic_cast<T*>(QPDF::Resolver::resolved(value->qpdf, value->og)->value.get())
  177|      0|                : nullptr;
  178|      0|        }
  179|  6.52k|    }
_ZN10QPDFObjectC2Ev:
   24|  2.44M|    QPDFObject() = default;

_ZN10QPDFParserC2ENSt3__110shared_ptrI11InputSourceEERKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEER13QPDFTokenizerPN16QPDFObjectHandle15StringDecrypterEP4QPDFb:
   29|  28.1k|    {
   30|  28.1k|    }
_ZN10QPDFParserD2Ev:
   31|  28.1k|    virtual ~QPDFParser() = default;
_ZN10QPDFParser10StackFrameC2ERKNSt3__110shared_ptrI11InputSourceEENS_14parser_state_eE:
   45|  6.52k|        {
   46|  6.52k|        }

_ZN9QPDFValue15getParsedOffsetEv:
   99|    116|    {
  100|    116|        return parsed_offset;
  101|    116|    }
_ZN9QPDFValue10JSON_DescrC2ENSt3__110shared_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEERKS8_:
   34|  18.8k|        {
   35|  18.8k|        }
_ZN9QPDFValue14setDescriptionEP4QPDFRNSt3__110shared_ptrINS2_7variantIJNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS_10JSON_DescrENS_10ChildDescrEEEEEEx:
   62|  2.43M|    {
   63|  2.43M|        qpdf = qpdf_p;
   64|  2.43M|        object_description = description;
   65|  2.43M|        setParsedOffset(offset);
   66|  2.43M|    }
_ZN9QPDFValue14hasDescriptionEv:
   87|  2.73M|    {
   88|  2.73M|        return object_description || og.isIndirect();
  ------------------
  |  Branch (88:16): [True: 77.8k, False: 2.65M]
  |  Branch (88:38): [True: 270k, False: 2.38M]
  ------------------
   89|  2.73M|    }
_ZN9QPDFValue15setParsedOffsetEx:
   92|  2.43M|    {
   93|  2.43M|        if (parsed_offset < 0) {
  ------------------
  |  Branch (93:13): [True: 2.42M, False: 12.3k]
  ------------------
   94|  2.42M|            parsed_offset = offset;
   95|  2.42M|        }
   96|  2.43M|    }
_ZN9QPDFValue10disconnectEv:
  114|  2.40M|    {
  115|  2.40M|    }
_ZN9QPDFValueC2E18qpdf_object_type_e:
  127|  2.39M|    {
  128|  2.39M|    }
_ZN9QPDFValueC2E18qpdf_object_type_eP4QPDF10QPDFObjGen:
  133|  44.9k|    {
  134|  44.9k|    }
_ZN9QPDFValueD2Ev:
   23|  2.44M|    virtual ~QPDFValue() = default;

_ZN10QPDF_ArrayD2Ev:
   19|  18.5k|    ~QPDF_Array() override = default;

_ZN15QPDF_DictionaryD2Ev:
   14|  44.3k|    ~QPDF_Dictionary() override = default;

_ZNK9QPDF_Name14getStringValueEv:
   24|  15.3k|    {
   25|  15.3k|        return name;
   26|  15.3k|    }
_ZN9QPDF_NameD2Ev:
    9|  43.6k|    ~QPDF_Name() override = default;

_ZN9QPDF_RealD2Ev:
    9|  5.21k|    ~QPDF_Real() override = default;

_ZN11QPDF_StreamD2Ev:
   19|  4.07k|    ~QPDF_Stream() override = default;

_ZN11QPDF_StringD2Ev:
   13|  8.40k|    ~QPDF_String() override = default;

