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

_ZN11InputSourceC2Ev:
   37|  46.0k|    {
   38|  46.0k|    }
_ZN11InputSource10loadBufferEv:
  116|   134k|{
  117|   134k|    this->buf_idx = 0;
  118|   134k|    this->buf_len = qpdf_offset_t(read(this->buffer, this->buf_size));
  119|       |    // NB read sets last_offset
  120|   134k|    this->buf_start = this->last_offset;
  121|   134k|}
_ZN11InputSource8fastTellEv:
  125|   181k|{
  126|   181k|    if (this->buf_len == 0) {
  ------------------
  |  Branch (126:9): [True: 25.8k, False: 155k]
  ------------------
  127|  25.8k|        loadBuffer();
  128|   155k|    } else {
  129|   155k|        auto curr = tell();
  130|   155k|        if (curr < this->buf_start || curr >= (this->buf_start + this->buf_len)) {
  ------------------
  |  Branch (130:13): [True: 6.73k, False: 148k]
  |  Branch (130:39): [True: 101k, False: 47.1k]
  ------------------
  131|   108k|            loadBuffer();
  132|   108k|        } else {
  133|  47.1k|            this->last_offset = curr;
  134|  47.1k|            this->buf_idx = curr - this->buf_start;
  135|  47.1k|        }
  136|   155k|    }
  137|   181k|    return this->last_offset;
  138|   181k|}
_ZN11InputSource8fastReadERc:
  142|  11.4M|{
  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|  11.4M|    if (this->buf_idx < this->buf_len) {
  ------------------
  |  Branch (145:9): [True: 11.3M, False: 117k]
  ------------------
  146|  11.3M|        ch = this->buffer[this->buf_idx];
  147|  11.3M|        ++(this->buf_idx);
  148|  11.3M|        ++(this->last_offset);
  149|  11.3M|        return true;
  150|       |
  151|  11.3M|    } else if (this->buf_len == 0) {
  ------------------
  |  Branch (151:16): [True: 15.8k, False: 101k]
  ------------------
  152|  15.8k|        return false;
  153|   101k|    } else {
  154|   101k|        seek(this->buf_start + this->buf_len, SEEK_SET);
  155|   101k|        fastTell();
  156|   101k|        return fastRead(ch);
  157|   101k|    }
  158|  11.4M|}
_ZN11InputSource10fastUnreadEb:
  162|  79.7k|{
  163|  79.7k|    this->last_offset -= back ? 1 : 0;
  ------------------
  |  Branch (163:26): [True: 50.3k, False: 29.3k]
  ------------------
  164|  79.7k|    seek(this->last_offset, SEEK_SET);
  165|  79.7k|}
_ZN11InputSourceD2Ev:
   40|  46.0k|    virtual ~InputSource() = default;
_ZN11InputSource6FinderC2Ev:
   46|  13.4k|        Finder() = default;
_ZN11InputSource6FinderD2Ev:
   48|  13.4k|        virtual ~Finder() = default;

_ZN4JSON10JSON_valueC2ENS_12value_type_eE:
  315|  6.42M|        {
  316|  6.42M|        }
_ZN4JSON15JSON_dictionaryC2Ev:
  325|   106k|        {
  326|   106k|        }
_ZN4JSON9JSON_nullC2Ev:
  361|    902|        {
  362|    902|        }
_ZN4JSON10JSON_arrayC2Ev:
  408|  62.2k|    {
  409|  62.2k|    }
_ZN4JSON10JSON_valueD2Ev:
  317|  6.42M|        virtual ~JSON_value() = default;
_ZN4JSONC2Ev:
   52|  13.4M|    JSON() = default;
_ZN4JSON15JSON_dictionaryD2Ev:
  327|   106k|        ~JSON_dictionary() override = default;
_ZN4JSON10JSON_arrayD2Ev:
  410|  62.2k|    ~JSON_array() override = default;
_ZN4JSON11JSON_stringD2Ev:
  336|   737k|        ~JSON_string() override = default;
_ZN4JSON11JSON_numberD2Ev:
  346|  5.51M|        ~JSON_number() override = default;
_ZN4JSON7MembersD2Ev:
  389|  6.42M|        ~Members() = default;
_ZN4JSON7ReactorD2Ev:
  220|  6.73k|        virtual ~Reactor() = default;

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

_ZN5QIntC9to_offsetImEExRKT_:
  221|   239k|    {
  222|   239k|        return IntConverter<T, qpdf_offset_t>::convert(i);
  223|   239k|    }
_ZN5QIntC12IntConverterImxLb0ELb1EE7convertERKm:
  146|   239k|        {
  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|   239k|            auto maxval = static_cast<typename to_u<To>::type>(std::numeric_limits<To>::max());
  150|   239k|            if (i > maxval) {
  ------------------
  |  Branch (150:17): [True: 0, False: 239k]
  ------------------
  151|      0|                error(i);
  152|      0|            }
  153|   239k|            return static_cast<To>(i);
  154|   239k|        }
_ZN5QIntC11range_checkIxEEvRKT_S3_:
  273|  6.73k|    {
  274|  6.73k|        if ((delta > 0) != (cur > 0)) {
  ------------------
  |  Branch (274:13): [True: 6.73k, False: 0]
  ------------------
  275|  6.73k|            return;
  276|  6.73k|        }
  277|      0|        QIntC::range_check_error<T>(cur, delta);
  278|      0|    }
_ZN5QIntC7to_sizeIxEEmRKT_:
  214|   239k|    {
  215|   239k|        return IntConverter<T, size_t>::convert(i);
  216|   239k|    }
_ZN5QIntC12IntConverterIxmLb1ELb0EE7convertERKx:
  118|   239k|        {
  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|   239k|            auto ii = static_cast<typename to_u<From>::type>(i);
  123|   239k|            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (123:17): [True: 0, False: 239k]
  |  Branch (123:28): [True: 0, False: 239k]
  ------------------
  124|      0|                error(i);
  125|      0|            }
  126|   239k|            return static_cast<To>(i);
  127|   239k|        }
_ZN5QIntC12IntConverterIimLb1ELb0EE7convertERKi:
  118|    929|        {
  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|    929|            auto ii = static_cast<typename to_u<From>::type>(i);
  123|    929|            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (123:17): [True: 0, False: 929]
  |  Branch (123:28): [True: 0, False: 929]
  ------------------
  124|      0|                error(i);
  125|      0|            }
  126|    929|            return static_cast<To>(i);
  127|    929|        }
_ZN5QIntC6to_intIlEEiRKT_:
  200|  6.73k|    {
  201|  6.73k|        return IntConverter<T, int>::convert(i);
  202|  6.73k|    }
_ZN5QIntC12IntConverterIliLb1ELb1EE7convertERKl:
   93|  6.73k|        {
   94|       |            // From and To are both signed.
   95|  6.73k|            if ((i < std::numeric_limits<To>::min()) || (i > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (95:17): [True: 0, False: 6.73k]
  |  Branch (95:57): [True: 0, False: 6.73k]
  ------------------
   96|      0|                error(i);
   97|      0|            }
   98|  6.73k|            return static_cast<To>(i);
   99|  6.73k|        }
_ZN5QIntC6to_intIxEEiRKT_:
  200|   633k|    {
  201|   633k|        return IntConverter<T, int>::convert(i);
  202|   633k|    }
_ZN5QIntC12IntConverterIxiLb1ELb1EE7convertERKx:
   93|   633k|        {
   94|       |            // From and To are both signed.
   95|   633k|            if ((i < std::numeric_limits<To>::min()) || (i > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (95:17): [True: 57, False: 633k]
  |  Branch (95:57): [True: 20, False: 632k]
  ------------------
   96|     77|                error(i);
   97|     77|            }
   98|   633k|            return static_cast<To>(i);
   99|   633k|        }
_ZN5QIntC12IntConverterIxiLb1ELb1EE5errorEx:
  103|     77|        {
  104|     77|            std::ostringstream msg;
  105|     77|            msg.imbue(std::locale::classic());
  106|     77|            msg << "integer out of range converting " << i << " from a " << sizeof(From)
  107|     77|                << "-byte signed type to a " << sizeof(To) << "-byte signed type";
  108|     77|            throw std::range_error(msg.str());
  109|     77|        }
_ZN5QIntC6to_intImEEiRKT_:
  200|  2.68M|    {
  201|  2.68M|        return IntConverter<T, int>::convert(i);
  202|  2.68M|    }
_ZN5QIntC12IntConverterImiLb0ELb1EE7convertERKm:
  146|  2.68M|        {
  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.68M|            auto maxval = static_cast<typename to_u<To>::type>(std::numeric_limits<To>::max());
  150|  2.68M|            if (i > maxval) {
  ------------------
  |  Branch (150:17): [True: 0, False: 2.68M]
  ------------------
  151|      0|                error(i);
  152|      0|            }
  153|  2.68M|            return static_cast<To>(i);
  154|  2.68M|        }
_ZN5QIntC7to_sizeIlEEmRKT_:
  214|  13.4k|    {
  215|  13.4k|        return IntConverter<T, size_t>::convert(i);
  216|  13.4k|    }
_ZN5QIntC12IntConverterIlmLb1ELb0EE7convertERKl:
  118|  13.4k|        {
  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.4k|            auto ii = static_cast<typename to_u<From>::type>(i);
  123|  13.4k|            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (123:17): [True: 0, False: 13.4k]
  |  Branch (123:28): [True: 0, False: 13.4k]
  ------------------
  124|      0|                error(i);
  125|      0|            }
  126|  13.4k|            return static_cast<To>(i);
  127|  13.4k|        }
_ZN5QIntC8to_ulongIcEEmRKT_:
  235|  7.62M|    {
  236|  7.62M|        return IntConverter<T, unsigned long>::convert(i);
  237|  7.62M|    }
_ZN5QIntC12IntConverterIcmLb1ELb0EE7convertERKc:
  118|  7.62M|        {
  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.62M|            auto ii = static_cast<typename to_u<From>::type>(i);
  123|  7.62M|            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
  ------------------
  |  Branch (123:17): [True: 0, False: 7.62M]
  |  Branch (123:28): [True: 0, False: 7.62M]
  ------------------
  124|      0|                error(i);
  125|      0|            }
  126|  7.62M|            return static_cast<To>(i);
  127|  7.62M|        }
_ZN5QIntC8to_ulongIhEEmRKT_:
  235|  3.42k|    {
  236|  3.42k|        return IntConverter<T, unsigned long>::convert(i);
  237|  3.42k|    }
_ZN5QIntC12IntConverterIhmLb0ELb0EE7convertERKh:
   68|  3.42k|        {
   69|       |            // From and To are both unsigned.
   70|  3.42k|            if (i > std::numeric_limits<To>::max()) {
  ------------------
  |  Branch (70:17): [True: 0, False: 3.42k]
  ------------------
   71|      0|                error(i);
   72|      0|            }
   73|  3.42k|            return static_cast<To>(i);
   74|  3.42k|        }
_ZN5QIntC8to_ulongIiEEmRKT_:
  235|    929|    {
  236|    929|        return IntConverter<T, unsigned long>::convert(i);
  237|    929|    }

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

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

_ZN10QPDFObjGenC2Ev:
   38|  5.66M|    {
   39|  5.66M|    }
_ZN10QPDFObjGenC2Eii:
   44|   319k|    {
   45|   319k|    }
_ZNK10QPDFObjGenltERKS_:
   49|  1.49M|    {
   50|  1.49M|        return (obj < rhs.obj) || ((obj == rhs.obj) && (gen < rhs.gen));
  ------------------
  |  Branch (50:16): [True: 329k, False: 1.16M]
  |  Branch (50:36): [True: 948k, False: 213k]
  |  Branch (50:56): [True: 298k, False: 649k]
  ------------------
   51|  1.49M|    }
_ZNK10QPDFObjGen6getObjEv:
   67|   140k|    {
   68|   140k|        return obj;
   69|   140k|    }
_ZNK10QPDFObjGen10isIndirectEv:
   79|  6.00M|    {
   80|  6.00M|        return obj != 0;
   81|  6.00M|    }

_ZN16QPDFObjectHandle16DisconnectAccess10disconnectES_:
 1271|  85.9k|        {
 1272|  85.9k|            o.disconnect();
 1273|  85.9k|        }
_ZN16QPDFObjectHandleC2ERKNSt3__110shared_ptrI10QPDFObjectEE:
 1337|  3.13M|    {
 1338|  3.13M|    }
_ZN16QPDFObjectHandle6getObjEv:
 1341|  10.7k|    {
 1342|  10.7k|        return obj;
 1343|  10.7k|    }
_ZNK16QPDFObjectHandle6getObjEv:
 1346|  2.97M|    {
 1347|  2.97M|        return obj;
 1348|  2.97M|    }
_ZN16QPDFObjectHandle12getObjectPtrEv:
 1351|  2.79M|    {
 1352|  2.79M|        return obj.get();
 1353|  2.79M|    }
_ZNK16QPDFObjectHandle12getObjectPtrEv:
 1356|  2.97M|    {
 1357|  2.97M|        return obj.get();
 1358|  2.97M|    }
_ZNK16QPDFObjectHandle11getObjectIDEv:
 1615|   134k|{
 1616|   134k|    return getObjGen().getObj();
 1617|   134k|}
_ZNK16QPDFObjectHandle10isIndirectEv:
 1627|   134k|{
 1628|   134k|    return (obj != nullptr) && (getObjectID() != 0);
  ------------------
  |  Branch (1628:12): [True: 134k, False: 0]
  |  Branch (1628:32): [True: 26.4k, False: 107k]
  ------------------
 1629|   134k|}
_ZNK16QPDFObjectHandle13isInitializedEv:
 1633|  3.56M|{
 1634|  3.56M|    return obj != nullptr;
 1635|  3.56M|}
_ZN16QPDFObjectHandleC2ERKS_:
  294|   462k|    QPDFObjectHandle(QPDFObjectHandle const&) = default;
_ZN16QPDFObjectHandleaSERKS_:
  296|  3.30M|    QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default;
_ZN16QPDFObjectHandleC2Ev:
  292|  3.28M|    QPDFObjectHandle() = default;

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

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

_ZN5QUtil8is_spaceEc:
  499|   201k|{
  500|   201k|    return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\v';
  ------------------
  |  Branch (500:12): [True: 53.8k, False: 147k]
  |  Branch (500:25): [True: 33.6k, False: 113k]
  |  Branch (500:39): [True: 3, False: 113k]
  |  Branch (500:53): [True: 5, False: 113k]
  |  Branch (500:67): [True: 0, False: 113k]
  |  Branch (500:81): [True: 0, False: 113k]
  ------------------
  501|   201k|}
_ZN5QUtil15hex_decode_charEc:
  546|  4.22M|{
  547|  4.22M|    return digit <= '9' && digit >= '0'
  ------------------
  |  Branch (547:12): [True: 4.15M, False: 68.3k]
  |  Branch (547:28): [True: 4.11M, False: 36.6k]
  ------------------
  548|  4.22M|        ? char(digit - '0')
  549|  4.22M|        : (digit >= 'a' ? char(digit - 'a' + 10) : (digit >= 'A' ? char(digit - 'A' + 10) : '\20'));
  ------------------
  |  Branch (549:12): [True: 18.8k, False: 86.2k]
  |  Branch (549:53): [True: 48.6k, False: 37.6k]
  ------------------
  550|  4.22M|}
_ZN5QUtil12is_hex_digitEc:
  493|  2.12M|{
  494|  2.12M|    return hex_decode_char(ch) < '\20';
  495|  2.12M|}
_ZN5QUtil8is_digitEc:
  505|  20.1M|{
  506|  20.1M|    return ((ch >= '0') && (ch <= '9'));
  ------------------
  |  Branch (506:13): [True: 19.4M, False: 718k]
  |  Branch (506:28): [True: 19.4M, False: 23.9k]
  ------------------
  507|  20.1M|}

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

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

_ZN11InputSource13setLastOffsetEx:
   10|  86.4k|{
   11|  86.4k|    this->last_offset = offset;
   12|  86.4k|}
_ZNK11InputSource13getLastOffsetEv:
   16|  20.4k|{
   17|  20.4k|    return this->last_offset;
   18|  20.4k|}
_ZN11InputSource8readLineEm:
   22|  6.73k|{
   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.73k|    qpdf_offset_t offset = this->tell();
   29|  6.73k|    auto bp = std::make_unique<char[]>(max_line_length + 1);
   30|  6.73k|    char* buf = bp.get();
   31|  6.73k|    memset(buf, '\0', max_line_length + 1);
   32|  6.73k|    this->read(buf, max_line_length);
   33|  6.73k|    this->seek(offset, SEEK_SET);
   34|  6.73k|    qpdf_offset_t eol = this->findAndSkipNextEOL();
   35|  6.73k|    this->last_offset = offset;
   36|  6.73k|    size_t line_length = QIntC::to_size(eol - offset);
   37|  6.73k|    if (line_length < max_line_length) {
  ------------------
  |  Branch (37:9): [True: 6.73k, False: 0]
  ------------------
   38|  6.73k|        buf[line_length] = '\0';
   39|  6.73k|    }
   40|  6.73k|    return {buf};
   41|  6.73k|}
