int dom_null(JSAXContextRef ctxt) { DomInfo *data = getDOMContext(ctxt); // no handle to the context CHECK_CONDITION_RETURN_VALUE(data == NULL, 0, "null encountered without any context"); // no parent node CHECK_CONDITION_RETURN_VALUE(data->m_prev == NULL, 0, "unexpected state - how is this possible?"); SANITY_CHECK_POINTER(ctxt); SANITY_CHECK_POINTER(data->m_prev); if (data->m_value == NULL) { CHECK_CONDITION_RETURN_VALUE(!jis_array(data->m_prev->m_value), 0, "Improper place for null"); jarray_append(data->m_prev->m_value, jnull()); } else if (jis_string(data->m_value)) { CHECK_CONDITION_RETURN_VALUE(!jis_object(data->m_prev->m_value), 0, "Improper place for null"); jobject_put(data->m_prev->m_value, data->m_value, jnull()); data->m_value = NULL; } else { PJ_LOG_ERR("PBNJSON_NULL_VALUE_WO_KEY", 0, "value portion of key-value pair without a key"); return 0; } return 1; }
static bool jobject_to_string_append (jvalue_ref jref, JStreamRef generating) { SANITY_CHECK_POINTER(jref); if (UNLIKELY(!generating->o_begin (generating))) { PJ_LOG_ERR("Schema validation error, objects are not allowed."); return false; } if (!jis_object (jref)) { const char *asStr = jvalue_tostring_internal_layer2 (jref, NULL, false); generating->string (generating, J_CSTR_TO_BUF("Internal error - not an object")); generating->string (generating, j_cstr_to_buffer(asStr)); // create invalid JSON on purpose return false; } jobject_iter it; jobject_iter_init(&it, jref); jobject_key_value key_value; while (jobject_iter_next(&it, &key_value)) { assert(jis_string(key_value.key)); if(UNLIKELY(!key_value_to_string_append(key_value, generating))) { return false; } } if (UNLIKELY(!generating->o_end (generating))) { PJ_LOG_ERR("Schema validation error, object did not validate against schema"); return false; } return true; }
int dom_string(JSAXContextRef ctxt, const char *string, size_t stringLen) { DomInfo *data = getDOMContext(ctxt); CHECK_CONDITION_RETURN_VALUE(data == NULL, 0, "string encountered without any context"); CHECK_CONDITION_RETURN_VALUE(data->m_prev == NULL, 0, "unexpected state - how is this possible?"); jvalue_ref jstr = createOptimalString(data->m_optInformation, string, stringLen); if (data->m_value == NULL) { if (UNLIKELY(!jis_array(data->m_prev->m_value))) { PJ_LOG_ERR("PBNJSON_ARR_MISPLACED_STR", 1, PMLOGKS("STRING", string), "Improper place for string"); j_release(&jstr); return 0; } jarray_append(data->m_prev->m_value, jstr); } else if (jis_string(data->m_value)) { if (UNLIKELY(!jis_object(data->m_prev->m_value))) { PJ_LOG_ERR("PBNJSON_OBJ_MISPLACED_STR", 1, PMLOGKS("STRING", string), "Improper place for string"); j_release(&jstr); return 0; } jobject_put(data->m_prev->m_value, data->m_value, jstr); data->m_value = NULL; } else { PJ_LOG_ERR("PBNJSON_STR_VALUE_WO_KEY", 1, PMLOGKS("STRING", string), "value portion of key-value pair without a key"); return 0; } return 1; }
int dom_number(JSAXContextRef ctxt, const char *number, size_t numberLen) { DomInfo *data = getDOMContext(ctxt); jvalue_ref jnum; CHECK_CONDITION_RETURN_VALUE(data == NULL, 0, "number encountered without any context"); CHECK_CONDITION_RETURN_VALUE(data->m_prev == NULL, 0, "unexpected state - how is this possible?"); CHECK_POINTER_RETURN_VALUE(number, 0); CHECK_CONDITION_RETURN_VALUE(numberLen == 0, 0, "unexpected - numeric string doesn't actually contain a number"); jnum = createOptimalNumber(data->m_optInformation, number, numberLen); if (data->m_value == NULL) { if (UNLIKELY(!jis_array(data->m_prev->m_value))) { PJ_LOG_ERR("PBNJSON_ARR_MISPLACED_NUM", 1, PMLOGKS("NUM", number), "Improper place for number"); j_release(&jnum); return 0; } jarray_append(data->m_prev->m_value, jnum); } else if (jis_string(data->m_value)) { if (UNLIKELY(!jis_object(data->m_prev->m_value))) { PJ_LOG_ERR("PBNJSON_OBJ_MISPLACED_NUM", 1, PMLOGKS("NUM", number), "Improper place for number"); j_release(&jnum); return 0; } jobject_put(data->m_prev->m_value, data->m_value, jnum); data->m_value = NULL; } else { PJ_LOG_ERR("PBNJSON_NUM_VALUE_WO_KEY", 1, PMLOGKS("NUM", number), "value portion of key-value pair without a key"); return 0; } return 1; }
bool jsax_parse_inject(JSAXContextRef ctxt, jvalue_ref key, jvalue_ref value) { assert (jis_string(key)); assert (jis_object(value)); return jsax_parse_inject_internal(ctxt, key, value); }
static int dom_object_start(JSAXContextRef ctxt) { DomInfo *data = getDOMContext(ctxt); jvalue_ref newParent; DomInfo *newChild; CHECK_CONDITION_RETURN_VALUE(data == NULL, 0, "object encountered without any context"); newParent = jobject_create(); newChild = calloc(1, sizeof(DomInfo)); if (UNLIKELY(newChild == NULL || jis_null(newParent))) { PJ_LOG_ERR("Failed to allocate space for new object"); j_release(&newParent); free(newChild); return 0; } newChild->m_prev = data; newChild->m_optInformation = data->m_optInformation; changeDOMContext(ctxt, newChild); if (data->m_prev != NULL) { if (jis_array(data->m_prev->m_value)) { assert(data->m_value == NULL); jarray_append(data->m_prev->m_value, newParent); } else { assert(jis_object(data->m_prev->m_value)); CHECK_CONDITION_RETURN_VALUE(!jis_string(data->m_value), 0, "improper place for a child object"); jobject_put(data->m_prev->m_value, data->m_value, newParent); } } // not using reference counting here on purpose data->m_value = newParent; return 1; }
char* luna_service_message_get_string(jvalue_ref parsed_obj, const char *name, const char *default_value) { jvalue_ref string_obj = NULL; raw_buffer string_buf; if (!jobject_get_exists(parsed_obj, j_str_to_buffer(name, strlen(name)), &string_obj) || !jis_string(string_obj)) return g_strdup(default_value); string_buf = jstring_get(string_obj); return g_strdup(string_buf.m_str); }
int dom_boolean(JSAXContextRef ctxt, bool value) { DomInfo *data = getDOMContext(ctxt); CHECK_CONDITION_RETURN_VALUE(data == NULL, 0, "boolean encountered without any context"); CHECK_CONDITION_RETURN_VALUE(data->m_prev == NULL, 0, "unexpected state - how is this possible?"); if (data->m_value == NULL) { CHECK_CONDITION_RETURN_VALUE(!jis_array(data->m_prev->m_value), 0, "Improper place for boolean"); jarray_append(data->m_prev->m_value, jboolean_create(value)); } else if (jis_string(data->m_value)) { CHECK_CONDITION_RETURN_VALUE(!jis_object(data->m_prev->m_value), 0, "Improper place for boolean"); jobject_put(data->m_prev->m_value, data->m_value, jboolean_create(value)); data->m_value = NULL; } else { PJ_LOG_ERR("PBNJSON_BOOL_VALUE_WO_KEY", 0, "value portion of key-value pair without a key"); return 0; } return 1; }
int dom_object_start(JSAXContextRef ctxt) { DomInfo *data = getDOMContext(ctxt); jvalue_ref newParent; DomInfo *newChild; CHECK_CONDITION_RETURN_VALUE(data == NULL, 0, "object encountered without any context"); newParent = jobject_create(); newChild = calloc(1, sizeof(DomInfo)); if (UNLIKELY(newChild == NULL || !jis_valid(newParent))) { PJ_LOG_ERR("PBNJSON_OBJ_CALLOC_ERR", 0, "Failed to allocate space for new object"); j_release(&newParent); free(newChild); return 0; } newChild->m_prev = data; newChild->m_optInformation = data->m_optInformation; changeDOMContext(ctxt, newChild); if (data->m_prev != NULL) { if (jis_array(data->m_prev->m_value)) { assert(data->m_value == NULL); jarray_append(data->m_prev->m_value, jvalue_copy(newParent)); } else { assert(jis_object(data->m_prev->m_value)); if (UNLIKELY(!jis_string(data->m_value))) { PJ_LOG_ERR("PBNJSON_OBJ_MISPLACED_CHILD", 0, "improper place for a child object"); j_release(&newParent); return 0; } jobject_put(data->m_prev->m_value, data->m_value, jvalue_copy(newParent)); } } data->m_value = newParent; return 1; }
bool JValue::isString() const { return jis_string(m_jval); }
bool JValue::remove(const JValue &key) { if (!jis_string(key.m_jval)) return false; return jobject_remove(m_jval, jstring_get_fast(key.m_jval)); }
bool get_property_cb(LSHandle *handle, LSMessage *message, void *user_data) { jvalue_ref parsed_obj = NULL; jvalue_ref keys_obj = NULL; jvalue_ref reply_obj = NULL; jvalue_ref props_obj = NULL; jvalue_ref prop_obj = NULL; char *payload, value[PROP_VALUE_MAX]; int n; raw_buffer key_buf; payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } if (!jobject_get_exists(parsed_obj, J_CSTR_TO_BUF("keys"), &keys_obj) || !jis_array(keys_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } reply_obj = jobject_create(); props_obj = jarray_create(NULL); for (n = 0; n < jarray_size(keys_obj); n++) { jvalue_ref key_obj = jarray_get(keys_obj, n); if (!jis_string(key_obj)) continue; key_buf = jstring_get(key_obj); if (strlen(key_buf.m_str) == 0) continue; property_get(key_buf.m_str, value, ""); prop_obj = jobject_create(); jobject_put(prop_obj, jstring_create(key_buf.m_str), jstring_create(value)); jarray_append(props_obj, prop_obj); } jobject_put(reply_obj, J_CSTR_TO_JVAL("properties"), props_obj); jobject_put(reply_obj, J_CSTR_TO_JVAL("returnValue"), jboolean_create(true)); if (!luna_service_message_validate_and_send(handle, message, reply_obj)) goto cleanup; cleanup: if (!jis_null(parsed_obj)) j_release(&parsed_obj); if (!jis_null(reply_obj)) j_release(&reply_obj); return true; }
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; }