/root/doris/be/src/util/jsonb_parser.h
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* | 
| 2 |  |  *  Copyright (c) 2014, Facebook, Inc. | 
| 3 |  |  *  All rights reserved. | 
| 4 |  |  * | 
| 5 |  |  *  This source code is licensed under the BSD-style license found in the | 
| 6 |  |  *  LICENSE file in the root directory of this source tree. An additional grant | 
| 7 |  |  *  of patent rights can be found in the PATENTS file in the same directory. | 
| 8 |  |  * | 
| 9 |  |  */ | 
| 10 |  |  | 
| 11 |  | /* | 
| 12 |  |  * This file defines JsonbParserT (template) and JsonbParser. | 
| 13 |  |  * | 
| 14 |  |  * JsonbParserT is a template class which implements a JSON parser. | 
| 15 |  |  * JsonbParserT parses JSON text, and serialize it to JSONB binary format | 
| 16 |  |  * by using JsonbWriterT object. By default, JsonbParserT creates a new | 
| 17 |  |  * JsonbWriterT object with an output stream object.  However, you can also | 
| 18 |  |  * pass in your JsonbWriterT or any stream object that implements some basic | 
| 19 |  |  * interface of std::ostream (see JsonbStream.h). | 
| 20 |  |  * | 
| 21 |  |  * JsonbParser specializes JsonbParserT with JsonbOutStream type (see | 
| 22 |  |  * JsonbStream.h). So unless you want to provide own a different output stream | 
| 23 |  |  * type, use JsonbParser object. | 
| 24 |  |  * | 
| 25 |  |  * ** Parsing JSON ** | 
| 26 |  |  * JsonbParserT parses JSON string, and directly serializes into JSONB | 
| 27 |  |  * packed bytes. There are three ways to parse a JSON string: (1) using | 
| 28 |  |  * c-string, (2) using string with len, (3) using std::istream object. You can | 
| 29 |  |  * use custom streambuf to redirect output. JsonbOutBuffer is a streambuf used | 
| 30 |  |  * internally if the input is raw character buffer. | 
| 31 |  |  * | 
| 32 |  |  * You can reuse an JsonbParserT object to parse/serialize multiple JSON | 
| 33 |  |  * strings, and the previous JSONB will be overwritten. | 
| 34 |  |  * | 
| 35 |  |  * If parsing fails (returned false), the error code will be set to one of | 
| 36 |  |  * JsonbErrType, and can be retrieved by calling getErrorCode(). | 
| 37 |  |  * | 
| 38 |  |  * ** External dictionary ** | 
| 39 |  |  * During parsing a JSON string, you can pass a call-back function to map a key | 
| 40 |  |  * string to an id, and store the dictionary id in JSONB to save space. The | 
| 41 |  |  * purpose of using an external dictionary is more towards a collection of | 
| 42 |  |  * documents (which has common keys) rather than a single document, so that | 
| 43 |  |  * space saving will be significant. | 
| 44 |  |  * | 
| 45 |  |  * ** Endianness ** | 
| 46 |  |  * Note: JSONB serialization doesn't assume endianness of the server. However | 
| 47 |  |  * you will need to ensure that the endianness at the reader side is the same | 
| 48 |  |  * as that at the writer side (if they are on different machines). Otherwise, | 
| 49 |  |  * proper conversion is needed when a number value is returned to the | 
| 50 |  |  * caller/writer. | 
| 51 |  |  * | 
| 52 |  |  * @author Tian Xia <tianx@fb.com> | 
| 53 |  |  *  | 
| 54 |  |  * this file is copied from  | 
| 55 |  |  * https://github.com/facebook/mysql-5.6/blob/fb-mysql-5.6.35/fbson/FbsonJsonParser.h | 
| 56 |  |  * and modified by Doris | 
| 57 |  |  */ | 
| 58 |  |  | 
| 59 |  | #ifndef JSONB_JSONBJSONPARSER_H | 
| 60 |  | #define JSONB_JSONBJSONPARSER_H | 
| 61 |  |  | 
| 62 |  | #include <cmath> | 
| 63 |  | #include <limits> | 
| 64 |  |  | 
| 65 |  | #include "jsonb_document.h" | 
| 66 |  | #include "jsonb_error.h" | 
| 67 |  | #include "jsonb_writer.h" | 
| 68 |  | #include "string_parser.hpp" | 
| 69 |  |  | 
| 70 |  | namespace doris { | 
| 71 |  |  | 
| 72 |  | const char* const kJsonDelim = " ,]}\t\r\n"; | 
| 73 |  | const char* const kWhiteSpace = " \t\n\r"; | 
| 74 |  |  | 
| 75 |  | /* | 
| 76 |  |  * Template JsonbParserT | 
| 77 |  |  */ | 
| 78 |  | template <class OS_TYPE> | 
| 79 |  | class JsonbParserT { | 
| 80 |  | public: | 
| 81 | 87.3k |     JsonbParserT() : stream_pos_(0), err_(JsonbErrType::E_NONE) {} | 
| 82 |  |  | 
| 83 |  |     explicit JsonbParserT(OS_TYPE& os) : writer_(os), stream_pos_(0), err_(JsonbErrType::E_NONE) {} | 
| 84 |  |  | 
| 85 |  |     // parse a UTF-8 JSON string | 
| 86 |  |     bool parse(const std::string& str, hDictInsert handler = nullptr) { | 
| 87 |  |         return parse(str.c_str(), (unsigned int)str.size(), handler); | 
| 88 |  |     } | 
| 89 |  |  | 
| 90 |  |     // parse a UTF-8 JSON c-style string (NULL terminated) | 
| 91 |  |     bool parse(const char* c_str, hDictInsert handler = nullptr) { | 
| 92 |  |         return parse(c_str, (unsigned int)strlen(c_str), handler); | 
| 93 |  |     } | 
| 94 |  |  | 
| 95 |  |     // parse a UTF-8 JSON string with length | 
| 96 | 87.5k |     bool parse(const char* pch, unsigned int len, hDictInsert handler = nullptr) { | 
| 97 | 87.5k |         if (!pch || len == 0) {  Branch (97:13): [True: 0, False: 87.5k]
  Branch (97:21): [True: 0, False: 87.5k]
 | 
| 98 | 0 |             err_ = JsonbErrType::E_EMPTY_DOCUMENT; | 
| 99 | 0 |             return false; | 
| 100 | 0 |         } | 
| 101 |  |  | 
| 102 | 87.5k |         JsonbInBuffer sb(pch, len); | 
| 103 | 87.5k |         std::istream in(&sb); | 
| 104 | 87.5k |         return parse(in, handler); | 
| 105 | 87.5k |     } | 
| 106 |  |  | 
| 107 |  |     // parse UTF-8 JSON text from an input stream | 
| 108 | 87.5k |     bool parse(std::istream& in, hDictInsert handler = nullptr) { | 
| 109 | 87.5k |         bool res = false; | 
| 110 | 87.5k |         err_ = JsonbErrType::E_NONE; | 
| 111 | 87.5k |         stream_pos_ = 0; | 
| 112 |  |  | 
| 113 |  |         // reset output stream | 
| 114 | 87.5k |         writer_.reset(); | 
| 115 |  |  | 
| 116 | 87.5k |         trim(in); | 
| 117 |  |  | 
| 118 |  |         // TODO(wzy): parsePrimitive should be implemented | 
| 119 | 87.5k |         if (in.peek() == '{') {  Branch (119:13): [True: 490, False: 87.0k]
 | 
| 120 | 490 |             skipChar(in); | 
| 121 | 490 |             res = parseObject(in, handler); | 
| 122 | 87.0k |         } else if (in.peek() == '[') {  Branch (122:20): [True: 86.0k, False: 1.02k]
 | 
| 123 | 86.0k |             skipChar(in); | 
| 124 | 86.0k |             res = parseArray(in, handler); | 
| 125 | 86.0k |         } else { | 
| 126 | 1.02k |             res = parsePrimitive(in, handler); | 
| 127 | 1.02k |             if (!res) err_ = handle_parse_failure(in);   Branch (127:17): [True: 59, False: 964]
 | 
| 128 | 1.02k |         } | 
| 129 |  |  | 
| 130 | 87.5k |         trim(in); | 
| 131 | 87.5k |         if (res && !in.eof()) {  Branch (131:13): [True: 86.7k, False: 868]
  Branch (131:20): [True: 0, False: 86.7k]
 | 
| 132 | 0 |             err_ = JsonbErrType::E_INVALID_DOCU; | 
| 133 | 0 |             return false; | 
| 134 | 0 |         } | 
| 135 |  |  | 
| 136 | 87.5k |         return res; | 
| 137 | 87.5k |     } | 
| 138 |  |  | 
| 139 | 173k |     JsonbWriterT<OS_TYPE>& getWriter() { return writer_; } | 
| 140 |  |  | 
| 141 | 70 |     JsonbErrType getErrorCode() { return err_; } | 
| 142 |  |  | 
| 143 |  |     JsonbErrInfo getErrorInfo() { | 
| 144 |  |         assert(err_ < JsonbErrType::E_NUM_ERRORS); | 
| 145 |  |  | 
| 146 |  |         JsonbErrInfo err_info; | 
| 147 |  |  | 
| 148 |  |         // stream_pos_ always points to the next char, so err_pos is 1-based | 
| 149 |  |         err_info.err_pos = stream_pos_; | 
| 150 |  |         err_info.err_msg = JsonbErrMsg::getErrMsg(err_); | 
| 151 |  |  | 
| 152 |  |         return err_info; | 
| 153 |  |     } | 
| 154 |  |  | 
| 155 |  |     // clear error code | 
| 156 |  |     void clearErr() { err_ = JsonbErrType::E_NONE; } | 
| 157 |  |  | 
| 158 |  | private: | 
| 159 | 0 |     JsonbErrType handle_parse_value_failure(bool parse_res, std::istream& in) { | 
| 160 | 0 |         if (parse_res) {  Branch (160:13): [True: 0, False: 0]
 | 
| 161 | 0 |             trim(in); | 
| 162 | 0 |             if (!in.good()) {  Branch (162:17): [True: 0, False: 0]
 | 
| 163 | 0 |                 return JsonbErrType::E_INVALID_DOCU_COMPAT; | 
| 164 | 0 |             } | 
| 165 | 0 |         } | 
| 166 | 0 |         return JsonbErrType::E_INVALID_DOCU; | 
| 167 | 0 |         ; | 
| 168 | 0 |     } | 
| 169 |  |  | 
| 170 |  |     // In case json is determined to be invalid at top level, | 
| 171 |  |     // try to parse literal values. | 
| 172 |  |     // We return a different error code E_INVALID_DOCU_COMPAT | 
| 173 |  |     // in case the input json contains these values. | 
| 174 |  |     // Returning a different error code will cause an | 
| 175 |  |     // auditing on the caller. | 
| 176 |  |     // This is mainly done because 8.0 JSON_VALID considers | 
| 177 |  |     // this as a valid input. | 
| 178 | 59 |     JsonbErrType handle_parse_failure(std::istream& in) { | 
| 179 | 59 |         JsonbErrType error = JsonbErrType::E_INVALID_DOCU; | 
| 180 | 59 |         if (!writer_.writeStartArray()) {  Branch (180:13): [True: 0, False: 59]
 | 
| 181 | 0 |             return error; | 
| 182 | 0 |         } | 
| 183 |  |  | 
| 184 | 59 |         switch (in.peek()) { | 
| 185 | 0 |         case 'n':   Branch (185:9): [True: 0, False: 59]
 | 
| 186 | 0 |             skipChar(in); | 
| 187 | 0 |             error = handle_parse_value_failure(parseNull(in), in); | 
| 188 | 0 |             break; | 
| 189 | 0 |         case 't':   Branch (189:9): [True: 0, False: 59]
 | 
| 190 | 0 |             skipChar(in); | 
| 191 | 0 |             error = handle_parse_value_failure(parseTrue(in), in); | 
| 192 | 0 |             break; | 
| 193 | 0 |         case 'f':   Branch (193:9): [True: 0, False: 59]
 | 
| 194 | 0 |             skipChar(in); | 
| 195 | 0 |             error = handle_parse_value_failure(parseFalse(in), in); | 
| 196 | 0 |             break; | 
| 197 | 0 |         case '"':   Branch (197:9): [True: 0, False: 59]
 | 
| 198 | 0 |             skipChar(in); | 
| 199 | 0 |             error = handle_parse_value_failure(parseString(in), in); | 
| 200 | 0 |             break; | 
| 201 | 59 |         default:   Branch (201:9): [True: 59, False: 0]
 | 
| 202 | 59 |             if (parseNumber(in)) {  Branch (202:17): [True: 0, False: 59]
 | 
| 203 | 0 |                 trim(in); | 
| 204 | 0 |                 if (in.eof()) {  Branch (204:21): [True: 0, False: 0]
 | 
| 205 | 0 |                     error = JsonbErrType::E_INVALID_DOCU_COMPAT; | 
| 206 | 0 |                 } | 
| 207 | 0 |             } | 
| 208 | 59 |         } | 
| 209 | 59 |         if (!writer_.writeEndArray()) {  Branch (209:13): [True: 0, False: 59]
 | 
| 210 | 0 |             return error; | 
| 211 | 0 |         } | 
| 212 |  |  | 
| 213 | 59 |         return error; | 
| 214 | 59 |     } | 
| 215 |  |  | 
| 216 |  |     // parse primitive | 
| 217 | 1.02k |     bool parsePrimitive(std::istream& in, hDictInsert handler) { | 
| 218 | 1.02k |         bool res = false; | 
| 219 | 1.02k |         switch (in.peek()) { | 
| 220 | 63 |         case 'n':   Branch (220:9): [True: 63, False: 960]
 | 
| 221 | 63 |             skipChar(in); | 
| 222 | 63 |             res = parseNull(in); | 
| 223 | 63 |             break; | 
| 224 | 63 |         case 't':   Branch (224:9): [True: 63, False: 960]
 | 
| 225 | 63 |             skipChar(in); | 
| 226 | 63 |             res = parseTrue(in); | 
| 227 | 63 |             break; | 
| 228 | 63 |         case 'f':   Branch (228:9): [True: 63, False: 960]
 | 
| 229 | 63 |             skipChar(in); | 
| 230 | 63 |             res = parseFalse(in); | 
| 231 | 63 |             break; | 
| 232 | 335 |         case '"':   Branch (232:9): [True: 335, False: 688]
 | 
| 233 | 335 |             skipChar(in); | 
| 234 | 335 |             res = parseString(in); | 
| 235 | 335 |             break; | 
| 236 | 499 |         default:   Branch (236:9): [True: 499, False: 524]
 | 
| 237 | 499 |             res = parseNumber(in); | 
| 238 | 1.02k |         } | 
| 239 |  |  | 
| 240 | 1.02k |         return res; | 
| 241 | 1.02k |     } | 
| 242 |  |  | 
| 243 |  |     // parse a JSON object (comma-separated list of key-value pairs) | 
| 244 | 15.1k |     bool parseObject(std::istream& in, hDictInsert handler) { | 
| 245 | 15.1k |         if (!writer_.writeStartObject()) {  Branch (245:13): [True: 0, False: 15.1k]
 | 
| 246 | 0 |             err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 247 | 0 |             return false; | 
| 248 | 0 |         } | 
| 249 |  |  | 
| 250 | 15.1k |         trim(in); | 
| 251 |  |  | 
| 252 | 15.1k |         if (in.peek() == '}') {  Branch (252:13): [True: 446, False: 14.7k]
 | 
| 253 | 446 |             skipChar(in); | 
| 254 |  |             // empty object | 
| 255 | 446 |             if (!writer_.writeEndObject()) {  Branch (255:17): [True: 0, False: 446]
 | 
| 256 | 0 |                 err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 257 | 0 |                 return false; | 
| 258 | 0 |             } | 
| 259 | 446 |             return true; | 
| 260 | 446 |         } | 
| 261 |  |  | 
| 262 | 16.6k |         while (in.good()) {  Branch (262:16): [True: 16.6k, False: 0]
 | 
| 263 | 16.6k |             if (nextChar(in) != '"') {  Branch (263:17): [True: 11, False: 16.6k]
 | 
| 264 | 11 |                 err_ = JsonbErrType::E_INVALID_OBJ; | 
| 265 | 11 |                 return false; | 
| 266 | 11 |             } | 
| 267 |  |  | 
| 268 | 16.6k |             if (!parseKVPair(in, handler)) {  Branch (268:17): [True: 9.40k, False: 7.23k]
 | 
| 269 | 9.40k |                 return false; | 
| 270 | 9.40k |             } | 
| 271 |  |  | 
| 272 | 7.23k |             trim(in); | 
| 273 |  |  | 
| 274 | 7.23k |             char ch = nextChar(in); | 
| 275 | 7.23k |             if (ch == '}') {  Branch (275:17): [True: 5.30k, False: 1.93k]
 | 
| 276 |  |                 // end of the object | 
| 277 | 5.30k |                 if (!writer_.writeEndObject()) {  Branch (277:21): [True: 0, False: 5.30k]
 | 
| 278 | 0 |                     err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 279 | 0 |                     return false; | 
| 280 | 0 |                 } | 
| 281 | 5.30k |                 return true; | 
| 282 | 5.30k |             } else if (ch != ',') {  Branch (282:24): [True: 0, False: 1.93k]
 | 
| 283 | 0 |                 err_ = JsonbErrType::E_INVALID_OBJ; | 
| 284 | 0 |                 return false; | 
| 285 | 0 |             } | 
| 286 |  |  | 
| 287 | 1.93k |             trim(in); | 
| 288 | 1.93k |         } | 
| 289 |  |  | 
| 290 | 0 |         err_ = JsonbErrType::E_INVALID_OBJ; | 
| 291 | 0 |         return false; | 
| 292 | 14.7k |     } | 
| 293 |  |  | 
| 294 |  |     // parse a JSON array (comma-separated list of values) | 
| 295 | 116k |     bool parseArray(std::istream& in, hDictInsert handler) { | 
| 296 | 116k |         if (!writer_.writeStartArray()) {  Branch (296:13): [True: 0, False: 116k]
 | 
| 297 | 0 |             err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 298 | 0 |             return false; | 
| 299 | 0 |         } | 
| 300 |  |  | 
| 301 | 116k |         trim(in); | 
| 302 |  |  | 
| 303 | 116k |         if (in.peek() == ']') {  Branch (303:13): [True: 978, False: 115k]
 | 
| 304 | 978 |             skipChar(in); | 
| 305 |  |             // empty array | 
| 306 | 978 |             if (!writer_.writeEndArray()) {  Branch (306:17): [True: 0, False: 978]
 | 
| 307 | 0 |                 err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 308 | 0 |                 return false; | 
| 309 | 0 |             } | 
| 310 | 978 |             return true; | 
| 311 | 978 |         } | 
| 312 |  |  | 
| 313 | 507k |         while (in.good()) {  Branch (313:16): [True: 507k, False: 0]
 | 
| 314 | 507k |             if (!parseValue(in, handler)) {  Branch (314:17): [True: 859, False: 506k]
 | 
| 315 | 859 |                 return false; | 
| 316 | 859 |             } | 
| 317 |  |  | 
| 318 | 506k |             trim(in); | 
| 319 |  |  | 
| 320 | 506k |             char ch = nextChar(in); | 
| 321 | 506k |             if (ch == ']') {  Branch (321:17): [True: 114k, False: 391k]
 | 
| 322 |  |                 // end of the array | 
| 323 | 114k |                 if (!writer_.writeEndArray()) {  Branch (323:21): [True: 0, False: 114k]
 | 
| 324 | 0 |                     err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 325 | 0 |                     return false; | 
| 326 | 0 |                 } | 
| 327 | 114k |                 return true; | 
| 328 | 391k |             } else if (ch != ',') {  Branch (328:24): [True: 0, False: 391k]
 | 
| 329 | 0 |                 err_ = JsonbErrType::E_INVALID_ARR; | 
| 330 | 0 |                 return false; | 
| 331 | 0 |             } | 
| 332 |  |  | 
| 333 | 391k |             trim(in); | 
| 334 | 391k |         } | 
| 335 |  |  | 
| 336 | 0 |         err_ = JsonbErrType::E_INVALID_ARR; | 
| 337 | 0 |         return false; | 
| 338 | 115k |     } | 
| 339 |  |  | 
| 340 |  |     // parse a key-value pair, separated by ":" | 
| 341 | 16.6k |     bool parseKVPair(std::istream& in, hDictInsert handler) { | 
| 342 | 16.6k |         if (parseKey(in, handler) && parseValue(in, handler)) {  Branch (342:13): [True: 16.4k, False: 185]
  Branch (342:38): [True: 7.23k, False: 9.22k]
 | 
| 343 | 7.23k |             return true; | 
| 344 | 7.23k |         } | 
| 345 |  |  | 
| 346 | 9.40k |         return false; | 
| 347 | 16.6k |     } | 
| 348 |  |  | 
| 349 |  |     // parse a key (must be string) | 
| 350 | 16.6k |     bool parseKey(std::istream& in, hDictInsert handler) { | 
| 351 | 16.6k |         char key[JsonbKeyValue::sMaxKeyLen]; | 
| 352 | 16.6k |         int key_len = 0; | 
| 353 | 109k |         while (in.good() && in.peek() != '"' && key_len < JsonbKeyValue::sMaxKeyLen) {  Branch (353:16): [True: 109k, False: 0]
  Branch (353:29): [True: 92.7k, False: 16.4k]
  Branch (353:49): [True: 92.5k, False: 185]
 | 
| 354 | 92.5k |             char ch = nextChar(in); | 
| 355 | 92.5k |             if (ch == '\\') {  Branch (355:17): [True: 3.77k, False: 88.7k]
 | 
| 356 | 3.77k |                 char escape_buffer[5]; // buffer for escape | 
| 357 | 3.77k |                 int len; | 
| 358 | 3.77k |                 if (!parseEscape(in, escape_buffer, len)) {  Branch (358:21): [True: 0, False: 3.77k]
 | 
| 359 | 0 |                     err_ = JsonbErrType::E_INVALID_KEY_STRING; | 
| 360 | 0 |                     return false; | 
| 361 | 0 |                 } | 
| 362 | 3.77k |                 if (key_len + len >= JsonbKeyValue::sMaxKeyLen) {  Branch (362:21): [True: 0, False: 3.77k]
 | 
| 363 | 0 |                     err_ = JsonbErrType::E_INVALID_KEY_LENGTH; | 
| 364 | 0 |                     return false; | 
| 365 | 0 |                 } | 
| 366 | 3.77k |                 memcpy(key + key_len, escape_buffer, len); | 
| 367 | 3.77k |                 key_len += len; | 
| 368 | 88.7k |             } else { | 
| 369 | 88.7k |                 key[key_len++] = ch; | 
| 370 | 88.7k |             } | 
| 371 | 92.5k |         } | 
| 372 |  |         // The JSON key can be an empty string. | 
| 373 | 16.6k |         if (!in.good() || in.peek() != '"') {  Branch (373:13): [True: 0, False: 16.6k]
  Branch (373:27): [True: 185, False: 16.4k]
 | 
| 374 | 185 |             if (key_len == JsonbKeyValue::sMaxKeyLen)   Branch (374:17): [True: 185, False: 0]
 | 
| 375 | 185 |                 err_ = JsonbErrType::E_INVALID_KEY_LENGTH; | 
| 376 | 0 |             else | 
| 377 | 0 |                 err_ = JsonbErrType::E_INVALID_KEY_STRING; | 
| 378 | 185 |             return false; | 
| 379 | 185 |         } | 
| 380 |  |  | 
| 381 | 16.4k |         skipChar(in); // discard '"' | 
| 382 |  |  | 
| 383 | 16.4k |         int key_id = -1; | 
| 384 | 16.4k |         if (handler) {  Branch (384:13): [True: 0, False: 16.4k]
 | 
| 385 | 0 |             key_id = handler(key, key_len); | 
| 386 | 0 |         } | 
| 387 |  |  | 
| 388 | 16.4k |         if (key_id < 0) {  Branch (388:13): [True: 16.4k, False: 0]
 | 
| 389 | 16.4k |             writer_.writeKey(key, key_len); | 
| 390 | 16.4k |         } else { | 
| 391 | 0 |             writer_.writeKey(key_id); | 
| 392 | 0 |         } | 
| 393 |  |  | 
| 394 | 16.4k |         trim(in); | 
| 395 |  |  | 
| 396 | 16.4k |         if (nextChar(in) != ':') {  Branch (396:13): [True: 0, False: 16.4k]
 | 
| 397 | 0 |             err_ = JsonbErrType::E_INVALID_OBJ; | 
| 398 | 0 |             return false; | 
| 399 | 0 |         } | 
| 400 |  |  | 
| 401 | 16.4k |         trim(in); | 
| 402 | 16.4k |         if (!in.good()) {  Branch (402:13): [True: 0, False: 16.4k]
 | 
| 403 | 0 |             err_ = JsonbErrType::E_INVALID_OBJ; | 
| 404 | 0 |             return false; | 
| 405 | 0 |         } | 
| 406 |  |  | 
| 407 | 16.4k |         return true; | 
| 408 | 16.4k |     } | 
| 409 |  |  | 
| 410 |  |     // parse a value | 
| 411 | 523k |     bool parseValue(std::istream& in, hDictInsert handler) { | 
| 412 | 523k |         bool res = false; | 
| 413 |  |  | 
| 414 | 523k |         switch (in.peek()) { | 
| 415 | 0 |         case 'N':   Branch (415:9): [True: 0, False: 523k]
 | 
| 416 | 11.3k |         case 'n': {  Branch (416:9): [True: 11.3k, False: 512k]
 | 
| 417 | 11.3k |             skipChar(in); | 
| 418 | 11.3k |             res = parseNull(in); | 
| 419 | 11.3k |             break; | 
| 420 | 0 |         } | 
| 421 | 0 |         case 'T':   Branch (421:9): [True: 0, False: 523k]
 | 
| 422 | 119 |         case 't': {  Branch (422:9): [True: 119, False: 523k]
 | 
| 423 | 119 |             skipChar(in); | 
| 424 | 119 |             res = parseTrue(in); | 
| 425 | 119 |             break; | 
| 426 | 0 |         } | 
| 427 | 0 |         case 'F':   Branch (427:9): [True: 0, False: 523k]
 | 
| 428 | 120 |         case 'f': {  Branch (428:9): [True: 120, False: 523k]
 | 
| 429 | 120 |             skipChar(in); | 
| 430 | 120 |             res = parseFalse(in); | 
| 431 | 120 |             break; | 
| 432 | 0 |         } | 
| 433 | 276k |         case '"': {  Branch (433:9): [True: 276k, False: 247k]
 | 
| 434 | 276k |             skipChar(in); | 
| 435 | 276k |             res = parseString(in); | 
| 436 | 276k |             break; | 
| 437 | 0 |         } | 
| 438 | 14.7k |         case '{': {  Branch (438:9): [True: 14.7k, False: 508k]
 | 
| 439 | 14.7k |             skipChar(in); | 
| 440 | 14.7k |             ++nesting_lvl_; | 
| 441 | 14.7k |             if (nesting_lvl_ >= MaxNestingLevel) {  Branch (441:17): [True: 89, False: 14.6k]
 | 
| 442 | 89 |                 err_ = JsonbErrType::E_NESTING_LVL_OVERFLOW; | 
| 443 | 89 |                 return false; | 
| 444 | 89 |             } | 
| 445 | 14.6k |             res = parseObject(in, handler); | 
| 446 | 14.6k |             if (res) {  Branch (446:17): [True: 5.46k, False: 9.22k]
 | 
| 447 | 5.46k |                 --nesting_lvl_; | 
| 448 | 5.46k |             } | 
| 449 | 14.6k |             break; | 
| 450 | 14.7k |         } | 
| 451 | 30.4k |         case '[': {  Branch (451:9): [True: 30.4k, False: 493k]
 | 
| 452 | 30.4k |             skipChar(in); | 
| 453 | 30.4k |             ++nesting_lvl_; | 
| 454 | 30.4k |             if (nesting_lvl_ >= MaxNestingLevel) {  Branch (454:17): [True: 0, False: 30.4k]
 | 
| 455 | 0 |                 err_ = JsonbErrType::E_NESTING_LVL_OVERFLOW; | 
| 456 | 0 |                 return false; | 
| 457 | 0 |             } | 
| 458 | 30.4k |             res = parseArray(in, handler); | 
| 459 | 30.4k |             if (res) {  Branch (459:17): [True: 30.1k, False: 248]
 | 
| 460 | 30.1k |                 --nesting_lvl_; | 
| 461 | 30.1k |             } | 
| 462 | 30.4k |             break; | 
| 463 | 30.4k |         } | 
| 464 | 190k |         default: {  Branch (464:9): [True: 190k, False: 333k]
 | 
| 465 | 190k |             res = parseNumber(in); | 
| 466 | 190k |             break; | 
| 467 | 30.4k |         } | 
| 468 | 523k |         } | 
| 469 |  |  | 
| 470 | 523k |         return res; | 
| 471 | 523k |     } | 
| 472 |  |  | 
| 473 |  |     // parse NULL value | 
| 474 | 11.4k |     bool parseNull(std::istream& in) { | 
| 475 | 11.4k |         if (tolower(nextChar(in)) == 'u' && tolower(nextChar(in)) == 'l' &&   Branch (475:13): [True: 11.4k, False: 0]
  Branch (475:45): [True: 11.4k, False: 0]
 | 
| 476 | 11.4k |             tolower(nextChar(in)) == 'l') {  Branch (476:13): [True: 11.4k, False: 0]
 | 
| 477 | 11.4k |             writer_.writeNull(); | 
| 478 | 11.4k |             return true; | 
| 479 | 11.4k |         } | 
| 480 |  |  | 
| 481 | 0 |         err_ = JsonbErrType::E_INVALID_SCALAR_VALUE; | 
| 482 | 0 |         return false; | 
| 483 | 11.4k |     } | 
| 484 |  |  | 
| 485 |  |     // parse TRUE value | 
| 486 | 182 |     bool parseTrue(std::istream& in) { | 
| 487 | 182 |         if (tolower(nextChar(in)) == 'r' && tolower(nextChar(in)) == 'u' &&   Branch (487:13): [True: 182, False: 0]
  Branch (487:45): [True: 182, False: 0]
 | 
| 488 | 182 |             tolower(nextChar(in)) == 'e') {  Branch (488:13): [True: 182, False: 0]
 | 
| 489 | 182 |             writer_.writeBool(true); | 
| 490 | 182 |             return true; | 
| 491 | 182 |         } | 
| 492 |  |  | 
| 493 | 0 |         err_ = JsonbErrType::E_INVALID_SCALAR_VALUE; | 
| 494 | 0 |         return false; | 
| 495 | 182 |     } | 
| 496 |  |  | 
| 497 |  |     // parse FALSE value | 
| 498 | 183 |     bool parseFalse(std::istream& in) { | 
| 499 | 183 |         if (tolower(nextChar(in)) == 'a' && tolower(nextChar(in)) == 'l' &&   Branch (499:13): [True: 183, False: 0]
  Branch (499:45): [True: 183, False: 0]
 | 
| 500 | 183 |             tolower(nextChar(in)) == 's' && tolower(nextChar(in)) == 'e') {  Branch (500:13): [True: 183, False: 0]
  Branch (500:45): [True: 183, False: 0]
 | 
| 501 | 183 |             writer_.writeBool(false); | 
| 502 | 183 |             return true; | 
| 503 | 183 |         } | 
| 504 |  |  | 
| 505 | 0 |         err_ = JsonbErrType::E_INVALID_SCALAR_VALUE; | 
| 506 | 0 |         return false; | 
| 507 | 183 |     } | 
| 508 |  |  | 
| 509 |  |     /* | 
| 510 |  |     This is a helper function to parse the hex value. hex_num means the | 
| 511 |  |     number of digits needed to be parsed. If less than zero, then it will | 
| 512 |  |     consider all the characters between current and any character in JsonDelim. | 
| 513 |  |   */ | 
| 514 | 0 |     unsigned parseHexHelper(std::istream& in, uint64_t& val, unsigned hex_num = 17) { | 
| 515 |  |         // We can't read more than 17 digits, so when read 17 digits, it's overflow | 
| 516 | 0 |         val = 0; | 
| 517 | 0 |         unsigned num_digits = 0; | 
| 518 | 0 |         char ch = tolower(in.peek()); | 
| 519 | 0 |         while (in.good() && !strchr(kJsonDelim, ch) && num_digits != hex_num) {  Branch (519:16): [True: 0, False: 0]
  Branch (519:29): [True: 0, False: 0]
  Branch (519:56): [True: 0, False: 0]
 | 
| 520 | 0 |             if (ch >= '0' && ch <= '9') {  Branch (520:17): [True: 0, False: 0]
  Branch (520:30): [True: 0, False: 0]
 | 
| 521 | 0 |                 val = (val << 4) + (ch - '0'); | 
| 522 | 0 |             } else if (ch >= 'a' && ch <= 'f') {  Branch (522:24): [True: 0, False: 0]
  Branch (522:37): [True: 0, False: 0]
 | 
| 523 | 0 |                 val = (val << 4) + (ch - 'a' + 10); | 
| 524 | 0 |             } else { | 
| 525 |  |                 // unrecognized hex digit | 
| 526 | 0 |                 return 0; | 
| 527 | 0 |             } | 
| 528 | 0 |             skipChar(in); | 
| 529 | 0 |             ch = tolower(in.peek()); | 
| 530 | 0 |             ++num_digits; | 
| 531 | 0 |         } | 
| 532 | 0 |         return num_digits; | 
| 533 | 0 |     } | 
| 534 |  |  | 
| 535 |  |     // parse HEX value | 
| 536 | 0 |     bool parseHex4(std::istream& in, unsigned& h) { | 
| 537 | 0 |         uint64_t val; | 
| 538 | 0 |         if (4 == parseHexHelper(in, val, 4)) {  Branch (538:13): [True: 0, False: 0]
 | 
| 539 | 0 |             h = (unsigned)val; | 
| 540 | 0 |             return true; | 
| 541 | 0 |         } | 
| 542 | 0 |         return false; | 
| 543 | 0 |     } | 
| 544 |  |  | 
| 545 |  |     /* | 
| 546 |  |      parse Escape char. | 
| 547 |  |   */ | 
| 548 | 26.2k |     bool parseEscape(std::istream& in, char* out, int& len) { | 
| 549 |  |         /* | 
| 550 |  |       This is extracted from cJSON implementation. | 
| 551 |  |       This is about the mask of the first byte in UTF-8. | 
| 552 |  |       The mask is defined in: | 
| 553 |  |       http://en.wikipedia.org/wiki/UTF-8#Description | 
| 554 |  |     */ | 
| 555 | 26.2k |         const unsigned char firstByteMark[6] = {0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; | 
| 556 | 26.2k |         if (!in.good()) {  Branch (556:13): [True: 0, False: 26.2k]
 | 
| 557 | 0 |             return false; | 
| 558 | 0 |         } | 
| 559 | 26.2k |         char c = nextChar(in); | 
| 560 | 26.2k |         len = 1; | 
| 561 | 26.2k |         switch (c) { | 
| 562 |  |         // \" \\ \/  \b \f \n \r \t | 
| 563 | 9.63k |         case '"':   Branch (563:9): [True: 9.63k, False: 16.5k]
 | 
| 564 | 9.63k |             *out = '"'; | 
| 565 | 9.63k |             return true; | 
| 566 | 13.5k |         case '\\':   Branch (566:9): [True: 13.5k, False: 12.6k]
 | 
| 567 | 13.5k |             *out = '\\'; | 
| 568 | 13.5k |             return true; | 
| 569 | 0 |         case '/':   Branch (569:9): [True: 0, False: 26.2k]
 | 
| 570 | 0 |             *out = '/'; | 
| 571 | 0 |             return true; | 
| 572 | 611 |         case 'b':   Branch (572:9): [True: 611, False: 25.5k]
 | 
| 573 | 611 |             *out = '\b'; | 
| 574 | 611 |             return true; | 
| 575 | 608 |         case 'f':   Branch (575:9): [True: 608, False: 25.5k]
 | 
| 576 | 608 |             *out = '\f'; | 
| 577 | 608 |             return true; | 
| 578 | 607 |         case 'n':   Branch (578:9): [True: 607, False: 25.5k]
 | 
| 579 | 607 |             *out = '\n'; | 
| 580 | 607 |             return true; | 
| 581 | 608 |         case 'r':   Branch (581:9): [True: 608, False: 25.5k]
 | 
| 582 | 608 |             *out = '\r'; | 
| 583 | 608 |             return true; | 
| 584 | 616 |         case 't':   Branch (584:9): [True: 616, False: 25.5k]
 | 
| 585 | 616 |             *out = '\t'; | 
| 586 | 616 |             return true; | 
| 587 | 0 |         case 'u': {  Branch (587:9): [True: 0, False: 26.2k]
 | 
| 588 | 0 |             unsigned uc; | 
| 589 | 0 |             if (!parseHex4(in, uc)) {  Branch (589:17): [True: 0, False: 0]
 | 
| 590 | 0 |                 return false; | 
| 591 | 0 |             } | 
| 592 |  |             /* | 
| 593 |  |           For DC00 to DFFF, it should be low surrogates for UTF16. | 
| 594 |  |           So if it display in the high bits, it's invalid. | 
| 595 |  |         */ | 
| 596 | 0 |             if (uc >= 0xDC00 && uc <= 0xDFFF) {  Branch (596:17): [True: 0, False: 0]
  Branch (596:33): [True: 0, False: 0]
 | 
| 597 | 0 |                 return false; | 
| 598 | 0 |             } | 
| 599 |  |  | 
| 600 |  |             /* | 
| 601 |  |           For D800 to DBFF, it's the high surrogates for UTF16. | 
| 602 |  |           So it's utf-16, there must be another one between 0xDC00 | 
| 603 |  |           and 0xDFFF. | 
| 604 |  |         */ | 
| 605 | 0 |             if (uc >= 0xD800 && uc <= 0xDBFF) {  Branch (605:17): [True: 0, False: 0]
  Branch (605:33): [True: 0, False: 0]
 | 
| 606 | 0 |                 unsigned uc2; | 
| 607 |  | 
 | 
| 608 | 0 |                 if (!in.good()) {  Branch (608:21): [True: 0, False: 0]
 | 
| 609 | 0 |                     return false; | 
| 610 | 0 |                 } | 
| 611 | 0 |                 c = nextChar(in); | 
| 612 | 0 |                 if (c != '\\') {  Branch (612:21): [True: 0, False: 0]
 | 
| 613 | 0 |                     return false; | 
| 614 | 0 |                 } | 
| 615 |  |  | 
| 616 | 0 |                 if (!in.good()) {  Branch (616:21): [True: 0, False: 0]
 | 
| 617 | 0 |                     return false; | 
| 618 | 0 |                 } | 
| 619 | 0 |                 c = nextChar(in); | 
| 620 | 0 |                 if (c != 'u') {  Branch (620:21): [True: 0, False: 0]
 | 
| 621 | 0 |                     return false; | 
| 622 | 0 |                 } | 
| 623 |  |  | 
| 624 | 0 |                 if (!parseHex4(in, uc2)) {  Branch (624:21): [True: 0, False: 0]
 | 
| 625 | 0 |                     return false; | 
| 626 | 0 |                 } | 
| 627 |  |                 /* | 
| 628 |  |             Now we need the low surrogates for UTF16. It should be | 
| 629 |  |             within 0xDC00 and 0xDFFF. | 
| 630 |  |           */ | 
| 631 | 0 |                 if (uc2 < 0xDC00 || uc2 > 0xDFFF) return false;   Branch (631:21): [True: 0, False: 0]
  Branch (631:37): [True: 0, False: 0]
 | 
| 632 |  |                 /* | 
| 633 |  |             For the character that not in the Basic Multilingual Plan, | 
| 634 |  |             it's represented as twelve-character, encoding the UTF-16 | 
| 635 |  |             surrogate pair. | 
| 636 |  |             UTF16 is between 0x10000 and 0x10FFFF. The high surrogate | 
| 637 |  |             present the high bits and the low surrogate present the | 
| 638 |  |             lower 10 bits. | 
| 639 |  |             For detailed explanation, please refer to: | 
| 640 |  |             http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf | 
| 641 |  |             Then it will be converted to UTF8. | 
| 642 |  |           */ | 
| 643 | 0 |                 uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF)); | 
| 644 | 0 |             } | 
| 645 |  |  | 
| 646 |  |             /* | 
| 647 |  |           Get the length of the unicode. | 
| 648 |  |           Please refer to http://en.wikipedia.org/wiki/UTF-8#Description. | 
| 649 |  |         */ | 
| 650 | 0 |             if (uc < 0x80)   Branch (650:17): [True: 0, False: 0]
 | 
| 651 | 0 |                 len = 1; | 
| 652 | 0 |             else if (uc < 0x800)   Branch (652:22): [True: 0, False: 0]
 | 
| 653 | 0 |                 len = 2; | 
| 654 | 0 |             else if (uc < 0x10000)   Branch (654:22): [True: 0, False: 0]
 | 
| 655 | 0 |                 len = 3; | 
| 656 | 0 |             else | 
| 657 | 0 |                 len = 4; | 
| 658 | 0 |             out += len; | 
| 659 |  |             /* | 
| 660 |  |           Encode it. | 
| 661 |  |           Please refer to http://en.wikipedia.org/wiki/UTF-8#Description. | 
| 662 |  |           This part of code has a reference to cJSON. | 
| 663 |  |         */ | 
| 664 | 0 |             switch (len) {  Branch (664:21): [True: 0, False: 0]
 | 
| 665 | 0 |             case 4:   Branch (665:13): [True: 0, False: 0]
 | 
| 666 | 0 |                 *--out = ((uc | 0x80) & 0xBF); | 
| 667 | 0 |                 uc >>= 6; | 
| 668 | 0 |                 [[fallthrough]]; | 
| 669 | 0 |             case 3:   Branch (669:13): [True: 0, False: 0]
 | 
| 670 | 0 |                 *--out = ((uc | 0x80) & 0xBF); | 
| 671 | 0 |                 uc >>= 6; | 
| 672 | 0 |                 [[fallthrough]]; | 
| 673 | 0 |             case 2:   Branch (673:13): [True: 0, False: 0]
 | 
| 674 | 0 |                 *--out = ((uc | 0x80) & 0xBF); | 
| 675 | 0 |                 uc >>= 6; | 
| 676 | 0 |                 [[fallthrough]]; | 
| 677 | 0 |             case 1:   Branch (677:13): [True: 0, False: 0]
 | 
| 678 |  |                 // Mask the first byte according to the standard. | 
| 679 | 0 |                 *--out = (uc | firstByteMark[len - 1]); | 
| 680 | 0 |             } | 
| 681 | 0 |             return true; | 
| 682 | 0 |             break; | 
| 683 | 0 |         } | 
| 684 | 0 |         default:   Branch (684:9): [True: 0, False: 26.2k]
 | 
| 685 | 0 |             return false; | 
| 686 | 0 |             break; | 
| 687 | 26.2k |         } | 
| 688 | 26.2k |     } | 
| 689 |  |  | 
| 690 |  |     // parse a string | 
| 691 | 276k |     bool parseString(std::istream& in) { | 
| 692 | 276k |         const int BUFFER_LEN = 4096; | 
| 693 | 276k |         if (!writer_.writeStartString()) {  Branch (693:13): [True: 0, False: 276k]
 | 
| 694 | 0 |             err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 695 | 0 |             return false; | 
| 696 | 0 |         } | 
| 697 |  |  | 
| 698 |  |         // write 4KB at a time | 
| 699 | 276k |         char buffer[BUFFER_LEN]; | 
| 700 | 276k |         int nread = 0; | 
| 701 | 7.15M |         while (in.good()) {  Branch (701:16): [True: 7.15M, False: 0]
 | 
| 702 | 7.15M |             char ch = nextChar(in); | 
| 703 | 7.15M |             if (ch == '"') {  Branch (703:17): [True: 276k, False: 6.87M]
 | 
| 704 |  |                 // write all remaining bytes in the buffer | 
| 705 | 276k |                 if (nread > 0) {  Branch (705:21): [True: 266k, False: 10.6k]
 | 
| 706 | 266k |                     if (!writer_.writeString(buffer, nread)) {  Branch (706:25): [True: 0, False: 266k]
 | 
| 707 | 0 |                         err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 708 | 0 |                         return false; | 
| 709 | 0 |                     } | 
| 710 | 266k |                 } | 
| 711 |  |                 // end writing string | 
| 712 | 276k |                 if (!writer_.writeEndString()) {  Branch (712:21): [True: 0, False: 276k]
 | 
| 713 | 0 |                     err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 714 | 0 |                     return false; | 
| 715 | 0 |                 } | 
| 716 | 276k |                 return true; | 
| 717 | 6.87M |             } else if (ch == '\\') {  Branch (717:24): [True: 22.4k, False: 6.85M]
 | 
| 718 |  |                 // this is a escape char | 
| 719 | 22.4k |                 char escape_buffer[5]; // buffer for escape | 
| 720 | 22.4k |                 int len; | 
| 721 | 22.4k |                 if (!parseEscape(in, escape_buffer, len)) {  Branch (721:21): [True: 0, False: 22.4k]
 | 
| 722 | 0 |                     err_ = JsonbErrType::E_INVALID_STR; | 
| 723 | 0 |                     return false; | 
| 724 | 0 |                 } | 
| 725 |  |  | 
| 726 |  |                 // Write each char to the buffer | 
| 727 | 44.8k |                 for (int i = 0; i != len; ++i) {  Branch (727:33): [True: 22.4k, False: 22.4k]
 | 
| 728 | 22.4k |                     buffer[nread++] = escape_buffer[i]; | 
| 729 | 22.4k |                     if (nread == BUFFER_LEN) {  Branch (729:25): [True: 0, False: 22.4k]
 | 
| 730 | 0 |                         if (!writer_.writeString(buffer, nread)) {  Branch (730:29): [True: 0, False: 0]
 | 
| 731 | 0 |                             err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 732 | 0 |                             return false; | 
| 733 | 0 |                         } | 
| 734 | 0 |                         nread = 0; | 
| 735 | 0 |                     } | 
| 736 | 22.4k |                 } | 
| 737 | 6.85M |             } else { | 
| 738 |  |                 // just a char | 
| 739 | 6.85M |                 buffer[nread++] = ch; | 
| 740 | 6.85M |                 if (nread == BUFFER_LEN) {  Branch (740:21): [True: 9, False: 6.85M]
 | 
| 741 |  |                     // flush buffer | 
| 742 | 9 |                     if (!writer_.writeString(buffer, nread)) {  Branch (742:25): [True: 0, False: 9]
 | 
| 743 | 0 |                         err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 744 | 0 |                         return false; | 
| 745 | 0 |                     } | 
| 746 | 9 |                     nread = 0; | 
| 747 | 9 |                 } | 
| 748 | 6.85M |             } | 
| 749 | 7.15M |         } | 
| 750 |  |  | 
| 751 | 0 |         err_ = JsonbErrType::E_INVALID_STR; | 
| 752 | 0 |         return false; | 
| 753 | 276k |     } | 
| 754 |  |  | 
| 755 |  |     // parse a number | 
| 756 |  |     // Number format can be hex, octal, or decimal (including float). | 
| 757 |  |     // Only decimal can have (+/-) sign prefix. | 
| 758 | 191k |     bool parseNumber(std::istream& in) { | 
| 759 | 191k |         bool ret = false; | 
| 760 | 191k |         switch (in.peek()) { | 
| 761 | 22.8k |         case '0': {  Branch (761:9): [True: 22.8k, False: 168k]
 | 
| 762 | 22.8k |             skipChar(in); | 
| 763 |  |  | 
| 764 | 22.8k |             if (in.peek() == 'x' || in.peek() == 'X') {  Branch (764:17): [True: 0, False: 22.8k]
  Branch (764:37): [True: 0, False: 22.8k]
 | 
| 765 | 0 |                 skipChar(in); | 
| 766 | 0 |                 ret = parseHex(in); | 
| 767 | 22.8k |             } else if (in.peek() == '.') {  Branch (767:24): [True: 0, False: 22.8k]
 | 
| 768 | 0 |                 skipChar(in); // remove '.' | 
| 769 | 0 |                 num_buf_[0] = '.'; | 
| 770 | 0 |                 ret = parseDouble(in, num_buf_ + 1); | 
| 771 | 22.8k |             } else { | 
| 772 | 22.8k |                 ret = parseOctal(in); | 
| 773 | 22.8k |             } | 
| 774 |  |  | 
| 775 | 22.8k |             break; | 
| 776 | 0 |         } | 
| 777 | 391 |         case '-': {  Branch (777:9): [True: 391, False: 190k]
 | 
| 778 | 391 |             skipChar(in); | 
| 779 | 391 |             ret = parseDecimal(in, true); | 
| 780 | 391 |             break; | 
| 781 | 0 |         } | 
| 782 | 0 |         case '+':   Branch (782:9): [True: 0, False: 191k]
 | 
| 783 | 0 |             skipChar(in); | 
| 784 |  |         // fall through | 
| 785 | 167k |         default:   Branch (785:9): [True: 167k, False: 23.2k]
 | 
| 786 | 167k |             ret = parseDecimal(in); | 
| 787 | 167k |             break; | 
| 788 | 191k |         } | 
| 789 |  |  | 
| 790 | 191k |         return ret; | 
| 791 | 191k |     } | 
| 792 |  |  | 
| 793 |  |     // parse a number in hex format | 
| 794 | 0 |     bool parseHex(std::istream& in) { | 
| 795 | 0 |         uint64_t val = 0; | 
| 796 | 0 |         int num_digits; | 
| 797 | 0 |         if (0 == (num_digits = parseHexHelper(in, val))) {  Branch (797:13): [True: 0, False: 0]
 | 
| 798 | 0 |             err_ = JsonbErrType::E_INVALID_HEX; | 
| 799 | 0 |             return false; | 
| 800 | 0 |         } | 
| 801 |  |  | 
| 802 | 0 |         int size = 0; | 
| 803 | 0 |         if (num_digits <= 2) {  Branch (803:13): [True: 0, False: 0]
 | 
| 804 | 0 |             size = writer_.writeInt8((int8_t)val); | 
| 805 | 0 |         } else if (num_digits <= 4) {  Branch (805:20): [True: 0, False: 0]
 | 
| 806 | 0 |             size = writer_.writeInt16((int16_t)val); | 
| 807 | 0 |         } else if (num_digits <= 8) {  Branch (807:20): [True: 0, False: 0]
 | 
| 808 | 0 |             size = writer_.writeInt32((int32_t)val); | 
| 809 | 0 |         } else if (num_digits <= 16) {  Branch (809:20): [True: 0, False: 0]
 | 
| 810 | 0 |             size = writer_.writeInt64(val); | 
| 811 | 0 |         } else { | 
| 812 | 0 |             err_ = JsonbErrType::E_HEX_OVERFLOW; | 
| 813 | 0 |             return false; | 
| 814 | 0 |         } | 
| 815 |  |  | 
| 816 | 0 |         if (size == 0) {  Branch (816:13): [True: 0, False: 0]
 | 
| 817 | 0 |             err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 818 | 0 |             return false; | 
| 819 | 0 |         } | 
| 820 |  |  | 
| 821 | 0 |         return true; | 
| 822 | 0 |     } | 
| 823 |  |  | 
| 824 |  |     // parse a number in octal format | 
| 825 | 22.8k |     bool parseOctal(std::istream& in) { | 
| 826 | 22.8k |         int64_t val = 0; | 
| 827 | 22.8k |         char ch = in.peek(); | 
| 828 | 22.8k |         while (in.good() && !strchr(kJsonDelim, ch)) {  Branch (828:16): [True: 22.8k, False: 42]
  Branch (828:29): [True: 0, False: 22.8k]
 | 
| 829 | 0 |             if (ch >= '0' && ch <= '7') {  Branch (829:17): [True: 0, False: 0]
  Branch (829:30): [True: 0, False: 0]
 | 
| 830 | 0 |                 val = val * 8 + (ch - '0'); | 
| 831 | 0 |             } else { | 
| 832 | 0 |                 err_ = JsonbErrType::E_INVALID_OCTAL; | 
| 833 | 0 |                 return false; | 
| 834 | 0 |             } | 
| 835 |  |  | 
| 836 |  |             // check if the number overflows | 
| 837 | 0 |             if (val < 0) {  Branch (837:17): [True: 0, False: 0]
 | 
| 838 | 0 |                 err_ = JsonbErrType::E_OCTAL_OVERFLOW; | 
| 839 | 0 |                 return false; | 
| 840 | 0 |             } | 
| 841 |  |  | 
| 842 | 0 |             skipChar(in); | 
| 843 | 0 |             ch = in.peek(); | 
| 844 | 0 |         } | 
| 845 |  |  | 
| 846 | 22.8k |         int size = 0; | 
| 847 | 22.8k |         if (val <= std::numeric_limits<int8_t>::max()) {  Branch (847:13): [True: 22.8k, False: 0]
 | 
| 848 | 22.8k |             size = writer_.writeInt8((int8_t)val); | 
| 849 | 22.8k |         } else if (val <= std::numeric_limits<int16_t>::max()) {  Branch (849:20): [True: 0, False: 0]
 | 
| 850 | 0 |             size = writer_.writeInt16((int16_t)val); | 
| 851 | 0 |         } else if (val <= std::numeric_limits<int32_t>::max()) {  Branch (851:20): [True: 0, False: 0]
 | 
| 852 | 0 |             size = writer_.writeInt32((int32_t)val); | 
| 853 | 0 |         } else { // val <= INT64_MAX | 
| 854 | 0 |             size = writer_.writeInt64(val); | 
| 855 | 0 |         } | 
| 856 |  |  | 
| 857 | 22.8k |         if (size == 0) {  Branch (857:13): [True: 0, False: 22.8k]
 | 
| 858 | 0 |             err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 859 | 0 |             return false; | 
| 860 | 0 |         } | 
| 861 |  |  | 
| 862 | 22.8k |         return true; | 
| 863 | 22.8k |     } | 
| 864 |  |  | 
| 865 |  |     // parse a number in decimal (including float) | 
| 866 | 168k |     bool parseDecimal(std::istream& in, bool neg = false) { | 
| 867 | 168k |         char ch = 0; | 
| 868 | 168k |         while (in.good() && (ch = in.peek()) == '0') skipChar(in);   Branch (868:16): [True: 168k, False: 11]
  Branch (868:29): [True: 158, False: 168k]
 | 
| 869 |  |  | 
| 870 | 168k |         char* pbuf = num_buf_; | 
| 871 | 168k |         if (neg) *(pbuf++) = '-';   Branch (871:13): [True: 391, False: 167k]
 | 
| 872 |  |  | 
| 873 | 168k |         char* save_pos = pbuf; | 
| 874 | 1.18M |         while (in.good() && !strchr(kJsonDelim, ch)) {  Branch (874:16): [True: 1.18M, False: 322]
  Branch (874:29): [True: 1.06M, False: 119k]
 | 
| 875 | 1.06M |             *(pbuf++) = ch; | 
| 876 | 1.06M |             if (pbuf == end_buf_) {  Branch (876:17): [True: 0, False: 1.06M]
 | 
| 877 | 0 |                 err_ = JsonbErrType::E_DECIMAL_OVERFLOW; | 
| 878 | 0 |                 return false; | 
| 879 | 0 |             } | 
| 880 |  |  | 
| 881 | 1.06M |             if (ch == '.') {  Branch (881:17): [True: 47.8k, False: 1.01M]
 | 
| 882 | 47.8k |                 skipChar(in); // remove '.' | 
| 883 | 47.8k |                 return parseDouble(in, pbuf); | 
| 884 | 1.01M |             } else if (ch == 'E' || ch == 'e') {  Branch (884:24): [True: 0, False: 1.01M]
  Branch (884:37): [True: 438, False: 1.01M]
 | 
| 885 | 438 |                 skipChar(in); // remove 'E' | 
| 886 | 438 |                 return parseExponent(in, pbuf); | 
| 887 | 1.01M |             } else if (ch < '0' || ch > '9') {  Branch (887:24): [True: 22, False: 1.01M]
  Branch (887:36): [True: 74, False: 1.01M]
 | 
| 888 | 96 |                 err_ = JsonbErrType::E_INVALID_DECIMAL; | 
| 889 | 96 |                 return false; | 
| 890 | 96 |             } | 
| 891 |  |  | 
| 892 | 1.01M |             skipChar(in); | 
| 893 | 1.01M |             ch = in.peek(); | 
| 894 | 1.01M |         } | 
| 895 | 119k |         if (save_pos == pbuf) {  Branch (895:13): [True: 169, False: 119k]
 | 
| 896 | 169 |             err_ = JsonbErrType::E_INVALID_DECIMAL; // empty input | 
| 897 | 169 |             return false; | 
| 898 | 169 |         } | 
| 899 |  |  | 
| 900 | 119k |         *pbuf = 0; // set null-terminator | 
| 901 | 119k |         StringParser::ParseResult parse_result = StringParser::PARSE_SUCCESS; | 
| 902 | 119k |         int128_t val = | 
| 903 | 119k |                 StringParser::string_to_int<int128_t>(num_buf_, pbuf - num_buf_, &parse_result); | 
| 904 | 119k |         if (parse_result != StringParser::PARSE_SUCCESS) {  Branch (904:13): [True: 0, False: 119k]
 | 
| 905 | 0 |             VLOG_ROW << "debug string_to_int error for " << num_buf_ << " val=" << val | Line | Count | Source |  | 38 | 0 | #define VLOG_ROW VLOG(10) | 
 | 
| 906 | 0 |                      << " parse_result=" << parse_result; | 
| 907 | 0 |             err_ = JsonbErrType::E_DECIMAL_OVERFLOW; | 
| 908 | 0 |             return false; | 
| 909 | 0 |         } | 
| 910 |  |  | 
| 911 | 119k |         int size = 0; | 
| 912 | 119k |         if (val >= std::numeric_limits<int8_t>::min() &&   Branch (912:13): [True: 119k, False: 232]
 | 
| 913 | 119k |             val <= std::numeric_limits<int8_t>::max()) {  Branch (913:13): [True: 45.4k, False: 73.9k]
 | 
| 914 | 45.4k |             size = writer_.writeInt8((int8_t)val); | 
| 915 | 74.1k |         } else if (val >= std::numeric_limits<int16_t>::min() &&   Branch (915:20): [True: 73.9k, False: 232]
 | 
| 916 | 74.1k |                    val <= std::numeric_limits<int16_t>::max()) {  Branch (916:20): [True: 20.2k, False: 53.6k]
 | 
| 917 | 20.2k |             size = writer_.writeInt16((int16_t)val); | 
| 918 | 53.8k |         } else if (val >= std::numeric_limits<int32_t>::min() &&   Branch (918:20): [True: 53.6k, False: 232]
 | 
| 919 | 53.8k |                    val <= std::numeric_limits<int32_t>::max()) {  Branch (919:20): [True: 20.0k, False: 33.5k]
 | 
| 920 | 20.0k |             size = writer_.writeInt32((int32_t)val); | 
| 921 | 33.8k |         } else if (val >= std::numeric_limits<int64_t>::min() &&   Branch (921:20): [True: 33.8k, False: 0]
 | 
| 922 | 33.8k |                    val <= std::numeric_limits<int64_t>::max()) {  Branch (922:20): [True: 33.8k, False: 0]
 | 
| 923 | 33.8k |             size = writer_.writeInt64((int64_t)val); | 
| 924 | 33.8k |         } else { // INT128 | 
| 925 | 0 |             size = writer_.writeInt128(val); | 
| 926 | 0 |         } | 
| 927 |  |  | 
| 928 | 119k |         if (size == 0) {  Branch (928:13): [True: 0, False: 119k]
 | 
| 929 | 0 |             err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 930 | 0 |             return false; | 
| 931 | 0 |         } | 
| 932 |  |  | 
| 933 | 119k |         return true; | 
| 934 | 119k |     } | 
| 935 |  |  | 
| 936 |  |     // parse IEEE745 double precision | 
| 937 | 47.8k |     bool parseDouble(std::istream& in, char* pbuf) { | 
| 938 | 47.8k |         char* save_pos = pbuf; | 
| 939 | 47.8k |         char ch = in.peek(); | 
| 940 | 385k |         while (in.good() && !strchr(kJsonDelim, ch)) {  Branch (940:16): [True: 385k, False: 66]
  Branch (940:29): [True: 338k, False: 46.9k]
 | 
| 941 | 338k |             *(pbuf++) = ch; | 
| 942 | 338k |             if (pbuf == end_buf_) {  Branch (942:17): [True: 0, False: 338k]
 | 
| 943 | 0 |                 err_ = JsonbErrType::E_DOUBLE_OVERFLOW; | 
| 944 | 0 |                 return false; | 
| 945 | 0 |             } | 
| 946 |  |  | 
| 947 | 338k |             if (ch == 'e' || ch == 'E') {  Branch (947:17): [True: 788, False: 337k]
  Branch (947:30): [True: 0, False: 337k]
 | 
| 948 | 788 |                 skipChar(in); // remove 'E' | 
| 949 | 788 |                 return parseExponent(in, pbuf); | 
| 950 | 337k |             } else if (ch < '0' || ch > '9') {  Branch (950:24): [True: 0, False: 337k]
  Branch (950:36): [True: 11, False: 337k]
 | 
| 951 | 11 |                 err_ = JsonbErrType::E_INVALID_DECIMAL; | 
| 952 | 11 |                 return false; | 
| 953 | 11 |             } | 
| 954 |  |  | 
| 955 | 337k |             skipChar(in); | 
| 956 | 337k |             ch = in.peek(); | 
| 957 | 337k |         } | 
| 958 | 47.0k |         if (save_pos == pbuf) {  Branch (958:13): [True: 0, False: 47.0k]
 | 
| 959 | 0 |             err_ = JsonbErrType::E_INVALID_DECIMAL; // empty input | 
| 960 | 0 |             return false; | 
| 961 | 0 |         } | 
| 962 |  |  | 
| 963 | 47.0k |         *pbuf = 0; // set null-terminator | 
| 964 | 47.0k |         return internConvertBufferToDouble(num_buf_, pbuf - num_buf_); | 
| 965 | 47.0k |     } | 
| 966 |  |  | 
| 967 |  |     // parse the exponent part of a double number | 
| 968 | 1.22k |     bool parseExponent(std::istream& in, char* pbuf) { | 
| 969 | 1.22k |         char ch = in.peek(); | 
| 970 | 1.22k |         if (in.good()) {  Branch (970:13): [True: 1.22k, False: 0]
 | 
| 971 | 1.22k |             if (ch == '+' || ch == '-') {  Branch (971:17): [True: 798, False: 428]
  Branch (971:30): [True: 428, False: 0]
 | 
| 972 | 1.22k |                 *(pbuf++) = ch; | 
| 973 | 1.22k |                 if (pbuf == end_buf_) {  Branch (973:21): [True: 0, False: 1.22k]
 | 
| 974 | 0 |                     err_ = JsonbErrType::E_DOUBLE_OVERFLOW; | 
| 975 | 0 |                     return false; | 
| 976 | 0 |                 } | 
| 977 | 1.22k |                 skipChar(in); | 
| 978 | 1.22k |                 ch = in.peek(); | 
| 979 | 1.22k |             } | 
| 980 | 1.22k |         } | 
| 981 |  |  | 
| 982 | 1.22k |         char* save_pos = pbuf; | 
| 983 | 4.90k |         while (in.good() && !strchr(kJsonDelim, ch)) {  Branch (983:16): [True: 4.87k, False: 32]
  Branch (983:29): [True: 3.67k, False: 1.19k]
 | 
| 984 | 3.67k |             *(pbuf++) = ch; | 
| 985 | 3.67k |             if (pbuf == end_buf_) {  Branch (985:17): [True: 0, False: 3.67k]
 | 
| 986 | 0 |                 err_ = JsonbErrType::E_DOUBLE_OVERFLOW; | 
| 987 | 0 |                 return false; | 
| 988 | 0 |             } | 
| 989 |  |  | 
| 990 | 3.67k |             if (ch < '0' || ch > '9') {  Branch (990:17): [True: 0, False: 3.67k]
  Branch (990:29): [True: 0, False: 3.67k]
 | 
| 991 | 0 |                 err_ = JsonbErrType::E_INVALID_EXPONENT; | 
| 992 | 0 |                 return false; | 
| 993 | 0 |             } | 
| 994 |  |  | 
| 995 | 3.67k |             skipChar(in); | 
| 996 | 3.67k |             ch = in.peek(); | 
| 997 | 3.67k |         } | 
| 998 | 1.22k |         if (save_pos == pbuf) {  Branch (998:13): [True: 0, False: 1.22k]
 | 
| 999 | 0 |             err_ = JsonbErrType::E_INVALID_EXPONENT; // empty input | 
| 1000 | 0 |             return false; | 
| 1001 | 0 |         } | 
| 1002 |  |  | 
| 1003 | 1.22k |         *pbuf = 0; // set null-terminator | 
| 1004 | 1.22k |         return internConvertBufferToDouble(num_buf_, pbuf - num_buf_); | 
| 1005 | 1.22k |     } | 
| 1006 |  |  | 
| 1007 |  |     // call system function to parse double to string | 
| 1008 | 48.2k |     bool internConvertBufferToDouble(char* num_buf_, int len) { | 
| 1009 | 48.2k |         StringParser::ParseResult parse_result = StringParser::PARSE_SUCCESS; | 
| 1010 | 48.2k |         double val = StringParser::string_to_float<double>(num_buf_, len, &parse_result); | 
| 1011 | 48.2k |         if (parse_result != StringParser::PARSE_SUCCESS) {  Branch (1011:13): [True: 366, False: 47.9k]
 | 
| 1012 | 366 |             VLOG_ROW << "debug string_to_float error for " << num_buf_ << " val=" << val | Line | Count | Source |  | 38 | 0 | #define VLOG_ROW VLOG(10) | 
 | 
| 1013 | 0 |                      << " parse_result=" << parse_result; | 
| 1014 | 366 |             err_ = JsonbErrType::E_DECIMAL_OVERFLOW; | 
| 1015 | 366 |             return false; | 
| 1016 | 366 |         } | 
| 1017 |  |  | 
| 1018 | 47.9k |         if (writer_.writeDouble(val) == 0) {  Branch (1018:13): [True: 0, False: 47.9k]
 | 
| 1019 | 0 |             err_ = JsonbErrType::E_OUTPUT_FAIL; | 
| 1020 | 0 |             return false; | 
| 1021 | 0 |         } | 
| 1022 |  |  | 
| 1023 | 47.9k |         return true; | 
| 1024 | 47.9k |     } | 
| 1025 |  |  | 
| 1026 | 1.24M |     void trim(std::istream& in) { | 
| 1027 | 1.34M |         while (in.good() && strchr(kWhiteSpace, in.peek())) {  Branch (1027:16): [True: 1.34M, False: 451]
  Branch (1027:29): [True: 97.3k, False: 1.24M]
 | 
| 1028 | 97.3k |             skipChar(in); | 
| 1029 | 97.3k |         } | 
| 1030 | 1.24M |     } | 
| 1031 |  |  | 
| 1032 |  |     /* | 
| 1033 |  |    * Helper functions to keep track of characters read. | 
| 1034 |  |    * Do not rely on std::istream's tellg() which may not be implemented. | 
| 1035 |  |    */ | 
| 1036 |  |  | 
| 1037 | 7.85M |     char nextChar(std::istream& in) { | 
| 1038 | 7.85M |         ++stream_pos_; | 
| 1039 | 7.85M |         return in.get(); | 
| 1040 | 7.85M |     } | 
| 1041 |  |  | 
| 1042 | 1.96M |     void skipChar(std::istream& in) { | 
| 1043 | 1.96M |         ++stream_pos_; | 
| 1044 | 1.96M |         in.ignore(); | 
| 1045 | 1.96M |     } | 
| 1046 |  |  | 
| 1047 |  | private: | 
| 1048 |  |     JsonbWriterT<OS_TYPE> writer_; | 
| 1049 |  |     uint32_t stream_pos_; | 
| 1050 |  |     JsonbErrType err_; | 
| 1051 |  |     char num_buf_[512]; // buffer to hold number string | 
| 1052 |  |     const char* end_buf_ = num_buf_ + sizeof(num_buf_) - 1; | 
| 1053 |  |     uint32_t nesting_lvl_ = 0; | 
| 1054 |  | }; | 
| 1055 |  |  | 
| 1056 |  | typedef JsonbParserT<JsonbOutStream> JsonbParser; | 
| 1057 |  |  | 
| 1058 |  | } // namespace doris | 
| 1059 |  |  | 
| 1060 |  | #endif // JSONB_JSONBJSONPARSER_H |