_ZN11InputSource9findFirstEPKcxmRNS_6FinderE:
   45|  20.1k|{
   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|  20.1k|    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|  20.1k|    size_t size = sizeof(buf) - 1;
   59|  20.1k|    if ((strlen(start_chars) < 1) || (strlen(start_chars) > size)) {
  ------------------
  |  Branch (59:9): [True: 0, False: 20.1k]
  |  Branch (59:38): [True: 0, False: 20.1k]
  ------------------
   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|  20.1k|    char* p = nullptr;
   65|  20.1k|    qpdf_offset_t buf_offset = offset;
   66|  20.1k|    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|  20.1k|    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|  20.1k|        if ((p == nullptr) || ((p + strlen(start_chars)) > (buf + bytes_read))) {
  ------------------
  |  Branch (77:13): [True: 20.1k, False: 0]
  |  Branch (77:31): [True: 0, False: 0]
  ------------------
   78|  20.1k|            if (p) {
  ------------------
  |  Branch (78:17): [True: 0, False: 20.1k]
  ------------------
   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|  20.1k|            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|  20.1k|            bytes_read = this->read(buf, size);
   88|  20.1k|            if (bytes_read < strlen(start_chars)) {
  ------------------
  |  Branch (88:17): [True: 6.73k, False: 13.4k]
  ------------------
   89|  6.73k|                QTC::TC("libtests", "InputSource find EOF", bytes_read == 0 ? 0 : 1);
  ------------------
  |  Branch (89:61): [True: 0, False: 6.73k]
  ------------------
   90|  6.73k|                return false;
   91|  6.73k|            }
   92|  13.4k|            memset(buf + bytes_read, '\0', 1 + (size - bytes_read));
   93|  13.4k|            p = buf;
   94|  13.4k|        }
   95|       |
   96|       |        // Search for the first character.
   97|  13.4k|        if ((p = static_cast<char*>(
  ------------------
  |  Branch (97:13): [True: 13.4k, False: 0]
  ------------------
   98|       |                 // line-break
   99|  13.4k|                 memchr(p, start_chars[0], bytes_read - QIntC::to_size(p - buf)))) != nullptr) {
  100|  13.4k|            if (p == buf) {
  ------------------
  |  Branch (100:17): [True: 6.73k, False: 6.73k]
  ------------------
  101|  6.73k|                QTC::TC("libtests", "InputSource found match at buf[0]");
  102|  6.73k|            }
  103|       |            // Found first letter.
  104|  13.4k|            if (len != 0) {
  ------------------
  |  Branch (104:17): [True: 6.73k, False: 6.73k]
  ------------------
  105|       |                // Make sure it's in range.
  106|  6.73k|                size_t p_relative_offset = QIntC::to_size((p - buf) + (buf_offset - offset));
  107|  6.73k|                if (p_relative_offset >= len) {
  ------------------
  |  Branch (107:21): [True: 0, False: 6.73k]
  ------------------
  108|       |                    // out of range
  109|      0|                    QTC::TC("libtests", "InputSource out of range");
  110|      0|                    return false;
  111|      0|                }
  112|  6.73k|            }
  113|  13.4k|            if ((p + strlen(start_chars)) > (buf + bytes_read)) {
  ------------------
  |  Branch (113:17): [True: 0, False: 13.4k]
  ------------------
  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.4k|            if (strncmp(p, start_chars, strlen(start_chars)) == 0) {
  ------------------
  |  Branch (122:17): [True: 13.4k, False: 0]
  ------------------
  123|       |                // Call finder.check() with the input source positioned to the point of the match.
  124|  13.4k|                this->seek(buf_offset + (p - buf), SEEK_SET);
  125|  13.4k|                if (finder.check()) {
  ------------------
  |  Branch (125:21): [True: 13.4k, False: 0]
  ------------------
  126|  13.4k|                    return true;
  127|  13.4k|                } else {
  128|      0|                    QTC::TC("libtests", "InputSource start_chars matched but not check");
  129|      0|                }
  130|  13.4k|            } 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.4k|    }
  141|      0|    throw std::logic_error("InputSource after while (true)");
  142|  20.1k|}
_ZN11InputSource8findLastEPKcxmRNS_6FinderE:
  146|  6.73k|{
  147|  6.73k|    bool found = false;
  148|  6.73k|    qpdf_offset_t after_found_offset = 0;
  149|  6.73k|    qpdf_offset_t cur_offset = offset;
  150|  6.73k|    size_t cur_len = len;
  151|  13.4k|    while (this->findFirst(start_chars, cur_offset, cur_len, finder)) {
  ------------------
  |  Branch (151:12): [True: 6.73k, False: 6.73k]
  ------------------
  152|  6.73k|        if (found) {
  ------------------
  |  Branch (152:13): [True: 0, False: 6.73k]
  ------------------
  153|      0|            QTC::TC("libtests", "InputSource findLast found more than one");
  154|  6.73k|        } else {
  155|  6.73k|            found = true;
  156|  6.73k|        }
  157|  6.73k|        after_found_offset = this->tell();
  158|  6.73k|        cur_offset = after_found_offset;
  159|  6.73k|        cur_len = len - QIntC::to_size((cur_offset - offset));
  160|  6.73k|    }
  161|  6.73k|    if (found) {
  ------------------
  |  Branch (161:9): [True: 6.73k, False: 0]
  ------------------
  162|  6.73k|        this->seek(after_found_offset, SEEK_SET);
  163|  6.73k|    }
  164|  6.73k|    return found;
  165|  6.73k|}

_ZN4JSON7MembersC2ENSt3__110unique_ptrINS_10JSON_valueENS1_14default_deleteIS3_EEEE:
   16|  6.42M|{
   17|  6.42M|}
_ZN4JSONC2ENSt3__110unique_ptrINS_10JSON_valueENS0_14default_deleteIS2_EEEE:
   21|  6.42M|{
   22|  6.42M|}
_ZN4JSON11JSON_stringC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  125|   737k|{
  126|   737k|}
_ZN4JSON11JSON_numberC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  149|  5.51M|{
  150|  5.51M|}
_ZN4JSON9JSON_boolC2Eb:
  161|  1.72k|{
  162|  1.72k|}
_ZN4JSON6Writer13encode_stringERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  217|   889k|{
  218|   889k|    static auto constexpr hexchars = "0123456789abcdef";
  219|       |
  220|   889k|    auto begin = str.cbegin();
  221|   889k|    auto end = str.cend();
  222|   889k|    auto iter = begin;
  223|   124M|    while (iter != end) {
  ------------------
  |  Branch (223:12): [True: 124M, False: 882k]
  ------------------
  224|   124M|        auto c = static_cast<unsigned char>(*iter);
  225|   124M|        if ((c > 34 && c != '\\') || c == ' ' || c == 33) {
  ------------------
  |  Branch (225:14): [True: 122M, False: 1.32M]
  |  Branch (225:24): [True: 122M, False: 454]
  |  Branch (225:38): [True: 1.25M, False: 69.0k]
  |  Branch (225:50): [True: 62.1k, False: 6.93k]
  ------------------
  226|       |            // Optimistically check that no char in str requires escaping. Hopefully we can just
  227|       |            // return the input str.
  228|   124M|            ++iter;
  229|   124M|        } 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|  6.93k|            std::string result{begin, iter};
  233|       |
  234|  6.82M|            for (; iter != end; ++iter) {
  ------------------
  |  Branch (234:20): [True: 6.82M, False: 6.93k]
  ------------------
  235|  6.82M|                auto ch = static_cast<unsigned char>(*iter);
  236|  6.82M|                if ((ch > 34 && ch != '\\') || ch == ' ' || ch == 33) {
  ------------------
  |  Branch (236:22): [True: 6.78M, False: 34.4k]
  |  Branch (236:33): [True: 6.78M, False: 3.74k]
  |  Branch (236:48): [True: 3.60k, False: 34.5k]
  |  Branch (236:61): [True: 22.0k, False: 12.4k]
  ------------------
  237|       |                    // Check for most common case first.
  238|  6.80M|                    result += *iter;
  239|  6.80M|                } else {
  240|  12.4k|                    switch (ch) {
  241|  3.74k|                    case '\\':
  ------------------
  |  Branch (241:21): [True: 3.74k, False: 8.75k]
  ------------------
  242|  3.74k|                        result += "\\\\";
  243|  3.74k|                        break;
  244|    273|                    case '\"':
  ------------------
  |  Branch (244:21): [True: 273, False: 12.2k]
  ------------------
  245|    273|                        result += "\\\"";
  246|    273|                        break;
  247|    234|                    case '\b':
  ------------------
  |  Branch (247:21): [True: 234, False: 12.2k]
  ------------------
  248|    234|                        result += "\\b";
  249|    234|                        break;
  250|    217|                    case '\f':
  ------------------
  |  Branch (250:21): [True: 217, False: 12.2k]
  ------------------
  251|    217|                        result += "\\f";
  252|    217|                        break;
  253|  1.00k|                    case '\n':
  ------------------
  |  Branch (253:21): [True: 1.00k, False: 11.4k]
  ------------------
  254|  1.00k|                        result += "\\n";
  255|  1.00k|                        break;
  256|    797|                    case '\r':
  ------------------
  |  Branch (256:21): [True: 797, False: 11.7k]
  ------------------
  257|    797|                        result += "\\r";
  258|    797|                        break;
  259|  4.89k|                    case '\t':
  ------------------
  |  Branch (259:21): [True: 4.89k, False: 7.60k]
  ------------------
  260|  4.89k|                        result += "\\t";
  261|  4.89k|                        break;
  262|  1.33k|                    default:
  ------------------
  |  Branch (262:21): [True: 1.33k, False: 11.1k]
  ------------------
  263|  1.33k|                        result += ch < 16 ? "\\u000" : "\\u001";
  ------------------
  |  Branch (263:35): [True: 721, False: 615]
  ------------------
  264|  1.33k|                        result += hexchars[ch % 16];
  265|  12.4k|                    }
  266|  12.4k|                }
  267|  6.82M|            }
  268|  6.93k|            return result;
  269|  6.93k|        }
  270|   124M|    }
  271|   882k|    return str;
  272|   889k|}
_ZN4JSON14makeDictionaryEv:
  276|   106k|{
  277|   106k|    return {std::make_unique<JSON_dictionary>()};
  278|   106k|}
_ZN4JSON19addDictionaryMemberERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKS_:
  282|   151k|{
  283|   151k|    if (auto* obj = m ? dynamic_cast<JSON_dictionary*>(m->value.get()) : nullptr) {
  ------------------
  |  Branch (283:15): [True: 151k, False: 0]
  ------------------
  284|   151k|        return obj->members[Writer::encode_string(key)] = val.m ? val : makeNull();
  ------------------
  |  Branch (284:59): [True: 151k, False: 0]
  ------------------
  285|   151k|    } else {
  286|      0|        throw std::runtime_error("JSON::addDictionaryMember called on non-dictionary");
  287|      0|    }
  288|   151k|}
_ZN4JSON22checkDictionaryKeySeenERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  292|   302k|{
  293|   302k|    if (auto* obj = m ? dynamic_cast<JSON_dictionary*>(m->value.get()) : nullptr) {
  ------------------
  |  Branch (293:15): [True: 302k, False: 0]
  ------------------
  294|   302k|        return !obj->parsed_keys.insert(key).second;
  295|   302k|    }
  296|      0|    throw std::logic_error("JSON::checkDictionaryKey called on non-dictionary");
  297|      0|    return false; // unreachable
  298|   302k|}
_ZN4JSON9makeArrayEv:
  302|  62.2k|{
  303|  62.2k|    return {std::make_unique<JSON_array>()};
  304|  62.2k|}
_ZN4JSON15addArrayElementERKS_:
  308|  3.10M|{
  309|  3.10M|    if (auto* arr = m ? dynamic_cast<JSON_array*>(m->value.get()) : nullptr) {
  ------------------
  |  Branch (309:15): [True: 3.10M, False: 0]
  ------------------
  310|  3.10M|        if (val.m) {
  ------------------
  |  Branch (310:13): [True: 3.10M, False: 0]
  ------------------
  311|  3.10M|            arr->elements.push_back(val);
  312|  3.10M|        } else {
  313|      0|            arr->elements.push_back(makeNull());
  314|      0|        }
  315|  3.10M|        return arr->elements.back();
  316|  3.10M|    }
  317|      0|    throw std::runtime_error("JSON::addArrayElement called on non-array");
  318|      0|    return {}; // unreachable
  319|  3.10M|}
_ZN4JSON10makeStringERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  323|   737k|{
  324|   737k|    return {std::make_unique<JSON_string>(utf8)};
  325|   737k|}
_ZN4JSON10makeNumberERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  341|  5.51M|{
  342|  5.51M|    return {std::make_unique<JSON_number>(encoded)};
  343|  5.51M|}
_ZN4JSON8makeBoolEb:
  347|  1.72k|{
  348|  1.72k|    return {std::make_unique<JSON_bool>(value)};
  349|  1.72k|}
_ZN4JSON8makeNullEv:
  353|    902|{
  354|    902|    return {std::make_unique<JSON_null>()};
  355|    902|}
_ZNK4JSON7isArrayEv:
  365|  9.44M|{
  366|  9.44M|    return m ? m->value->type_code == vt_array : false;
  ------------------
  |  Branch (366:12): [True: 9.44M, False: 0]
  ------------------
  367|  9.44M|}
_ZNK4JSON12isDictionaryEv:
  371|  9.71M|{
  372|  9.71M|    return m && m->value->type_code == vt_dictionary;
  ------------------
  |  Branch (372:12): [True: 9.71M, False: 0]
  |  Branch (372:17): [True: 270k, False: 9.44M]
  ------------------
  373|  9.71M|}
_ZNK4JSON9getStringERNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  377|   363k|{
  378|   363k|    if (m && m->value->type_code == vt_string) {
  ------------------
  |  Branch (378:9): [True: 363k, False: 0]
  |  Branch (378:14): [True: 363k, False: 132]
  ------------------
  379|   363k|        auto v = dynamic_cast<JSON_string const*>(m->value.get());
  380|   363k|        utf8 = v->utf8;
  381|   363k|        return true;
  382|   363k|    }
  383|    132|    return false;
  384|   363k|}
_ZNK4JSON9getNumberERNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  388|  3.04M|{
  389|  3.04M|    if (m && m->value->type_code == vt_number) {
  ------------------
  |  Branch (389:9): [True: 3.04M, False: 0]
  |  Branch (389:14): [True: 2.68M, False: 360k]
  ------------------
  390|  2.68M|        auto v = dynamic_cast<JSON_number const*>(m->value.get());
  391|  2.68M|        value = v->encoded;
  392|  2.68M|        return true;
  393|  2.68M|    }
  394|   360k|    return false;
  395|  3.04M|}
_ZNK4JSON7getBoolERb:
  399|  3.04M|{
  400|  3.04M|    if (m && m->value->type_code == vt_bool) {
  ------------------
  |  Branch (400:9): [True: 3.04M, False: 0]
  |  Branch (400:14): [True: 462, False: 3.04M]
  ------------------
  401|    462|        auto v = dynamic_cast<JSON_bool const*>(m->value.get());
  402|    462|        value = v->value;
  403|    462|        return true;
  404|    462|    }
  405|  3.04M|    return false;
  406|  3.04M|}
_ZNK4JSON6isNullEv:
  410|  3.04M|{
  411|  3.04M|    return m && m->value->type_code == vt_null;
  ------------------
  |  Branch (411:12): [True: 3.04M, False: 0]
  |  Branch (411:17): [True: 218, False: 3.04M]
  ------------------
  412|  3.04M|}
_ZN4JSON5parseER11InputSourcePNS_7ReactorE:
 1362|  6.73k|{
 1363|  6.73k|    JSONParser jp(is, reactor);
 1364|  6.73k|    return jp.parse();
 1365|  6.73k|}
_ZN4JSON5parseERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1369|  6.73k|{
 1370|  6.73k|    BufferInputSource bis("json input", s);
 1371|  6.73k|    JSONParser jp(bis, nullptr);
 1372|  6.73k|    return jp.parse();
 1373|  6.73k|}
_ZN4JSON8setStartEx:
 1377|  6.42M|{
 1378|  6.42M|    if (m) {
  ------------------
  |  Branch (1378:9): [True: 6.42M, False: 0]
  ------------------
 1379|  6.42M|        m->start = start;
 1380|  6.42M|    }
 1381|  6.42M|}
_ZN4JSON6setEndEx:
 1385|  6.47M|{
 1386|  6.47M|    if (m) {
  ------------------
  |  Branch (1386:9): [True: 6.47M, False: 0]
  ------------------
 1387|  6.47M|        m->end = end;
 1388|  6.47M|    }
 1389|  6.47M|}
_ZNK4JSON8getStartEv:
 1393|  2.84M|{
 1394|  2.84M|    return m ? m->start : 0;
  ------------------
  |  Branch (1394:12): [True: 2.84M, False: 0]
  ------------------
 1395|  2.84M|}
_ZNK4JSON6getEndEv:
 1399|  2.90k|{
 1400|  2.90k|    return m ? m->end : 0;
  ------------------
  |  Branch (1400:12): [True: 2.90k, False: 0]
  ------------------
 1401|  2.90k|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParserC2ER11InputSourcePN4JSON7ReactorE:
  602|  13.4k|        {
  603|  13.4k|        }
JSON.cc:_ZN12_GLOBAL__N_110JSONParser5parseEv:
 1344|  13.4k|{
 1345|  13.3M|    while (!done) {
  ------------------
  |  Branch (1345:12): [True: 13.3M, False: 13.4k]
  ------------------
 1346|  13.3M|        getToken();
 1347|  13.3M|        handleToken();
 1348|  13.3M|    }
 1349|  13.4k|    if (parser_state != ps_done) {
  ------------------
  |  Branch (1349:9): [True: 9.33k, False: 4.12k]
  ------------------
 1350|  9.33k|        QTC::TC("libtests", "JSON parse premature EOF");
 1351|  9.33k|        throw std::runtime_error("JSON: premature end of input");
 1352|  9.33k|    }
 1353|  4.12k|    auto const& tos = stack.back().item;
 1354|  4.12k|    if (reactor && !(tos.isArray() || tos.isDictionary())) {
  ------------------
  |  Branch (1354:9): [True: 311, False: 3.81k]
  |  Branch (1354:22): [True: 0, False: 311]
  |  Branch (1354:39): [True: 53, False: 258]
  ------------------
 1355|    258|        reactor->topLevelScalar();
 1356|    258|    }
 1357|  4.12k|    return tos;
 1358|  13.4k|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser8getTokenEv:
  829|  13.3M|{
  830|  13.3M|    token.clear();
  831|       |
  832|       |    // Keep track of UTF-16 surrogate pairs.
  833|  13.3M|    unsigned long high_surrogate = 0;
  834|  13.3M|    qpdf_offset_t high_offset = 0;
  835|       |
  836|   261M|    while (true) {
  ------------------
  |  Branch (836:12): [Folded - Ignored]
  ------------------
  837|   261M|        if (p == (buf + bytes)) {
  ------------------
  |  Branch (837:13): [True: 39.5k, False: 261M]
  ------------------
  838|  39.5k|            p = buf;
  839|  39.5k|            bytes = is.read(buf, sizeof(buf));
  840|  39.5k|            if (bytes == 0) {
  ------------------
  |  Branch (840:17): [True: 11.1k, False: 28.3k]
  ------------------
  841|  11.1k|                done = true;
  842|  11.1k|                break;
  843|  11.1k|            }
  844|  39.5k|        }
  845|       |
  846|   261M|        if ((*p < 32 && *p >= 0)) {
  ------------------
  |  Branch (846:14): [True: 11.2M, False: 249M]
  |  Branch (846:25): [True: 543k, False: 10.6M]
  ------------------
  847|   543k|            if (*p == '\t' || *p == '\n' || *p == '\r') {
  ------------------
  |  Branch (847:17): [True: 557, False: 542k]
  |  Branch (847:31): [True: 542k, False: 367]
  |  Branch (847:45): [True: 297, False: 70]
  ------------------
  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|   543k|                if (lex_state == ls_top) {
  ------------------
  |  Branch (850:21): [True: 527k, False: 16.1k]
  ------------------
  851|   527k|                    ignore();
  852|   527k|                } else {
  853|  16.1k|                    break;
  854|  16.1k|                }
  855|       |
  856|   543k|            } else {
  857|     70|                QTC::TC("libtests", "JSON parse null character");
  858|     70|                throw std::runtime_error(
  859|     70|                    "JSON: control or null character at offset " + std::to_string(offset));
  860|     70|            }
  861|   260M|        } else if (*p == ',') {
  ------------------
  |  Branch (861:20): [True: 14.7M, False: 245M]
  ------------------
  862|  14.7M|            if (lex_state == ls_top) {
  ------------------
  |  Branch (862:17): [True: 6.26M, False: 8.47M]
  ------------------
  863|  6.26M|                ignore(ls_comma);
  864|  6.26M|                return;
  865|  8.47M|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (865:24): [True: 2.97M, False: 5.49M]
  ------------------
  866|  2.97M|                append();
  867|  5.49M|            } else {
  868|  5.49M|                break;
  869|  5.49M|            }
  870|   245M|        } else if (*p == ':') {
  ------------------
  |  Branch (870:20): [True: 451k, False: 245M]
  ------------------
  871|   451k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (871:17): [True: 302k, False: 148k]
  ------------------
  872|   302k|                ignore(ls_colon);
  873|   302k|                return;
  874|   302k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (874:24): [True: 148k, False: 50]
  ------------------
  875|   148k|                append();
  876|   148k|            } else {
  877|     50|                break;
  878|     50|            }
  879|   245M|        } else if (*p == ' ') {
  ------------------
  |  Branch (879:20): [True: 3.01M, False: 242M]
  ------------------
  880|  3.01M|            if (lex_state == ls_top) {
  ------------------
  |  Branch (880:17): [True: 1.71M, False: 1.30M]
  ------------------
  881|  1.71M|                ignore();
  882|  1.71M|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (882:24): [True: 1.30M, False: 738]
  ------------------
  883|  1.30M|                append();
  884|  1.30M|            } else {
  885|    738|                break;
  886|    738|            }
  887|   242M|        } else if (*p == '{') {
  ------------------
  |  Branch (887:20): [True: 111k, False: 242M]
  ------------------
  888|   111k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (888:17): [True: 106k, False: 4.84k]
  ------------------
  889|   106k|                token_start = offset;
  890|   106k|                ignore(ls_begin_dict);
  891|   106k|                return;
  892|   106k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (892:24): [True: 4.79k, False: 51]
  ------------------
  893|  4.79k|                append();
  894|  4.79k|            } else {
  895|     51|                break;
  896|     51|            }
  897|   242M|        } else if (*p == '}') {
  ------------------
  |  Branch (897:20): [True: 74.5k, False: 242M]
  ------------------
  898|  74.5k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (898:17): [True: 46.3k, False: 28.2k]
  ------------------
  899|  46.3k|                ignore(ls_end_dict);
  900|  46.3k|                return;
  901|  46.3k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (901:24): [True: 26.8k, False: 1.35k]
  ------------------
  902|  26.8k|                append();
  903|  26.8k|            } else {
  904|  1.35k|                break;
  905|  1.35k|            }
  906|   242M|        } else if (*p == '[') {
  ------------------
  |  Branch (906:20): [True: 123k, False: 241M]
  ------------------
  907|   123k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (907:17): [True: 62.2k, False: 61.4k]
  ------------------
  908|  62.2k|                token_start = offset;
  909|  62.2k|                ignore(ls_begin_array);
  910|  62.2k|                return;
  911|  62.2k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (911:24): [True: 61.4k, False: 20]
  ------------------
  912|  61.4k|                append();
  913|  61.4k|            } else {
  914|     20|                break;
  915|     20|            }
  916|   241M|        } else if (*p == ']') {
  ------------------
  |  Branch (916:20): [True: 80.4k, False: 241M]
  ------------------
  917|  80.4k|            if (lex_state == ls_top) {
  ------------------
  |  Branch (917:17): [True: 11.5k, False: 68.8k]
  ------------------
  918|  11.5k|                ignore(ls_end_array);
  919|  11.5k|                return;
  920|  68.8k|            } else if (lex_state == ls_string) {
  ------------------
  |  Branch (920:24): [True: 68.6k, False: 269]
  ------------------
  921|  68.6k|                append();
  922|  68.6k|            } else {
  923|    269|                break;
  924|    269|            }
  925|   241M|        } else {
  926|   241M|            switch (lex_state) {
  927|  6.55M|            case ls_top:
  ------------------
  |  Branch (927:13): [True: 6.55M, False: 235M]
  ------------------
  928|  6.55M|                token_start = offset;
  929|  6.55M|                if (*p == '"') {
  ------------------
  |  Branch (929:21): [True: 1.04M, False: 5.51M]
  ------------------
  930|  1.04M|                    ignore(ls_string);
  931|  5.51M|                } else if ((*p >= 'a') && (*p <= 'z')) {
  ------------------
  |  Branch (931:28): [True: 3.01k, False: 5.51M]
  |  Branch (931:43): [True: 3.00k, False: 11]
  ------------------
  932|  3.00k|                    append(ls_alpha);
  933|  5.51M|                } else if (*p == '-') {
  ------------------
  |  Branch (933:28): [True: 1.68k, False: 5.51M]
  ------------------
  934|  1.68k|                    append(ls_number_minus);
  935|  5.51M|                } else if ((*p >= '1') && (*p <= '9')) {
  ------------------
  |  Branch (935:28): [True: 5.48M, False: 20.9k]
  |  Branch (935:43): [True: 5.48M, False: 82]
  ------------------
  936|  5.48M|                    append(ls_number_before_point);
  937|  5.48M|                } else if (*p == '0') {
  ------------------
  |  Branch (937:28): [True: 20.7k, False: 274]
  ------------------
  938|  20.7k|                    append(ls_number_leading_zero);
  939|  20.7k|                } else {
  940|    274|                    QTC::TC("libtests", "JSON parse bad character");
  941|    274|                    throw std::runtime_error(
  942|    274|                        "JSON: offset " + std::to_string(offset) + ": unexpected character " +
  943|    274|                        std::string(p, 1));
  944|    274|                }
  945|  6.55M|                break;
  946|       |
  947|  6.55M|            case ls_number_minus:
  ------------------
  |  Branch (947:13): [True: 1.64k, False: 241M]
  ------------------
  948|  1.64k|                if ((*p >= '1') && (*p <= '9')) {
  ------------------
  |  Branch (948:21): [True: 886, False: 758]
  |  Branch (948:36): [True: 877, False: 9]
  ------------------
  949|    877|                    append(ls_number_before_point);
  950|    877|                } else if (*p == '0') {
  ------------------
  |  Branch (950:28): [True: 747, False: 20]
  ------------------
  951|    747|                    append(ls_number_leading_zero);
  952|    747|                } else {
  953|     20|                    QTC::TC("libtests", "JSON parse number minus no digits");
  954|     20|                    throw std::runtime_error(
  955|     20|                        "JSON: offset " + std::to_string(offset) +
  956|     20|                        ": numeric literal: no digit after minus sign");
  957|     20|                }
  958|  1.62k|                break;
  959|       |
  960|  2.01k|            case ls_number_leading_zero:
  ------------------
  |  Branch (960:13): [True: 2.01k, False: 241M]
  ------------------
  961|  2.01k|                if (*p == '.') {
  ------------------
  |  Branch (961:21): [True: 475, False: 1.53k]
  ------------------
  962|    475|                    append(ls_number_point);
  963|  1.53k|                } else if (*p == 'e' || *p == 'E') {
  ------------------
  |  Branch (963:28): [True: 615, False: 922]
  |  Branch (963:41): [True: 877, False: 45]
  ------------------
  964|  1.49k|                    append(ls_number_e);
  965|  1.49k|                } else {
  966|     45|                    QTC::TC("libtests", "JSON parse leading zero");
  967|     45|                    throw std::runtime_error(
  968|     45|                        "JSON: offset " + std::to_string(offset) + ": number with leading zero");
  969|     45|                }
  970|  1.96k|                break;
  971|       |
  972|  6.28M|            case ls_number_before_point:
  ------------------
  |  Branch (972:13): [True: 6.28M, False: 235M]
  ------------------
  973|  6.28M|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (973:21): [True: 6.28M, False: 2.04k]
  |  Branch (973:36): [True: 6.28M, False: 3.73k]
  ------------------
  974|  6.28M|                    append();
  975|  6.28M|                } else if (*p == '.') {
  ------------------
  |  Branch (975:28): [True: 2.00k, False: 3.78k]
  ------------------
  976|  2.00k|                    append(ls_number_point);
  977|  3.78k|                } else if (*p == 'e' || *p == 'E') {
  ------------------
  |  Branch (977:28): [True: 1.99k, False: 1.78k]
  |  Branch (977:41): [True: 1.72k, False: 66]
  ------------------
  978|  3.71k|                    append(ls_number_e);
  979|  3.71k|                } else {
  980|     66|                    tokenError();
  981|     66|                }
  982|  6.28M|                break;
  983|       |
  984|  2.44k|            case ls_number_point:
  ------------------
  |  Branch (984:13): [True: 2.44k, False: 241M]
  ------------------
  985|  2.44k|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (985:21): [True: 2.43k, False: 7]
  |  Branch (985:36): [True: 2.42k, False: 9]
  ------------------
  986|  2.42k|                    append(ls_number_after_point);
  987|  2.42k|                } else {
  988|     16|                    tokenError();
  989|     16|                }
  990|  2.44k|                break;
  991|       |
  992|  16.2M|            case ls_number_after_point:
  ------------------
  |  Branch (992:13): [True: 16.2M, False: 225M]
  ------------------
  993|  16.2M|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (993:21): [True: 16.2M, False: 21]
  |  Branch (993:36): [True: 16.2M, False: 1.24k]
  ------------------
  994|  16.2M|                    append();
  995|  16.2M|                } else if (*p == 'e' || *p == 'E') {
  ------------------
  |  Branch (995:28): [True: 1.01k, False: 249]
  |  Branch (995:41): [True: 222, False: 27]
  ------------------
  996|  1.24k|                    append(ls_number_e);
  997|  1.24k|                } else {
  998|     27|                    tokenError();
  999|     27|                }
 1000|  16.2M|                break;
 1001|       |
 1002|  6.34k|            case ls_number_e:
  ------------------
  |  Branch (1002:13): [True: 6.34k, False: 241M]
  ------------------
 1003|  6.34k|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (1003:21): [True: 4.42k, False: 1.91k]
  |  Branch (1003:36): [True: 4.41k, False: 12]
  ------------------
 1004|  4.41k|                    append(ls_number);
 1005|  4.41k|                } else if ((*p == '+') || (*p == '-')) {
  ------------------
  |  Branch (1005:28): [True: 1.21k, False: 716]
  |  Branch (1005:43): [True: 685, False: 31]
  ------------------
 1006|  1.90k|                    append(ls_number_e_sign);
 1007|  1.90k|                } else {
 1008|     31|                    tokenError();
 1009|     31|                }
 1010|  6.34k|                break;
 1011|       |
 1012|  1.87k|            case ls_number_e_sign:
  ------------------
  |  Branch (1012:13): [True: 1.87k, False: 241M]
  ------------------
 1013|  1.87k|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (1013:21): [True: 1.85k, False: 23]
  |  Branch (1013:36): [True: 1.84k, False: 11]
  ------------------
 1014|  1.84k|                    append(ls_number);
 1015|  1.84k|                } else {
 1016|     34|                    tokenError();
 1017|     34|                }
 1018|  1.87k|                break;
 1019|       |
 1020|  4.23M|            case ls_number:
  ------------------
  |  Branch (1020:13): [True: 4.23M, False: 237M]
  ------------------
 1021|       |                // We only get here after we have seen an exponent.
 1022|  4.23M|                if ((*p >= '0') && (*p <= '9')) {
  ------------------
  |  Branch (1022:21): [True: 4.23M, False: 15]
  |  Branch (1022:36): [True: 4.23M, False: 9]
  ------------------
 1023|  4.23M|                    append();
 1024|  4.23M|                } else {
 1025|     24|                    tokenError();
 1026|     24|                }
 1027|  4.23M|                break;
 1028|       |
 1029|  10.7M|            case ls_alpha:
  ------------------
  |  Branch (1029:13): [True: 10.7M, False: 231M]
  ------------------
 1030|  10.7M|                if ((*p >= 'a') && (*p <= 'z')) {
  ------------------
  |  Branch (1030:21): [True: 10.7M, False: 82]
  |  Branch (1030:36): [True: 10.7M, False: 3]
  ------------------
 1031|  10.7M|                    append();
 1032|  10.7M|                } else {
 1033|     85|                    tokenError();
 1034|     85|                }
 1035|  10.7M|                break;
 1036|       |
 1037|   197M|            case ls_string:
  ------------------
  |  Branch (1037:13): [True: 197M, False: 44.2M]
  ------------------
 1038|   197M|                if (*p == '"') {
  ------------------
  |  Branch (1038:21): [True: 1.04M, False: 196M]
  ------------------
 1039|  1.04M|                    if (high_offset) {
  ------------------
  |  Branch (1039:25): [True: 29, False: 1.04M]
  ------------------
 1040|     29|                        QTC::TC("libtests", "JSON 16 dangling high");
 1041|     29|                        throw std::runtime_error(
 1042|     29|                            "JSON: offset " + std::to_string(high_offset) +
 1043|     29|                            ": UTF-16 high surrogate not followed by low surrogate");
 1044|     29|                    }
 1045|  1.04M|                    ignore(ls_after_string);
 1046|  1.04M|                    return;
 1047|   196M|                } else if (*p == '\\') {
  ------------------
  |  Branch (1047:28): [True: 19.6k, False: 196M]
  ------------------
 1048|  19.6k|                    ignore(ls_backslash);
 1049|   196M|                } else {
 1050|   196M|                    append();
 1051|   196M|                }
 1052|   196M|                break;
 1053|       |
 1054|   196M|            case ls_backslash:
  ------------------
  |  Branch (1054:13): [True: 19.6k, False: 241M]
  ------------------
 1055|  19.6k|                lex_state = ls_string;
 1056|  19.6k|                switch (*p) {
 1057|  6.89k|                case '\\':
  ------------------
  |  Branch (1057:17): [True: 6.89k, False: 12.7k]
  ------------------
 1058|  7.40k|                case '\"':
  ------------------
  |  Branch (1058:17): [True: 517, False: 19.1k]
  ------------------
 1059|  7.61k|                case '/':
  ------------------
  |  Branch (1059:17): [True: 211, False: 19.4k]
  ------------------
 1060|       |                    // \/ is allowed in json input, but so is /, so we don't map / to \/ in output.
 1061|  7.61k|                    token += *p;
 1062|  7.61k|                    break;
 1063|    443|                case 'b':
  ------------------
  |  Branch (1063:17): [True: 443, False: 19.2k]
  ------------------
 1064|    443|                    token += '\b';
 1065|    443|                    break;
 1066|    587|                case 'f':
  ------------------
  |  Branch (1066:17): [True: 587, False: 19.0k]
  ------------------
 1067|    587|                    token += '\f';
 1068|    587|                    break;
 1069|  1.46k|                case 'n':
  ------------------
  |  Branch (1069:17): [True: 1.46k, False: 18.1k]
  ------------------
 1070|  1.46k|                    token += '\n';
 1071|  1.46k|                    break;
 1072|  1.10k|                case 'r':
  ------------------
  |  Branch (1072:17): [True: 1.10k, False: 18.5k]
  ------------------
 1073|  1.10k|                    token += '\r';
 1074|  1.10k|                    break;
 1075|  4.96k|                case 't':
  ------------------
  |  Branch (1075:17): [True: 4.96k, False: 14.6k]
  ------------------
 1076|  4.96k|                    token += '\t';
 1077|  4.96k|                    break;
 1078|  3.45k|                case 'u':
  ------------------
  |  Branch (1078:17): [True: 3.45k, False: 16.1k]
  ------------------
 1079|  3.45k|                    lex_state = ls_u4;
 1080|  3.45k|                    u_count = 0;
 1081|  3.45k|                    u_value = 0;
 1082|  3.45k|                    break;
 1083|      9|                default:
  ------------------
  |  Branch (1083:17): [True: 9, False: 19.6k]
  ------------------
 1084|      9|                    lex_state = ls_backslash;
 1085|      9|                    tokenError();
 1086|  19.6k|                }
 1087|  19.6k|                ignore();
 1088|  19.6k|                break;
 1089|       |
 1090|  13.6k|            case ls_u4:
  ------------------
  |  Branch (1090:13): [True: 13.6k, False: 241M]
  ------------------
 1091|  13.6k|                using ui = unsigned int;
 1092|  13.6k|                if (ui val = ui(QUtil::hex_decode_char(*p)); val < 16) {
  ------------------
  |  Branch (1092:62): [True: 13.5k, False: 31]
  ------------------
 1093|  13.5k|                    u_value = 16 * u_value + val;
 1094|  13.5k|                } else {
 1095|     31|                    tokenError();
 1096|     31|                }
 1097|  13.6k|                if (++u_count == 4) {
  ------------------
  |  Branch (1097:21): [True: 3.38k, False: 10.2k]
  ------------------
 1098|  3.38k|                    handle_u_code(u_value, offset - 5, high_surrogate, high_offset, token);
 1099|  3.38k|                    lex_state = ls_string;
 1100|  3.38k|                }
 1101|  13.6k|                ignore();
 1102|  13.6k|                break;
 1103|       |
 1104|      0|            default:
  ------------------
  |  Branch (1104:13): [True: 0, False: 241M]
  ------------------
 1105|      0|                throw std::logic_error("JSONParser::getToken : trying to handle delimiter state");
 1106|   241M|            }
 1107|   241M|        }
 1108|   261M|    }
 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.52M|    if (!token.empty()) {
  ------------------
  |  Branch (1113:9): [True: 5.51M, False: 7.22k]
  ------------------
 1114|  5.51M|        switch (lex_state) {
 1115|      0|        case ls_top:
  ------------------
  |  Branch (1115:9): [True: 0, False: 5.51M]
  ------------------
 1116|       |            // Can't happen
 1117|      0|            throw std::logic_error("tok_start set in ls_top while parsing");
 1118|      0|            break;
 1119|       |
 1120|  19.4k|        case ls_number_leading_zero:
  ------------------
  |  Branch (1120:9): [True: 19.4k, False: 5.49M]
  ------------------
 1121|  5.50M|        case ls_number_before_point:
  ------------------
  |  Branch (1121:9): [True: 5.48M, False: 30.5k]
  ------------------
 1122|  5.50M|        case ls_number_after_point:
  ------------------
  |  Branch (1122:9): [True: 1.15k, False: 5.51M]
  ------------------
 1123|  5.50M|            lex_state = ls_number;
 1124|  5.50M|            break;
 1125|       |
 1126|  6.23k|        case ls_number:
  ------------------
  |  Branch (1126:9): [True: 6.23k, False: 5.50M]
  ------------------
 1127|  9.15k|        case ls_alpha:
  ------------------
  |  Branch (1127:9): [True: 2.91k, False: 5.51M]
  ------------------
 1128|       |            // terminal state
 1129|  9.15k|            break;
 1130|       |
 1131|    740|        default:
  ------------------
  |  Branch (1131:9): [True: 740, False: 5.51M]
  ------------------
 1132|    740|            tokenError();
 1133|  5.51M|        }
 1134|  5.51M|    }
 1135|  5.52M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser6ignoreEv:
  812|  2.27M|{
  813|  2.27M|    ++p;
  814|  2.27M|    ++offset;
  815|  2.27M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser6ignoreENS0_11lex_state_eE:
  821|  8.89M|{
  822|  8.89M|    lex_state = next;
  823|  8.89M|    ++p;
  824|  8.89M|    ++offset;
  825|  8.89M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser6appendEv:
  792|   238M|{
  793|   238M|    token += *p;
  794|   238M|    ++p;
  795|   238M|    ++offset;
  796|   238M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser6appendENS0_11lex_state_eE:
  802|  5.53M|{
  803|  5.53M|    lex_state = next;
  804|  5.53M|    token += *p;
  805|  5.53M|    ++p;
  806|  5.53M|    ++offset;
  807|  5.53M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser10tokenErrorEv:
  727|  1.06k|{
  728|  1.06k|    if (done) {
  ------------------
  |  Branch (728:9): [True: 654, False: 409]
  ------------------
  729|    654|        QTC::TC("libtests", "JSON parse ls premature end of input");
  730|    654|        throw std::runtime_error("JSON: premature end of input");
  731|    654|    }
  732|       |
  733|    409|    if (lex_state == ls_u4) {
  ------------------
  |  Branch (733:9): [True: 31, False: 378]
  ------------------
  734|     31|        QTC::TC("libtests", "JSON parse bad hex after u");
  735|     31|        throw std::runtime_error(
  736|     31|            "JSON: offset " + std::to_string(offset - u_count - 1) +
  737|     31|            ": \\u must be followed by four hex digits");
  738|    378|    } else if (lex_state == ls_alpha) {
  ------------------
  |  Branch (738:16): [True: 85, False: 293]
  ------------------
  739|     85|        QTC::TC("libtests", "JSON parse keyword bad character");
  740|     85|        throw std::runtime_error(
  741|     85|            "JSON: offset " + std::to_string(offset) + ": keyword: unexpected character " +
  742|     85|            std::string(p, 1));
  743|    293|    } else if (lex_state == ls_string) {
  ------------------
  |  Branch (743:16): [True: 27, False: 266]
  ------------------
  744|     27|        QTC::TC("libtests", "JSON parse control char in string");
  745|     27|        throw std::runtime_error(
  746|     27|            "JSON: offset " + std::to_string(offset) +
  747|     27|            ": control character in string (missing \"?)");
  748|    266|    } else if (lex_state == ls_backslash) {
  ------------------
  |  Branch (748:16): [True: 9, False: 257]
  ------------------
  749|      9|        QTC::TC("libtests", "JSON parse backslash bad character");
  750|      9|        throw std::runtime_error(
  751|      9|            "JSON: offset " + std::to_string(offset) +
  752|      9|            ": invalid character after backslash: " + std::string(p, 1));
  753|      9|    }
  754|       |
  755|    257|    if (*p == '.') {
  ------------------
  |  Branch (755:9): [True: 14, False: 243]
  ------------------
  756|     14|        if (lex_state == ls_number || lex_state == ls_number_e || lex_state == ls_number_e_sign) {
  ------------------
  |  Branch (756:13): [True: 3, False: 11]
  |  Branch (756:39): [True: 3, False: 8]
  |  Branch (756:67): [True: 3, False: 5]
  ------------------
  757|      9|            QTC::TC("libtests", "JSON parse point after e");
  758|      9|            throw std::runtime_error(
  759|      9|                "JSON: offset " + std::to_string(offset) +
  760|      9|                ": numeric literal: decimal point after e");
  761|      9|        } else {
  762|      5|            QTC::TC("libtests", "JSON parse duplicate point");
  763|      5|            throw std::runtime_error(
  764|      5|                "JSON: offset " + std::to_string(offset) +
  765|      5|                ": numeric literal: decimal point already seen");
  766|      5|        }
  767|    243|    } else if (*p == 'e' || *p == 'E') {
  ------------------
  |  Branch (767:16): [True: 9, False: 234]
  |  Branch (767:29): [True: 9, False: 225]
  ------------------
  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|    225|    } else if ((*p == '+') || (*p == '-')) {
  ------------------
  |  Branch (771:16): [True: 9, False: 216]
  |  Branch (771:31): [True: 19, False: 197]
  ------------------
  772|     28|        QTC::TC("libtests", "JSON parse unexpected sign");
  773|     28|        throw std::runtime_error(
  774|     28|            "JSON: offset " + std::to_string(offset) + ": numeric literal: unexpected sign");
  775|    197|    } else if (QUtil::is_space(*p) || strchr("{}[]:,", *p)) {
  ------------------
  |  Branch (775:16): [True: 18, False: 179]
  |  Branch (775:39): [True: 41, False: 138]
  ------------------
  776|     59|        QTC::TC("libtests", "JSON parse incomplete number");
  777|     59|        throw std::runtime_error(
  778|     59|            "JSON: offset " + std::to_string(offset) + ": numeric literal: incomplete number");
  779|       |
  780|    138|    } else {
  781|    138|        QTC::TC("libtests", "JSON parse numeric bad character");
  782|    138|        throw std::runtime_error(
  783|    138|            "JSON: offset " + std::to_string(offset) + ": numeric literal: unexpected character " +
  784|    138|            std::string(p, 1));
  785|    138|    }
  786|      0|    throw std::logic_error("JSON::tokenError : unhandled error");
  787|    257|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser13handle_u_codeEmxRmRxRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  696|  3.38k|{
  697|  3.38k|    if ((codepoint & 0xFC00) == 0xD800) {
  ------------------
  |  Branch (697:9): [True: 732, False: 2.65k]
  ------------------
  698|       |        // high surrogate
  699|    732|        qpdf_offset_t new_high_offset = offset;
  700|    732|        if (high_offset) {
  ------------------
  |  Branch (700:13): [True: 30, False: 702]
  ------------------
  701|     30|            QTC::TC("libtests", "JSON 16 high high");
  702|     30|            throw std::runtime_error(
  703|     30|                "JSON: offset " + std::to_string(new_high_offset) +
  704|     30|                ": UTF-16 high surrogate found after previous high surrogate at offset " +
  705|     30|                std::to_string(high_offset));
  706|     30|        }
  707|    702|        high_offset = new_high_offset;
  708|    702|        high_surrogate = codepoint;
  709|  2.65k|    } else if ((codepoint & 0xFC00) == 0xDC00) {
  ------------------
  |  Branch (709:16): [True: 670, False: 1.98k]
  ------------------
  710|       |        // low surrogate
  711|    670|        if (offset != (high_offset + 6)) {
  ------------------
  |  Branch (711:13): [True: 30, False: 640]
  ------------------
  712|     30|            QTC::TC("libtests", "JSON 16 low not after high");
  713|     30|            throw std::runtime_error(
  714|     30|                "JSON: offset " + std::to_string(offset) +
  715|     30|                ": UTF-16 low surrogate found not immediately after high surrogate");
  716|     30|        }
  717|    640|        high_offset = 0;
  718|    640|        codepoint = 0x10000U + ((high_surrogate & 0x3FFU) << 10U) + (codepoint & 0x3FF);
  719|    640|        result += QUtil::toUTF8(codepoint);
  720|  1.98k|    } else {
  721|  1.98k|        result += QUtil::toUTF8(codepoint);
  722|  1.98k|    }
  723|  3.38k|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser11handleTokenEv:
 1139|  13.3M|{
 1140|  13.3M|    if (lex_state == ls_top) {
  ------------------
  |  Branch (1140:9): [True: 7.06k, False: 13.3M]
  ------------------
 1141|  7.06k|        return;
 1142|  7.06k|    }
 1143|       |
 1144|  13.3M|    if (parser_state == ps_done) {
  ------------------
  |  Branch (1144:9): [True: 67, False: 13.3M]
  ------------------
 1145|     67|        QTC::TC("libtests", "JSON parse junk after object");
 1146|     67|        throw std::runtime_error(
 1147|     67|            "JSON: offset " + std::to_string(offset) +
 1148|     67|            ": material follows end of object: " + token);
 1149|     67|    }
 1150|       |
 1151|  13.3M|    const static JSON null_item = JSON::makeNull();
 1152|  13.3M|    JSON item;
 1153|  13.3M|    auto tos = stack.empty() ? null_item : stack.back().item;
  ------------------
  |  Branch (1153:16): [True: 12.6k, False: 13.3M]
  ------------------
 1154|  13.3M|    auto ls = lex_state;
 1155|  13.3M|    lex_state = ls_top;
 1156|       |
 1157|  13.3M|    switch (ls) {
 1158|   106k|    case ls_begin_dict:
  ------------------
  |  Branch (1158:5): [True: 106k, False: 13.2M]
  ------------------
 1159|   106k|        item = JSON::makeDictionary();
 1160|   106k|        break;
 1161|       |
 1162|  62.2k|    case ls_begin_array:
  ------------------
  |  Branch (1162:5): [True: 62.2k, False: 13.2M]
  ------------------
 1163|  62.2k|        item = JSON::makeArray();
 1164|  62.2k|        break;
 1165|       |
 1166|   302k|    case ls_colon:
  ------------------
  |  Branch (1166:5): [True: 302k, False: 13.0M]
  ------------------
 1167|   302k|        if (parser_state != ps_dict_after_key) {
  ------------------
  |  Branch (1167:13): [True: 142, False: 302k]
  ------------------
 1168|    142|            QTC::TC("libtests", "JSON parse unexpected :");
 1169|    142|            throw std::runtime_error(
 1170|    142|                "JSON: offset " + std::to_string(offset) + ": unexpected colon");
 1171|    142|        }
 1172|   302k|        parser_state = ps_dict_after_colon;
 1173|   302k|        return;
 1174|       |
 1175|  6.26M|    case ls_comma:
  ------------------
  |  Branch (1175:5): [True: 6.26M, False: 7.08M]
  ------------------
 1176|  6.26M|        if (!((parser_state == ps_dict_after_item) || (parser_state == ps_array_after_item))) {
  ------------------
  |  Branch (1176:15): [True: 208k, False: 6.05M]
  |  Branch (1176:55): [True: 6.05M, False: 69]
  ------------------
 1177|     69|            QTC::TC("libtests", "JSON parse unexpected ,");
 1178|     69|            throw std::runtime_error(
 1179|     69|                "JSON: offset " + std::to_string(offset) + ": unexpected comma");
 1180|     69|        }
 1181|  6.26M|        if (parser_state == ps_dict_after_item) {
  ------------------
  |  Branch (1181:13): [True: 208k, False: 6.05M]
  ------------------
 1182|   208k|            parser_state = ps_dict_after_comma;
 1183|  6.05M|        } else if (parser_state == ps_array_after_item) {
  ------------------
  |  Branch (1183:20): [True: 6.05M, False: 0]
  ------------------
 1184|  6.05M|            parser_state = ps_array_after_comma;
 1185|  6.05M|        } else {
 1186|      0|            throw std::logic_error("JSONParser::handleToken: unexpected parser state for comma");
 1187|      0|        }
 1188|  6.26M|        return;
 1189|       |
 1190|  6.26M|    case ls_end_array:
  ------------------
  |  Branch (1190:5): [True: 11.5k, False: 13.3M]
  ------------------
 1191|  11.5k|        if (!(parser_state == ps_array_begin || parser_state == ps_array_after_item)) {
  ------------------
  |  Branch (1191:15): [True: 8.56k, False: 2.98k]
  |  Branch (1191:49): [True: 2.95k, False: 30]
  ------------------
 1192|     30|            QTC::TC("libtests", "JSON parse unexpected ]");
 1193|     30|            throw std::runtime_error(
 1194|     30|                "JSON: offset " + std::to_string(offset) + ": unexpected array end delimiter");
 1195|     30|        }
 1196|  11.5k|        parser_state = stack.back().state;
 1197|  11.5k|        tos.setEnd(offset);
 1198|  11.5k|        if (reactor) {
  ------------------
  |  Branch (1198:13): [True: 5.64k, False: 5.87k]
  ------------------
 1199|  5.64k|            reactor->containerEnd(tos);
 1200|  5.64k|        }
 1201|  11.5k|        if (parser_state != ps_done) {
  ------------------
  |  Branch (1201:13): [True: 11.5k, False: 16]
  ------------------
 1202|  11.5k|            stack.pop_back();
 1203|  11.5k|        }
 1204|  11.5k|        return;
 1205|       |
 1206|  46.3k|    case ls_end_dict:
  ------------------
  |  Branch (1206:5): [True: 46.3k, False: 13.3M]
  ------------------
 1207|  46.3k|        if (!((parser_state == ps_dict_begin) || (parser_state == ps_dict_after_item))) {
  ------------------
  |  Branch (1207:15): [True: 10.3k, False: 35.9k]
  |  Branch (1207:50): [True: 35.9k, False: 17]
  ------------------
 1208|     17|            QTC::TC("libtests", "JSON parse unexpected }");
 1209|     17|            throw std::runtime_error(
 1210|     17|                "JSON: offset " + std::to_string(offset) + ": unexpected dictionary end delimiter");
 1211|     17|        }
 1212|  46.3k|        parser_state = stack.back().state;
 1213|  46.3k|        tos.setEnd(offset);
 1214|  46.3k|        if (reactor) {
  ------------------
  |  Branch (1214:13): [True: 23.0k, False: 23.2k]
  ------------------
 1215|  23.0k|            reactor->containerEnd(tos);
 1216|  23.0k|        }
 1217|  46.3k|        if (parser_state != ps_done) {
  ------------------
  |  Branch (1217:13): [True: 46.2k, False: 125]
  ------------------
 1218|  46.2k|            stack.pop_back();
 1219|  46.2k|        }
 1220|  46.3k|        return;
 1221|       |
 1222|  5.51M|    case ls_number:
  ------------------
  |  Branch (1222:5): [True: 5.51M, False: 7.83M]
  ------------------
 1223|  5.51M|        item = JSON::makeNumber(token);
 1224|  5.51M|        break;
 1225|       |
 1226|  2.91k|    case ls_alpha:
  ------------------
  |  Branch (1226:5): [True: 2.91k, False: 13.3M]
  ------------------
 1227|  2.91k|        if (token == "true") {
  ------------------
  |  Branch (1227:13): [True: 604, False: 2.31k]
  ------------------
 1228|    604|            item = JSON::makeBool(true);
 1229|  2.31k|        } else if (token == "false") {
  ------------------
  |  Branch (1229:20): [True: 1.12k, False: 1.18k]
  ------------------
 1230|  1.12k|            item = JSON::makeBool(false);
 1231|  1.18k|        } else if (token == "null") {
  ------------------
  |  Branch (1231:20): [True: 901, False: 286]
  ------------------
 1232|    901|            item = JSON::makeNull();
 1233|    901|        } else {
 1234|    286|            QTC::TC("libtests", "JSON parse invalid keyword");
 1235|    286|            throw std::runtime_error(
 1236|    286|                "JSON: offset " + std::to_string(offset) + ": invalid keyword " + token);
 1237|    286|        }
 1238|  2.62k|        break;
 1239|       |
 1240|  1.04M|    case ls_after_string:
  ------------------
  |  Branch (1240:5): [True: 1.04M, False: 12.3M]
  ------------------
 1241|  1.04M|        if (parser_state == ps_dict_begin || parser_state == ps_dict_after_comma) {
  ------------------
  |  Branch (1241:13): [True: 94.7k, False: 945k]
  |  Branch (1241:46): [True: 208k, False: 737k]
  ------------------
 1242|   302k|            dict_key = token;
 1243|   302k|            dict_key_offset = token_start;
 1244|   302k|            parser_state = ps_dict_after_key;
 1245|   302k|            return;
 1246|   737k|        } else {
 1247|   737k|            item = JSON::makeString(token);
 1248|   737k|        }
 1249|   737k|        break;
 1250|       |
 1251|   737k|    default:
  ------------------
  |  Branch (1251:5): [True: 161, False: 13.3M]
  ------------------
 1252|    161|        throw std::runtime_error(
 1253|    161|            "JSON: offset " + std::to_string(offset) + ": premature end of input");
 1254|      0|        break;
 1255|  13.3M|    }
 1256|       |
 1257|  6.42M|    item.setStart(token_start);
 1258|  6.42M|    item.setEnd(offset);
 1259|       |
 1260|  6.42M|    switch (parser_state) {
  ------------------
  |  Branch (1260:13): [True: 0, False: 6.42M]
  ------------------
 1261|     26|    case ps_dict_begin:
  ------------------
  |  Branch (1261:5): [True: 26, False: 6.42M]
  ------------------
 1262|     48|    case ps_dict_after_comma:
  ------------------
  |  Branch (1262:5): [True: 22, False: 6.42M]
  ------------------
 1263|     48|        QTC::TC("libtests", "JSON parse string as dict key");
 1264|     48|        throw std::runtime_error(
 1265|     48|            "JSON: offset " + std::to_string(offset) + ": expect string as dictionary key");
 1266|      0|        break;
 1267|       |
 1268|   302k|    case ps_dict_after_colon:
  ------------------
  |  Branch (1268:5): [True: 302k, False: 6.11M]
  ------------------
 1269|   302k|        if (tos.checkDictionaryKeySeen(dict_key)) {
  ------------------
  |  Branch (1269:13): [True: 69, False: 302k]
  ------------------
 1270|     69|            QTC::TC("libtests", "JSON parse duplicate key");
 1271|     69|            throw std::runtime_error(
 1272|     69|                "JSON: offset " + std::to_string(dict_key_offset) + ": duplicated dictionary key");
 1273|     69|        }
 1274|   302k|        if (!reactor || !reactor->dictionaryItem(dict_key, item)) {
  ------------------
  |  Branch (1274:13): [True: 151k, False: 150k]
  |  Branch (1274:25): [True: 288, False: 150k]
  ------------------
 1275|   151k|            tos.addDictionaryMember(dict_key, item);
 1276|   151k|        }
 1277|   302k|        parser_state = ps_dict_after_item;
 1278|   302k|        break;
 1279|       |
 1280|  52.1k|    case ps_array_begin:
  ------------------
  |  Branch (1280:5): [True: 52.1k, False: 6.36M]
  ------------------
 1281|  6.10M|    case ps_array_after_comma:
  ------------------
  |  Branch (1281:5): [True: 6.05M, False: 367k]
  ------------------
 1282|  6.10M|        if (!reactor || !reactor->arrayItem(item)) {
  ------------------
  |  Branch (1282:13): [True: 3.10M, False: 3.00M]
  |  Branch (1282:25): [True: 35, False: 3.00M]
  ------------------
 1283|  3.10M|            tos.addArrayElement(item);
 1284|  3.10M|        }
 1285|  6.10M|        parser_state = ps_array_after_item;
 1286|  6.10M|        break;
 1287|       |
 1288|  12.4k|    case ps_top:
  ------------------
  |  Branch (1288:5): [True: 12.4k, False: 6.40M]
  ------------------
 1289|  12.4k|        if (!(item.isDictionary() || item.isArray())) {
  ------------------
  |  Branch (1289:15): [True: 11.0k, False: 1.43k]
  |  Branch (1289:38): [True: 844, False: 586]
  ------------------
 1290|    586|            stack.emplace_back(ps_done, item);
 1291|    586|            parser_state = ps_done;
 1292|    586|            return;
 1293|    586|        }
 1294|  11.8k|        parser_state = ps_done;
 1295|  11.8k|        break;
 1296|       |
 1297|     49|    case ps_dict_after_key:
  ------------------
  |  Branch (1297:5): [True: 49, False: 6.42M]
  ------------------
 1298|     49|        QTC::TC("libtests", "JSON parse expected colon");
 1299|     49|        throw std::runtime_error("JSON: offset " + std::to_string(offset) + ": expected ':'");
 1300|      0|        break;
 1301|       |
 1302|    105|    case ps_dict_after_item:
  ------------------
  |  Branch (1302:5): [True: 105, False: 6.42M]
  ------------------
 1303|    105|        QTC::TC("libtests", "JSON parse expected , or }");
 1304|    105|        throw std::runtime_error(
 1305|    105|            "JSON: offset " + std::to_string(offset) + ": expected ',' or '}'");
 1306|      0|        break;
 1307|       |
 1308|    136|    case ps_array_after_item:
  ------------------
  |  Branch (1308:5): [True: 136, False: 6.42M]
  ------------------
 1309|    136|        QTC::TC("libtests", "JSON parse expected, or ]");
 1310|    136|        throw std::runtime_error(
 1311|    136|            "JSON: offset " + std::to_string(offset) + ": expected ',' or ']'");
 1312|      0|        break;
 1313|       |
 1314|      0|    case ps_done:
  ------------------
  |  Branch (1314:5): [True: 0, False: 6.42M]
  ------------------
 1315|      0|        throw std::logic_error("JSONParser::handleToken: unexpected parser state");
 1316|  6.42M|    }
 1317|       |
 1318|  6.41M|    if (item.isDictionary() || item.isArray()) {
  ------------------
  |  Branch (1318:9): [True: 106k, False: 6.31M]
  |  Branch (1318:32): [True: 62.1k, False: 6.25M]
  ------------------
 1319|   168k|        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|   168k|        if (item.isDictionary()) {
  ------------------
  |  Branch (1323:13): [True: 106k, False: 62.1k]
  ------------------
 1324|   106k|            if (reactor) {
  ------------------
  |  Branch (1324:17): [True: 52.9k, False: 53.5k]
  ------------------
 1325|  52.9k|                reactor->dictionaryStart();
 1326|  52.9k|            }
 1327|   106k|            parser_state = ps_dict_begin;
 1328|   106k|        } else if (item.isArray()) {
  ------------------
  |  Branch (1328:20): [True: 62.1k, False: 0]
  ------------------
 1329|  62.1k|            if (reactor) {
  ------------------
  |  Branch (1329:17): [True: 27.5k, False: 34.5k]
  ------------------
 1330|  27.5k|                reactor->arrayStart();
 1331|  27.5k|            }
 1332|  62.1k|            parser_state = ps_array_begin;
 1333|  62.1k|        }
 1334|       |
 1335|   168k|        if (stack.size() > 500) {
  ------------------
  |  Branch (1335:13): [True: 3, False: 168k]
  ------------------
 1336|      3|            throw std::runtime_error(
 1337|      3|                "JSON: offset " + std::to_string(offset) + ": maximum object depth exceeded");
 1338|      3|        }
 1339|   168k|    }
 1340|  6.41M|}
JSON.cc:_ZN12_GLOBAL__N_110JSONParser10StackFrameC2ENS0_14parser_state_eER4JSON:
  649|   169k|            {
  650|   169k|            }

_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|   152k|{
   31|   152k|    this->write(cstr, strlen(cstr));
   32|   152k|}
_ZN8PipelinelsEPKc:
   42|   152k|{
   43|   152k|    this->writeCStr(cstr);
   44|   152k|    return *this;
   45|   152k|}
_ZN8Pipeline5writeEPKcm:
  112|   152k|{
  113|   152k|    this->write(reinterpret_cast<unsigned char const*>(data), len);
  114|   152k|}

_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|   152k|{
   24|   152k|    m->os.write(reinterpret_cast<char const*>(buf), static_cast<std::streamsize>(len));
   25|   152k|}
_ZN10Pl_OStream6finishEv:
   29|      2|{
   30|      2|    m->os.flush();
   31|      2|}

_ZN4QPDF20EncryptionParametersC2Ev:
  196|  6.73k|{
  197|  6.73k|}
_ZN4QPDF7MembersC2Ev:
  203|  6.73k|{
  204|  6.73k|}
_ZN4QPDFC2Ev:
  208|  6.73k|{
  209|  6.73k|    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.73k|    static std::atomic<unsigned long long> unique_id{0};
  213|  6.73k|    m->unique_id = unique_id.fetch_add(1ULL);
  214|  6.73k|}
_ZN4QPDFD2Ev:
  217|  6.73k|{
  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.73k|    m->xref_table.clear();
  231|  16.1k|    for (auto const& iter: m->obj_cache) {
  ------------------
  |  Branch (231:26): [True: 16.1k, False: 6.73k]
  ------------------
  232|  16.1k|        iter.second.object->disconnect();
  233|  16.1k|        if (iter.second.object->getTypeCode() != ::ot_null) {
  ------------------
  |  Branch (233:13): [True: 10.2k, False: 5.84k]
  ------------------
  234|  10.2k|            iter.second.object->destroy();
  235|  10.2k|        }
  236|  16.1k|    }
  237|  6.73k|}
_ZN4QPDF17processMemoryFileEPKcS1_mS1_:
  262|  6.73k|{
  263|  6.73k|    processInputSource(
  264|  6.73k|        std::shared_ptr<InputSource>(
  265|       |            // line-break
  266|  6.73k|            new BufferInputSource(
  267|  6.73k|                description, new Buffer(QUtil::unsigned_char_pointer(buf), length), true)),
  268|  6.73k|        password);
  269|  6.73k|}
_ZN4QPDF18processInputSourceENSt3__110shared_ptrI11InputSourceEEPKc:
  273|  6.73k|{
  274|  6.73k|    m->file = source;
  275|  6.73k|    parse(password);
  276|  6.73k|}
_ZN4QPDF14setMaxWarningsEm:
  336|  6.73k|{
  337|  6.73k|    m->max_warnings = val;
  338|  6.73k|}
_ZN4QPDF18validatePDFVersionERPKcRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  374|  6.83k|{
  375|  6.83k|    bool valid = QUtil::is_digit(*p);
  376|  6.83k|    if (valid) {
  ------------------
  |  Branch (376:9): [True: 6.82k, False: 11]
  ------------------
  377|  13.8k|        while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (377:16): [True: 7.02k, False: 6.82k]
  ------------------
  378|  7.02k|            version.append(1, *p++);
  379|  7.02k|        }
  380|  6.82k|        if ((*p == '.') && QUtil::is_digit(*(p + 1))) {
  ------------------
  |  Branch (380:13): [True: 6.80k, False: 20]
  |  Branch (380:28): [True: 6.79k, False: 11]
  ------------------
  381|  6.79k|            version.append(1, *p++);
  382|  13.8k|            while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (382:20): [True: 7.04k, False: 6.79k]
  ------------------
  383|  7.04k|                version.append(1, *p++);
  384|  7.04k|            }
  385|  6.79k|        } else {
  386|     31|            valid = false;
  387|     31|        }
  388|  6.82k|    }
  389|  6.83k|    return valid;
  390|  6.83k|}
_ZN4QPDF10findHeaderEv:
  394|  6.73k|{
  395|  6.73k|    qpdf_offset_t global_offset = m->file->tell();
  396|  6.73k|    std::string line = m->file->readLine(1024);
  397|  6.73k|    char const* p = line.c_str();
  398|  6.73k|    if (strncmp(p, "%PDF-", 5) != 0) {
  ------------------
  |  Branch (398:9): [True: 0, False: 6.73k]
  ------------------
  399|      0|        throw std::logic_error("findHeader is not looking at %PDF-");
  400|      0|    }
  401|  6.73k|    p += 5;
  402|  6.73k|    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.73k|    bool valid = validatePDFVersion(p, version);
  406|  6.73k|    if (valid) {
  ------------------
  |  Branch (406:9): [True: 6.73k, False: 0]
  ------------------
  407|  6.73k|        m->pdf_version = version;
  408|  6.73k|        if (global_offset != 0) {
  ------------------
  |  Branch (408:13): [True: 0, False: 6.73k]
  ------------------
  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.73k|    }
  416|  6.73k|    return valid;
  417|  6.73k|}
_ZN4QPDF13findStartxrefEv:
  421|  6.73k|{
  422|  6.73k|    if (readToken(m->file).isWord("startxref") && readToken(m->file).isInteger()) {
  ------------------
  |  Branch (422:9): [True: 6.73k, False: 0]
  |  Branch (422:9): [True: 6.73k, False: 0]
  |  Branch (422:51): [True: 6.73k, False: 0]
  ------------------
  423|       |        // Position in front of offset token
  424|  6.73k|        m->file->seek(m->file->getLastOffset(), SEEK_SET);
  425|  6.73k|        return true;
  426|  6.73k|    }
  427|      0|    return false;
  428|  6.73k|}
_ZN4QPDF5parseEPKc:
  432|  6.73k|{
  433|  6.73k|    if (password) {
  ------------------
  |  Branch (433:9): [True: 0, False: 6.73k]
  ------------------
  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.73k|    PatternFinder hf(*this, &QPDF::findHeader);
  439|  6.73k|    if (!m->file->findFirst("%PDF-", 0, 1024, hf)) {
  ------------------
  |  Branch (439:9): [True: 0, False: 6.73k]
  ------------------
  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.73k|    m->file->seek(0, SEEK_END);
  449|  6.73k|    qpdf_offset_t end_offset = m->file->tell();
  450|  6.73k|    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.73k|    if (m->xref_table_max_id > m->xref_table_max_offset / 3) {
  ------------------
  |  Branch (453:9): [True: 6.73k, False: 0]
  ------------------
  454|  6.73k|        m->xref_table_max_id = static_cast<int>(m->xref_table_max_offset / 3);
  455|  6.73k|    }
  456|  6.73k|    qpdf_offset_t start_offset = (end_offset > 1054 ? end_offset - 1054 : 0);
  ------------------
  |  Branch (456:35): [True: 0, False: 6.73k]
  ------------------
  457|  6.73k|    PatternFinder sf(*this, &QPDF::findStartxref);
  458|  6.73k|    qpdf_offset_t xref_offset = 0;
  459|  6.73k|    if (m->file->findLast("startxref", start_offset, 0, sf)) {
  ------------------
  |  Branch (459:9): [True: 6.73k, False: 0]
  ------------------
  460|  6.73k|        xref_offset = QUtil::string_to_ll(readToken(m->file).getValue().c_str());
  461|  6.73k|    }
  462|       |
  463|  6.73k|    try {
  464|  6.73k|        if (xref_offset == 0) {
  ------------------
  |  Branch (464:13): [True: 0, False: 6.73k]
  ------------------
  465|      0|            QTC::TC("qpdf", "QPDF can't find startxref");
  466|      0|            throw damagedPDF("", 0, "can't find startxref");
  467|      0|        }
  468|  6.73k|        try {
  469|  6.73k|            read_xref(xref_offset);
  470|  6.73k|        } 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.73k|    } 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.73k|    initializeEncryption();
  485|  6.73k|    m->parsed = true;
  486|  6.73k|    if (m->xref_table.size() > 0 && !getRoot().getKey("/Pages").isDictionary()) {
  ------------------
  |  Branch (486:9): [True: 0, False: 6.73k]
  |  Branch (486:9): [True: 0, False: 6.73k]
  |  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.73k|}
_ZN4QPDF7inParseEb:
  494|  13.4k|{
  495|  13.4k|    if (m->in_parse == v) {
  ------------------
  |  Branch (495:9): [True: 0, False: 13.4k]
  ------------------
  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.4k|    m->in_parse = v;
  502|  13.4k|}
_ZN4QPDF4warnERK7QPDFExc:
  506|  50.9k|{
  507|  50.9k|    if (m->max_warnings > 0 && m->warnings.size() >= m->max_warnings) {
  ------------------
  |  Branch (507:9): [True: 50.9k, False: 0]
  |  Branch (507:32): [True: 13, False: 50.9k]
  ------------------
  508|     13|        stopOnError("Too many warnings - file is too badly damaged");
  509|     13|    }
  510|  50.9k|    m->warnings.push_back(e);
  511|  50.9k|    if (!m->suppress_warnings) {
  ------------------
  |  Branch (511:9): [True: 50.9k, False: 13]
  ------------------
  512|  50.9k|        *m->log->getWarn() << "WARNING: " << m->warnings.back().what() << "\n";
  513|  50.9k|    }
  514|  50.9k|}
_ZN4QPDF4warnE17qpdf_error_code_eRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEExS9_:
  522|  50.9k|{
  523|  50.9k|    warn(QPDFExc(error_code, getFilename(), object, offset, message));
  524|  50.9k|}
_ZN4QPDF10setTrailerE16QPDFObjectHandle:
  528|  6.73k|{
  529|  6.73k|    if (m->trailer.isInitialized()) {
  ------------------
  |  Branch (529:9): [True: 0, False: 6.73k]
  ------------------
  530|      0|        return;
  531|      0|    }
  532|  6.73k|    m->trailer = obj;
  533|  6.73k|}
_ZN4QPDF9read_xrefEx:
  674|  6.73k|{
  675|  6.73k|    std::map<int, int> free_table;
  676|  6.73k|    std::set<qpdf_offset_t> visited;
  677|  13.4k|    while (xref_offset) {
  ------------------
  |  Branch (677:12): [True: 6.73k, False: 6.73k]
  ------------------
  678|  6.73k|        visited.insert(xref_offset);
  679|  6.73k|        char buf[7];
  680|  6.73k|        memset(buf, 0, sizeof(buf));
  681|  6.73k|        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.73k|        bool done = false;
  687|  6.73k|        bool skipped_space = false;
  688|  13.4k|        while (!done) {
  ------------------
  |  Branch (688:16): [True: 6.73k, False: 6.73k]
  ------------------
  689|  6.73k|            char ch;
  690|  6.73k|            if (1 == m->file->read(&ch, 1)) {
  ------------------
  |  Branch (690:17): [True: 6.73k, False: 0]
  ------------------
  691|  6.73k|                if (QUtil::is_space(ch)) {
  ------------------
  |  Branch (691:21): [True: 0, False: 6.73k]
  ------------------
  692|      0|                    skipped_space = true;
  693|  6.73k|                } else {
  694|  6.73k|                    m->file->unreadCh(ch);
  695|  6.73k|                    done = true;
  696|  6.73k|                }
  697|  6.73k|            } 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.73k|        }
  702|       |
  703|  6.73k|        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.73k|        if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) {
  ------------------
  |  Branch (706:13): [True: 6.73k, False: 0]
  |  Branch (706:47): [True: 6.73k, False: 0]
  ------------------
  707|  6.73k|            if (skipped_space) {
  ------------------
  |  Branch (707:17): [True: 0, False: 6.73k]
  ------------------
  708|      0|                QTC::TC("qpdf", "QPDF xref skipped space");
  709|      0|                warn(damagedPDF("", 0, "extraneous whitespace seen before xref"));
  710|      0|            }
  711|  6.73k|            QTC::TC(
  712|  6.73k|                "qpdf",
  713|  6.73k|                "QPDF xref space",
  714|  6.73k|                ((buf[4] == '\n')       ? 0
  ------------------
  |  Branch (714:18): [True: 6.73k, False: 0]
  ------------------
  715|  6.73k|                     : (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.73k|            int skip = 4;
  719|       |            // buf is null-terminated, and QUtil::is_space('\0') is false, so this won't overrun.
  720|  13.4k|            while (QUtil::is_space(buf[skip])) {
  ------------------
  |  Branch (720:20): [True: 6.73k, False: 6.73k]
  ------------------
  721|  6.73k|                ++skip;
  722|  6.73k|            }
  723|  6.73k|            xref_offset = read_xrefTable(xref_offset + skip);
  724|  6.73k|        } else {
  725|      0|            xref_offset = read_xrefStream(xref_offset);
  726|      0|        }
  727|  6.73k|        if (visited.count(xref_offset) != 0) {
  ------------------
  |  Branch (727:13): [True: 0, False: 6.73k]
  ------------------
  728|      0|            QTC::TC("qpdf", "QPDF xref loop");
  729|      0|            throw damagedPDF("", 0, "loop detected following xref tables");
  730|      0|        }
  731|  6.73k|    }
  732|       |
  733|  6.73k|    if (!m->trailer.isInitialized()) {
  ------------------
  |  Branch (733:9): [True: 0, False: 6.73k]
  ------------------
  734|      0|        throw damagedPDF("", 0, "unable to find trailer while reading xref");
  735|      0|    }
  736|  6.73k|    int size = m->trailer.getKey("/Size").getIntValueAsInt();
  737|  6.73k|    int max_obj = 0;
  738|  6.73k|    if (!m->xref_table.empty()) {
  ------------------
  |  Branch (738:9): [True: 0, False: 6.73k]
  ------------------
  739|      0|        max_obj = m->xref_table.rbegin()->first.getObj();
  740|      0|    }
  741|  6.73k|    if (!m->deleted_objects.empty()) {
  ------------------
  |  Branch (741:9): [True: 6.73k, False: 0]
  ------------------
  742|  6.73k|        max_obj = std::max(max_obj, *(m->deleted_objects.rbegin()));
  743|  6.73k|    }
  744|  6.73k|    if ((size < 1) || (size - 1 != max_obj)) {
  ------------------
  |  Branch (744:9): [True: 0, False: 6.73k]
  |  Branch (744:23): [True: 0, False: 6.73k]
  ------------------
  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.73k|    m->deleted_objects.clear();
  756|       |
  757|       |    // Make sure we keep only the highest generation for any object.
  758|  6.73k|    QPDFObjGen last_og{-1, 0};
  759|  6.73k|    for (auto const& item: m->xref_table) {
  ------------------
  |  Branch (759:26): [True: 0, False: 6.73k]
  ------------------
  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.73k|}
_ZN4QPDF15parse_xrefFirstERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERiS9_S9_:
  770|  6.73k|{
  771|       |    // is_space and is_digit both return false on '\0', so this will not overrun the null-terminated
  772|       |    // buffer.
  773|  6.73k|    char const* p = line.c_str();
  774|  6.73k|    char const* start = line.c_str();
  775|       |
  776|       |    // Skip zero or more spaces
  777|  6.73k|    while (QUtil::is_space(*p)) {
  ------------------
  |  Branch (777:12): [True: 0, False: 6.73k]
  ------------------
  778|      0|        ++p;
  779|      0|    }
  780|       |    // Require digit
  781|  6.73k|    if (!QUtil::is_digit(*p)) {
  ------------------
  |  Branch (781:9): [True: 0, False: 6.73k]
  ------------------
  782|      0|        return false;
  783|      0|    }
  784|       |    // Gather digits
  785|  6.73k|    std::string obj_str;
  786|  13.4k|    while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (786:12): [True: 6.73k, False: 6.73k]
  ------------------
  787|  6.73k|        obj_str.append(1, *p++);
  788|  6.73k|    }
  789|       |    // Require space
  790|  6.73k|    if (!QUtil::is_space(*p)) {
  ------------------
  |  Branch (790:9): [True: 0, False: 6.73k]
  ------------------
  791|      0|        return false;
  792|      0|    }
  793|       |    // Skip spaces
  794|  13.4k|    while (QUtil::is_space(*p)) {
  ------------------
  |  Branch (794:12): [True: 6.73k, False: 6.73k]
  ------------------
  795|  6.73k|        ++p;
  796|  6.73k|    }
  797|       |    // Require digit
  798|  6.73k|    if (!QUtil::is_digit(*p)) {
  ------------------
  |  Branch (798:9): [True: 0, False: 6.73k]
  ------------------
  799|      0|        return false;
  800|      0|    }
  801|       |    // Gather digits
  802|  6.73k|    std::string num_str;
  803|  13.4k|    while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (803:12): [True: 6.73k, False: 6.73k]
  ------------------
  804|  6.73k|        num_str.append(1, *p++);
  805|  6.73k|    }
  806|       |    // Skip any space including line terminators
  807|  13.4k|    while (QUtil::is_space(*p)) {
  ------------------
  |  Branch (807:12): [True: 6.73k, False: 6.73k]
  ------------------
  808|  6.73k|        ++p;
  809|  6.73k|    }
  810|  6.73k|    bytes = toI(p - start);
  811|  6.73k|    obj = QUtil::string_to_int(obj_str.c_str());
  812|  6.73k|    num = QUtil::string_to_int(num_str.c_str());
  813|  6.73k|    return true;
  814|  6.73k|}
_ZN4QPDF14read_xrefEntryERxRiRc:
  900|  6.73k|{
  901|  6.73k|    std::array<char, 21> line;
  902|  6.73k|    if (m->file->read(line.data(), 20) != 20) {
  ------------------
  |  Branch (902:9): [True: 0, False: 6.73k]
  ------------------
  903|       |        // C++20: [[unlikely]]
  904|      0|        return false;
  905|      0|    }
  906|  6.73k|    line[20] = '\0';
  907|  6.73k|    char const* p = line.data();
  908|       |
  909|  6.73k|    int f1_len = 0;
  910|  6.73k|    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|  74.0k|    while (*p == '0') {
  ------------------
  |  Branch (916:12): [True: 67.3k, False: 6.73k]
  ------------------
  917|  67.3k|        ++f1_len;
  918|  67.3k|        ++p;
  919|  67.3k|    }
  920|  6.73k|    while (QUtil::is_digit(*p) && f1_len++ < 10) {
  ------------------
  |  Branch (920:12): [True: 0, False: 6.73k]
  |  Branch (920:35): [True: 0, False: 0]
  ------------------
  921|      0|        f1 *= 10;
  922|      0|        f1 += *p++ - '0';
  923|      0|    }
  924|       |    // Require space
  925|  6.73k|    if (!QUtil::is_space(*p++)) {
  ------------------
  |  Branch (925:9): [True: 0, False: 6.73k]
  ------------------
  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.73k|    while (*p == '0') {
  ------------------
  |  Branch (931:12): [True: 0, False: 6.73k]
  ------------------
  932|      0|        ++f2_len;
  933|      0|        ++p;
  934|      0|    }
  935|  40.3k|    while (QUtil::is_digit(*p) && f2_len++ < 5) {
  ------------------
  |  Branch (935:12): [True: 33.6k, False: 6.73k]
  |  Branch (935:35): [True: 33.6k, False: 0]
  ------------------
  936|  33.6k|        f2 *= 10;
  937|  33.6k|        f2 += static_cast<int>(*p++ - '0');
  938|  33.6k|    }
  939|  6.73k|    if (QUtil::is_space(*p++) && (*p == 'f' || *p == 'n')) {
  ------------------
  |  Branch (939:9): [True: 6.73k, False: 0]
  |  Branch (939:35): [True: 6.73k, False: 0]
  |  Branch (939:48): [True: 0, False: 0]
  ------------------
  940|       |        // C++20: [[likely]]
  941|  6.73k|        type = *p;
  942|       |        // No test for valid line[19].
  943|  6.73k|        if (*(++p) && *(++p) && (*p == '\n' || *p == '\r') && f1_len == 10 && f2_len == 5) {
  ------------------
  |  Branch (943:13): [True: 6.73k, False: 0]
  |  Branch (943:23): [True: 6.73k, False: 0]
  |  Branch (943:34): [True: 6.73k, False: 0]
  |  Branch (943:48): [True: 0, False: 0]
  |  Branch (943:63): [True: 6.73k, False: 0]
  |  Branch (943:79): [True: 6.73k, False: 0]
  ------------------
  944|       |            // C++20: [[likely]]
  945|  6.73k|            return true;
  946|  6.73k|        }
  947|  6.73k|    }
  948|      0|    return read_bad_xrefEntry(f1, f2, type);
  949|  6.73k|}
_ZN4QPDF14read_xrefTableEx:
  954|  6.73k|{
  955|  6.73k|    std::vector<QPDFObjGen> deleted_items;
  956|       |
  957|  6.73k|    m->file->seek(xref_offset, SEEK_SET);
  958|  6.73k|    std::string line;
  959|  6.73k|    while (true) {
  ------------------
  |  Branch (959:12): [Folded - Ignored]
  ------------------
  960|  6.73k|        line.assign(50, '\0');
  961|  6.73k|        m->file->read(line.data(), line.size());
  962|  6.73k|        int obj = 0;
  963|  6.73k|        int num = 0;
  964|  6.73k|        int bytes = 0;
  965|  6.73k|        if (!parse_xrefFirst(line, obj, num, bytes)) {
  ------------------
  |  Branch (965:13): [True: 0, False: 6.73k]
  ------------------
  966|      0|            QTC::TC("qpdf", "QPDF invalid xref");
  967|      0|            throw damagedPDF("xref table", "xref syntax invalid");
  968|      0|        }
  969|  6.73k|        m->file->seek(m->file->getLastOffset() + bytes, SEEK_SET);
  970|  13.4k|        for (qpdf_offset_t i = obj; i - num < obj; ++i) {
  ------------------
  |  Branch (970:37): [True: 6.73k, False: 6.73k]
  ------------------
  971|  6.73k|            if (i == 0) {
  ------------------
  |  Branch (971:17): [True: 6.73k, False: 0]
  ------------------
  972|       |                // This is needed by checkLinearization()
  973|  6.73k|                m->first_xref_item_offset = m->file->tell();
  974|  6.73k|            }
  975|       |            // For xref_table, these will always be small enough to be ints
  976|  6.73k|            qpdf_offset_t f1 = 0;
  977|  6.73k|            int f2 = 0;
  978|  6.73k|            char type = '\0';
  979|  6.73k|            if (!read_xrefEntry(f1, f2, type)) {
  ------------------
  |  Branch (979:17): [True: 0, False: 6.73k]
  ------------------
  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.73k|            if (type == 'f') {
  ------------------
  |  Branch (984:17): [True: 6.73k, False: 0]
  ------------------
  985|       |                // Save deleted items until after we've checked the XRefStm, if any.
  986|  6.73k|                deleted_items.emplace_back(toI(i), f2);
  987|  6.73k|            } else {
  988|      0|                insertXrefEntry(toI(i), 1, f1, f2);
  989|      0|            }
  990|  6.73k|        }
  991|  6.73k|        qpdf_offset_t pos = m->file->tell();
  992|  6.73k|        if (readToken(m->file).isWord("trailer")) {
  ------------------
  |  Branch (992:13): [True: 6.73k, False: 0]
  ------------------
  993|  6.73k|            break;
  994|  6.73k|        } else {
  995|      0|            m->file->seek(pos, SEEK_SET);
  996|      0|        }
  997|  6.73k|    }
  998|       |
  999|       |    // Set offset to previous xref table if any
 1000|  6.73k|    QPDFObjectHandle cur_trailer = readTrailer();
 1001|  6.73k|    if (!cur_trailer.isDictionary()) {
  ------------------
  |  Branch (1001:9): [True: 0, False: 6.73k]
  ------------------
 1002|      0|        QTC::TC("qpdf", "QPDF missing trailer");
 1003|      0|        throw damagedPDF("", "expected trailer dictionary");
 1004|      0|    }
 1005|       |
 1006|  6.73k|    if (!m->trailer.isInitialized()) {
  ------------------
  |  Branch (1006:9): [True: 6.73k, False: 0]
  ------------------
 1007|  6.73k|        setTrailer(cur_trailer);
 1008|       |
 1009|  6.73k|        if (!m->trailer.hasKey("/Size")) {
  ------------------
  |  Branch (1009:13): [True: 0, False: 6.73k]
  ------------------
 1010|      0|            QTC::TC("qpdf", "QPDF trailer lacks size");
 1011|      0|            throw damagedPDF("trailer", "trailer dictionary lacks /Size key");
 1012|      0|        }
 1013|  6.73k|        if (!m->trailer.getKey("/Size").isInteger()) {
  ------------------
  |  Branch (1013:13): [True: 0, False: 6.73k]
  ------------------
 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.73k|    }
 1018|       |
 1019|  6.73k|    if (cur_trailer.hasKey("/XRefStm")) {
  ------------------
  |  Branch (1019:9): [True: 0, False: 6.73k]
  ------------------
 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.73k|    for (auto const& og: deleted_items) {
  ------------------
  |  Branch (1034:24): [True: 6.73k, False: 6.73k]
  ------------------
 1035|  6.73k|        insertFreeXrefEntry(og);
 1036|  6.73k|    }
 1037|       |
 1038|  6.73k|    if (cur_trailer.hasKey("/Prev")) {
  ------------------
  |  Branch (1038:9): [True: 0, False: 6.73k]
  ------------------
 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.73k|    } else {
 1046|  6.73k|        xref_offset = 0;
 1047|  6.73k|    }
 1048|       |
 1049|  6.73k|    return xref_offset;
 1050|  6.73k|}
_ZN4QPDF19insertFreeXrefEntryE10QPDFObjGen:
 1337|  6.73k|{
 1338|  6.73k|    if (!m->xref_table.count(og)) {
  ------------------
  |  Branch (1338:9): [True: 6.73k, False: 0]
  ------------------
 1339|  6.73k|        m->deleted_objects.insert(og.getObj());
 1340|  6.73k|    }
 1341|  6.73k|}
_ZN4QPDF11readTrailerEv:
 1464|  6.73k|{
 1465|  6.73k|    qpdf_offset_t offset = m->file->tell();
 1466|  6.73k|    bool empty = false;
 1467|  6.73k|    auto object =
 1468|  6.73k|        QPDFParser(m->file, "trailer", m->tokenizer, nullptr, this, true).parse(empty, false);
 1469|  6.73k|    if (empty) {
  ------------------
  |  Branch (1469:9): [True: 0, False: 6.73k]
  ------------------
 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.73k|    } else if (object.isDictionary() && readToken(m->file).isWord("stream")) {
  ------------------
  |  Branch (1473:16): [True: 6.73k, False: 0]
  |  Branch (1473:16): [True: 0, False: 6.73k]
  |  Branch (1473:41): [True: 0, False: 6.73k]
  ------------------
 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.73k|    m->file->setLastOffset(offset);
 1478|  6.73k|    return object;
 1479|  6.73k|}
_ZN4QPDF9readTokenENSt3__110shared_ptrI11InputSourceEEm:
 1689|  33.6k|{
 1690|  33.6k|    return m->tokenizer.readToken(input, m->last_object_description, true, max_len);
 1691|  33.6k|}
_ZN4QPDF11updateCacheERK10QPDFObjGenRKNSt3__110shared_ptrI10QPDFObjectEExx:
 2018|  10.7k|{
 2019|  10.7k|    object->setObjGen(this, og);
 2020|  10.7k|    if (isCached(og)) {
  ------------------
  |  Branch (2020:9): [True: 10.7k, False: 0]
  ------------------
 2021|  10.7k|        auto& cache = m->obj_cache[og];
 2022|  10.7k|        cache.object->assign(object);
 2023|  10.7k|        cache.end_before_space = end_before_space;
 2024|  10.7k|        cache.end_after_space = end_after_space;
 2025|  10.7k|    } else {
 2026|      0|        m->obj_cache[og] = ObjCache(object, end_before_space, end_after_space);
 2027|      0|    }
 2028|  10.7k|}
_ZN4QPDF8isCachedERK10QPDFObjGen:
 2032|  10.7k|{
 2033|  10.7k|    return m->obj_cache.count(og) != 0;
 2034|  10.7k|}
_ZN4QPDF13reserveStreamERK10QPDFObjGen:
 2106|  3.73k|{
 2107|  3.73k|    return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)};
 2108|  3.73k|}
_ZN4QPDF16getObjectForJSONEii:
 2129|   306k|{
 2130|   306k|    auto og = QPDFObjGen(id, gen);
 2131|   306k|    auto [it, inserted] = m->obj_cache.try_emplace(og);
 2132|   306k|    auto& obj = it->second.object;
 2133|   306k|    if (inserted) {
  ------------------
  |  Branch (2133:9): [True: 16.1k, False: 289k]
  ------------------
 2134|  16.1k|        obj = (m->parsed && !m->xref_table.count(og)) ? QPDF_Null::create(this, og)
  ------------------
  |  Branch (2134:16): [True: 16.1k, False: 0]
  |  Branch (2134:29): [True: 16.1k, False: 0]
  ------------------
 2135|  16.1k|                                                      : QPDF_Unresolved::create(this, og);
 2136|  16.1k|    }
 2137|   306k|    return obj;
 2138|   306k|}
_ZN4QPDF9getObjectERK10QPDFObjGen:
 2142|  10.7k|{
 2143|  10.7k|    if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
  ------------------
  |  Branch (2143:42): [True: 10.7k, False: 0]
  ------------------
 2144|  10.7k|        return {it->second.object};
 2145|  10.7k|    } 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|  10.7k|}
_ZN4QPDF13replaceObjectERK10QPDFObjGen16QPDFObjectHandle:
 2179|  10.7k|{
 2180|  10.7k|    if (oh.isIndirect() || !oh.isInitialized()) {
  ------------------
  |  Branch (2180:9): [True: 0, False: 10.7k]
  |  Branch (2180:28): [True: 0, False: 10.7k]
  ------------------
 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|  10.7k|    updateCache(og, oh.getObj(), -1, -1);
 2185|  10.7k|}
_ZNK4QPDF11getFilenameEv:
 2493|   105k|{
 2494|   105k|    return m->file->getName();
 2495|   105k|}
_ZN4QPDF11stopOnErrorERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2821|     13|{
 2822|     13|    throw damagedPDF("", message);
 2823|     13|}
_ZN4QPDF10damagedPDFERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEExS8_:
 2848|     13|{
 2849|     13|    return {qpdf_e_damaged_pdf, m->file->getName(), object, offset, message};
 2850|     13|}
_ZN4QPDF10damagedPDFERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_:
 2856|     13|{
 2857|     13|    return damagedPDF(object, m->file->getLastOffset(), message);
 2858|     13|}

_ZN7QPDFExcC2E17qpdf_error_code_eRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_xS9_:
   15|  51.1k|{
   16|  51.1k|}
_ZN7QPDFExc10createWhatERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_xS8_:
   24|  51.1k|{
   25|  51.1k|    std::string result;
   26|  51.1k|    if (!filename.empty()) {
  ------------------
  |  Branch (26:9): [True: 51.1k, False: 0]
  ------------------
   27|  51.1k|        result += filename;
   28|  51.1k|    }
   29|  51.1k|    if (!(object.empty() && offset == 0)) {
  ------------------
  |  Branch (29:11): [True: 17.4k, False: 33.6k]
  |  Branch (29:29): [True: 324, False: 17.1k]
  ------------------
   30|  50.8k|        if (!filename.empty()) {
  ------------------
  |  Branch (30:13): [True: 50.8k, False: 0]
  ------------------
   31|  50.8k|            result += " (";
   32|  50.8k|        }
   33|  50.8k|        if (!object.empty()) {
  ------------------
  |  Branch (33:13): [True: 33.6k, False: 17.1k]
  ------------------
   34|  33.6k|            result += object;
   35|  33.6k|            if (offset > 0) {
  ------------------
  |  Branch (35:17): [True: 33.5k, False: 99]
  ------------------
   36|  33.5k|                result += ", ";
   37|  33.5k|            }
   38|  33.6k|        }
   39|  50.8k|        if (offset > 0) {
  ------------------
  |  Branch (39:13): [True: 50.7k, False: 99]
  ------------------
   40|  50.7k|            result += "offset " + std::to_string(offset);
   41|  50.7k|        }
   42|  50.8k|        if (!filename.empty()) {
  ------------------
  |  Branch (42:13): [True: 50.8k, False: 0]
  ------------------
   43|  50.8k|            result += ")";
   44|  50.8k|        }
   45|  50.8k|    }
   46|  51.1k|    if (!result.empty()) {
  ------------------
  |  Branch (46:9): [True: 51.1k, False: 0]
  ------------------
   47|  51.1k|        result += ": ";
   48|  51.1k|    }
   49|  51.1k|    result += message;
   50|  51.1k|    return result;
   51|  51.1k|}

_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.73k|{
   75|  6.73k|    static auto l = create();
   76|  6.73k|    return l;
   77|  6.73k|}
_ZN10QPDFLogger7getWarnEb:
  111|  50.9k|{
  112|  50.9k|    if (m->p_warn) {
  ------------------
  |  Branch (112:9): [True: 0, False: 50.9k]
  ------------------
  113|      0|        return m->p_warn;
  114|      0|    }
  115|  50.9k|    return getError(null_okay);
  116|  50.9k|}
_ZN10QPDFLogger8getErrorEb:
  132|  50.9k|{
  133|  50.9k|    return throwIfNull(m->p_error, null_okay);
  134|  50.9k|}
_ZN10QPDFLogger11throwIfNullENSt3__110shared_ptrI8PipelineEEb:
  250|  50.9k|{
  251|  50.9k|    if (!(null_okay || p)) {
  ------------------
  |  Branch (251:11): [True: 0, False: 50.9k]
  |  Branch (251:24): [True: 50.9k, False: 0]
  ------------------
  252|      0|        throw std::logic_error("QPDFLogger: requested a null pipeline without null_okay == true");
  253|      0|    }
  254|  50.9k|    return p;
  255|  50.9k|}
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|  3.73k|{
   21|  3.73k|    return std::to_string(obj) + separator + std::to_string(gen);
   22|  3.73k|}

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

_ZN16QPDFObjectHandle18StreamDataProviderC2Eb:
   51|  3.05k|{
   52|  3.05k|}
_ZN16QPDFObjectHandle18StreamDataProviderD2Ev:
   55|  3.05k|{
   56|       |    // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
   57|  3.05k|}
_ZN16QPDFObjectHandle10disconnectEv:
  239|  85.9k|{
  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|  85.9k|    if (obj && !isIndirect()) {
  ------------------
  |  Branch (243:9): [True: 85.9k, False: 0]
  |  Branch (243:16): [True: 74.0k, False: 11.8k]
  ------------------
  244|  74.0k|        this->obj->disconnect();
  245|  74.0k|    }
  246|  85.9k|}
_ZNK16QPDFObjectHandle7asArrayEv:
  288|  2.97M|{
  289|  2.97M|    return obj ? obj->as<QPDF_Array>() : nullptr;
  ------------------
  |  Branch (289:12): [True: 2.97M, False: 0]
  ------------------
  290|  2.97M|}
_ZNK16QPDFObjectHandle12asDictionaryEv:
  300|   146k|{
  301|   146k|    return obj ? obj->as<QPDF_Dictionary>() : nullptr;
  ------------------
  |  Branch (301:12): [True: 146k, False: 0]
  ------------------
  302|   146k|}
_ZNK16QPDFObjectHandle9asIntegerEv:
  312|  6.73k|{
  313|  6.73k|    return obj ? obj->as<QPDF_Integer>() : nullptr;
  ------------------
  |  Branch (313:12): [True: 6.73k, False: 0]
  ------------------
  314|  6.73k|}
_ZNK16QPDFObjectHandle8asStreamEv:
  348|  5.93k|{
  349|  5.93k|    return obj ? obj->as<QPDF_Stream>() : nullptr;
  ------------------
  |  Branch (349:12): [True: 5.93k, False: 0]
  ------------------
  350|  5.93k|}
_ZNK16QPDFObjectHandle18asStreamWithAssertEv:
  354|  5.93k|{
  355|  5.93k|    auto stream = asStream();
  356|  5.93k|    assertType("stream", stream);
  357|  5.93k|    return stream;
  358|  5.93k|}
_ZN16QPDFObjectHandle6isNullEv:
  403|   109k|{
  404|   109k|    return obj && obj->getResolvedTypeCode() == ::ot_null;
  ------------------
  |  Branch (404:12): [True: 109k, False: 0]
  |  Branch (404:19): [True: 26.4k, False: 83.4k]
  ------------------
  405|   109k|}
_ZN16QPDFObjectHandle9isIntegerEv:
  414|  6.73k|{
  415|  6.73k|    return obj && obj->getResolvedTypeCode() == ::ot_integer;
  ------------------
  |  Branch (415:12): [True: 6.73k, False: 0]
  |  Branch (415:19): [True: 6.73k, False: 0]
  ------------------
  416|  6.73k|}
_ZN16QPDFObjectHandle6isNameEv:
  481|  9.93k|{
  482|  9.93k|    return obj && obj->getResolvedTypeCode() == ::ot_name;
  ------------------
  |  Branch (482:12): [True: 9.93k, False: 0]
  |  Branch (482:19): [True: 9.93k, False: 0]
  ------------------
  483|  9.93k|}
_ZN16QPDFObjectHandle12isDictionaryEv:
  536|   120k|{
  537|   120k|    return obj && obj->getResolvedTypeCode() == ::ot_dictionary;
  ------------------
  |  Branch (537:12): [True: 120k, False: 0]
  |  Branch (537:19): [True: 120k, False: 0]
  ------------------
  538|   120k|}
_ZN16QPDFObjectHandle8isStreamEv:
  547|   113k|{
  548|   113k|    return obj && obj->getResolvedTypeCode() == ::ot_stream;
  ------------------
  |  Branch (548:12): [True: 113k, False: 0]
  |  Branch (548:19): [True: 6.79k, False: 106k]
  ------------------
  549|   113k|}
_ZN16QPDFObjectHandle11getIntValueEv:
  652|  6.73k|{
  653|  6.73k|    auto integer = asInteger();
  654|  6.73k|    if (integer) {
  ------------------
  |  Branch (654:9): [True: 6.73k, False: 0]
  ------------------
  655|  6.73k|        return integer->getVal();
  656|  6.73k|    } else {
  657|      0|        typeWarning("integer", "returning 0");
  658|      0|        QTC::TC("qpdf", "QPDFObjectHandle integer returning 0");
  659|      0|        return 0;
  660|      0|    }
  661|  6.73k|}
_ZN16QPDFObjectHandle16getIntValueAsIntEv:
  686|  6.73k|{
  687|  6.73k|    int result = 0;
  688|  6.73k|    long long v = getIntValue();
  689|  6.73k|    if (v < INT_MIN) {
  ------------------
  |  Branch (689:9): [True: 0, False: 6.73k]
  ------------------
  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.73k|    } else if (v > INT_MAX) {
  ------------------
  |  Branch (693:16): [True: 0, False: 6.73k]
  ------------------
  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.73k|    } else {
  698|  6.73k|        result = static_cast<int>(v);
  699|  6.73k|    }
  700|  6.73k|    return result;
  701|  6.73k|}
_ZN16QPDFObjectHandle7getNameEv:
  831|  9.93k|{
  832|  9.93k|    if (isName()) {
  ------------------
  |  Branch (832:9): [True: 9.93k, False: 0]
  ------------------
  833|  9.93k|        return obj->getStringValue();
  834|  9.93k|    } 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|  9.93k|}
_ZN16QPDFObjectHandle10appendItemERKS_:
 1193|  2.97M|{
 1194|  2.97M|    if (auto array = asArray()) {
  ------------------
  |  Branch (1194:14): [True: 2.97M, False: 0]
  ------------------
 1195|  2.97M|        array->push_back(item);
 1196|  2.97M|    } else {
 1197|      0|        typeWarning("array", "ignoring attempt to append item");
 1198|      0|        QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item");
 1199|      0|    }
 1200|  2.97M|}
_ZN16QPDFObjectHandle6hasKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1247|  26.9k|{
 1248|  26.9k|    auto dict = asDictionary();
 1249|  26.9k|    if (dict) {
  ------------------
  |  Branch (1249:9): [True: 26.9k, False: 0]
  ------------------
 1250|  26.9k|        return dict->hasKey(key);
 1251|  26.9k|    } 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.9k|}
_ZN16QPDFObjectHandle6getKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1265|  13.4k|{
 1266|  13.4k|    if (auto dict = asDictionary()) {
  ------------------
  |  Branch (1266:14): [True: 13.4k, False: 0]
  ------------------
 1267|  13.4k|        return dict->getKey(key);
 1268|  13.4k|    } 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.4k|}
_ZN16QPDFObjectHandle10replaceKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKS_:
 1517|   103k|{
 1518|   103k|    auto dict = asDictionary();
 1519|   103k|    if (dict) {
  ------------------
  |  Branch (1519:9): [True: 103k, False: 0]
  ------------------
 1520|   103k|        checkOwnership(value);
 1521|   103k|        dict->replaceKey(key, value);
 1522|   103k|    } else {
 1523|      0|        typeWarning("dictionary", "ignoring key replacement request");
 1524|      0|        QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey");
 1525|      0|    }
 1526|   103k|}
_ZN16QPDFObjectHandle9removeKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1545|  3.17k|{
 1546|  3.17k|    auto dict = asDictionary();
 1547|  3.17k|    if (dict) {
  ------------------
  |  Branch (1547:9): [True: 3.17k, False: 0]
  ------------------
 1548|  3.17k|        dict->removeKey(key);
 1549|  3.17k|    } else {
 1550|      0|        typeWarning("dictionary", "ignoring key removal request");
 1551|      0|        QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey");
 1552|      0|    }
 1553|  3.17k|}
_ZN16QPDFObjectHandle11replaceDictERKS_:
 1605|  2.75k|{
 1606|  2.75k|    asStreamWithAssert()->replaceDict(new_dict);
 1607|  2.75k|}
_ZN16QPDFObjectHandle17replaceStreamDataERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKS_SA_:
 1677|    129|{
 1678|    129|    auto b = std::make_shared<Buffer>(data.length());
 1679|    129|    unsigned char* bp = b->getBuffer();
 1680|    129|    if (bp) {
  ------------------
  |  Branch (1680:9): [True: 0, False: 129]
  ------------------
 1681|      0|        memcpy(bp, data.c_str(), data.length());
 1682|      0|    }
 1683|    129|    asStreamWithAssert()->replaceStreamData(b, filter, decode_parms);
 1684|    129|}
_ZN16QPDFObjectHandle17replaceStreamDataENSt3__18functionIFvP8PipelineEEERKS_S7_:
 1737|  3.05k|{
 1738|  3.05k|    auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
 1739|  3.05k|    asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
 1740|  3.05k|}
_ZN16QPDFObjectHandle5parseERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_:
 2027|  19.1k|{
 2028|  19.1k|    return parse(nullptr, object_str, object_description);
 2029|  19.1k|}
_ZN16QPDFObjectHandle5parseEP4QPDFRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_:
 2034|  19.1k|{
 2035|  19.1k|    auto input = std::shared_ptr<InputSource>(new BufferInputSource("parsed object", object_str));
 2036|  19.1k|    QPDFTokenizer tokenizer;
 2037|  19.1k|    bool empty = false;
 2038|  19.1k|    QPDFObjectHandle result = parse(input, object_description, tokenizer, empty, nullptr, context);
 2039|  19.1k|    size_t offset = QIntC::to_size(input->tell());
 2040|  23.2k|    while (offset < object_str.length()) {
  ------------------
  |  Branch (2040:12): [True: 4.14k, False: 19.0k]
  ------------------
 2041|  4.14k|        if (!isspace(object_str.at(offset))) {
  ------------------
  |  Branch (2041:13): [True: 75, False: 4.07k]
  ------------------
 2042|     75|            QTC::TC("qpdf", "QPDFObjectHandle trailing data in parse");
 2043|     75|            throw QPDFExc(
 2044|     75|                qpdf_e_damaged_pdf,
 2045|     75|                input->getName(),
 2046|     75|                object_description,
 2047|     75|                input->getLastOffset(),
 2048|     75|                "trailing data found parsing object from string");
 2049|     75|        }
 2050|  4.07k|        ++offset;
 2051|  4.07k|    }
 2052|  19.0k|    return result;
 2053|  19.1k|}
_ZN16QPDFObjectHandle5parseENSt3__110shared_ptrI11InputSourceEERKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEER13QPDFTokenizerRbPNS_15StringDecrypterEP4QPDF:
 2225|  19.1k|{
 2226|  19.1k|    return QPDFParser(input, object_description, tokenizer, decrypter, context, false)
 2227|  19.1k|        .parse(empty, false);
 2228|  19.1k|}
_ZN16QPDFObjectHandle15getParsedOffsetEv:
 2237|     85|{
 2238|     85|    return obj ? obj->getParsedOffset() : -1;
  ------------------
  |  Branch (2238:12): [True: 85, False: 0]
  ------------------
 2239|     85|}
_ZN16QPDFObjectHandle7newBoolEb:
 2243|    412|{
 2244|    412|    return {QPDF_Bool::create(value)};
 2245|    412|}
_ZN16QPDFObjectHandle7newNullEv:
 2249|  29.0k|{
 2250|  29.0k|    return {QPDF_Null::create()};
 2251|  29.0k|}
_ZN16QPDFObjectHandle10newIntegerEx:
 2255|  2.67M|{
 2256|  2.67M|    return {QPDF_Integer::create(value)};
 2257|  2.67M|}
_ZN16QPDFObjectHandle7newRealERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2261|  5.23k|{
 2262|  5.23k|    return {QPDF_Real::create(value)};
 2263|  5.23k|}
_ZN16QPDFObjectHandle7newNameERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2273|  22.4k|{
 2274|  22.4k|    return {QPDF_Name::create(name)};
 2275|  22.4k|}
_ZN16QPDFObjectHandle9newStringERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2279|  1.21k|{
 2280|  1.21k|    return {QPDF_String::create(str)};
 2281|  1.21k|}
_ZN16QPDFObjectHandle16newUnicodeStringERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 2285|  4.15k|{
 2286|  4.15k|    return {QPDF_String::create_utf16(utf8_str)};
 2287|  4.15k|}
_ZN16QPDFObjectHandle8newArrayEv:
 2303|  19.1k|{
 2304|  19.1k|    return newArray(std::vector<QPDFObjectHandle>());
 2305|  19.1k|}
_ZN16QPDFObjectHandle8newArrayERKNSt3__16vectorIS_NS0_9allocatorIS_EEEE:
 2309|  19.1k|{
 2310|  19.1k|    return {QPDF_Array::create(items)};
 2311|  19.1k|}
_ZN16QPDFObjectHandle13newDictionaryEv:
 2363|  24.6k|{
 2364|  24.6k|    return newDictionary(std::map<std::string, QPDFObjectHandle>());
 2365|  24.6k|}
_ZN16QPDFObjectHandle13newDictionaryERKNSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES_NS0_4lessIS7_EENS5_INS0_4pairIKS7_S_EEEEEE:
 2369|  24.6k|{
 2370|  24.6k|    return {QPDF_Dictionary::create(items)};
 2371|  24.6k|}
_ZN16QPDFObjectHandle20setObjectDescriptionEP4QPDFRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
 2414|  3.73k|{
 2415|  3.73k|    if (obj) {
  ------------------
  |  Branch (2415:9): [True: 3.73k, False: 0]
  ------------------
 2416|  3.73k|        auto descr = std::make_shared<QPDFValue::Description>(object_description);
 2417|  3.73k|        obj->setDescription(owning_qpdf, descr);
 2418|  3.73k|    }
 2419|  3.73k|}
_ZN16QPDFObjectHandle20hasObjectDescriptionEv:
 2428|  3.09M|{
 2429|  3.09M|    return obj && obj->hasDescription();
  ------------------
  |  Branch (2429:12): [True: 3.09M, False: 0]
  |  Branch (2429:19): [True: 310k, False: 2.78M]
  ------------------
 2430|  3.09M|}
_ZNK16QPDFObjectHandle10assertTypeEPKcb:
 2581|  5.93k|{
 2582|  5.93k|    if (!istype) {
  ------------------
  |  Branch (2582:9): [True: 0, False: 5.93k]
  ------------------
 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|  5.93k|}
_ZNK16QPDFObjectHandle14checkOwnershipERKS_:
 2817|   103k|{
 2818|   103k|    auto qpdf = getOwningQPDF();
 2819|   103k|    auto item_qpdf = item.getOwningQPDF();
 2820|   103k|    if ((qpdf != nullptr) && (item_qpdf != nullptr) && (qpdf != item_qpdf)) {
  ------------------
  |  Branch (2820:9): [True: 103k, False: 0]
  |  Branch (2820:30): [True: 102k, False: 210]
  |  Branch (2820:56): [True: 0, False: 102k]
  ------------------
 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|   103k|}
_ZNK16QPDFObjectHandle9getObjGenEv:
 3020|   148k|{
 3021|   148k|    return isInitialized() ? obj->getObjGen() : QPDFObjGen();
  ------------------
  |  Branch (3021:12): [True: 148k, False: 0]
  ------------------
 3022|   148k|}
_ZNK16QPDFObjectHandle13getOwningQPDFEv:
 3027|   206k|{
 3028|   206k|    return isInitialized() ? this->obj->getQPDF() : nullptr;
  ------------------
  |  Branch (3028:12): [True: 206k, False: 0]
  ------------------
 3029|   206k|}
QPDFObjectHandle.cc:_ZN12_GLOBAL__N_116FunctionProviderC2ENSt3__18functionIFvP8PipelineEEE:
 1704|  3.05k|        {
 1705|  3.05k|        }

_ZN10QPDFParser5parseERbb:
   28|  25.8k|{
   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|  25.8k|    QPDF::ParseGuard pg(context);
   35|  25.8k|    empty = false;
   36|  25.8k|    start = input->tell();
   37|       |
   38|  25.8k|    if (!tokenizer.nextToken(*input, object_description)) {
  ------------------
  |  Branch (38:9): [True: 149, False: 25.7k]
  ------------------
   39|    149|        warn(tokenizer.getErrorMessage());
   40|    149|    }
   41|       |
   42|  25.8k|    switch (tokenizer.getType()) {
   43|      0|    case QPDFTokenizer::tt_eof:
  ------------------
  |  Branch (43:5): [True: 0, False: 25.8k]
  ------------------
   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: 25.8k]
  ------------------
   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: 25.8k]
  ------------------
   57|      0|    case QPDFTokenizer::tt_brace_close:
  ------------------
  |  Branch (57:5): [True: 0, False: 25.8k]
  ------------------
   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: 25.8k]
  ------------------
   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: 25.8k]
  ------------------
   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: 25.8k]
  ------------------
   73|  6.73k|    case QPDFTokenizer::tt_dict_open:
  ------------------
  |  Branch (73:5): [True: 6.73k, False: 19.1k]
  ------------------
   74|  6.73k|        stack.clear();
   75|  6.73k|        stack.emplace_back(
   76|  6.73k|            input,
   77|  6.73k|            (tokenizer.getType() == QPDFTokenizer::tt_array_open) ? st_array : st_dictionary_key);
  ------------------
  |  Branch (77:13): [True: 0, False: 6.73k]
  ------------------
   78|  6.73k|        frame = &stack.back();
   79|  6.73k|        return parseRemainder(content_stream);
   80|       |
   81|      0|    case QPDFTokenizer::tt_bool:
  ------------------
  |  Branch (81:5): [True: 0, False: 25.8k]
  ------------------
   82|      0|        return withDescription<QPDF_Bool>(tokenizer.getValue() == "true");
   83|       |
   84|      0|    case QPDFTokenizer::tt_null:
  ------------------
  |  Branch (84:5): [True: 0, False: 25.8k]
  ------------------
   85|      0|        return {QPDF_Null::create()};
   86|       |
   87|      0|    case QPDFTokenizer::tt_integer:
  ------------------
  |  Branch (87:5): [True: 0, False: 25.8k]
  ------------------
   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: 25.8k]
  ------------------
   91|      0|        return withDescription<QPDF_Real>(tokenizer.getValue());
   92|       |
   93|  19.0k|    case QPDFTokenizer::tt_name:
  ------------------
  |  Branch (93:5): [True: 19.0k, False: 6.87k]
  ------------------
   94|  19.0k|        return withDescription<QPDF_Name>(tokenizer.getValue());
   95|       |
   96|      0|    case QPDFTokenizer::tt_word:
  ------------------
  |  Branch (96:5): [True: 0, False: 25.8k]
  ------------------
   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: 25.8k]
  ------------------
  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: 25.8k]
  ------------------
  124|      0|        warn("treating unknown token type as null while reading object");
  125|      0|        return {QPDF_Null::create()};
  126|  25.8k|    }
  127|  25.8k|}
_ZN10QPDFParser14parseRemainderEb:
  131|  6.73k|{
  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.73k|    bad_count = 0;
  138|  6.73k|    bool b_contents = false;
  139|       |
  140|  20.1k|    while (true) {
  ------------------
  |  Branch (140:12): [Folded - Ignored]
  ------------------
  141|  20.1k|        if (!tokenizer.nextToken(*input, object_description)) {
  ------------------
  |  Branch (141:13): [True: 0, False: 20.1k]
  ------------------
  142|      0|            warn(tokenizer.getErrorMessage());
  143|      0|        }
  144|  20.1k|        ++good_count; // optimistically
  145|       |
  146|  20.1k|        if (int_count != 0) {
  ------------------
  |  Branch (146:13): [True: 6.73k, False: 13.4k]
  ------------------
  147|       |            // Special handling of indirect references. Treat integer tokens as part of an indirect
  148|       |            // reference until proven otherwise.
  149|  6.73k|            if (tokenizer.getType() == QPDFTokenizer::tt_integer) {
  ------------------
  |  Branch (149:17): [True: 0, False: 6.73k]
  ------------------
  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.73k|            } else if (
  159|  6.73k|                int_count >= 2 && tokenizer.getType() == QPDFTokenizer::tt_word &&
  ------------------
  |  Branch (159:17): [True: 0, False: 6.73k]
  |  Branch (159:35): [True: 0, False: 0]
  ------------------
  160|  6.73k|                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.73k|            } else if (int_count > 0) {
  ------------------
  |  Branch (177:24): [True: 6.73k, False: 0]
  ------------------
  178|       |                // Process the buffered integers before processing the current token.
  179|  6.73k|                if (int_count > 1) {
  ------------------
  |  Branch (179:21): [True: 0, False: 6.73k]
  ------------------
  180|      0|                    addInt(int_count - 1);
  181|      0|                }
  182|  6.73k|                addInt(int_count);
  183|  6.73k|                int_count = 0;
  184|  6.73k|            }
  185|  6.73k|        }
  186|       |
  187|  20.1k|        switch (tokenizer.getType()) {
  188|      0|        case QPDFTokenizer::tt_eof:
  ------------------
  |  Branch (188:9): [True: 0, False: 20.1k]
  ------------------
  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: 20.1k]
  ------------------
  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: 20.1k]
  ------------------
  207|      0|        case QPDFTokenizer::tt_brace_close:
  ------------------
  |  Branch (207:9): [True: 0, False: 20.1k]
  ------------------
  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: 20.1k]
  ------------------
  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.73k|        case QPDFTokenizer::tt_dict_close:
  ------------------
  |  Branch (240:9): [True: 6.73k, False: 13.4k]
  ------------------
  241|  6.73k|            if (frame->state <= st_dictionary_value) {
  ------------------
  |  Branch (241:17): [True: 6.73k, False: 0]
  ------------------
  242|       |                // Attempt to recover more or less gracefully from invalid dictionaries.
  243|  6.73k|                auto& dict = frame->dict;
  244|       |
  245|  6.73k|                if (frame->state == st_dictionary_value) {
  ------------------
  |  Branch (245:21): [True: 0, False: 6.73k]
  ------------------
  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.73k|                if (!frame->olist.empty()) {
  ------------------
  |  Branch (253:21): [True: 0, False: 6.73k]
  ------------------
  254|      0|                    fixMissingKeys();
  255|      0|                }
  256|       |
  257|  6.73k|                if (!frame->contents_string.empty() && dict.count("/Type") &&
  ------------------
  |  Branch (257:21): [True: 0, False: 6.73k]
  |  Branch (257:21): [True: 0, False: 6.73k]
  |  Branch (257:56): [True: 0, False: 0]
  ------------------
  258|  6.73k|                    dict["/Type"].isNameAndEquals("/Sig") && dict.count("/ByteRange") &&
  ------------------
  |  Branch (258:21): [True: 0, False: 0]
  |  Branch (258:62): [True: 0, False: 0]
  ------------------
  259|  6.73k|                    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.73k|                auto object = QPDF_Dictionary::create(std::move(dict));
  264|  6.73k|                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.73k|                if (stack.size() <= 1) {
  ------------------
  |  Branch (269:21): [True: 6.73k, False: 0]
  ------------------
  270|  6.73k|                    return object;
  271|  6.73k|                }
  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: 20.1k]
  ------------------
  286|      0|        case QPDFTokenizer::tt_dict_open:
  ------------------
  |  Branch (286:9): [True: 0, False: 20.1k]
  ------------------
  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: 20.1k]
  ------------------
  302|      0|            addScalar<QPDF_Bool>(tokenizer.getValue() == "true");
  303|      0|            continue;
  304|       |
  305|      0|        case QPDFTokenizer::tt_null:
  ------------------
  |  Branch (305:9): [True: 0, False: 20.1k]
  ------------------
  306|      0|            addNull();
  307|      0|            continue;
  308|       |
  309|  6.73k|        case QPDFTokenizer::tt_integer:
  ------------------
  |  Branch (309:9): [True: 6.73k, False: 13.4k]
  ------------------
  310|  6.73k|            if (!content_stream) {
  ------------------
  |  Branch (310:17): [True: 6.73k, False: 0]
  ------------------
  311|       |                // Buffer token in case it is part of an indirect reference.
  312|  6.73k|                last_offset_buffer[1] = input->getLastOffset();
  313|  6.73k|                int_buffer[1] = QUtil::string_to_ll(tokenizer.getValue().c_str());
  314|  6.73k|                int_count = 1;
  315|  6.73k|            } else {
  316|      0|                addScalar<QPDF_Integer>(QUtil::string_to_ll(tokenizer.getValue().c_str()));
  317|      0|            }
  318|  6.73k|            continue;
  319|       |
  320|      0|        case QPDFTokenizer::tt_real:
  ------------------
  |  Branch (320:9): [True: 0, False: 20.1k]
  ------------------
  321|      0|            addScalar<QPDF_Real>(tokenizer.getValue());
  322|      0|            continue;
  323|       |
  324|  6.73k|        case QPDFTokenizer::tt_name:
  ------------------
  |  Branch (324:9): [True: 6.73k, False: 13.4k]
  ------------------
  325|  6.73k|            if (frame->state == st_dictionary_key) {
  ------------------
  |  Branch (325:17): [True: 6.73k, False: 0]
  ------------------
  326|  6.73k|                frame->key = tokenizer.getValue();
  327|  6.73k|                frame->state = st_dictionary_value;
  328|  6.73k|                b_contents = decrypter && frame->key == "/Contents";
  ------------------
  |  Branch (328:30): [True: 0, False: 6.73k]
  |  Branch (328:43): [True: 0, False: 0]
  ------------------
  329|  6.73k|                continue;
  330|  6.73k|            } 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: 20.1k]
  ------------------
  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: 20.1k]
  ------------------
  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: 20.1k]
  ------------------
  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|  20.1k|        }
  373|  20.1k|    }
  374|  6.73k|}
_ZN10QPDFParser3addEONSt3__110shared_ptrI10QPDFObjectEE:
  378|  6.73k|{
  379|  6.73k|    if (frame->state != st_dictionary_value) {
  ------------------
  |  Branch (379:9): [True: 0, False: 6.73k]
  ------------------
  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.73k|    } else {
  384|  6.73k|        if (auto res = frame->dict.insert_or_assign(frame->key, std::move(obj)); !res.second) {
  ------------------
  |  Branch (384:82): [True: 0, False: 6.73k]
  ------------------
  385|      0|            warnDuplicateKey();
  386|      0|        }
  387|  6.73k|        frame->state = st_dictionary_key;
  388|  6.73k|    }
  389|  6.73k|}
_ZN10QPDFParser6addIntEi:
  411|  6.73k|{
  412|  6.73k|    auto obj = QPDF_Integer::create(int_buffer[count % 2]);
  413|  6.73k|    obj->setDescription(context, description, last_offset_buffer[count % 2]);
  414|  6.73k|    add(std::move(obj));
  415|  6.73k|}
_ZN10QPDFParser14setDescriptionERNSt3__110shared_ptrI10QPDFObjectEEx:
  437|  6.73k|{
  438|  6.73k|    if (obj) {
  ------------------
  |  Branch (438:9): [True: 6.73k, False: 0]
  ------------------
  439|  6.73k|        obj->setDescription(context, description, parsed_offset);
  440|  6.73k|    }
  441|  6.73k|}
_ZNK10QPDFParser4warnERK7QPDFExc:
  486|    149|{
  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|    149|    if (context) {
  ------------------
  |  Branch (490:9): [True: 0, False: 149]
  ------------------
  491|      0|        context->warn(e);
  492|    149|    } else {
  493|    149|        throw e;
  494|    149|    }
  495|    149|}
_ZNK10QPDFParser4warnExRKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  508|    149|{
  509|    149|    warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(), object_description, offset, msg));
  510|    149|}
_ZNK10QPDFParser4warnERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  514|    149|{
  515|    149|    warn(input->getLastOffset(), msg);
  516|    149|}
_ZN10QPDFParser15withDescriptionI9QPDF_NameJRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEEE16QPDFObjectHandleDpOT0_:
  429|  19.0k|{
  430|  19.0k|    auto obj = T::create(args...);
  431|  19.0k|    obj->setDescription(context, description, start);
  432|  19.0k|    return {obj};
  433|  19.0k|}

_ZN13QPDFTokenizer5resetEv:
   78|   139k|{
   79|   139k|    state = st_before_token;
   80|   139k|    type = tt_bad;
   81|   139k|    val.clear();
   82|   139k|    raw_val.clear();
   83|   139k|    error_message = "";
   84|   139k|    before_token = true;
   85|   139k|    in_token = false;
   86|   139k|    char_to_unread = '\0';
   87|   139k|    inline_image_bytes = 0;
   88|   139k|    string_depth = 0;
   89|   139k|    bad = false;
   90|   139k|}
_ZN13QPDFTokenizerC2Ev:
  107|  25.8k|{
  108|  25.8k|    reset();
  109|  25.8k|}
_ZN13QPDFTokenizer8allowEOFEv:
  113|  6.73k|{
  114|  6.73k|    this->allow_eof = true;
  115|  6.73k|}
_ZN13QPDFTokenizer7isSpaceEc:
  125|   120k|{
  126|   120k|    return ((ch == '\0') || QUtil::is_space(ch));
  ------------------
  |  Branch (126:13): [True: 0, False: 120k]
  |  Branch (126:29): [True: 40.3k, False: 79.7k]
  ------------------
  127|   120k|}
_ZN13QPDFTokenizer11isDelimiterEc:
  131|  11.2M|{
  132|  11.2M|    return is_delimiter(ch);
  133|  11.2M|}
_ZN13QPDFTokenizer16presentCharacterEc:
  137|  15.8k|{
  138|  15.8k|    handleCharacter(ch);
  139|       |
  140|  15.8k|    if (this->in_token) {
  ------------------
  |  Branch (140:9): [True: 0, False: 15.8k]
  ------------------
  141|      0|        this->raw_val += ch;
  142|      0|    }
  143|  15.8k|}
_ZN13QPDFTokenizer15handleCharacterEc:
  147|  11.3M|{
  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|  11.3M|    switch (this->state) {
  152|      0|    case st_top:
  ------------------
  |  Branch (152:5): [True: 0, False: 11.3M]
  ------------------
  153|      0|        inTop(ch);
  154|      0|        return;
  155|       |
  156|      0|    case st_in_space:
  ------------------
  |  Branch (156:5): [True: 0, False: 11.3M]
  ------------------
  157|      0|        inSpace(ch);
  158|      0|        return;
  159|       |
  160|      0|    case st_in_comment:
  ------------------
  |  Branch (160:5): [True: 0, False: 11.3M]
  ------------------
  161|      0|        inComment(ch);
  162|      0|        return;
  163|       |
  164|  6.73k|    case st_lt:
  ------------------
  |  Branch (164:5): [True: 6.73k, False: 11.3M]
  ------------------
  165|  6.73k|        inLt(ch);
  166|  6.73k|        return;
  167|       |
  168|  6.73k|    case st_gt:
  ------------------
  |  Branch (168:5): [True: 6.73k, False: 11.3M]
  ------------------
  169|  6.73k|        inGt(ch);
  170|  6.73k|        return;
  171|       |
  172|      0|    case st_in_string:
  ------------------
  |  Branch (172:5): [True: 0, False: 11.3M]
  ------------------
  173|      0|        inString(ch);
  174|      0|        return;
  175|       |
  176|  11.0M|    case st_name:
  ------------------
  |  Branch (176:5): [True: 11.0M, False: 374k]
  ------------------
  177|  11.0M|        inName(ch);
  178|  11.0M|        return;
  179|       |
  180|  20.1k|    case st_number:
  ------------------
  |  Branch (180:5): [True: 20.1k, False: 11.3M]
  ------------------
  181|  20.1k|        inNumber(ch);
  182|  20.1k|        return;
  183|       |
  184|      0|    case st_real:
  ------------------
  |  Branch (184:5): [True: 0, False: 11.3M]
  ------------------
  185|      0|        inReal(ch);
  186|      0|        return;
  187|       |
  188|      0|    case st_string_after_cr:
  ------------------
  |  Branch (188:5): [True: 0, False: 11.3M]
  ------------------
  189|      0|        inStringAfterCR(ch);
  190|      0|        return;
  191|       |
  192|      0|    case st_string_escape:
  ------------------
  |  Branch (192:5): [True: 0, False: 11.3M]
  ------------------
  193|      0|        inStringEscape(ch);
  194|      0|        return;
  195|       |
  196|      0|    case st_char_code:
  ------------------
  |  Branch (196:5): [True: 0, False: 11.3M]
  ------------------
  197|      0|        inCharCode(ch);
  198|      0|        return;
  199|       |
  200|   168k|    case st_literal:
  ------------------
  |  Branch (200:5): [True: 168k, False: 11.2M]
  ------------------
  201|   168k|        inLiteral(ch);
  202|   168k|        return;
  203|       |
  204|      0|    case st_inline_image:
  ------------------
  |  Branch (204:5): [True: 0, False: 11.3M]
  ------------------
  205|      0|        inInlineImage(ch);
  206|      0|        return;
  207|       |
  208|      0|    case st_in_hexstring:
  ------------------
  |  Branch (208:5): [True: 0, False: 11.3M]
  ------------------
  209|      0|        inHexstring(ch);
  210|      0|        return;
  211|       |
  212|      0|    case st_in_hexstring_2nd:
  ------------------
  |  Branch (212:5): [True: 0, False: 11.3M]
  ------------------
  213|      0|        inHexstring2nd(ch);
  214|      0|        return;
  215|       |
  216|  43.2k|    case st_name_hex1:
  ------------------
  |  Branch (216:5): [True: 43.2k, False: 11.3M]
  ------------------
  217|  43.2k|        inNameHex1(ch);
  218|  43.2k|        return;
  219|       |
  220|  9.31k|    case st_name_hex2:
  ------------------
  |  Branch (220:5): [True: 9.31k, False: 11.3M]
  ------------------
  221|  9.31k|        inNameHex2(ch);
  222|  9.31k|        return;
  223|       |
  224|      0|    case st_sign:
  ------------------
  |  Branch (224:5): [True: 0, False: 11.3M]
  ------------------
  225|      0|        inSign(ch);
  226|      0|        return;
  227|       |
  228|      0|    case st_decimal:
  ------------------
  |  Branch (228:5): [True: 0, False: 11.3M]
  ------------------
  229|      0|        inDecimal(ch);
  230|      0|        return;
  231|       |
  232|   120k|    case (st_before_token):
  ------------------
  |  Branch (232:5): [True: 120k, False: 11.2M]
  ------------------
  233|   120k|        inBeforeToken(ch);
  234|   120k|        return;
  235|       |
  236|      0|    case (st_token_ready):
  ------------------
  |  Branch (236:5): [True: 0, False: 11.3M]
  ------------------
  237|      0|        inTokenReady(ch);
  238|      0|        return;
  239|       |
  240|      0|    default:
  ------------------
  |  Branch (240:5): [True: 0, False: 11.3M]
  ------------------
  241|      0|        throw std::logic_error("INTERNAL ERROR: invalid state while reading token");
  242|  11.3M|    }
  243|  11.3M|}
_ZN13QPDFTokenizer13inBeforeTokenEc:
  254|   120k|{
  255|       |    // Note: we specifically do not use ctype here.  It is locale-dependent.
  256|   120k|    if (isSpace(ch)) {
  ------------------
  |  Branch (256:9): [True: 40.3k, False: 79.7k]
  ------------------
  257|  40.3k|        this->before_token = !this->include_ignorable;
  258|  40.3k|        this->in_token = this->include_ignorable;
  259|  40.3k|        if (this->include_ignorable) {
  ------------------
  |  Branch (259:13): [True: 0, False: 40.3k]
  ------------------
  260|      0|            this->state = st_in_space;
  261|      0|        }
  262|  79.7k|    } else if (ch == '%') {
  ------------------
  |  Branch (262:16): [True: 0, False: 79.7k]
  ------------------
  263|      0|        this->before_token = !this->include_ignorable;
  264|      0|        this->in_token = this->include_ignorable;
  265|      0|        this->state = st_in_comment;
  266|  79.7k|    } else {
  267|  79.7k|        this->before_token = false;
  268|  79.7k|        this->in_token = true;
  269|  79.7k|        inTop(ch);
  270|  79.7k|    }
  271|   120k|}
_ZN13QPDFTokenizer5inTopEc:
  275|  79.7k|{
  276|  79.7k|    switch (ch) {
  277|      0|    case '(':
  ------------------
  |  Branch (277:5): [True: 0, False: 79.7k]
  ------------------
  278|      0|        this->string_depth = 1;
  279|      0|        this->state = st_in_string;
  280|      0|        return;
  281|       |
  282|  6.73k|    case '<':
  ------------------
  |  Branch (282:5): [True: 6.73k, False: 72.9k]
  ------------------
  283|  6.73k|        this->state = st_lt;
  284|  6.73k|        return;
  285|       |
  286|  6.73k|    case '>':
  ------------------
  |  Branch (286:5): [True: 6.73k, False: 72.9k]
  ------------------
  287|  6.73k|        this->state = st_gt;
  288|  6.73k|        return;
  289|       |
  290|      0|    case (')'):
  ------------------
  |  Branch (290:5): [True: 0, False: 79.7k]
  ------------------
  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: 79.7k]
  ------------------
  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: 79.7k]
  ------------------
  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: 79.7k]
  ------------------
  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: 79.7k]
  ------------------
  313|      0|        this->type = tt_brace_close;
  314|      0|        this->state = st_token_ready;
  315|      0|        return;
  316|       |
  317|  25.8k|    case '/':
  ------------------
  |  Branch (317:5): [True: 25.8k, False: 53.8k]
  ------------------
  318|  25.8k|        this->state = st_name;
  319|  25.8k|        this->val += ch;
  320|  25.8k|        return;
  321|       |
  322|      0|    case '0':
  ------------------
  |  Branch (322:5): [True: 0, False: 79.7k]
  ------------------
  323|  6.73k|    case '1':
  ------------------
  |  Branch (323:5): [True: 6.73k, False: 72.9k]
  ------------------
  324|  6.73k|    case '2':
  ------------------
  |  Branch (324:5): [True: 0, False: 79.7k]
  ------------------
  325|  6.73k|    case '3':
  ------------------
  |  Branch (325:5): [True: 0, False: 79.7k]
  ------------------
  326|  6.73k|    case '4':
  ------------------
  |  Branch (326:5): [True: 0, False: 79.7k]
  ------------------
  327|  6.73k|    case '5':
  ------------------
  |  Branch (327:5): [True: 0, False: 79.7k]
  ------------------
  328|  6.73k|    case '6':
  ------------------
  |  Branch (328:5): [True: 0, False: 79.7k]
  ------------------
  329|  6.73k|    case '7':
  ------------------
  |  Branch (329:5): [True: 0, False: 79.7k]
  ------------------
  330|  6.73k|    case '8':
  ------------------
  |  Branch (330:5): [True: 0, False: 79.7k]
  ------------------
  331|  20.1k|    case '9':
  ------------------
  |  Branch (331:5): [True: 13.4k, False: 66.2k]
  ------------------
  332|  20.1k|        this->state = st_number;
  333|  20.1k|        return;
  334|       |
  335|      0|    case '+':
  ------------------
  |  Branch (335:5): [True: 0, False: 79.7k]
  ------------------
  336|      0|    case '-':
  ------------------
  |  Branch (336:5): [True: 0, False: 79.7k]
  ------------------
  337|      0|        this->state = st_sign;
  338|      0|        return;
  339|       |
  340|      0|    case '.':
  ------------------
  |  Branch (340:5): [True: 0, False: 79.7k]
  ------------------
  341|      0|        this->state = st_decimal;
  342|      0|        return;
  343|       |
  344|  20.1k|    default:
  ------------------
  |  Branch (344:5): [True: 20.1k, False: 59.5k]
  ------------------
  345|  20.1k|        this->state = st_literal;
  346|  20.1k|        return;
  347|  79.7k|    }
  348|  79.7k|}
