diff --git a/winpr/WinPRConfig.cmake.in b/winpr/WinPRConfig.cmake.in index 00c69c984..ccc3a8869 100644 --- a/winpr/WinPRConfig.cmake.in +++ b/winpr/WinPRConfig.cmake.in @@ -1,9 +1,18 @@ +include(CMakeFindDependencyMacro) +if(NOT "@WITH_JSON_DISABLED@" AND NOT "@BUILD_SHARED_LIBS@") + if("@JSONC_FOUND@" AND NOT "@WITH_CJSON_REQUIRED@") + find_dependency(JSONC) + elseif("@CJSON_FOUND@") + find_dependency(cJSON) + endif() +endif() @PACKAGE_INIT@ set(WinPR_VERSION_MAJOR "@WINPR_VERSION_MAJOR@") set(WinPR_VERSION_MINOR "@WINPR_VERSION_MINOR@") set(WinPR_VERSION_REVISION "@WINPR_VERSION_REVISION@") +set(WITH_WINPR_JSON "@WITH_WINPR_JSON@") set_and_check(WinPR_INCLUDE_DIR "@PACKAGE_WINPR_INCLUDE_DIR@") diff --git a/winpr/include/config/config.h.in b/winpr/include/config/config.h.in index 8d289aa28..e233e56d4 100644 --- a/winpr/include/config/config.h.in +++ b/winpr/include/config/config.h.in @@ -34,6 +34,8 @@ #cmakedefine WITH_INTERNAL_MD4 #cmakedefine WITH_INTERNAL_MD5 +#cmakedefine WITH_WINPR_JSON + #cmakedefine WITH_DEBUG_NTLM #cmakedefine WITH_DEBUG_THREADS #cmakedefine WITH_DEBUG_EVENTS diff --git a/winpr/include/winpr/json.h b/winpr/include/winpr/json.h new file mode 100644 index 000000000..7e276c455 --- /dev/null +++ b/winpr/include/winpr/json.h @@ -0,0 +1,93 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * JSON parser wrapper + * + * Copyright 2024 Armin Novak + * Copyright 2024 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WINPR_UTILS_JSON +#define WINPR_UTILS_JSON + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef void WINPR_JSON; + + WINPR_API int WINPR_JSON_version(char* buffer, size_t len); + + WINPR_API WINPR_JSON* WINPR_JSON_Parse(const char* value); + WINPR_API WINPR_JSON* WINPR_JSON_ParseWithLength(const char* value, size_t buffer_length); + + WINPR_API void WINPR_JSON_Delete(WINPR_JSON* item); + + WINPR_API size_t WINPR_JSON_GetArraySize(const WINPR_JSON* array); + WINPR_API WINPR_JSON* WINPR_JSON_GetArrayItem(const WINPR_JSON* array, size_t index); + + WINPR_API WINPR_JSON* WINPR_JSON_GetObjectItem(const WINPR_JSON* object, const char* string); + WINPR_API WINPR_JSON* WINPR_JSON_GetObjectItemCaseSensitive(const WINPR_JSON* object, + const char* string); + WINPR_API BOOL WINPR_JSON_HasObjectItem(const WINPR_JSON* object, const char* string); + + WINPR_API const char* WINPR_JSON_GetErrorPtr(void); + + WINPR_API const char* WINPR_JSON_GetStringValue(WINPR_JSON* item); + WINPR_API double WINPR_JSON_GetNumberValue(const WINPR_JSON* item); + + WINPR_API BOOL WINPR_JSON_IsInvalid(const WINPR_JSON* item); + WINPR_API BOOL WINPR_JSON_IsFalse(const WINPR_JSON* item); + WINPR_API BOOL WINPR_JSON_IsTrue(const WINPR_JSON* item); + WINPR_API BOOL WINPR_JSON_IsBool(const WINPR_JSON* item); + WINPR_API BOOL WINPR_JSON_IsNull(const WINPR_JSON* item); + WINPR_API BOOL WINPR_JSON_IsNumber(const WINPR_JSON* item); + WINPR_API BOOL WINPR_JSON_IsString(const WINPR_JSON* item); + WINPR_API BOOL WINPR_JSON_IsArray(const WINPR_JSON* item); + WINPR_API BOOL WINPR_JSON_IsObject(const WINPR_JSON* item); + + WINPR_API WINPR_JSON* WINPR_JSON_CreateNull(void); + WINPR_API WINPR_JSON* WINPR_JSON_CreateTrue(void); + WINPR_API WINPR_JSON* WINPR_JSON_CreateFalse(void); + WINPR_API WINPR_JSON* WINPR_JSON_CreateBool(BOOL boolean); + WINPR_API WINPR_JSON* WINPR_JSON_CreateNumber(double num); + WINPR_API WINPR_JSON* WINPR_JSON_CreateString(const char* string); + WINPR_API WINPR_JSON* WINPR_JSON_CreateArray(void); + WINPR_API WINPR_JSON* WINPR_JSON_CreateObject(void); + + WINPR_API WINPR_JSON* WINPR_JSON_AddNullToObject(WINPR_JSON* object, const char* name); + WINPR_API WINPR_JSON* WINPR_JSON_AddTrueToObject(WINPR_JSON* object, const char* name); + WINPR_API WINPR_JSON* WINPR_JSON_AddFalseToObject(WINPR_JSON* object, const char* name); + WINPR_API WINPR_JSON* WINPR_JSON_AddBoolToObject(WINPR_JSON* object, const char* name, + BOOL boolean); + WINPR_API WINPR_JSON* WINPR_JSON_AddNumberToObject(WINPR_JSON* object, const char* name, + double number); + WINPR_API WINPR_JSON* WINPR_JSON_AddStringToObject(WINPR_JSON* object, const char* name, + const char* string); + WINPR_API WINPR_JSON* WINPR_JSON_AddObjectToObject(WINPR_JSON* object, const char* name); + WINPR_API WINPR_JSON* WINPR_JSON_AddArrayToObject(WINPR_JSON* object, const char* name); + + WINPR_API char* WINPR_JSON_Print(WINPR_JSON* item); + WINPR_API char* WINPR_JSON_PrintUnformatted(WINPR_JSON* item); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 91c7353e8..4b5c54aa9 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -16,6 +16,7 @@ # limitations under the License. include(CheckFunctionExists) +include(CMakeDependentOption) set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -185,6 +186,42 @@ if (WINPR_HAVE_UNWIND_H) endif() endif() +option(WITH_JSON_DISABLED "Build without any JSON support" OFF) +CMAKE_DEPENDENT_OPTION(WITH_CJSON_REQUIRED "Build with cJSON (fail if not found)" OFF "NOT WITH_JSON_DISABLED" OFF) +CMAKE_DEPENDENT_OPTION(WITH_JSONC_REQUIRED "Build with JSON-C (fail if not found)" OFF "NOT WITH_JSON_DISABLED" OFF) +if (NOT WITH_JSON_DISABLED) + if (WITH_CJSON_REQUIRED) + find_package(cJSON REQUIRED) + else() + find_package(cJSON) + endif() + if (WITH_JSONC_REQUIRED) + find_package(JSONC REQUIRED) + else() + find_package(JSONC) + endif() + + if (JSONC_FOUND AND NOT WITH_CJSON_REQUIRED) + winpr_library_add_private(${JSONC_LIBRARIES}) + winpr_include_directory_add(${JSONC_INCLUDE_DIRS}) + winpr_definition_add(-DWITH_JSONC) + set(WITH_WINPR_JSON ON CACHE INTERNAL "internal") + elseif (CJSON_FOUND) + winpr_library_add_private(${CJSON_LIBRARIES}) + winpr_include_directory_add(${CJSON_INCLUDE_DIRS}) + winpr_definition_add(-DWITH_CJSON) + set(WITH_WINPR_JSON ON CACHE INTERNAL "internal") + else() + set(WITH_WINPR_JSON OFF CACHE INTERNAL "internal") + message("compiling without JSON support. Install cJSON or json-c to enable") + endif() +else() + set(WITH_WINPR_JSON OFF CACHE INTERNAL "internal") + message("forced compile without JSON support. Set -DWITH_JSON_DISABLED=OFF to enable compile time detection") +endif() + +winpr_module_add(json/json.c) + winpr_module_add(${SRCS} ${COLLECTIONS_SRCS} ${WLOG_SRCS} diff --git a/winpr/libwinpr/utils/json/json.c b/winpr/libwinpr/utils/json/json.c new file mode 100644 index 000000000..4c84812c4 --- /dev/null +++ b/winpr/libwinpr/utils/json/json.c @@ -0,0 +1,651 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * JSON parser wrapper + * + * Copyright 2024 Armin Novak + * Copyright 2024 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include +#include + +#if defined(WITH_CJSON) +#include +#endif +#if defined(WITH_JSONC) +#include +#endif + +#if defined(WITH_CJSON) +#if CJSON_VERSION_MAJOR == 1 +#if CJSON_VERSION_MINOR <= 7 +#if CJSON_VERSION_PATCH < 13 +#define USE_CJSON_COMPAT +#endif +#endif +#endif +#endif + +#if defined(USE_CJSON_COMPAT) +static double cJSON_GetNumberValue(const cJSON* const prop) +{ +#ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#define COMPAT_NAN_UNDEF +#else +#define NAN 0.0 / 0.0 +#define COMPAT_NAN_UNDEF +#endif +#endif + + if (!cJSON_IsNumber(prop)) + return NAN; + char* val = cJSON_GetStringValue(prop); + if (!val) + return NAN; + + errno = 0; + char* endptr = NULL; + double dval = strtod(val, &endptr); + if (val == endptr) + return NAN; + if (endptr != NULL) + return NAN; + if (errno != 0) + return NAN; + return dval; + +#ifdef COMPAT_NAN_UNDEF +#undef NAN +#endif +} + +static cJSON* cJSON_ParseWithLength(const char* value, size_t buffer_length) +{ + // Check for string '\0' termination. + const size_t slen = strnlen(value, buffer_length); + if (slen >= buffer_length) + { + if (value[buffer_length] != '\0') + return NULL; + } + return cJSON_Parse(value); +} +#endif + +int WINPR_JSON_version(char* buffer, size_t len) +{ +#if defined(WITH_JSONC) + return _snprintf(buffer, len, "json-c %s", json_c_version()); +#elif defined(WITH_CJSON) + return _snprintf(buffer, len, "cJSON %s", cJSON_Version()); +#else + return _snprintf(buffer, len, "JSON support not available"); +#endif +} + +WINPR_JSON* WINPR_JSON_Parse(const char* value) +{ +#if defined(WITH_JSONC) + return json_tokener_parse(value); +#elif defined(WITH_CJSON) + return cJSON_Parse(value); +#else + WINPR_UNUSED(value); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_ParseWithLength(const char* value, size_t buffer_length) +{ +#if defined(WITH_JSONC) + WINPR_ASSERT(buffer_length <= INT_MAX); + json_tokener* tok = json_tokener_new(); + if (!tok) + return NULL; + json_object* obj = json_tokener_parse_ex(tok, value, (int)buffer_length); + json_tokener_free(tok); + return obj; +#elif defined(WITH_CJSON) + return cJSON_ParseWithLength(value, buffer_length); +#else + WINPR_UNUSED(value); + WINPR_UNUSED(buffer_length); + return NULL; +#endif +} + +void WINPR_JSON_Delete(WINPR_JSON* item) +{ +#if defined(WITH_JSONC) + json_object_put((json_object*)item); +#elif defined(WITH_CJSON) + cJSON_Delete((cJSON*)item); +#else + WINPR_UNUSED(item); +#endif +} + +WINPR_JSON* WINPR_JSON_GetArrayItem(const WINPR_JSON* array, size_t index) +{ +#if defined(WITH_JSONC) + return json_object_array_get_idx((const json_object*)array, index); +#elif defined(WITH_CJSON) + WINPR_ASSERT(index <= INT_MAX); + return cJSON_GetArrayItem((const cJSON*)array, (INT)index); +#else + WINPR_UNUSED(array); + WINPR_UNUSED(index); + return NULL; +#endif +} + +size_t WINPR_JSON_GetArraySize(const WINPR_JSON* array) +{ +#if defined(WITH_JSONC) + return json_object_array_length((const json_object*)array); +#elif defined(WITH_CJSON) + const int rc = cJSON_GetArraySize((const cJSON*)array); + if (rc <= 0) + return 0; + return (size_t)rc; +#else + WINPR_UNUSED(array); + return 0; +#endif +} + +WINPR_JSON* WINPR_JSON_GetObjectItem(const WINPR_JSON* const object, const char* const string) +{ +#if defined(WITH_JSONC) + return json_object_object_get((const json_object*)object, string); +#elif defined(WITH_CJSON) + return cJSON_GetObjectItem((const cJSON*)object, string); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(string); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_GetObjectItemCaseSensitive(const WINPR_JSON* const object, + const char* const string) +{ +#if defined(WITH_JSONC) + return json_object_object_get((const json_object*)object, string); +#elif defined(WITH_CJSON) + return cJSON_GetObjectItemCaseSensitive((const cJSON*)object, string); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(string); + return NULL; +#endif +} + +BOOL WINPR_JSON_HasObjectItem(const WINPR_JSON* object, const char* string) +{ +#if defined(WITH_JSONC) + return json_object_object_get_ex((const json_object*)object, string, NULL); +#elif defined(WITH_CJSON) + return cJSON_HasObjectItem((const cJSON*)object, string); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(string); + return FALSE; +#endif +} + +const char* WINPR_JSON_GetErrorPtr(void) +{ +#if defined(WITH_JSONC) + return json_util_get_last_err(); +#elif defined(WITH_CJSON) + return cJSON_GetErrorPtr(); +#else + return NULL; +#endif +} + +const char* WINPR_JSON_GetStringValue(WINPR_JSON* item) +{ +#if defined(WITH_JSONC) + return json_object_get_string((json_object*)item); +#elif defined(WITH_CJSON) + return cJSON_GetStringValue((cJSON*)item); +#else + WINPR_UNUSED(item); + return NULL; +#endif +} + +double WINPR_JSON_GetNumberValue(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + return json_object_get_double((const json_object*)item); +#elif defined(WITH_CJSON) + return cJSON_GetNumberValue((const cJSON*)item); +#else + WINPR_UNUSED(item); + return nan(NULL); +#endif +} + +BOOL WINPR_JSON_IsInvalid(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + if (WINPR_JSON_IsArray(item)) + return FALSE; + if (WINPR_JSON_IsObject(item)) + return FALSE; + if (WINPR_JSON_IsNull(item)) + return FALSE; + if (WINPR_JSON_IsNumber(item)) + return FALSE; + if (WINPR_JSON_IsBool(item)) + return FALSE; + if (WINPR_JSON_IsString(item)) + return FALSE; + return TRUE; +#elif defined(WITH_CJSON) + return cJSON_IsInvalid((const cJSON*)item); +#else + WINPR_UNUSED(item); + return TRUE; +#endif +} + +BOOL WINPR_JSON_IsFalse(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + if (!json_object_is_type((const json_object*)item, json_type_boolean)) + return FALSE; + json_bool val = json_object_get_boolean((const json_object*)item); + return val == 0; +#elif defined(WITH_CJSON) + return cJSON_IsFalse((const cJSON*)item); +#else + WINPR_UNUSED(item); + return FALSE; +#endif +} + +BOOL WINPR_JSON_IsTrue(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + if (!json_object_is_type((const json_object*)item, json_type_boolean)) + return FALSE; + json_bool val = json_object_get_boolean((const json_object*)item); + return val != 0; +#elif defined(WITH_CJSON) + return cJSON_IsTrue((const cJSON*)item); +#else + WINPR_UNUSED(item); + return FALSE; +#endif +} + +BOOL WINPR_JSON_IsBool(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + return json_object_is_type((const json_object*)item, json_type_boolean); +#elif defined(WITH_CJSON) + return cJSON_IsBool((const cJSON*)item); +#else + WINPR_UNUSED(item); + return FALSE; +#endif +} + +BOOL WINPR_JSON_IsNull(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + return json_object_is_type((const json_object*)item, json_type_null); +#elif defined(WITH_CJSON) + return cJSON_IsNull((const cJSON*)item); +#else + WINPR_UNUSED(item); + return FALSE; +#endif +} + +BOOL WINPR_JSON_IsNumber(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + return json_object_is_type((const json_object*)item, json_type_int) || + json_object_is_type((const json_object*)item, json_type_double); +#elif defined(WITH_CJSON) + return cJSON_IsNumber((const cJSON*)item); +#else + WINPR_UNUSED(item); + return FALSE; +#endif +} + +BOOL WINPR_JSON_IsString(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + return json_object_is_type((const json_object*)item, json_type_string); +#elif defined(WITH_CJSON) + return cJSON_IsString((const cJSON*)item); +#else + WINPR_UNUSED(item); + return FALSE; +#endif +} + +BOOL WINPR_JSON_IsArray(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + return json_object_is_type((const json_object*)item, json_type_array); +#elif defined(WITH_CJSON) + return cJSON_IsArray((const cJSON*)item); +#else + WINPR_UNUSED(item); + return FALSE; +#endif +} + +BOOL WINPR_JSON_IsObject(const WINPR_JSON* const item) +{ +#if defined(WITH_JSONC) + return json_object_is_type((const json_object*)item, json_type_object); +#elif defined(WITH_CJSON) + return cJSON_IsObject((const cJSON*)item); +#else + WINPR_UNUSED(item); + return FALSE; +#endif +} + +WINPR_JSON* WINPR_JSON_CreateNull(void) +{ +#if defined(WITH_JSONC) + return json_object_new_null(); +#elif defined(WITH_CJSON) + return cJSON_CreateNull(); +#else + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_CreateTrue(void) +{ +#if defined(WITH_JSONC) + return json_object_new_boolean(TRUE); +#elif defined(WITH_CJSON) + return cJSON_CreateTrue(); +#else + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_CreateFalse(void) +{ +#if defined(WITH_JSONC) + return json_object_new_boolean(FALSE); +#elif defined(WITH_CJSON) + return cJSON_CreateFalse(); +#else + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_CreateBool(BOOL boolean) +{ +#if defined(WITH_JSONC) + return json_object_new_boolean(boolean); +#elif defined(WITH_CJSON) + return cJSON_CreateBool(boolean); +#else + WINPR_UNUSED(boolean); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_CreateNumber(double num) +{ +#if defined(WITH_JSONC) + return json_object_new_double(num); +#elif defined(WITH_CJSON) + return cJSON_CreateNumber(num); +#else + WINPR_UNUSED(num); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_CreateString(const char* string) +{ +#if defined(WITH_JSONC) + return json_object_new_string(string); +#elif defined(WITH_CJSON) + return cJSON_CreateString(string); +#else + WINPR_UNUSED(string); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_CreateArray(void) +{ +#if defined(WITH_JSONC) + return json_object_new_array(); +#elif defined(WITH_CJSON) + return cJSON_CreateArray(); +#else + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_CreateObject(void) +{ +#if defined(WITH_JSONC) + return json_object_new_object(); +#elif defined(WITH_CJSON) + return cJSON_CreateObject(); +#else + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_AddNullToObject(WINPR_JSON* const object, const char* const name) +{ +#if defined(WITH_JSONC) + struct json_object* obj = json_object_new_null(); + if (json_object_object_add((json_object*)object, name, obj) != 0) + { + json_object_put(obj); + return NULL; + } + return obj; +#elif defined(WITH_CJSON) + return cJSON_AddNullToObject((cJSON*)object, name); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(name); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_AddTrueToObject(WINPR_JSON* const object, const char* const name) +{ +#if defined(WITH_JSONC) + struct json_object* obj = json_object_new_boolean(TRUE); + if (json_object_object_add((json_object*)object, name, obj) != 0) + { + json_object_put(obj); + return NULL; + } + return obj; +#elif defined(WITH_CJSON) + return cJSON_AddTrueToObject((cJSON*)object, name); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(name); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_AddFalseToObject(WINPR_JSON* const object, const char* const name) +{ +#if defined(WITH_JSONC) + struct json_object* obj = json_object_new_boolean(FALSE); + if (json_object_object_add((json_object*)object, name, obj) != 0) + { + json_object_put(obj); + return NULL; + } + return obj; +#elif defined(WITH_CJSON) + return cJSON_AddFalseToObject((cJSON*)object, name); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(name); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_AddBoolToObject(WINPR_JSON* const object, const char* const name, + BOOL boolean) +{ +#if defined(WITH_JSONC) + struct json_object* obj = json_object_new_boolean(boolean); + if (json_object_object_add((json_object*)object, name, obj) != 0) + { + json_object_put(obj); + return NULL; + } + return obj; +#elif defined(WITH_CJSON) + return cJSON_AddBoolToObject((cJSON*)object, name, boolean); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(name); + WINPR_UNUSED(boolean); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_AddNumberToObject(WINPR_JSON* const object, const char* const name, + double number) +{ +#if defined(WITH_JSONC) + struct json_object* obj = json_object_new_double(number); + if (json_object_object_add((json_object*)object, name, obj) != 0) + { + json_object_put(obj); + return NULL; + } + return obj; +#elif defined(WITH_CJSON) + return cJSON_AddNumberToObject((cJSON*)object, name, number); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(name); + WINPR_UNUSED(number); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_AddStringToObject(WINPR_JSON* const object, const char* const name, + const char* const string) +{ +#if defined(WITH_JSONC) + struct json_object* obj = json_object_new_string(string); + if (json_object_object_add((json_object*)object, name, obj) != 0) + { + json_object_put(obj); + return NULL; + } + return obj; +#elif defined(WITH_CJSON) + return cJSON_AddStringToObject((cJSON*)object, name, string); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(name); + WINPR_UNUSED(string); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_AddObjectToObject(WINPR_JSON* const object, const char* const name) +{ +#if defined(WITH_JSONC) + struct json_object* obj = json_object_new_object(); + if (json_object_object_add((json_object*)object, name, obj) != 0) + { + json_object_put(obj); + return NULL; + } + return obj; +#elif defined(WITH_CJSON) + return cJSON_AddObjectToObject((cJSON*)object, name); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(name); + return NULL; +#endif +} + +WINPR_JSON* WINPR_JSON_AddArrayToObject(WINPR_JSON* const object, const char* const name) +{ +#if defined(WITH_JSONC) + struct json_object* obj = json_object_new_array(); + if (json_object_object_add((json_object*)object, name, obj) != 0) + { + json_object_put(obj); + return NULL; + } + return obj; +#elif defined(WITH_CJSON) + return cJSON_AddArrayToObject((cJSON*)object, name); +#else + WINPR_UNUSED(object); + WINPR_UNUSED(name); + return NULL; +#endif +} + +char* WINPR_JSON_Print(WINPR_JSON* item) +{ +#if defined(WITH_JSONC) + const char* str = json_object_to_json_string_ext((json_object*)item, JSON_C_TO_STRING_PRETTY); + if (!str) + return NULL; + return _strdup(str); +#elif defined(WITH_CJSON) + return cJSON_Print((const cJSON*)item); +#else + WINPR_UNUSED(item); + return NULL; +#endif +} + +char* WINPR_JSON_PrintUnformatted(WINPR_JSON* item) +{ +#if defined(WITH_JSONC) + const char* str = json_object_to_json_string_ext((json_object*)item, JSON_C_TO_STRING_PLAIN); + if (!str) + return NULL; + return _strdup(str); +#elif defined(WITH_CJSON) + return cJSON_PrintUnformatted((const cJSON*)item); +#else + WINPR_UNUSED(item); + return NULL; +#endif +}