Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright 2014 BitPay Inc.2// Copyright (c) 2015-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or https://opensource.org/licenses/mit-license.php.6#include <univalue.h>7#include <univalue_utffilter.h>9#include <cstdint>10#include <cstring>11#include <string>12#include <string_view>13#include <utility>14#include <vector>16/*17* According to stackexchange, the original json test suite wanted18* to limit depth to 22. Widely-deployed PHP bails at depth 512,19* so we will follow PHP's lead, which should be more than sufficient20* (further stackexchange comments indicate depth > 32 rarely occurs).21*/22static constexpr size_t MAX_JSON_DEPTH = 512;24static bool json_isdigit(int ch)25{26return ((ch >= '0') && (ch <= '9'));27}29// convert hexadecimal string to unsigned integer30static const char *hatoui(const char *first, const char *last,31unsigned int& out)32{33unsigned int result = 0;34for (; first != last; ++first)35{36int digit;37if (json_isdigit(*first))38digit = *first - '0';40else if (*first >= 'a' && *first <= 'f')41digit = *first - 'a' + 10;43else if (*first >= 'A' && *first <= 'F')44digit = *first - 'A' + 10;46else47break;49result = 16 * result + digit;50}51out = result;53return first;54}56enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed,57const char *raw, const char *end)58{59tokenVal.clear();60consumed = 0;62const char *rawStart = raw;64while (raw < end && (json_isspace(*raw))) // skip whitespace65raw++;67if (raw >= end)68return JTOK_NONE;70switch (*raw) {72case '{':73raw++;74consumed = (raw - rawStart);75return JTOK_OBJ_OPEN;76case '}':77raw++;78consumed = (raw - rawStart);79return JTOK_OBJ_CLOSE;80case '[':81raw++;82consumed = (raw - rawStart);83return JTOK_ARR_OPEN;84case ']':85raw++;86consumed = (raw - rawStart);87return JTOK_ARR_CLOSE;89case ':':90raw++;91consumed = (raw - rawStart);92return JTOK_COLON;93case ',':94raw++;95consumed = (raw - rawStart);96return JTOK_COMMA;98case 'n':99case 't':100case 'f':101if (!strncmp(raw, "null", 4)) {102raw += 4;103consumed = (raw - rawStart);104return JTOK_KW_NULL;105} else if (!strncmp(raw, "true", 4)) {106raw += 4;107consumed = (raw - rawStart);108return JTOK_KW_TRUE;109} else if (!strncmp(raw, "false", 5)) {110raw += 5;111consumed = (raw - rawStart);112return JTOK_KW_FALSE;113} else114return JTOK_ERR;116case '-':117case '0':118case '1':119case '2':120case '3':121case '4':122case '5':123case '6':124case '7':125case '8':126case '9': {127// part 1: int128std::string numStr;130const char *first = raw;132const char *firstDigit = first;133if (!json_isdigit(*firstDigit))134firstDigit++;135if ((*firstDigit == '0') && json_isdigit(firstDigit[1]))136return JTOK_ERR;138numStr += *raw; // copy first char139raw++;141if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))142return JTOK_ERR;144while (raw < end && json_isdigit(*raw)) { // copy digits145numStr += *raw;146raw++;147}149// part 2: frac150if (raw < end && *raw == '.') {151numStr += *raw; // copy .152raw++;154if (raw >= end || !json_isdigit(*raw))155return JTOK_ERR;156while (raw < end && json_isdigit(*raw)) { // copy digits157numStr += *raw;158raw++;159}160}162// part 3: exp163if (raw < end && (*raw == 'e' || *raw == 'E')) {164numStr += *raw; // copy E165raw++;167if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-168numStr += *raw;169raw++;170}172if (raw >= end || !json_isdigit(*raw))173return JTOK_ERR;174while (raw < end && json_isdigit(*raw)) { // copy digits175numStr += *raw;176raw++;177}178}180tokenVal = numStr;181consumed = (raw - rawStart);182return JTOK_NUMBER;183}185case '"': {186raw++; // skip "188std::string valStr;189JSONUTF8StringFilter writer(valStr);191while (true) {192if (raw >= end || (unsigned char)*raw < 0x20)193return JTOK_ERR;195else if (*raw == '\\') {196raw++; // skip backslash198if (raw >= end)199return JTOK_ERR;201switch (*raw) {202case '"': writer.push_back('\"'); break;203case '\\': writer.push_back('\\'); break;204case '/': writer.push_back('/'); break;205case 'b': writer.push_back('\b'); break;206case 'f': writer.push_back('\f'); break;207case 'n': writer.push_back('\n'); break;208case 'r': writer.push_back('\r'); break;209case 't': writer.push_back('\t'); break;211case 'u': {212unsigned int codepoint;213if (raw + 1 + 4 >= end ||214hatoui(raw + 1, raw + 1 + 4, codepoint) !=215raw + 1 + 4)216return JTOK_ERR;217writer.push_back_u(codepoint);218raw += 4;219break;220}221default:222return JTOK_ERR;224}226raw++; // skip esc'd char227}229else if (*raw == '"') {230raw++; // skip "231break; // stop scanning232}234else {235writer.push_back(static_cast<unsigned char>(*raw));236raw++;237}238}240if (!writer.finalize())241return JTOK_ERR;242tokenVal = valStr;243consumed = (raw - rawStart);244return JTOK_STRING;245}247default:248return JTOK_ERR;249}250}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.