_ZN13QPDFTokenizer6inNameEc:
  418|  11.0M|{
  419|  11.0M|    if (isDelimiter(ch)) {
  ------------------
  |  Branch (419:9): [True: 25.8k, False: 11.0M]
  ------------------
  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|  25.8k|        this->type = this->bad ? tt_bad : tt_name;
  ------------------
  |  Branch (426:22): [True: 58, False: 25.8k]
  ------------------
  427|  25.8k|        this->in_token = false;
  428|  25.8k|        this->char_to_unread = ch;
  429|  25.8k|        this->state = st_token_ready;
  430|  11.0M|    } else if (ch == '#') {
  ------------------
  |  Branch (430:16): [True: 43.2k, False: 10.9M]
  ------------------
  431|  43.2k|        this->char_code = 0;
  432|  43.2k|        this->state = st_name_hex1;
  433|  10.9M|    } else {
  434|  10.9M|        this->val += ch;
  435|  10.9M|    }
  436|  11.0M|}
_ZN13QPDFTokenizer10inNameHex1Ec:
  440|  43.2k|{
  441|  43.2k|    this->hex_char = ch;
  442|       |
  443|  43.2k|    if (char hval = QUtil::hex_decode_char(ch); hval < '\20') {
  ------------------
  |  Branch (443:49): [True: 9.31k, False: 33.9k]
  ------------------
  444|  9.31k|        this->char_code = int(hval) << 4;
  445|  9.31k|        this->state = st_name_hex2;
  446|  33.9k|    } else {
  447|  33.9k|        QTC::TC("qpdf", "QPDFTokenizer bad name 1");
  448|  33.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|  33.9k|        this->val += '\0';
  451|  33.9k|        this->state = st_name;
  452|  33.9k|        inName(ch);
  453|  33.9k|    }
  454|  43.2k|}
