static int __number(JSAXContextRef ctxt, const char *number, size_t len) { JParser *p = static_cast<JParser *>(jsax_getContext(ctxt)); switch (SaxBounce::conversionToUse(p)) { case JParser::JNUM_CONV_RAW: return SaxBounce::n(p, std::string(number, len)); case JParser::JNUM_CONV_NATIVE: { jvalue_ref toConv = jnumber_create_unsafe(j_str_to_buffer(number, len), NULL); int64_t asInteger; double asFloat; ConversionResultFlags toFloatErrors; if (CONV_OK == jnumber_get_i64(toConv, &asInteger)) { j_release(&toConv); return SaxBounce::n(p, (asInteger)); } toFloatErrors = jnumber_get_f64(toConv, &asFloat); j_release(&toConv); return SaxBounce::n(p, asFloat, toFloatErrors); } default: PJ_LOG_ERR("PBNJSON_NO_NUMS_TYPE", 0, "Actual parser hasn't told us a valid type for how it wants numbers presented to it"); return 0; } }
static inline DomInfo* getDOMContext(JSAXContextRef ctxt) { return (DomInfo*)jsax_getContext(ctxt); }
static void *jsaxparser_get_sax_context(jsaxparser_ref parser) { SANITY_CHECK_POINTER(parser); return jsax_getContext(&parser->internalCtxt); }
static bool jsax_parse_internal(PJSAXCallbacks *parser, raw_buffer input, JSchemaInfoRef schemaInfo, void **ctxt, bool logError, bool comments) { yajl_status parseResult; PJ_LOG_TRACE("Parsing '%.*s'", RB_PRINTF(input)); if (parser == NULL) parser = &no_callbacks; if (jis_null_schema(schemaInfo->m_schema)) { PJ_LOG_WARN("Cannot match against schema that matches nothing: Schema pointer = %p", schemaInfo->m_schema); return false; } if (schemaInfo->m_schema == jschema_all()) { PJ_LOG_DBG("Using default empty schema for matching"); } else { if (schemaInfo->m_resolver == NULL) { PJ_LOG_DBG("No resolver specified for the schema. Make sure %p doesn't contain any external references", schemaInfo->m_schema); } } if (schemaInfo->m_errHandler == NULL) schemaInfo->m_errHandler = &null_err_handler; #ifdef _DEBUG logError = true; #endif yajl_callbacks yajl_cb = { (pj_yajl_null)parser->m_null, // yajl_null (pj_yajl_boolean)parser->m_boolean, // yajl_boolean NULL, // yajl_integer NULL, // yajl_double (pj_yajl_number)parser->m_number, // yajl_number (pj_yajl_string)parser->m_string, // yajl_stirng (pj_yajl_start_map)parser->m_objStart, // yajl_start_map (pj_yajl_map_key)parser->m_objKey, // yajl_map_key (pj_yajl_end_map)parser->m_objEnd, // yajl_end_map (pj_yajl_start_array)parser->m_arrStart, // yajl_start_array (pj_yajl_end_array)parser->m_arrEnd, // yajl_end_array }; yajl_parser_config yajl_opts = { comments, // comments are not allowed 0, // currently only UTF-8 will be supported for input. }; PJSAXContext internalCtxt = { .ctxt = (ctxt != NULL ? *ctxt : NULL), .m_handlers = &yajl_cb, .m_errors = schemaInfo->m_errHandler, }; #if !BYPASS_SCHEMA internalCtxt.m_validation = jschema_init(schemaInfo); if (internalCtxt.m_validation == NULL) { PJ_LOG_WARN("Failed to initialize validation state machine"); return false; } #endif yajl_handle handle = yajl_alloc(&my_bounce, &yajl_opts, NULL, &internalCtxt); parseResult = yajl_parse(handle, (unsigned char *)input.m_str, input.m_len); if (ctxt != NULL) *ctxt = jsax_getContext(&internalCtxt); switch (parseResult) { case yajl_status_ok: break; case yajl_status_client_canceled: if (ERR_HANDLER_FAILED(schemaInfo->m_errHandler, m_unknown, &internalCtxt)) goto parse_failure; PJ_LOG_WARN("Client claims they handled an unknown error in '%.*s'", (int)input.m_len, input.m_str); break; case yajl_status_insufficient_data: if (ERR_HANDLER_FAILED(schemaInfo->m_errHandler, m_parser, &internalCtxt)) goto parse_failure; PJ_LOG_WARN("Client claims they handled incomplete JSON input provided '%.*s'", (int)input.m_len, input.m_str); break; case yajl_status_error: default: if (ERR_HANDLER_FAILED(schemaInfo->m_errHandler, m_unknown, &internalCtxt)) goto parse_failure; PJ_LOG_WARN("Client claims they handled an unknown error in '%.*s'", (int)input.m_len, input.m_str); break; } #if !BYPASS_SCHEMA jschema_state_release(&internalCtxt.m_validation); #endif #ifndef NDEBUG assert(yajl_get_error(handle, 0, NULL, 0) == NULL); #endif yajl_free(handle); return true; parse_failure: if (UNLIKELY(logError)) { unsigned char *errMsg = yajl_get_error(handle, 1, (unsigned char *)input.m_str, input.m_len); PJ_LOG_WARN("Parser reason for failure:\n'%s'", errMsg); yajl_free_error(handle, errMsg); } #if !BYPASS_SCHEMA jschema_state_release(&internalCtxt.m_validation); #endif yajl_free(handle); return false; } bool jsax_parse_ex(PJSAXCallbacks *parser, raw_buffer input, JSchemaInfoRef schemaInfo, void **ctxt, bool logError) { return jsax_parse_internal(parser, input, schemaInfo, ctxt, logError, false); } bool jsax_parse(PJSAXCallbacks *parser, raw_buffer input, JSchemaInfoRef schema) { assert(schema != NULL); return jsax_parse_ex(parser, input, schema, NULL, false); }
static int __string(JSAXContextRef ctxt, const char *str, size_t len) { return SaxBounce::s(static_cast<JParser *>(jsax_getContext(ctxt)), std::string(str, len)); }
static int __arr_end(JSAXContextRef ctxt) { return SaxBounce::ac(static_cast<JParser *>(jsax_getContext(ctxt))); }
static int __obj_key(JSAXContextRef ctxt, const char *key, size_t len) { return SaxBounce::ok(static_cast<JParser *>(jsax_getContext(ctxt)), std::string(key, len)); }
static int __obj_start(JSAXContextRef ctxt) { return SaxBounce::oo(static_cast<JParser *>(jsax_getContext(ctxt))); }
static int __jnull(JSAXContextRef ctxt) { return SaxBounce::N(static_cast<JParser *>(jsax_getContext(ctxt))); }
static int __boolean(JSAXContextRef ctxt, bool value) { return SaxBounce::b(static_cast<JParser *>(jsax_getContext(ctxt)), value); }