コード例 #1
0
ファイル: jparse_stream.c プロジェクト: liuzhiping/libpbnjson
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);
}
コード例 #2
0
ファイル: jparse_stream.c プロジェクト: FreeWebOS/libpbnjson
bool jsax_parse_ex(PJSAXCallbacks *parser, raw_buffer input, JSchemaInfoRef schemaInfo, void **ctxt)
{
	return jsax_parse_internal(parser, input, schemaInfo, ctxt);
}
コード例 #3
0
ファイル: jparse_stream.c プロジェクト: liuzhiping/libpbnjson
jvalue_ref jdom_parse_ex(raw_buffer input, JDOMOptimizationFlags optimizationMode, JSchemaInfoRef schemaInfo, bool allowComments)
{
	jvalue_ref result;
	PJSAXCallbacks callbacks = {
		dom_object_start, // m_objStart
		dom_object_key, // m_objKey
		dom_object_end, // m_objEnd

		dom_array_start, // m_arrStart
		dom_array_end, // m_arrEnd

		dom_string, // m_string
		dom_number, // m_number
		dom_boolean, // m_boolean
		dom_null, // m_null
	};
	DomInfo *topLevelContext = calloc(1, sizeof(struct DomInfo));
	CHECK_POINTER_RETURN_NULL(topLevelContext);
	void *domCtxt = topLevelContext;

	bool parsedOK = jsax_parse_internal(&callbacks, input, schemaInfo, &domCtxt, false /* don't log errors*/, allowComments);

	result = topLevelContext->m_value;

	if (domCtxt != topLevelContext) {
		// unbalanced state machine (probably a result of parser failure)
		// cleanup so there's no memory leak
		PJ_LOG_ERR("state machine indicates invalid input");
		parsedOK = false;
		DomInfo *ctxt = domCtxt;
		DomInfo *parentCtxt;
		while (ctxt) {
#ifdef _DEBUG
			if (ctxt == topLevelContext) {
				assert(ctxt->m_prev == NULL);
			} else {
				assert(ctxt->m_prev != NULL);
			}
#endif

			parentCtxt = ctxt->m_prev;

			// top-level json value can only be an object or array,
			// thus we do not need to check that we aren't releasing topLevelContext->m_value.
			// the only other object type that m_value will contain is string (representing the key of an object).
			//if (ctxt->m_value && !jis_array(ctxt->m_value) && !jis_object(ctxt->m_value)) {
			if (ctxt->m_value && jis_string(ctxt->m_value)) {
				j_release(&ctxt->m_value);
			}
			free(ctxt);

			ctxt = parentCtxt;
		}
		topLevelContext = NULL;
	}

	free(topLevelContext);

	if (!parsedOK) {
		PJ_LOG_ERR("Parser failure");
		j_release(&result);
		return jnull();
	}

	if (result == NULL)
		PJ_LOG_ERR("result was NULL - unexpected. input was '%.*s'", (int)input.m_len, input.m_str);
	else if (result == jnull())
		PJ_LOG_WARN("result was NULL JSON - unexpected.  input was '%.*s'", (int)input.m_len, input.m_str);
	else {
		if ((optimizationMode & (DOMOPT_INPUT_NOCHANGE | DOMOPT_INPUT_OUTLIVES_DOM | DOMOPT_INPUT_NULL_TERMINATED)) && input.m_str[input.m_len] == '\0') {
			result->m_toString = (char *)input.m_str;
			result->m_toStringDealloc = NULL;
		}
	}

	return result;
}