_ZN13QPDFTokenizer10inNameHex2Ec:
  458|  9.31k|{
  459|  9.31k|    if (char hval = QUtil::hex_decode_char(ch); hval < '\20') {
  ------------------
  |  Branch (459:49): [True: 5.13k, False: 4.18k]
  ------------------
  460|  5.13k|        this->char_code |= int(hval);
  461|  5.13k|    } else {
  462|  4.18k|        QTC::TC("qpdf", "QPDFTokenizer bad name 2");
  463|  4.18k|        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|  4.18k|        this->val += '\0';
  466|  4.18k|        this->val += this->hex_char;
  467|  4.18k|        this->state = st_name;
  468|  4.18k|        inName(ch);
  469|  4.18k|        return;
  470|  4.18k|    }
  471|  5.13k|    if (this->char_code == 0) {
  ------------------
  |  Branch (471:9): [True: 2.61k, False: 2.51k]
  ------------------
  472|  2.61k|        QTC::TC("qpdf", "QPDFTokenizer null in name");
  473|  2.61k|        this->error_message = "null character not allowed in name token";
  474|  2.61k|        this->val += "#00";
  475|  2.61k|        this->state = st_name;
  476|  2.61k|        this->bad = true;
  477|  2.61k|    } else {
  478|  2.51k|        this->val += char(this->char_code);
  479|  2.51k|        this->state = st_name;
  480|  2.51k|    }
  481|  5.13k|}
