variant variant_from_stream( T& in, uint32_t depth ) { depth++; FC_ASSERT( depth <= JSON_MAX_RECURSION_DEPTH ); skip_white_space( in, depth ); variant var; while( true ) { signed char c = in.peek(); switch( c ) { case ' ': case '\t': case '\n': case '\r': in.get(); continue; case '"': return stringFromStream( in, depth ); case '{': return objectFromStream<T, parser_type>( in, depth ); case '[': return arrayFromStream<T, parser_type>( in, depth ); case '-': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return number_from_stream<T, parser_type>( in, depth ); // null, true, false, or 'warning' / string case 'n': case 't': case 'f': return token_from_stream( in, depth ); case 0x04: // ^D end of transmission case EOF: case 0: FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"", ("c", c)("s", stringFromToken( in, depth )) ); } } return variant(); }
variant variant_from_stream( T& in, uint32_t max_depth ) { if( max_depth == 0 ) FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" ); skip_white_space(in); signed char c = in.peek(); switch( c ) { case '"': return json_relaxed::stringFromStream<T, strict>( in ); case '{': return json_relaxed::objectFromStream<T, strict>( in, max_depth - 1 ); case '[': return json_relaxed::arrayFromStream<T, strict>( in, max_depth - 1 ); case '-': case '+': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return json_relaxed::numberFromStream<T, strict>( in ); // null, true, false, or 'warning' / string case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case '/': return json_relaxed::wordFromStream<T, strict>( in ); case 0x04: // ^D end of transmission case EOF: FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); case 0: default: FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"", ("c", c)("s", stringFromToken(in)) ); } }
variant variant_from_stream( T& in, uint32_t max_depth ) { if( max_depth == 0 ) FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" ); skip_white_space(in); signed char c = in.peek(); switch( c ) { case '"': return stringFromStream( in ); case '{': return objectFromStream<T, parser_type>( in, max_depth - 1 ); case '[': return arrayFromStream<T, parser_type>( in, max_depth - 1 ); case '-': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return number_from_stream<T, parser_type>( in ); // null, true, false, or 'warning' / string case 'n': case 't': case 'f': return token_from_stream( in ); case 0x04: // ^D end of transmission case EOF: FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); case 0: if( parser_type == fc::json::broken_nul_parser ) return variant(); FALLTHROUGH default: FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"", ("c", c)("s", stringFromToken(in)) ); } }
variant token_from_stream( T& in ) { std::stringstream ss; ss.exceptions( std::ifstream::badbit ); bool received_eof = false; bool done = false; try { char c; while((c = in.peek()) && !done) { switch( c ) { case 'n': case 'u': case 'l': case 't': case 'r': case 'e': case 'f': case 'a': case 's': ss.put( in.get() ); break; default: done = true; break; } } } catch (fc::eof_exception&) { received_eof = true; } catch (const std::ios_base::failure&) { received_eof = true; } // we can get here either by processing a delimiter as in "null," // an EOF like "null<EOF>", or an invalid token like "nullZ" std::string str = ss.str(); if( str == "null" ) return variant(); if( str == "true" ) return true; if( str == "false" ) return false; else { if (received_eof) { if (str.empty()) FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF" ); else return str; } else { // if we've reached this point, we've either seen a partial // token ("tru<EOF>") or something our simple parser couldn't // make out ("falfe") // A strict JSON parser would signal this as an error, but we // will just treat the malformed token as an un-quoted string. return str + stringFromToken(in); } } }
variant number_from_stream( T& in ) { fc::stringstream ss; bool dot = false; bool neg = false; if( in.peek() == '-') { neg = true; ss.put( in.get() ); } bool done = false; try { char c; while((c = in.peek()) && !done) { switch( c ) { case '.': if (dot) FC_THROW_EXCEPTION(parse_error_exception, "Can't parse a number with two decimal places"); dot = true; FALLTHROUGH case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ss.put( in.get() ); break; default: if( isalnum( c ) ) { return ss.str() + stringFromToken( in ); } done = true; break; } } } catch (fc::eof_exception&) { // EOF ends the loop } catch (const std::ios_base::failure&) { // read error ends the loop } std::string str = ss.str(); if (str == "-." || str == "." || str == "-") // check the obviously wrong things we could have encountered FC_THROW_EXCEPTION(parse_error_exception, "Can't parse token \"${token}\" as a JSON numeric constant", ("token", str)); if( dot ) return #ifdef WITH_EXOTIC_JSON_PARSERS parser_type == json::legacy_parser_with_string_doubles ? variant(str) : #endif variant(to_double(str)); if( neg ) return to_int64(str); return to_uint64(str); }