_ZN13QPDFTokenizer8inNumberEc:
  509|  20.1k|{
  510|  20.1k|    if (QUtil::is_digit(ch)) {
  ------------------
  |  Branch (510:9): [True: 0, False: 20.1k]
  ------------------
  511|  20.1k|    } else if (ch == '.') {
  ------------------
  |  Branch (511:16): [True: 0, False: 20.1k]
  ------------------
  512|      0|        this->state = st_real;
  513|  20.1k|    } else if (isDelimiter(ch)) {
  ------------------
  |  Branch (513:16): [True: 20.1k, False: 0]
  ------------------
  514|  20.1k|        this->type = tt_integer;
  515|  20.1k|        this->state = st_token_ready;
  516|  20.1k|        this->in_token = false;
  517|  20.1k|        this->char_to_unread = ch;
  518|  20.1k|    } else {
  519|      0|        this->state = st_literal;
  520|      0|    }
  521|  20.1k|}
_ZN13QPDFTokenizer4inLtEc:
  600|  6.73k|{
  601|  6.73k|    if (ch == '<') {
  ------------------
  |  Branch (601:9): [True: 6.73k, False: 0]
  ------------------
  602|  6.73k|        this->type = tt_dict_open;
  603|  6.73k|        this->state = st_token_ready;
  604|  6.73k|        return;
  605|  6.73k|    }
  606|       |
  607|      0|    this->state = st_in_hexstring;
  608|      0|    inHexstring(ch);
  609|      0|}
_ZN13QPDFTokenizer4inGtEc:
  613|  6.73k|{
  614|  6.73k|    if (ch == '>') {
  ------------------
  |  Branch (614:9): [True: 6.73k, False: 0]
  ------------------
  615|  6.73k|        this->type = tt_dict_close;
  616|  6.73k|        this->state = st_token_ready;
  617|  6.73k|    } 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.73k|}
_ZN13QPDFTokenizer9inLiteralEc:
  629|   168k|{
  630|   168k|    if (isDelimiter(ch)) {
  ------------------
  |  Branch (630:9): [True: 20.1k, False: 148k]
  ------------------
  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|  20.1k|        this->in_token = false;
  637|  20.1k|        this->char_to_unread = ch;
  638|  20.1k|        this->state = st_token_ready;
  639|  20.1k|        this->type = (this->raw_val == "true") || (this->raw_val == "false")
  ------------------
  |  Branch (639:22): [True: 0, False: 20.1k]
  |  Branch (639:51): [True: 0, False: 20.1k]
  ------------------
  640|  20.1k|            ? tt_bool
  641|  20.1k|            : (this->raw_val == "null" ? tt_null : tt_word);
  ------------------
  |  Branch (641:16): [True: 0, False: 20.1k]
  ------------------
  642|  20.1k|    }
  643|   168k|}
_ZN13QPDFTokenizer10presentEOFEv:
  724|  15.8k|{
  725|  15.8k|    switch (this->state) {
  726|  15.8k|    case st_name:
  ------------------
  |  Branch (726:5): [True: 15.8k, False: 32]
  ------------------
  727|  15.8k|    case st_name_hex1:
  ------------------
  |  Branch (727:5): [True: 11, False: 15.8k]
  ------------------
  728|  15.8k|    case st_name_hex2:
  ------------------
  |  Branch (728:5): [True: 21, False: 15.8k]
  ------------------
  729|  15.8k|    case st_number:
  ------------------
  |  Branch (729:5): [True: 0, False: 15.8k]
  ------------------
  730|  15.8k|    case st_real:
  ------------------
  |  Branch (730:5): [True: 0, False: 15.8k]
  ------------------
  731|  15.8k|    case st_sign:
  ------------------
  |  Branch (731:5): [True: 0, False: 15.8k]
  ------------------
  732|  15.8k|    case st_decimal:
  ------------------
  |  Branch (732:5): [True: 0, False: 15.8k]
  ------------------
  733|  15.8k|    case st_literal:
  ------------------
  |  Branch (733:5): [True: 0, False: 15.8k]
  ------------------
  734|  15.8k|        QTC::TC("qpdf", "QPDFTokenizer EOF reading appendable token");
  735|       |        // Push any delimiter to the state machine to finish off the final token.
  736|  15.8k|        presentCharacter('\f');
  737|  15.8k|        this->in_token = true;
  738|  15.8k|        break;
  739|       |
  740|      0|    case st_top:
  ------------------
  |  Branch (740:5): [True: 0, False: 15.8k]
  ------------------
  741|      0|    case st_before_token:
  ------------------
  |  Branch (741:5): [True: 0, False: 15.8k]
  ------------------
  742|      0|        this->type = tt_eof;
  743|      0|        break;
  744|       |
  745|      0|    case st_in_space:
  ------------------
  |  Branch (745:5): [True: 0, False: 15.8k]
  ------------------
  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: 15.8k]
  ------------------
  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: 15.8k]
  ------------------
  754|      0|        break;
  755|       |
  756|      0|    default:
  ------------------
  |  Branch (756:5): [True: 0, False: 15.8k]
  ------------------
  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|  15.8k|    }
  761|  15.8k|    this->state = st_token_ready;
  762|  15.8k|}
_ZN13QPDFTokenizer8getTokenERNS_5TokenERbRc:
  869|  33.6k|{
  870|  33.6k|    bool ready = (this->state == st_token_ready);
  871|  33.6k|    unread_char = !this->in_token && !this->before_token;
  ------------------
  |  Branch (871:19): [True: 33.6k, False: 0]
  |  Branch (871:38): [True: 33.6k, False: 0]
  ------------------
  872|  33.6k|    ch = this->char_to_unread;
  873|  33.6k|    if (ready) {
  ------------------
  |  Branch (873:9): [True: 33.6k, False: 0]
  ------------------
  874|  33.6k|        token = (!(this->type == tt_name || this->type == tt_string))
  ------------------
  |  Branch (874:20): [True: 0, False: 33.6k]
  |  Branch (874:45): [True: 0, False: 33.6k]
  ------------------
  875|  33.6k|            ? Token(this->type, this->raw_val, this->raw_val, this->error_message)
  876|  33.6k|            : Token(this->type, this->val, this->raw_val, this->error_message);
  877|       |
  878|  33.6k|        this->reset();
  879|  33.6k|    }
  880|  33.6k|    return ready;
  881|  33.6k|}
_ZN13QPDFTokenizer9readTokenER11InputSourceRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbm:
  892|  33.6k|{
  893|  33.6k|    nextToken(input, context, max_len);
  894|       |
  895|  33.6k|    Token token;
  896|  33.6k|    bool unread_char;
  897|  33.6k|    char char_to_unread;
  898|  33.6k|    getToken(token, unread_char, char_to_unread);
  899|       |
  900|  33.6k|    if (token.getType() == tt_bad) {
  ------------------
  |  Branch (900:9): [True: 0, False: 33.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|  33.6k|    return token;
  913|  33.6k|}
_ZN13QPDFTokenizer9readTokenENSt3__110shared_ptrI11InputSourceEERKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEbm:
  918|  33.6k|{
  919|  33.6k|    return readToken(*input, context, allow_bad, max_len);
  920|  33.6k|}
_ZN13QPDFTokenizer9nextTokenER11InputSourceRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEm:
  924|  79.7k|{
  925|  79.7k|    if (this->state != st_inline_image) {
  ------------------
  |  Branch (925:9): [True: 79.7k, False: 0]
  ------------------
  926|  79.7k|        reset();
  927|  79.7k|    }
  928|  79.7k|    qpdf_offset_t offset = input.fastTell();
  929|       |
  930|  11.4M|    while (this->state != st_token_ready) {
  ------------------
  |  Branch (930:12): [True: 11.3M, False: 79.7k]
  ------------------
  931|  11.3M|        char ch;
  932|  11.3M|        if (!input.fastRead(ch)) {
  ------------------
  |  Branch (932:13): [True: 15.8k, False: 11.3M]
  ------------------
  933|  15.8k|            presentEOF();
  934|       |
  935|  15.8k|            if ((this->type == tt_eof) && (!this->allow_eof)) {
  ------------------
  |  Branch (935:17): [True: 0, False: 15.8k]
  |  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|  11.3M|        } else {
  943|  11.3M|            handleCharacter(ch);
  944|  11.3M|            if (this->before_token) {
  ------------------
  |  Branch (944:17): [True: 40.3k, False: 11.3M]
  ------------------
  945|  40.3k|                ++offset;
  946|  40.3k|            }
  947|  11.3M|            if (this->in_token) {
  ------------------
  |  Branch (947:17): [True: 11.2M, False: 90.7k]
  ------------------
  948|  11.2M|                this->raw_val += ch;
  949|  11.2M|            }
  950|  11.3M|            if (max_len && (this->raw_val.length() >= max_len) && (this->state != st_token_ready)) {
  ------------------
  |  Branch (950:17): [True: 0, False: 11.3M]
  |  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|  11.3M|        }
  958|  11.3M|    }
  959|       |
  960|  79.7k|    input.fastUnread(!this->in_token && !this->before_token);
  ------------------
  |  Branch (960:22): [True: 50.3k, False: 29.3k]
  |  Branch (960:41): [True: 50.3k, False: 0]
  ------------------
  961|       |
  962|  79.7k|    if (this->type != tt_eof) {
  ------------------
  |  Branch (962:9): [True: 79.7k, False: 0]
  ------------------
  963|  79.7k|        input.setLastOffset(offset);
  964|  79.7k|    }
  965|       |
  966|  79.7k|    return this->error_message.empty();
  967|  79.7k|}
QPDFTokenizer.cc:_ZL12is_delimiterc:
   18|  11.2M|{
   19|  11.2M|    return (
   20|  11.2M|        ch == ' ' || ch == '\n' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
  ------------------
  |  Branch (20:9): [True: 20.6k, False: 11.2M]
  |  Branch (20:22): [True: 27.1k, False: 11.2M]
  |  Branch (20:36): [True: 36, False: 11.2M]
  |  Branch (20:49): [True: 4, False: 11.2M]
  |  Branch (20:62): [True: 6, False: 11.2M]
  |  Branch (20:75): [True: 7, False: 11.2M]
  |  Branch (20:88): [True: 1, False: 11.2M]
  ------------------
   21|  11.2M|        ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch == '\t' || ch == '\r' ||
  ------------------
  |  Branch (21:9): [True: 4, False: 11.2M]
  |  Branch (21:22): [True: 6, False: 11.2M]
  |  Branch (21:35): [True: 10, False: 11.2M]
  |  Branch (21:48): [True: 6, False: 11.2M]
  |  Branch (21:61): [True: 6, False: 11.2M]
  |  Branch (21:74): [True: 2.16k, False: 11.1M]
  |  Branch (21:88): [True: 203, False: 11.1M]
  ------------------
   22|  11.2M|        ch == '\v' || ch == '\f' || ch == 0);
  ------------------
  |  Branch (22:9): [True: 194, False: 11.1M]
  |  Branch (22:23): [True: 15.8k, False: 11.1M]
  |  Branch (22:37): [True: 2, False: 11.1M]
  ------------------
   23|  11.2M|}

_ZN9QPDFValue9do_createEPS_:
    7|  2.83M|{
    8|  2.83M|    std::shared_ptr<QPDFObject> obj(new QPDFObject());
    9|  2.83M|    obj->value = std::shared_ptr<QPDFValue>(object);
   10|  2.83M|    return obj;
   11|  2.83M|}
_ZN9QPDFValue14getDescriptionEv:
   15|  3.73k|{
   16|  3.73k|    if (object_description) {
  ------------------
  |  Branch (16:9): [True: 3.73k, False: 0]
  ------------------
   17|  3.73k|        switch (object_description->index()) {
  ------------------
  |  Branch (17:17): [True: 0, False: 3.73k]
  ------------------
   18|  3.73k|        case 0:
  ------------------
  |  Branch (18:9): [True: 3.73k, False: 0]
  ------------------
   19|  3.73k|            {
   20|       |                // Simple template string
   21|  3.73k|                auto description = std::get<0>(*object_description);
   22|       |
   23|  3.73k|                if (auto pos = description.find("$OG"); pos != std::string::npos) {
  ------------------
  |  Branch (23:57): [True: 0, False: 3.73k]
  ------------------
   24|      0|                    description.replace(pos, 3, og.unparse(' '));
   25|      0|                }
   26|  3.73k|                if (auto pos = description.find("$PO"); pos != std::string::npos) {
  ------------------
  |  Branch (26:57): [True: 0, False: 3.73k]
  ------------------
   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|  3.73k|                return description;
   34|      0|            }
   35|      0|        case 1:
  ------------------
  |  Branch (35:9): [True: 0, False: 3.73k]
  ------------------
   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: 3.73k]
  ------------------
   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|  3.73k|        }
   58|  3.73k|    } else if (og.isIndirect()) {
  ------------------
  |  Branch (58:16): [True: 0, False: 0]
  ------------------
   59|      0|        return "object " + og.unparse(' ');
   60|      0|    }
   61|      0|    return {};
   62|  3.73k|}

_ZN10QPDF_ArrayC2ERKNSt3__16vectorI16QPDFObjectHandleNS0_9allocatorIS2_EEEE:
   41|  19.1k|{
   42|  19.1k|    setFromVector(v);
   43|  19.1k|}
_ZN10QPDF_Array6createERKNSt3__16vectorI16QPDFObjectHandleNS0_9allocatorIS2_EEEE:
   63|  19.1k|{
   64|  19.1k|    return do_create(new QPDF_Array(items));
   65|  19.1k|}
_ZN10QPDF_Array10disconnectEv:
  105|  18.8k|{
  106|  18.8k|    if (sp) {
  ------------------
  |  Branch (106:9): [True: 0, False: 18.8k]
  ------------------
  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|  18.8k|    } else {
  114|  2.97M|        for (auto& obj: elements) {
  ------------------
  |  Branch (114:23): [True: 2.97M, False: 18.8k]
  ------------------
  115|  2.97M|            if (!obj->getObjGen().isIndirect()) {
  ------------------
  |  Branch (115:17): [True: 2.74M, False: 221k]
  ------------------
  116|  2.74M|                obj->disconnect();
  117|  2.74M|            }
  118|  2.97M|        }
  119|  18.8k|    }
  120|  18.8k|}
_ZN10QPDF_Array13setFromVectorERKNSt3__16vectorI16QPDFObjectHandleNS0_9allocatorIS2_EEEE:
  234|  19.1k|{
  235|  19.1k|    elements.resize(0);
  236|  19.1k|    elements.reserve(v.size());
  237|  19.1k|    for (auto const& item: v) {
  ------------------
  |  Branch (237:26): [True: 0, False: 19.1k]
  ------------------
  238|      0|        checkOwnership(item);
  239|      0|        elements.push_back(item.getObj());
  240|      0|    }
  241|  19.1k|}
_ZN10QPDF_Array9push_backERK16QPDFObjectHandle:
  277|  2.97M|{
  278|  2.97M|    checkOwnership(item);
  279|  2.97M|    if (sp) {
  ------------------
  |  Branch (279:9): [True: 0, False: 2.97M]
  ------------------
  280|      0|        sp->elements[(sp->size)++] = item.getObj();
  281|  2.97M|    } else {
  282|  2.97M|        elements.push_back(item.getObj());
  283|  2.97M|    }
  284|  2.97M|}
_ZNK10QPDF_Array14checkOwnershipERK16QPDFObjectHandle:
   12|  2.97M|{
   13|  2.97M|    if (auto obj = item.getObjectPtr()) {
  ------------------
  |  Branch (13:14): [True: 2.97M, False: 0]
  ------------------
   14|  2.97M|        if (qpdf) {
  ------------------
  |  Branch (14:13): [True: 2.97M, False: 0]
  ------------------
   15|  2.97M|            if (auto item_qpdf = obj->getQPDF()) {
  ------------------
  |  Branch (15:22): [True: 2.96M, False: 8.65k]
  ------------------
   16|  2.96M|                if (qpdf != item_qpdf) {
  ------------------
  |  Branch (16:21): [True: 0, False: 2.96M]
  ------------------
   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.96M|            }
   22|  2.97M|        }
   23|  2.97M|    } else {
   24|      0|        throw std::logic_error("Attempting to add an uninitialized object to a QPDF_Array.");
   25|      0|    }
   26|  2.97M|}

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

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

_ZN15QPDF_DictionaryC2ERKNSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE16QPDFObjectHandleNS0_4lessIS7_EENS5_INS0_4pairIKS7_S8_EEEEEE:
   14|  31.3k|{
   15|  31.3k|}
_ZN15QPDF_Dictionary6createERKNSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE16QPDFObjectHandleNS0_4lessIS7_EENS5_INS0_4pairIKS7_S8_EEEEEE:
   25|  24.6k|{
   26|  24.6k|    return do_create(new QPDF_Dictionary(items));
   27|  24.6k|}
_ZN15QPDF_Dictionary6createEONSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE16QPDFObjectHandleNS0_4lessIS7_EENS5_INS0_4pairIKS7_S8_EEEEEE:
   31|  6.73k|{
   32|  6.73k|    return do_create(new QPDF_Dictionary(items));
   33|  6.73k|}
_ZN15QPDF_Dictionary10disconnectEv:
   52|  21.4k|{
   53|  82.3k|    for (auto& iter: this->items) {
  ------------------
  |  Branch (53:20): [True: 82.3k, False: 21.4k]
  ------------------
   54|  82.3k|        QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
   55|  82.3k|    }
   56|  21.4k|}
_ZN15QPDF_Dictionary6hasKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   99|  26.9k|{
  100|  26.9k|    return ((this->items.count(key) > 0) && (!this->items[key].isNull()));
  ------------------
  |  Branch (100:13): [True: 6.73k, False: 20.1k]
  |  Branch (100:45): [True: 6.73k, False: 0]
  ------------------
  101|  26.9k|}
_ZN15QPDF_Dictionary6getKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  105|  13.4k|{
  106|       |    // PDF spec says fetching a non-existent key from a dictionary returns the null object.
  107|  13.4k|    auto item = this->items.find(key);
  108|  13.4k|    if (item != this->items.end()) {
  ------------------
  |  Branch (108:9): [True: 13.4k, False: 0]
  ------------------
  109|       |        // May be a null object
  110|  13.4k|        return item->second;
  111|  13.4k|    } 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.4k|}
_ZN15QPDF_Dictionary10replaceKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE16QPDFObjectHandle:
  137|   103k|{
  138|   103k|    if (value.isNull() && !value.isIndirect()) {
  ------------------
  |  Branch (138:9): [True: 26.4k, False: 76.6k]
  |  Branch (138:27): [True: 12.0k, False: 14.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|  12.0k|        removeKey(key);
  143|  91.1k|    } else {
  144|       |        // add or replace value
  145|  91.1k|        this->items[key] = value;
  146|  91.1k|    }
  147|   103k|}
_ZN15QPDF_Dictionary9removeKeyERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  151|  15.2k|{
  152|       |    // no-op if key does not exist
  153|  15.2k|    this->items.erase(key);
  154|  15.2k|}

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

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

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

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

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

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

_ZN4QPDF20initializeEncryptionEv:
  720|  6.73k|{
  721|  6.73k|    if (m->encp->encryption_initialized) {
  ------------------
  |  Branch (721:9): [True: 0, False: 6.73k]
  ------------------
  722|      0|        return;
  723|      0|    }
  724|  6.73k|    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.73k|    if (!m->trailer.hasKey("/Encrypt")) {
  ------------------
  |  Branch (730:9): [True: 6.73k, False: 0]
  ------------------
  731|  6.73k|        return;
  732|  6.73k|    }
  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|  50.9k|{
  311|  50.9k|    errors = true;
  312|  50.9k|    std::string object = this->cur_object;
  313|  50.9k|    if (is->getName() != pdf.getFilename()) {
  ------------------
  |  Branch (313:9): [True: 0, False: 50.9k]
  ------------------
  314|      0|        object += " from " + is->getName();
  315|      0|    }
  316|  50.9k|    pdf.warn(qpdf_e_json, object, offset, msg);
  317|  50.9k|}
_ZNK4QPDF11JSONReactor9anyErrorsEv:
  321|     53|{
  322|     53|    return errors;
  323|     53|}
_ZN4QPDF11JSONReactor14containerStartEv:
  327|  80.1k|{
  328|  80.1k|    if (next_obj.isInitialized()) {
  ------------------
  |  Branch (328:9): [True: 55.3k, False: 24.8k]
  ------------------
  329|  55.3k|        stack.emplace_back(next_state, std::move(next_obj));
  330|  55.3k|        next_obj = QPDFObjectHandle();
  331|  55.3k|    } else {
  332|  24.8k|        stack.emplace_back(next_state);
  333|  24.8k|    }
  334|  80.1k|}
_ZN4QPDF11JSONReactor15dictionaryStartEv:
  338|  52.9k|{
  339|  52.9k|    containerStart();
  340|  52.9k|}
_ZN4QPDF11JSONReactor10arrayStartEv:
  344|  27.5k|{
  345|  27.5k|    if (stack.empty()) {
  ------------------
  |  Branch (345:9): [True: 422, False: 27.1k]
  ------------------
  346|    422|        QTC::TC("qpdf", "QPDF_json top-level array");
  347|    422|        throw std::runtime_error("QPDF JSON must be a dictionary");
  348|    422|    }
  349|  27.1k|    containerStart();
  350|  27.1k|}
_ZN4QPDF11JSONReactor12containerEndERK4JSON:
  354|  28.7k|{
  355|  28.7k|    auto from_state = stack.back().state;
  356|  28.7k|    stack.pop_back();
  357|  28.7k|    if (stack.empty()) {
  ------------------
  |  Branch (357:9): [True: 62, False: 28.6k]
  ------------------
  358|     62|        if (!this->saw_qpdf) {
  ------------------
  |  Branch (358:13): [True: 19, False: 43]
  ------------------
  359|     19|            QTC::TC("qpdf", "QPDF_json missing qpdf");
  360|     19|            error(0, "\"qpdf\" object was not seen");
  361|     43|        } else {
  362|     43|            if (!this->saw_json_version) {
  ------------------
  |  Branch (362:17): [True: 33, False: 10]
  ------------------
  363|     33|                QTC::TC("qpdf", "QPDF_json missing json version");
  364|     33|                error(0, "\"qpdf[0].jsonversion\" was not seen");
  365|     33|            }
  366|     43|            if (must_be_complete && !this->saw_pdf_version) {
  ------------------
  |  Branch (366:17): [True: 42, False: 1]
  |  Branch (366:37): [True: 32, False: 10]
  ------------------
  367|     32|                QTC::TC("qpdf", "QPDF_json missing pdf version");
  368|     32|                error(0, "\"qpdf[0].pdfversion\" was not seen");
  369|     32|            }
  370|     43|            if (!this->saw_objects) {
  ------------------
  |  Branch (370:17): [True: 4, False: 39]
  ------------------
  371|      4|                QTC::TC("qpdf", "QPDF_json missing objects");
  372|      4|                error(0, "\"qpdf[1]\" was not seen");
  373|     39|            } else {
  374|     39|                if (must_be_complete && !this->saw_trailer) {
  ------------------
  |  Branch (374:21): [True: 37, False: 2]
  |  Branch (374:41): [True: 26, False: 11]
  ------------------
  375|     26|                    QTC::TC("qpdf", "QPDF_json missing trailer");
  376|     26|                    error(0, "\"qpdf[1].trailer\" was not seen");
  377|     26|                }
  378|     39|            }
  379|     43|        }
  380|  28.6k|    } else if (from_state == st_trailer) {
  ------------------
  |  Branch (380:16): [True: 14, False: 28.6k]
  ------------------
  381|     14|        if (!saw_value) {
  ------------------
  |  Branch (381:13): [True: 2, False: 12]
  ------------------
  382|      2|            QTC::TC("qpdf", "QPDF_json trailer no value");
  383|      2|            error(value.getStart(), "\"trailer\" is missing \"value\"");
  384|      2|        }
  385|  28.6k|    } else if (from_state == st_object_top) {
  ------------------
  |  Branch (385:16): [True: 7.99k, False: 20.6k]
  ------------------
  386|  7.99k|        if (saw_value == saw_stream) {
  ------------------
  |  Branch (386:13): [True: 493, False: 7.49k]
  ------------------
  387|    493|            QTC::TC("qpdf", "QPDF_json value stream both or neither");
  388|    493|            error(value.getStart(), "object must have exactly one of \"value\" or \"stream\"");
  389|    493|        }
  390|  7.99k|        if (saw_stream) {
  ------------------
  |  Branch (390:13): [True: 3.51k, False: 4.47k]
  ------------------
  391|  3.51k|            if (!saw_dict) {
  ------------------
  |  Branch (391:17): [True: 757, False: 2.76k]
  ------------------
  392|    757|                QTC::TC("qpdf", "QPDF_json stream no dict");
  393|    757|                error(value.getStart(), "\"stream\" is missing \"dict\"");
  394|    757|            }
  395|  3.51k|            if (saw_data == saw_datafile) {
  ------------------
  |  Branch (395:17): [True: 601, False: 2.91k]
  ------------------
  396|    601|                if (this_stream_needs_data) {
  ------------------
  |  Branch (396:21): [True: 550, False: 51]
  ------------------
  397|    550|                    QTC::TC("qpdf", "QPDF_json data datafile both or neither");
  398|    550|                    error(
  399|    550|                        value.getStart(),
  400|    550|                        "new \"stream\" must have exactly one of \"data\" or "
  401|    550|                        "\"datafile\"");
  402|    550|                } else if (saw_datafile) {
  ------------------
  |  Branch (402:28): [True: 19, False: 32]
  ------------------
  403|     19|                    QTC::TC("qpdf", "QPDF_json data and datafile");
  404|     19|                    error(
  405|     19|                        value.getStart(),
  406|     19|                        "existing \"stream\" may at most one of \"data\" or "
  407|     19|                        "\"datafile\"");
  408|     32|                } else {
  409|     32|                    QTC::TC("qpdf", "QPDF_json no stream data in update mode");
  410|     32|                }
  411|    601|            }
  412|  3.51k|        }
  413|  7.99k|    }
  414|  28.7k|    if (!stack.empty()) {
  ------------------
  |  Branch (414:9): [True: 28.6k, False: 62]
  ------------------
  415|  28.6k|        auto state = stack.back().state;
  416|  28.6k|        if (state == st_objects) {
  ------------------
  |  Branch (416:13): [True: 8.41k, False: 20.2k]
  ------------------
  417|  8.41k|            this->cur_object = "";
  418|  8.41k|            this->saw_dict = false;
  419|  8.41k|            this->saw_data = false;
  420|  8.41k|            this->saw_datafile = false;
  421|  8.41k|            this->saw_value = false;
  422|  8.41k|            this->saw_stream = false;
  423|  8.41k|        }
  424|  28.6k|    }
  425|  28.7k|}
_ZN4QPDF11JSONReactor13replaceObjectEO16QPDFObjectHandleRK4JSON:
  429|  10.8k|{
  430|  10.8k|    if (replacement.isIndirect()) {
  ------------------
  |  Branch (430:9): [True: 85, False: 10.7k]
  ------------------
  431|     85|        error(
  432|     85|            replacement.getParsedOffset(),
  433|     85|            "the value of an object may not be an indirect object reference");
  434|     85|        return;
  435|     85|    }
  436|  10.7k|    auto& tos = stack.back();
  437|  10.7k|    auto og = tos.object.getObjGen();
  438|  10.7k|    this->pdf.replaceObject(og, replacement);
  439|  10.7k|    next_obj = pdf.getObject(og);
  440|  10.7k|    setObjectDescription(tos.object, value);
  441|  10.7k|}
_ZN4QPDF11JSONReactor14topLevelScalarEv:
  445|    258|{
  446|    258|    QTC::TC("qpdf", "QPDF_json top-level scalar");
  447|    258|    throw std::runtime_error("QPDF JSON must be a dictionary");
  448|    258|}
_ZN4QPDF11JSONReactor24setNextStateIfDictionaryERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERK4JSONNS0_7state_eE:
  452|  27.8k|{
  453|       |    // Use this method when the next state is for processing a nested dictionary.
  454|  27.8k|    if (value.isDictionary()) {
  ------------------
  |  Branch (454:9): [True: 25.3k, False: 2.43k]
  ------------------
  455|  25.3k|        this->next_state = next;
  456|  25.3k|        return true;
  457|  25.3k|    }
  458|  2.43k|    error(value.getStart(), "\"" + key + "\" must be a dictionary");
  459|  2.43k|    return false;
  460|  27.8k|}
_ZN4QPDF11JSONReactor14dictionaryItemERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERK4JSON:
  464|   150k|{
  465|   150k|    if (stack.empty()) {
  ------------------
  |  Branch (465:9): [True: 0, False: 150k]
  ------------------
  466|      0|        throw std::logic_error("stack is empty in dictionaryItem");
  467|      0|    }
  468|   150k|    next_state = st_ignore;
  469|   150k|    auto state = stack.back().state;
  470|   150k|    if (state == st_ignore) {
  ------------------
  |  Branch (470:9): [True: 5.75k, False: 145k]
  ------------------
  471|  5.75k|        QTC::TC("qpdf", "QPDF_json ignoring in st_ignore");
  472|       |        // ignore
  473|   145k|    } else if (state == st_top) {
  ------------------
  |  Branch (473:16): [True: 7.39k, False: 137k]
  ------------------
  474|  7.39k|        if (key == "qpdf") {
  ------------------
  |  Branch (474:13): [True: 4.75k, False: 2.64k]
  ------------------
  475|  4.75k|            this->saw_qpdf = true;
  476|  4.75k|            if (!value.isArray()) {
  ------------------
  |  Branch (476:17): [True: 5, False: 4.74k]
  ------------------
  477|      5|                QTC::TC("qpdf", "QPDF_json qpdf not array");
  478|      5|                error(value.getStart(), "\"qpdf\" must be an array");
  479|  4.74k|            } else {
  480|  4.74k|                next_state = st_qpdf;
  481|  4.74k|            }
  482|  4.75k|        } else {
  483|       |            // Ignore all other fields.
  484|  2.64k|            QTC::TC("qpdf", "QPDF_json ignoring unknown top-level key");
  485|  2.64k|        }
  486|   137k|    } else if (state == st_qpdf_meta) {
  ------------------
  |  Branch (486:16): [True: 1.51k, False: 136k]
  ------------------
  487|  1.51k|        if (key == "pdfversion") {
  ------------------
  |  Branch (487:13): [True: 106, False: 1.41k]
  ------------------
  488|    106|            this->saw_pdf_version = true;
  489|    106|            std::string v;
  490|    106|            bool okay = false;
  491|    106|            if (value.getString(v)) {
  ------------------
  |  Branch (491:17): [True: 103, False: 3]
  ------------------
  492|    103|                std::string version;
  493|    103|                char const* p = v.c_str();
  494|    103|                if (QPDF::validatePDFVersion(p, version) && (*p == '\0')) {
  ------------------
  |  Branch (494:21): [True: 61, False: 42]
  |  Branch (494:61): [True: 48, False: 13]
  ------------------
  495|     48|                    this->pdf.m->pdf_version = version;
  496|     48|                    okay = true;
  497|     48|                }
  498|    103|            }
  499|    106|            if (!okay) {
  ------------------
  |  Branch (499:17): [True: 58, False: 48]
  ------------------
  500|     58|                QTC::TC("qpdf", "QPDF_json bad pdf version");
  501|     58|                error(value.getStart(), "invalid PDF version (must be \"x.y\")");
  502|     58|            }
  503|  1.41k|        } else if (key == "jsonversion") {
  ------------------
  |  Branch (503:20): [True: 170, False: 1.24k]
  ------------------
  504|    170|            this->saw_json_version = true;
  505|    170|            std::string v;
  506|    170|            bool okay = false;
  507|    170|            if (value.getNumber(v)) {
  ------------------
  |  Branch (507:17): [True: 165, False: 5]
  ------------------
  508|    165|                std::string version;
  509|    165|                if (QUtil::string_to_int(v.c_str()) == 2) {
  ------------------
  |  Branch (509:21): [True: 33, False: 132]
  ------------------
  510|     33|                    okay = true;
  511|     33|                }
  512|    165|            }
  513|    170|            if (!okay) {
  ------------------
  |  Branch (513:17): [True: 75, False: 95]
  ------------------
  514|     75|                QTC::TC("qpdf", "QPDF_json bad json version");
  515|     75|                error(value.getStart(), "invalid JSON version (must be numeric value 2)");
  516|     75|            }
  517|  1.24k|        } else if (key == "pushedinheritedpageresources") {
  ------------------
  |  Branch (517:20): [True: 25, False: 1.21k]
  ------------------
  518|     25|            bool v;
  519|     25|            if (value.getBool(v)) {
  ------------------
  |  Branch (519:17): [True: 24, False: 1]
  ------------------
  520|     24|                if (!this->must_be_complete && v) {
  ------------------
  |  Branch (520:21): [True: 0, False: 24]
  |  Branch (520:48): [True: 0, False: 0]
  ------------------
  521|      0|                    this->pdf.pushInheritedAttributesToPage();
  522|      0|                }
  523|     24|            } else {
  524|      1|                QTC::TC("qpdf", "QPDF_json bad pushedinheritedpageresources");
  525|      1|                error(value.getStart(), "pushedinheritedpageresources must be a boolean");
  526|      1|            }
  527|  1.21k|        } else if (key == "calledgetallpages") {
  ------------------
  |  Branch (527:20): [True: 31, False: 1.18k]
  ------------------
  528|     31|            bool v;
  529|     31|            if (value.getBool(v)) {
  ------------------
  |  Branch (529:17): [True: 26, False: 5]
  ------------------
  530|     26|                if (!this->must_be_complete && v) {
  ------------------
  |  Branch (530:21): [True: 0, False: 26]
  |  Branch (530:48): [True: 0, False: 0]
  ------------------
  531|      0|                    this->pdf.getAllPages();
  532|      0|                }
  533|     26|            } else {
  534|      5|                QTC::TC("qpdf", "QPDF_json bad calledgetallpages");
  535|      5|                error(value.getStart(), "calledgetallpages must be a boolean");
  536|      5|            }
  537|  1.18k|        } else {
  538|       |            // ignore unknown keys for forward compatibility and to skip keys we don't care about
  539|       |            // like "maxobjectid".
  540|  1.18k|            QTC::TC("qpdf", "QPDF_json ignore second-level key");
  541|  1.18k|        }
  542|   136k|    } else if (state == st_objects) {
  ------------------
  |  Branch (542:16): [True: 13.5k, False: 122k]
  ------------------
  543|  13.5k|        int obj = 0;
  544|  13.5k|        int gen = 0;
  545|  13.5k|        if (key == "trailer") {
  ------------------
  |  Branch (545:13): [True: 259, False: 13.2k]
  ------------------
  546|    259|            this->saw_trailer = true;
  547|    259|            this->cur_object = "trailer";
  548|    259|            setNextStateIfDictionary(key, value, st_trailer);
  549|  13.2k|        } else if (is_obj_key(key, obj, gen)) {
  ------------------
  |  Branch (549:20): [True: 11.6k, False: 1.61k]
  ------------------
  550|  11.6k|            this->cur_object = key;
  551|  11.6k|            if (setNextStateIfDictionary(key, value, st_object_top)) {
  ------------------
  |  Branch (551:17): [True: 11.4k, False: 194]
  ------------------
  552|  11.4k|                next_obj = pdf.getObjectForJSON(obj, gen);
  553|  11.4k|            }
  554|  11.6k|        } else {
  555|  1.61k|            QTC::TC("qpdf", "QPDF_json bad object key");
  556|  1.61k|            error(value.getStart(), "object key should be \"trailer\" or \"obj:n n R\"");
  557|  1.61k|        }
  558|   122k|    } else if (state == st_object_top) {
  ------------------
  |  Branch (558:16): [True: 12.2k, False: 110k]
  ------------------
  559|  12.2k|        if (stack.empty()) {
  ------------------
  |  Branch (559:13): [True: 0, False: 12.2k]
  ------------------
  560|      0|            throw std::logic_error("stack empty in st_object_top");
  561|      0|        }
  562|  12.2k|        auto& tos = stack.back();
  563|  12.2k|        if (!tos.object.isInitialized()) {
  ------------------
  |  Branch (563:13): [True: 0, False: 12.2k]
  ------------------
  564|      0|            throw std::logic_error("current object uninitialized in st_object_top");
  565|      0|        }
  566|  12.2k|        if (key == "value") {
  ------------------
  |  Branch (566:13): [True: 7.29k, False: 4.97k]
  ------------------
  567|       |            // Don't use setNextStateIfDictionary since this can have any type.
  568|  7.29k|            this->saw_value = true;
  569|  7.29k|            replaceObject(makeObject(value), value);
  570|  7.29k|            next_state = st_object;
  571|  7.29k|        } else if (key == "stream") {
  ------------------
  |  Branch (571:20): [True: 3.81k, False: 1.15k]
  ------------------
  572|  3.81k|            this->saw_stream = true;
  573|  3.81k|            if (setNextStateIfDictionary(key, value, st_stream)) {
  ------------------
  |  Branch (573:17): [True: 3.79k, False: 20]
  ------------------
  574|  3.79k|                this->this_stream_needs_data = false;
  575|  3.79k|                if (tos.object.isStream()) {
  ------------------
  |  Branch (575:21): [True: 60, False: 3.73k]
  ------------------
  576|     60|                    QTC::TC("qpdf", "QPDF_json updating existing stream");
  577|  3.73k|                } else {
  578|  3.73k|                    this->this_stream_needs_data = true;
  579|  3.73k|                    replaceObject(pdf.reserveStream(tos.object.getObjGen()), value);
  580|  3.73k|                }
  581|  3.79k|                next_obj = tos.object;
  582|  3.79k|            } else {
  583|       |                // Error message already given above
  584|     20|                QTC::TC("qpdf", "QPDF_json stream not a dictionary");
  585|     20|            }
  586|  3.81k|        } else {
  587|       |            // Ignore unknown keys for forward compatibility
  588|  1.15k|            QTC::TC("qpdf", "QPDF_json ignore unknown key in object_top");
  589|  1.15k|        }
  590|   110k|    } else if (state == st_trailer) {
  ------------------
  |  Branch (590:16): [True: 440, False: 109k]
  ------------------
  591|    440|        if (key == "value") {
  ------------------
  |  Branch (591:13): [True: 239, False: 201]
  ------------------
  592|    239|            this->saw_value = true;
  593|       |            // The trailer must be a dictionary, so we can use setNextStateIfDictionary.
  594|    239|            if (setNextStateIfDictionary("trailer.value", value, st_object)) {
  ------------------
  |  Branch (594:17): [True: 237, False: 2]
  ------------------
  595|    237|                this->pdf.m->trailer = makeObject(value);
  596|    237|                setObjectDescription(this->pdf.m->trailer, value);
  597|    237|            }
  598|    239|        } else if (key == "stream") {
  ------------------
  |  Branch (598:20): [True: 1, False: 200]
  ------------------
  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|    200|        } else {
  603|       |            // Ignore unknown keys for forward compatibility
  604|    200|            QTC::TC("qpdf", "QPDF_json ignore unknown key in trailer");
  605|    200|        }
  606|   109k|    } else if (state == st_stream) {
  ------------------
  |  Branch (606:16): [True: 6.73k, False: 103k]
  ------------------
  607|  6.73k|        if (stack.empty()) {
  ------------------
  |  Branch (607:13): [True: 0, False: 6.73k]
  ------------------
  608|      0|            throw std::logic_error("stack empty in st_stream");
  609|      0|        }
  610|  6.73k|        auto& tos = stack.back();
  611|  6.73k|        if (!tos.object.isStream()) {
  ------------------
  |  Branch (611:13): [True: 0, False: 6.73k]
  ------------------
  612|      0|            throw std::logic_error("current object is not stream in st_stream");
  613|      0|        }
  614|  6.73k|        auto uninitialized = QPDFObjectHandle();
  615|  6.73k|        if (key == "dict") {
  ------------------
  |  Branch (615:13): [True: 2.78k, False: 3.94k]
  ------------------
  616|  2.78k|            this->saw_dict = true;
  617|  2.78k|            if (setNextStateIfDictionary("stream.dict", value, st_object)) {
  ------------------
  |  Branch (617:17): [True: 2.75k, False: 33]
  ------------------
  618|  2.75k|                tos.object.replaceDict(makeObject(value));
  619|  2.75k|            } else {
  620|       |                // An error had already been given by setNextStateIfDictionary
  621|     33|                QTC::TC("qpdf", "QPDF_json stream dict not dict");
  622|     33|            }
  623|  3.94k|        } else if (key == "data") {
  ------------------
  |  Branch (623:20): [True: 2.97k, False: 971]
  ------------------
  624|  2.97k|            this->saw_data = true;
  625|  2.97k|            std::string v;
  626|  2.97k|            if (!value.getString(v)) {
  ------------------
  |  Branch (626:17): [True: 70, False: 2.90k]
  ------------------
  627|     70|                QTC::TC("qpdf", "QPDF_json stream data not string");
  628|     70|                error(value.getStart(), "\"stream.data\" must be a string");
  629|     70|                tos.object.replaceStreamData("", uninitialized, uninitialized);
  630|  2.90k|            } else {
  631|       |                // The range includes the quotes.
  632|  2.90k|                auto start = value.getStart() + 1;
  633|  2.90k|                auto end = value.getEnd() - 1;
  634|  2.90k|                if (end < start) {
  ------------------
  |  Branch (634:21): [True: 0, False: 2.90k]
  ------------------
  635|      0|                    throw std::logic_error("QPDF_json: JSON string length < 0");
  636|      0|                }
  637|  2.90k|                tos.object.replaceStreamData(
  638|  2.90k|                    provide_data(is, start, end), uninitialized, uninitialized);
  639|  2.90k|            }
  640|  2.97k|        } else if (key == "datafile") {
  ------------------
  |  Branch (640:20): [True: 207, False: 764]
  ------------------
  641|    207|            this->saw_datafile = true;
  642|    207|            std::string filename;
  643|    207|            if (!value.getString(filename)) {
  ------------------
  |  Branch (643:17): [True: 59, False: 148]
  ------------------
  644|     59|                QTC::TC("qpdf", "QPDF_json stream datafile not string");
  645|     59|                error(
  646|     59|                    value.getStart(),
  647|     59|                    "\"stream.datafile\" must be a string containing a file name");
  648|     59|                tos.object.replaceStreamData("", uninitialized, uninitialized);
  649|    148|            } else {
  650|    148|                tos.object.replaceStreamData(
  651|    148|                    QUtil::file_provider(filename), uninitialized, uninitialized);
  652|    148|            }
  653|    764|        } else {
  654|       |            // Ignore unknown keys for forward compatibility.
  655|    764|            QTC::TC("qpdf", "QPDF_json ignore unknown key in stream");
  656|    764|        }
  657|   103k|    } else if (state == st_object) {
  ------------------
  |  Branch (657:16): [True: 103k, False: 0]
  ------------------
  658|   103k|        if (stack.empty()) {
  ------------------
  |  Branch (658:13): [True: 0, False: 103k]
  ------------------
  659|      0|            throw std::logic_error("stack empty in st_object");
  660|      0|        }
  661|   103k|        auto& tos = stack.back();
  662|   103k|        auto dict = tos.object;
  663|   103k|        if (dict.isStream()) {
  ------------------
  |  Branch (663:13): [True: 0, False: 103k]
  ------------------
  664|      0|            dict = dict.getDict();
  665|      0|        }
  666|   103k|        if (!dict.isDictionary()) {
  ------------------
  |  Branch (666:13): [True: 0, False: 103k]
  ------------------
  667|      0|            throw std::logic_error(
  668|      0|                "current object is not stream or dictionary in st_object dictionary item");
  669|      0|        }
  670|   103k|        dict.replaceKey(
  671|   103k|            is_pdf_name(key) ? QPDFObjectHandle::parse(key.substr(2)).getName() : key,
  ------------------
  |  Branch (671:13): [True: 9.95k, False: 93.2k]
  ------------------
  672|   103k|            makeObject(value));
  673|   103k|    } else {
  674|      0|        throw std::logic_error("QPDF_json: unknown state " + std::to_string(state));
  675|      0|    }
  676|   150k|    return true;
  677|   150k|}
_ZN4QPDF11JSONReactor9arrayItemERK4JSON:
  681|  3.00M|{
  682|  3.00M|    if (stack.empty()) {
  ------------------
  |  Branch (682:9): [True: 0, False: 3.00M]
  ------------------
  683|      0|        throw std::logic_error("stack is empty in arrayItem");
  684|      0|    }
  685|  3.00M|    next_state = st_ignore;
  686|  3.00M|    auto state = stack.back().state;
  687|  3.00M|    if (state == st_qpdf) {
  ------------------
  |  Branch (687:9): [True: 24.8k, False: 2.97M]
  ------------------
  688|  24.8k|        if (!this->saw_qpdf_meta) {
  ------------------
  |  Branch (688:13): [True: 4.74k, False: 20.1k]
  ------------------
  689|  4.74k|            this->saw_qpdf_meta = true;
  690|  4.74k|            setNextStateIfDictionary("qpdf[0]", value, st_qpdf_meta);
  691|  20.1k|        } else if (!this->saw_objects) {
  ------------------
  |  Branch (691:20): [True: 4.32k, False: 15.7k]
  ------------------
  692|  4.32k|            this->saw_objects = true;
  693|  4.32k|            setNextStateIfDictionary("qpdf[1]", value, st_objects);
  694|  15.7k|        } else {
  695|  15.7k|            QTC::TC("qpdf", "QPDF_json more than two qpdf elements");
  696|  15.7k|            error(value.getStart(), "\"qpdf\" must have two elements");
  697|  15.7k|        }
  698|  2.97M|    } else if (state == st_object) {
  ------------------
  |  Branch (698:16): [True: 2.97M, False: 7.06k]
  ------------------
  699|  2.97M|        stack.back().object.appendItem(makeObject(value));
  700|  2.97M|    }
  701|  3.00M|    return true;
  702|  3.00M|}
_ZN4QPDF11JSONReactor20setObjectDescriptionER16QPDFObjectHandleRK4JSON:
  706|  2.79M|{
  707|  2.79M|    auto j_descr = std::get<QPDFValue::JSON_Descr>(*descr);
  708|  2.79M|    if (j_descr.object != cur_object) {
  ------------------
  |  Branch (708:9): [True: 10.8k, False: 2.78M]
  ------------------
  709|  10.8k|        descr = std::make_shared<QPDFValue::Description>(
  710|  10.8k|            QPDFValue::JSON_Descr(j_descr.input, cur_object));
  711|  10.8k|    }
  712|       |
  713|  2.79M|    oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart());
  714|  2.79M|}
_ZN4QPDF11JSONReactor10makeObjectERK4JSON:
  718|  3.08M|{
  719|  3.08M|    QPDFObjectHandle result;
  720|  3.08M|    std::string str_v;
  721|  3.08M|    bool bool_v = false;
  722|  3.08M|    if (value.isDictionary()) {
  ------------------
  |  Branch (722:9): [True: 20.8k, False: 3.06M]
  ------------------
  723|  20.8k|        result = QPDFObjectHandle::newDictionary();
  724|  20.8k|        next_obj = result;
  725|  20.8k|        next_state = st_object;
  726|  3.06M|    } else if (value.isArray()) {
  ------------------
  |  Branch (726:16): [True: 19.1k, False: 3.04M]
  ------------------
  727|  19.1k|        result = QPDFObjectHandle::newArray();
  728|  19.1k|        next_obj = result;
  729|  19.1k|        next_state = st_object;
  730|  3.04M|    } else if (value.isNull()) {
  ------------------
  |  Branch (730:16): [True: 218, False: 3.04M]
  ------------------
  731|    218|        result = QPDFObjectHandle::newNull();
  732|  3.04M|    } else if (value.getBool(bool_v)) {
  ------------------
  |  Branch (732:16): [True: 412, False: 3.04M]
  ------------------
  733|    412|        result = QPDFObjectHandle::newBool(bool_v);
  734|  3.04M|    } else if (value.getNumber(str_v)) {
  ------------------
  |  Branch (734:16): [True: 2.68M, False: 360k]
  ------------------
  735|  2.68M|        if (QUtil::is_long_long(str_v.c_str())) {
  ------------------
  |  Branch (735:13): [True: 2.67M, False: 5.23k]
  ------------------
  736|  2.67M|            result = QPDFObjectHandle::newInteger(QUtil::string_to_ll(str_v.c_str()));
  737|  2.67M|        } else {
  738|       |            // JSON allows scientific notation, but PDF does not.
  739|  5.23k|            if (str_v.find('e') != std::string::npos || str_v.find('E') != std::string::npos) {
  ------------------
  |  Branch (739:17): [True: 1.05k, False: 4.17k]
  |  Branch (739:57): [True: 1.07k, False: 3.09k]
  ------------------
  740|  2.13k|                try {
  741|  2.13k|                    auto v = std::stod(str_v);
  742|  2.13k|                    str_v = QUtil::double_to_string(v);
  743|  2.13k|                } catch (std::exception&) {
  744|       |                    // Keep it as it was
  745|    223|                }
  746|  2.13k|            }
  747|  5.23k|            result = QPDFObjectHandle::newReal(str_v);
  748|  5.23k|        }
  749|  2.68M|    } else if (value.getString(str_v)) {
  ------------------
  |  Branch (749:16): [True: 360k, False: 0]
  ------------------
  750|   360k|        int obj = 0;
  751|   360k|        int gen = 0;
  752|   360k|        std::string str;
  753|   360k|        if (is_indirect_object(str_v, obj, gen)) {
  ------------------
  |  Branch (753:13): [True: 294k, False: 65.8k]
  ------------------
  754|   294k|            result = pdf.getObjectForJSON(obj, gen);
  755|   294k|        } else if (is_unicode_string(str_v, str)) {
  ------------------
  |  Branch (755:20): [True: 4.15k, False: 61.6k]
  ------------------
  756|  4.15k|            result = QPDFObjectHandle::newUnicodeString(str);
  757|  61.6k|        } else if (is_binary_string(str_v, str)) {
  ------------------
  |  Branch (757:20): [True: 1.21k, False: 60.4k]
  ------------------
  758|  1.21k|            result = QPDFObjectHandle::newString(QUtil::hex_decode(str));
  759|  60.4k|        } else if (is_name(str_v)) {
  ------------------
  |  Branch (759:20): [True: 22.4k, False: 38.0k]
  ------------------
  760|  22.4k|            result = QPDFObjectHandle::newName(str_v);
  761|  38.0k|        } else if (is_pdf_name(str_v)) {
  ------------------
  |  Branch (761:20): [True: 9.19k, False: 28.8k]
  ------------------
  762|  9.19k|            result = QPDFObjectHandle::parse(str_v.substr(2));
  763|  28.8k|        } else {
  764|  28.8k|            QTC::TC("qpdf", "QPDF_json unrecognized string value");
  765|  28.8k|            error(value.getStart(), "unrecognized string value");
  766|  28.8k|            result = QPDFObjectHandle::newNull();
  767|  28.8k|        }
  768|   360k|    }
  769|  3.08M|    if (!result.isInitialized()) {
  ------------------
  |  Branch (769:9): [True: 0, False: 3.08M]
  ------------------
  770|      0|        throw std::logic_error("JSONReactor::makeObject didn't initialize the object");
  771|      0|    }
  772|       |
  773|  3.08M|    if (!result.hasObjectDescription()) {
  ------------------
  |  Branch (773:9): [True: 2.78M, False: 303k]
  ------------------
  774|  2.78M|        setObjectDescription(result, value);
  775|  2.78M|    }
  776|  3.08M|    return result;
  777|  3.08M|}
_ZN4QPDF14createFromJSONENSt3__110shared_ptrI11InputSourceEE:
  787|  6.73k|{
  788|  6.73k|    processMemoryFile(is->getName().c_str(), JSON_PDF, strlen(JSON_PDF));
  789|  6.73k|    importJSON(is, true);
  790|  6.73k|}
_ZN4QPDF10importJSONENSt3__110shared_ptrI11InputSourceEEb:
  806|  6.73k|{
  807|  6.73k|    JSONReactor reactor(*this, is, must_be_complete);
  808|  6.73k|    try {
  809|  6.73k|        JSON::parse(*is, &reactor);
  810|  6.73k|    } catch (std::runtime_error& e) {
  811|  6.67k|        throw std::runtime_error(is->getName() + ": " + e.what());
  812|  6.67k|    }
  813|     53|    if (reactor.anyErrors()) {
  ------------------
  |  Branch (813:9): [True: 44, False: 9]
  ------------------
  814|     44|        throw std::runtime_error(is->getName() + ": errors found in JSON");
  815|     44|    }
  816|     53|}
QPDF_json.cc:_ZL18is_indirect_objectRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERiS8_:
   68|   372k|{
   69|   372k|    char const* p = v.c_str();
   70|   372k|    std::string o_str;
   71|   372k|    std::string g_str;
   72|   372k|    if (!QUtil::is_digit(*p)) {
  ------------------
  |  Branch (72:9): [True: 53.5k, False: 319k]
  ------------------
   73|  53.5k|        return false;
   74|  53.5k|    }
   75|  3.28M|    while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (75:12): [True: 2.96M, False: 319k]
  ------------------
   76|  2.96M|        o_str.append(1, *p++);
   77|  2.96M|    }
   78|   319k|    if (*p != ' ') {
  ------------------
  |  Branch (78:9): [True: 9.76k, False: 309k]
  ------------------
   79|  9.76k|        return false;
   80|  9.76k|    }
   81|   619k|    while (*p == ' ') {
  ------------------
  |  Branch (81:12): [True: 310k, False: 309k]
  ------------------
   82|   310k|        ++p;
   83|   310k|    }
   84|   309k|    if (!QUtil::is_digit(*p)) {
  ------------------
  |  Branch (84:9): [True: 986, False: 308k]
  ------------------
   85|    986|        return false;
   86|    986|    }
   87|  16.0M|    while (QUtil::is_digit(*p)) {
  ------------------
  |  Branch (87:12): [True: 15.7M, False: 308k]
  ------------------
   88|  15.7M|        g_str.append(1, *p++);
   89|  15.7M|    }
   90|   308k|    if (*p != ' ') {
  ------------------
  |  Branch (90:9): [True: 934, False: 307k]
  ------------------
   91|    934|        return false;
   92|    934|    }
   93|   615k|    while (*p == ' ') {
  ------------------
  |  Branch (93:12): [True: 307k, False: 307k]
  ------------------
   94|   307k|        ++p;
   95|   307k|    }
   96|   307k|    if (*p++ != 'R') {
  ------------------
  |  Branch (96:9): [True: 486, False: 306k]
  ------------------
   97|    486|        return false;
   98|    486|    }
   99|   306k|    if (*p) {
  ------------------
  |  Branch (99:9): [True: 520, False: 306k]
  ------------------
  100|    520|        return false;
  101|    520|    }
  102|   306k|    obj = QUtil::string_to_int(o_str.c_str());
  103|   306k|    gen = QUtil::string_to_int(g_str.c_str());
  104|   306k|    return obj > 0;
  105|   306k|}
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: 1.08k, False: 12.1k]
  ------------------
  111|  1.08k|        return false;
  112|  1.08k|    }
  113|  12.1k|    return is_indirect_object(v.substr(4), obj, gen);
  114|  13.2k|}
QPDF_json.cc:_ZL17is_unicode_stringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERS5_:
  118|  65.8k|{
  119|  65.8k|    if (v.substr(0, 2) == "u:") {
  ------------------
  |  Branch (119:9): [True: 4.15k, False: 61.6k]
  ------------------
  120|  4.15k|        str = v.substr(2);
  121|  4.15k|        return true;
  122|  4.15k|    }
  123|  61.6k|    return false;
  124|  65.8k|}
QPDF_json.cc:_ZL16is_binary_stringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERS5_:
  128|  61.6k|{
  129|  61.6k|    if (v.substr(0, 2) == "b:") {
  ------------------
  |  Branch (129:9): [True: 3.07k, False: 58.6k]
  ------------------
  130|  3.07k|        str = v.substr(2);
  131|  3.07k|        int count = 0;
  132|  2.12M|        for (char c: str) {
  ------------------
  |  Branch (132:20): [True: 2.12M, False: 1.52k]
  ------------------
  133|  2.12M|            if (!QUtil::is_hex_digit(c)) {
  ------------------
  |  Branch (133:17): [True: 1.54k, False: 2.12M]
  ------------------
  134|  1.54k|                return false;
  135|  1.54k|            }
  136|  2.12M|            ++count;
  137|  2.12M|        }
  138|  1.52k|        return (count % 2 == 0);
  139|  3.07k|    }
  140|  58.6k|    return false;
  141|  61.6k|}
QPDF_json.cc:_ZL7is_nameRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
  145|  60.4k|{
  146|  60.4k|    return ((v.length() > 1) && (v.at(0) == '/'));
  ------------------
  |  Branch (146:13): [True: 44.1k, False: 16.3k]
  |  Branch (146:33): [True: 22.4k, False: 21.6k]
  ------------------
  147|  60.4k|}
QPDF_json.cc:_ZL12provide_dataNSt3__110shared_ptrI11InputSourceEExx:
  214|  2.90k|{
  215|  2.90k|    return [is, start, end](Pipeline* p) {
  216|  2.90k|        Pl_Base64 decode("base64-decode", p, Pl_Base64::a_decode);
  217|  2.90k|        p = &decode;
  218|  2.90k|        size_t bytes = QIntC::to_size(end - start);
  219|  2.90k|        char buf[8192];
  220|  2.90k|        is->seek(start, SEEK_SET);
  221|  2.90k|        size_t len = 0;
  222|  2.90k|        while ((len = is->read(buf, std::min(bytes, sizeof(buf)))) > 0) {
  223|  2.90k|            p->write(buf, len);
  224|  2.90k|            bytes -= len;
  225|  2.90k|            if (bytes == 0) {
  226|  2.90k|                break;
  227|  2.90k|            }
  228|  2.90k|        }
  229|  2.90k|        decode.finish();
  230|  2.90k|    };
  231|  2.90k|}
QPDF_json.cc:_ZL11is_pdf_nameRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
  151|   141k|{
  152|   141k|    return ((v.length() > 3) && (v.substr(0, 3) == "n:/"));
  ------------------
  |  Branch (152:13): [True: 60.6k, False: 80.5k]
  |  Branch (152:33): [True: 19.1k, False: 41.5k]
  ------------------
  153|   141k|}
_ZN4QPDF11JSONReactorC2ERS_NSt3__110shared_ptrI11InputSourceEEb:
  242|  6.73k|    {
  243|  6.73k|    }
_ZN4QPDF11JSONReactorD2Ev:
  244|  6.73k|    ~JSONReactor() override = default;
_ZN4QPDF11JSONReactor10StackFrameC2ENS0_7state_eEO16QPDFObjectHandle:
  273|  55.3k|            object(object) {};
_ZN4QPDF11JSONReactor10StackFrameC2ENS0_7state_eE:
  270|  24.8k|            state(state) {};

_ZN5QUtil13int_to_stringExi:
  326|  2.68M|{
  327|  2.68M|    return int_to_string_base(num, 10, length);
  328|  2.68M|}
_ZN5QUtil18int_to_string_baseExii:
  338|  2.68M|{
  339|  2.68M|    return int_to_string_base_internal(num, base, length);
  340|  2.68M|}
_ZN5QUtil16double_to_stringEdib:
  350|  1.91k|{
  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|  1.91k|    if (decimal_places <= 0) {
  ------------------
  |  Branch (354:9): [True: 1.91k, False: 0]
  ------------------
  355|  1.91k|        decimal_places = 6;
  356|  1.91k|    }
  357|  1.91k|    std::ostringstream buf;
  358|  1.91k|    buf.imbue(std::locale::classic());
  359|  1.91k|    buf << std::setprecision(decimal_places) << std::fixed << num;
  360|  1.91k|    std::string result = buf.str();
  361|  1.91k|    if (trim_trailing_zeroes) {
  ------------------
  |  Branch (361:9): [True: 1.91k, False: 0]
  ------------------
  362|  12.2k|        while ((result.length() > 1) && (result.back() == '0')) {
  ------------------
  |  Branch (362:16): [True: 12.2k, False: 0]
  |  Branch (362:41): [True: 10.3k, False: 1.91k]
  ------------------
  363|  10.3k|            result.pop_back();
  364|  10.3k|        }
  365|  1.91k|        if ((result.length() > 1) && (result.back() == '.')) {
  ------------------
  |  Branch (365:13): [True: 1.91k, False: 0]
  |  Branch (365:38): [True: 1.65k, False: 254]
  ------------------
  366|  1.65k|            result.pop_back();
  367|  1.65k|        }
  368|  1.91k|    }
  369|  1.91k|    return result;
  370|  1.91k|}
_ZN5QUtil12string_to_llEPKc:
  374|  6.00M|{
  375|  6.00M|    errno = 0;
  376|       |#ifdef _MSC_VER
  377|       |    long long result = _strtoi64(str, 0, 10);
  378|       |#else
  379|  6.00M|    long long result = strtoll(str, nullptr, 10);
  380|  6.00M|#endif
  381|  6.00M|    if (errno == ERANGE) {
  ------------------
  |  Branch (381:9): [True: 2.57k, False: 5.99M]
  ------------------
  382|  2.57k|        throw std::range_error(
  383|  2.57k|            std::string("overflow/underflow converting ") + str + " to 64-bit integer");
  384|  2.57k|    }
  385|  5.99M|    return result;
  386|  6.00M|}
_ZN5QUtil13string_to_intEPKc:
  390|   626k|{
  391|       |    // QIntC::to_int does range checking
  392|   626k|    return QIntC::to_int(string_to_ll(str));
  393|   626k|}
_ZN5QUtil12is_long_longEPKc:
  429|  2.68M|{
  430|  2.68M|    try {
  431|  2.68M|        auto i1 = string_to_ll(str);
  432|  2.68M|        std::string s1 = int_to_string(i1);
  433|  2.68M|        return str == s1;
  434|  2.68M|    } catch (std::exception&) {
  435|       |        // overflow or other error
  436|  2.56k|    }
  437|  2.56k|    return false;
  438|  2.68M|}
_ZN5QUtil21unsigned_char_pointerEPKc:
  448|  6.73k|{
  449|  6.73k|    return reinterpret_cast<unsigned char*>(const_cast<char*>(str));
  450|  6.73k|}
_ZN5QUtil13file_providerERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  661|    148|{
  662|    148|    return [filename](Pipeline* p) { pipe_file(filename.c_str(), p); };
  663|    148|}
_ZN5QUtil10hex_decodeERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  735|  1.21k|{
  736|  1.21k|    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.21k|    bool first = true;
  740|  1.21k|    char decoded;
  741|  2.03M|    for (auto ch: input) {
  ------------------
  |  Branch (741:17): [True: 2.03M, False: 1.21k]
  ------------------
  742|  2.03M|        ch = hex_decode_char(ch);
  743|  2.03M|        if (ch < '\20') {
  ------------------
  |  Branch (743:13): [True: 2.03M, False: 0]
  ------------------
  744|  2.03M|            if (first) {
  ------------------
  |  Branch (744:17): [True: 1.01M, False: 1.01M]
  ------------------
  745|  1.01M|                decoded = static_cast<char>(ch << 4);
  746|  1.01M|                first = false;
  747|  1.01M|            } else {
  748|  1.01M|                result.push_back(decoded | ch);
  749|  1.01M|                first = true;
  750|  1.01M|            }
  751|  2.03M|        }
  752|  2.03M|    }
  753|  1.21k|    if (!first) {
  ------------------
  |  Branch (753:9): [True: 0, False: 1.21k]
  ------------------
  754|      0|        result.push_back(decoded);
  755|      0|    }
  756|  1.21k|    return result;
  757|  1.21k|}
_ZN5QUtil6toUTF8Em:
  998|  2.62k|{
  999|  2.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|  2.62k|    if (uval > 0x7fffffff) {
  ------------------
  |  Branch (1008:9): [True: 0, False: 2.62k]
  ------------------
 1009|      0|        throw std::runtime_error("bounds error in QUtil::toUTF8");
 1010|  2.62k|    } else if (uval < 128) {
  ------------------
  |  Branch (1010:16): [True: 1.69k, False: 929]
  ------------------
 1011|  1.69k|        result += static_cast<char>(uval);
 1012|  1.69k|    } else {
 1013|    929|        unsigned char bytes[7];
 1014|    929|        bytes[6] = '\0';
 1015|    929|        unsigned char* cur_byte = &bytes[5];
 1016|       |
 1017|       |        // maximum value that will fit in the current number of bytes
 1018|    929|        unsigned char maxval = 0x3f; // six bits
 1019|       |
 1020|  3.42k|        while (uval > QIntC::to_ulong(maxval)) {
  ------------------
  |  Branch (1020:16): [True: 2.49k, False: 929]
  ------------------
 1021|       |            // Assign low six bits plus 10000000 to lowest unused byte position, then shift
 1022|  2.49k|            *cur_byte = static_cast<unsigned char>(0x80 + (uval & 0x3f));
 1023|  2.49k|            uval >>= 6;
 1024|       |            // Maximum that will fit in high byte now shrinks by one bit
 1025|  2.49k|            maxval = static_cast<unsigned char>(maxval >> 1);
 1026|       |            // Slide to the left one byte
 1027|  2.49k|            if (cur_byte <= bytes) {
  ------------------
  |  Branch (1027:17): [True: 0, False: 2.49k]
  ------------------
 1028|      0|                throw std::logic_error("QUtil::toUTF8: overflow error");
 1029|      0|            }
 1030|  2.49k|            --cur_byte;
 1031|  2.49k|        }
 1032|       |        // If maxval is k bits long, the high (7 - k) bits of the resulting byte must be high.
 1033|    929|        *cur_byte = static_cast<unsigned char>(QIntC::to_ulong(0xff - (1 + (maxval << 1))) + uval);
 1034|       |
 1035|    929|        result += reinterpret_cast<char*>(cur_byte);
 1036|    929|    }
 1037|       |
 1038|  2.62k|    return result;
 1039|  2.62k|}
_ZN5QUtil7toUTF16Em:
 1043|  7.63M|{
 1044|  7.63M|    std::string result;
 1045|  7.63M|    if ((uval >= 0xd800) && (uval <= 0xdfff)) {
  ------------------
  |  Branch (1045:9): [True: 4.35k, False: 7.63M]
  |  Branch (1045:29): [True: 303, False: 4.05k]
  ------------------
 1046|    303|        result = "\xff\xfd";
 1047|  7.63M|    } else if (uval <= 0xffff) {
  ------------------
  |  Branch (1047:16): [True: 7.63M, False: 3.83k]
  ------------------
 1048|  7.63M|        char out[2];
 1049|  7.63M|        out[0] = static_cast<char>((uval & 0xff00) >> 8);
 1050|  7.63M|        out[1] = static_cast<char>(uval & 0xff);
 1051|  7.63M|        result = std::string(out, 2);
 1052|  7.63M|    } else if (uval <= 0x10ffff) {
  ------------------
  |  Branch (1052:16): [True: 1.79k, False: 2.03k]
  ------------------
 1053|  1.79k|        char out[4];
 1054|  1.79k|        uval -= 0x10000;
 1055|  1.79k|        unsigned short high = static_cast<unsigned short>(((uval & 0xffc00) >> 10) + 0xd800);
 1056|  1.79k|        unsigned short low = static_cast<unsigned short>((uval & 0x3ff) + 0xdc00);
 1057|  1.79k|        out[0] = static_cast<char>((high & 0xff00) >> 8);
 1058|  1.79k|        out[1] = static_cast<char>(high & 0xff);
 1059|  1.79k|        out[2] = static_cast<char>((low & 0xff00) >> 8);
 1060|  1.79k|        out[3] = static_cast<char>(low & 0xff);
 1061|  1.79k|        result = std::string(out, 4);
 1062|  2.03k|    } else {
 1063|  2.03k|        result = "\xff\xfd";
 1064|  2.03k|    }
 1065|       |
 1066|  7.63M|    return result;
 1067|  7.63M|}
_ZN5QUtil23get_next_utf8_codepointERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERmRb:
 1465|  16.7M|{
 1466|  16.7M|    auto o_pos = pos;
 1467|  16.7M|    size_t len = utf8_val.length();
 1468|  16.7M|    unsigned char ch = static_cast<unsigned char>(utf8_val.at(pos++));
 1469|  16.7M|    error = false;
 1470|  16.7M|    if (ch < 128) {
  ------------------
  |  Branch (1470:9): [True: 15.2M, False: 1.51M]
  ------------------
 1471|  15.2M|        return static_cast<unsigned long>(ch);
 1472|  15.2M|    }
 1473|       |
 1474|  1.51M|    size_t bytes_needed = 0;
 1475|  1.51M|    unsigned bit_check = 0x40;
 1476|  1.51M|    unsigned char to_clear = 0x80;
 1477|  4.24M|    while (ch & bit_check) {
  ------------------
  |  Branch (1477:12): [True: 2.73M, False: 1.51M]
  ------------------
 1478|  2.73M|        ++bytes_needed;
 1479|  2.73M|        to_clear = static_cast<unsigned char>(to_clear | bit_check);
 1480|  2.73M|        bit_check >>= 1;
 1481|  2.73M|    }
 1482|  1.51M|    if (((bytes_needed > 5) || (bytes_needed < 1)) || ((pos + bytes_needed) > len)) {
  ------------------
  |  Branch (1482:10): [True: 293k, False: 1.21M]
  |  Branch (1482:32): [True: 908k, False: 308k]
  |  Branch (1482:55): [True: 862, False: 307k]
  ------------------
 1483|  1.20M|        error = true;
 1484|  1.20M|        return 0xfffd;
 1485|  1.20M|    }
 1486|       |
 1487|   307k|    auto codepoint = static_cast<unsigned long>(ch & ~to_clear);
 1488|   366k|    while (bytes_needed > 0) {
  ------------------
  |  Branch (1488:12): [True: 338k, False: 27.4k]
  ------------------
 1489|   338k|        --bytes_needed;
 1490|   338k|        ch = static_cast<unsigned char>(utf8_val.at(pos++));
 1491|   338k|        if ((ch & 0xc0) != 0x80) {
  ------------------
  |  Branch (1491:13): [True: 280k, False: 58.4k]
  ------------------
 1492|   280k|            --pos;
 1493|   280k|            error = true;
 1494|   280k|            return 0xfffd;
 1495|   280k|        }
 1496|  58.4k|        codepoint <<= 6;
 1497|  58.4k|        codepoint += (ch & 0x3f);
 1498|  58.4k|    }
 1499|  27.4k|    unsigned long lower_bound = 0;
 1500|  27.4k|    switch (pos - o_pos) {
 1501|  17.5k|    case 2:
  ------------------
  |  Branch (1501:5): [True: 17.5k, False: 9.93k]
  ------------------
 1502|  17.5k|        lower_bound = 1 << 7;
 1503|  17.5k|        break;
 1504|  2.26k|    case 3:
  ------------------
  |  Branch (1504:5): [True: 2.26k, False: 25.2k]
  ------------------
 1505|  2.26k|        lower_bound = 1 << 11;
 1506|  2.26k|        break;
 1507|  4.31k|    case 4:
  ------------------
  |  Branch (1507:5): [True: 4.31k, False: 23.1k]
  ------------------
 1508|  4.31k|        lower_bound = 1 << 16;
 1509|  4.31k|        break;
 1510|  2.45k|    case 5:
  ------------------
  |  Branch (1510:5): [True: 2.45k, False: 25.0k]
  ------------------
 1511|  2.45k|        lower_bound = 1 << 12;
 1512|  2.45k|        break;
 1513|    904|    case 6:
  ------------------
  |  Branch (1513:5): [True: 904, False: 26.5k]
  ------------------
 1514|    904|        lower_bound = 1 << 26;
 1515|    904|        break;
 1516|      0|    default:
  ------------------
  |  Branch (1516:5): [True: 0, False: 27.4k]
  ------------------
 1517|      0|        lower_bound = 0;
 1518|  27.4k|    }
 1519|       |
 1520|  27.4k|    if (lower_bound > 0 && codepoint < lower_bound) {
  ------------------
  |  Branch (1520:9): [True: 27.4k, False: 0]
  |  Branch (1520:28): [True: 3.87k, False: 23.6k]
  ------------------
 1521|       |        // Too many bytes were used, but return whatever character was encoded.
 1522|  3.87k|        error = true;
 1523|  3.87k|    }
 1524|  27.4k|    return codepoint;
 1525|  27.4k|}
_ZN5QUtil13utf8_to_utf16ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
 1623|  2.70k|{
 1624|  2.70k|    return transcode_utf8(utf8, e_utf16, 0);
 1625|  2.70k|}
_ZN5QUtil15utf8_to_pdf_docERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERS6_c:
 1671|  4.15k|{
 1672|  4.15k|    return transcode_utf8(utf8, pdfdoc, e_pdfdoc, unknown_char);
 1673|  4.15k|}
QUtil.cc:_ZL14transcode_utf8RKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE10encoding_ec:
 1615|  2.70k|{
 1616|  2.70k|    std::string result;
 1617|  2.70k|    transcode_utf8(utf8_val, result, encoding, unknown);
 1618|  2.70k|    return result;
 1619|  2.70k|}
QUtil.cc:_ZL14transcode_utf8RKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERS5_10encoding_ec:
 1529|  6.86k|{
 1530|  6.86k|    bool okay = true;
 1531|  6.86k|    result.clear();
 1532|  6.86k|    size_t len = utf8_val.length();
 1533|  6.86k|    switch (encoding) {
 1534|  2.70k|    case e_utf16:
  ------------------
  |  Branch (1534:5): [True: 2.70k, False: 4.15k]
  ------------------
 1535|  2.70k|        result += "\xfe\xff";
 1536|  2.70k|        break;
 1537|  4.15k|    case e_pdfdoc:
  ------------------
  |  Branch (1537:5): [True: 4.15k, False: 2.70k]
  ------------------
 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|  4.15k|        if ((len >= 4) && (utf8_val[0] == '\xc3')) {
  ------------------
  |  Branch (1544:13): [True: 3.01k, False: 1.14k]
  |  Branch (1544:27): [True: 1.71k, False: 1.29k]
  ------------------
 1545|  1.71k|            static std::string fe_ff("\xbe\xc3\xbf");
 1546|  1.71k|            static std::string ff_fe("\xbf\xc3\xbe");
 1547|  1.71k|            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|  1.71k|            if ((utf8_val.compare(1, 3, fe_ff) == 0) || (utf8_val.compare(1, 3, ff_fe) == 0) ||
  ------------------
  |  Branch (1550:17): [True: 194, False: 1.52k]
  |  Branch (1550:57): [True: 230, False: 1.29k]
  ------------------
 1551|  1.71k|                (utf8_val.compare(1, 5, ef_bb_bf) == 0)) {
  ------------------
  |  Branch (1551:17): [True: 200, False: 1.09k]
  ------------------
 1552|    624|                result += unknown;
 1553|    624|                okay = false;
 1554|    624|            }
 1555|  1.71k|        }
 1556|  4.15k|        break;
 1557|      0|    default:
  ------------------
  |  Branch (1557:5): [True: 0, False: 6.86k]
  ------------------
 1558|      0|        break;
 1559|  6.86k|    }
 1560|  6.86k|    size_t pos = 0;
 1561|  16.7M|    while (pos < len) {
  ------------------
  |  Branch (1561:12): [True: 16.7M, False: 6.86k]
  ------------------
 1562|  16.7M|        bool error = false;
 1563|  16.7M|        unsigned long codepoint = QUtil::get_next_utf8_codepoint(utf8_val, pos, error);
 1564|  16.7M|        if (error) {
  ------------------
  |  Branch (1564:13): [True: 1.48M, False: 15.2M]
  ------------------
 1565|  1.48M|            okay = false;
 1566|  1.48M|            if (encoding == e_utf16) {
  ------------------
  |  Branch (1566:17): [True: 743k, False: 743k]
  ------------------
 1567|   743k|                result += "\xff\xfd";
 1568|   743k|            } else {
 1569|   743k|                result.append(1, unknown);
 1570|   743k|            }
 1571|  15.2M|        } else if (codepoint < 128) {
  ------------------
  |  Branch (1571:20): [True: 15.2M, False: 23.6k]
  ------------------
 1572|  15.2M|            char ch = static_cast<char>(codepoint);
 1573|  15.2M|            if (encoding == e_utf16) {
  ------------------
  |  Branch (1573:17): [True: 7.62M, False: 7.62M]
  ------------------
 1574|  7.62M|                result += QUtil::toUTF16(QIntC::to_ulong(ch));
 1575|  7.62M|            } else if ((encoding == e_pdfdoc) && (((ch >= 0x18) && (ch <= 0x1f)) || (ch == 127))) {
  ------------------
  |  Branch (1575:24): [True: 7.62M, False: 0]
  |  Branch (1575:52): [True: 7.62M, False: 198]
  |  Branch (1575:68): [True: 195, False: 7.62M]
  |  Branch (1575:85): [True: 1.02k, False: 7.62M]
  ------------------
 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|  1.22k|                okay = false;
 1580|  1.22k|                result.append(1, unknown);
 1581|  7.62M|            } else {
 1582|  7.62M|                result.append(1, ch);
 1583|  7.62M|            }
 1584|  15.2M|        } else if (encoding == e_utf16) {
  ------------------
  |  Branch (1584:20): [True: 11.0k, False: 12.5k]
  ------------------
 1585|  11.0k|            result += QUtil::toUTF16(codepoint);
 1586|  12.5k|        } else if ((codepoint == 0xad) && (encoding == e_pdfdoc)) {
  ------------------
  |  Branch (1586:20): [True: 209, False: 12.3k]
  |  Branch (1586:43): [True: 209, False: 0]
  ------------------
 1587|       |            // PDFDocEncoding omits 0x00ad (soft hyphen).
 1588|    209|            okay = false;
 1589|    209|            result.append(1, unknown);
 1590|  12.3k|        } else if (
 1591|  12.3k|            (codepoint > 160) && (codepoint < 256) &&
  ------------------
  |  Branch (1591:13): [True: 12.0k, False: 250]
  |  Branch (1591:34): [True: 5.54k, False: 6.52k]
  ------------------
 1592|  12.3k|            ((encoding == e_winansi) || (encoding == e_pdfdoc))) {
  ------------------
  |  Branch (1592:14): [True: 0, False: 5.54k]
  |  Branch (1592:41): [True: 5.54k, False: 0]
  ------------------
 1593|  5.54k|            result.append(1, static_cast<char>(codepoint & 0xff));
 1594|  6.77k|        } else {
 1595|  6.77k|            unsigned char ch = '\0';
 1596|  6.77k|            if (encoding == e_winansi) {
  ------------------
  |  Branch (1596:17): [True: 0, False: 6.77k]
  ------------------
 1597|      0|                ch = encode_winansi(codepoint);
 1598|  6.77k|            } else if (encoding == e_macroman) {
  ------------------
  |  Branch (1598:24): [True: 0, False: 6.77k]
  ------------------
 1599|      0|                ch = encode_macroman(codepoint);
 1600|  6.77k|            } else if (encoding == e_pdfdoc) {
  ------------------
  |  Branch (1600:24): [True: 6.77k, False: 0]
  ------------------
 1601|  6.77k|                ch = encode_pdfdoc(codepoint);
 1602|  6.77k|            }
 1603|  6.77k|            if (ch == '\0') {
  ------------------
  |  Branch (1603:17): [True: 6.09k, False: 679]
  ------------------
 1604|  6.09k|                okay = false;
 1605|  6.09k|                ch = static_cast<unsigned char>(unknown);
 1606|  6.09k|            }
 1607|  6.77k|            result.append(1, static_cast<char>(ch));
 1608|  6.77k|        }
 1609|  16.7M|    }
 1610|  6.86k|    return okay;
 1611|  6.86k|}
QUtil.cc:_ZL13encode_pdfdocm:
 1455|  6.77k|{
 1456|  6.77k|    auto i = unicode_to_pdf_doc.find(codepoint);
 1457|  6.77k|    if (i != unicode_to_pdf_doc.end()) {
  ------------------
  |  Branch (1457:9): [True: 679, False: 6.09k]
  ------------------
 1458|    679|        return i->second;
 1459|    679|    }
 1460|  6.09k|    return '\0';
 1461|  6.77k|}
QUtil.cc:_ZL27int_to_string_base_internalIxENSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEET_ii:
  295|  2.68M|{
  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.68M|    if (!((base == 8) || (base == 10) || (base == 16))) {
  ------------------
  |  Branch (299:11): [True: 0, False: 2.68M]
  |  Branch (299:26): [True: 2.68M, 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.68M|    std::string cvt;
  303|  2.68M|    if (base == 10) {
  ------------------
  |  Branch (303:9): [True: 2.68M, False: 0]
  ------------------
  304|       |        // Use the more efficient std::to_string when possible
  305|  2.68M|        cvt = std::to_string(num);
  306|  2.68M|    } 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.68M|    std::string result;
  313|  2.68M|    int str_length = QIntC::to_int(cvt.length());
  314|  2.68M|    if ((length > 0) && (str_length < length)) {
  ------------------
  |  Branch (314:9): [True: 0, False: 2.68M]
  |  Branch (314:25): [True: 0, False: 0]
  ------------------
  315|      0|        result.append(QIntC::to_size(length - str_length), '0');
  316|      0|    }
  317|  2.68M|    result += cvt;
  318|  2.68M|    if ((length < 0) && (str_length < -length)) {
  ------------------
  |  Branch (318:9): [True: 0, False: 2.68M]
  |  Branch (318:25): [True: 0, False: 0]
  ------------------
  319|      0|        result.append(QIntC::to_size(-length - str_length), ' ');
  320|      0|    }
  321|  2.68M|    return result;
  322|  2.68M|}

_ZN10QPDFObject10disconnectEv:
  148|  2.83M|    {
  149|       |        // Disconnect an object from its owning QPDF. This is called by QPDF's destructor.
  150|  2.83M|        value->disconnect();
  151|  2.83M|        value->qpdf = nullptr;
  152|  2.83M|        value->og = QPDFObjGen();
  153|  2.83M|    }
_ZNK10QPDFObject11getTypeCodeEv:
   58|  16.1k|    {
   59|  16.1k|        return value->type_code;
   60|  16.1k|    }
_ZN10QPDFObject9setObjGenEP4QPDFRK10QPDFObjGen:
  142|  10.7k|    {
  143|  10.7k|        value->qpdf = qpdf;
  144|  10.7k|        value->og = og;
  145|  10.7k|    }
_ZN10QPDFObject6assignENSt3__110shared_ptrIS_EE:
  120|  10.7k|    {
  121|  10.7k|        value = o->value;
  122|  10.7k|    }
_ZNK10QPDFObject2asI11QPDF_StreamEEPT_v:
  171|  5.93k|    {
  172|  5.93k|        if (auto result = dynamic_cast<T*>(value.get())) {
  ------------------
  |  Branch (172:18): [True: 5.93k, False: 0]
  ------------------
  173|  5.93k|            return result;
  174|  5.93k|        } 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|  5.93k|    }
_ZNK10QPDFObject14getStringValueEv:
   43|  9.93k|    {
   44|  9.93k|        return value->getStringValue();
   45|  9.93k|    }
_ZNK10QPDFObject19getResolvedTypeCodeEv:
   49|   360k|    {
   50|   360k|        auto tc = value->type_code;
   51|   360k|        return tc == ::ot_unresolved
  ------------------
  |  Branch (51:16): [True: 0, False: 360k]
  ------------------
   52|   360k|            ? QPDF::Resolver::resolved(value->qpdf, value->og)->value->type_code
   53|   360k|            : tc;
   54|   360k|    }
_ZNK10QPDFObject7getQPDFEv:
   64|  3.17M|    {
   65|  3.17M|        return value->qpdf;
   66|  3.17M|    }
_ZNK10QPDFObject9getObjGenEv:
   69|  3.11M|    {
   70|  3.11M|        return value->og;
   71|  3.11M|    }
_ZN10QPDFObject14setDescriptionEP4QPDFRNSt3__110shared_ptrINS2_7variantIJNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEN9QPDFValue10JSON_DescrENSB_10ChildDescrEEEEEEx:
   75|  2.82M|    {
   76|  2.82M|        return value->setDescription(qpdf, description, offset);
   77|  2.82M|    }
_ZN10QPDFObject14hasDescriptionEv:
  105|  3.09M|    {
  106|  3.09M|        return value->hasDescription();
  107|  3.09M|    }
_ZN10QPDFObject15getParsedOffsetEv:
  115|     85|    {
  116|     85|        return value->getParsedOffset();
  117|     85|    }
_ZNK10QPDFObject2asI10QPDF_ArrayEEPT_v:
  171|  2.97M|    {
  172|  2.97M|        if (auto result = dynamic_cast<T*>(value.get())) {
  ------------------
  |  Branch (172:18): [True: 2.97M, False: 0]
  ------------------
  173|  2.97M|            return result;
  174|  2.97M|        } 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.97M|    }
_ZNK10QPDFObject2asI15QPDF_DictionaryEEPT_v:
  171|   146k|    {
  172|   146k|        if (auto result = dynamic_cast<T*>(value.get())) {
  ------------------
  |  Branch (172:18): [True: 146k, False: 0]
  ------------------
  173|   146k|            return result;
  174|   146k|        } 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|   146k|    }
_ZNK10QPDFObject2asI12QPDF_IntegerEEPT_v:
  171|  6.73k|    {
  172|  6.73k|        if (auto result = dynamic_cast<T*>(value.get())) {
  ------------------
  |  Branch (172:18): [True: 6.73k, False: 0]
  ------------------
  173|  6.73k|            return result;
  174|  6.73k|        } 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.73k|    }
_ZN10QPDFObjectC2Ev:
   24|  2.83M|    QPDFObject() = default;

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

_ZN9QPDFValue15getParsedOffsetEv:
   99|     85|    {
  100|     85|        return parsed_offset;
  101|     85|    }
_ZN9QPDFValue10JSON_DescrC2ENSt3__110shared_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEERKS8_:
   34|  17.5k|        {
   35|  17.5k|        }
_ZN9QPDFValue14setDescriptionEP4QPDFRNSt3__110shared_ptrINS2_7variantIJNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS_10JSON_DescrENS_10ChildDescrEEEEEEx:
   62|  2.83M|    {
   63|  2.83M|        qpdf = qpdf_p;
   64|  2.83M|        object_description = description;
   65|  2.83M|        setParsedOffset(offset);
   66|  2.83M|    }
_ZN9QPDFValue14hasDescriptionEv:
   87|  3.09M|    {
   88|  3.09M|        return object_description || og.isIndirect();
  ------------------
  |  Branch (88:16): [True: 59.2k, False: 3.03M]
  |  Branch (88:38): [True: 250k, False: 2.78M]
  ------------------
   89|  3.09M|    }
_ZN9QPDFValue15setParsedOffsetEx:
   92|  2.83M|    {
   93|  2.83M|        if (parsed_offset < 0) {
  ------------------
  |  Branch (93:13): [True: 2.82M, False: 10.9k]
  ------------------
   94|  2.82M|            parsed_offset = offset;
   95|  2.82M|        }
   96|  2.83M|    }
_ZN9QPDFValue10disconnectEv:
  114|  2.79M|    {
  115|  2.79M|    }
_ZN9QPDFValueC2E18qpdf_object_type_e:
  127|  2.79M|    {
  128|  2.79M|    }
_ZN9QPDFValueC2E18qpdf_object_type_eP4QPDF10QPDFObjGen:
  133|  45.1k|    {
  134|  45.1k|    }
_ZN9QPDFValueD2Ev:
   23|  2.83M|    virtual ~QPDFValue() = default;

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

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

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

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

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

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

