Merge pull request #10183 from akallabeth/jsonc

Jsonc
This commit is contained in:
akallabeth
2024-05-16 15:17:11 +02:00
committed by GitHub
23 changed files with 1181 additions and 367 deletions

View File

@@ -561,9 +561,6 @@ endif()
find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DESCRIPTION})
find_package(cJSON)
option(WITH_AAD "Compile with support for Azure AD authentication" ${cJSON_FOUND})
if (WITH_DSP_FFMPEG OR WITH_VIDEO_FFMPEG OR WITH_FFMPEG)
set(FFMPEG_FEATURE_TYPE "REQUIRED" )
endif()
@@ -730,6 +727,8 @@ else()
include_directories(${WinPR_INCLUDE_DIR})
endif()
option(WITH_AAD "Compile with support for Azure AD authentication" ${WITH_WINPR_JSON})
# Include directories
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)

View File

@@ -62,14 +62,6 @@ endif()
find_package(SDL2 REQUIRED COMPONENTS)
include_directories(${SDL2_INCLUDE_DIR})
include_directories(${SDL2_INCLUDE_DIRS})
find_package(cJSON)
set(LIBS "")
if (cJSON_FOUND)
include_directories(${CJSON_INCLUDE_DIRS})
list(APPEND LIBS ${CJSON_LIBRARIES})
add_compile_definitions(CJSON_FOUND)
endif()
find_package(Threads REQUIRED)
@@ -96,8 +88,13 @@ set(SRCS
sdl_window.cpp
)
add_library(sdl_prefs STATIC
sdl_prefs.hpp
sdl_prefs.cpp
)
add_subdirectory(aad)
list(APPEND LIBS
set(LIBS
winpr
freerdp
freerdp-client
@@ -105,6 +102,7 @@ list(APPEND LIBS
sdl_client_res
dialogs
aad-view
sdl_prefs
)
if (NOT WITH_SDL_LINK_SHARED)
@@ -116,6 +114,7 @@ endif()
AddTargetWithResourceFile(${PROJECT_NAME} "${WIN32_GUI_FLAG}" "${PROJECT_VERSION}" SRCS)
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBS})
target_link_libraries(sdl_prefs winpr)
set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "Client/SDL")
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client)

View File

@@ -40,6 +40,7 @@
#include <freerdp/channels/channels.h>
#include <winpr/crt.h>
#include <winpr/config.h>
#include <winpr/assert.h>
#include <winpr/synch.h>
#include <freerdp/log.h>
@@ -56,6 +57,7 @@
#include "sdl_kbd.hpp"
#include "sdl_touch.hpp"
#include "sdl_pointer.hpp"
#include "sdl_prefs.hpp"
#include "dialogs/sdl_dialogs.hpp"
#include "aad/sdl_webview.hpp"
@@ -1553,7 +1555,7 @@ static void SDLCALL winpr_LogOutputFunction(void* userdata, int category, SDL_Lo
static void print_config_file_help()
{
#if defined(CJSON_FOUND)
#if defined(WITH_WINPR_JSON)
std::cout << "CONFIGURATION FILE" << std::endl;
std::cout << std::endl;
std::cout << " The SDL client supports some user defined configuration options." << std::endl;

View File

@@ -21,6 +21,7 @@
#include "sdl_disp.hpp"
#include "sdl_freerdp.hpp"
#include "sdl_utils.hpp"
#include "sdl_prefs.hpp"
#include <map>

145
client/SDL/sdl_prefs.cpp Normal file
View File

@@ -0,0 +1,145 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Prefs
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* 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 <fstream>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#elif __has_include(<experimental/filesystem>)
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#else
#error Could not find system header "<filesystem>" or "<experimental/filesystem>"
#endif
#include "sdl_prefs.hpp"
#include <winpr/path.h>
#include <winpr/config.h>
#include <freerdp/version.h>
#include <winpr/json.h>
#if defined(WITH_WINPR_JSON)
using WINPR_JSONPtr = std::unique_ptr<WINPR_JSON, decltype(&WINPR_JSON_Delete)>;
static WINPR_JSONPtr get()
{
auto config = sdl_get_pref_file();
std::ifstream ifs(config);
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
return { WINPR_JSON_ParseWithLength(content.c_str(), content.size()), WINPR_JSON_Delete };
}
static WINPR_JSON* get_item(const std::string& key)
{
static WINPR_JSONPtr config{ nullptr, WINPR_JSON_Delete };
if (!config)
config = get();
if (!config)
return nullptr;
return WINPR_JSON_GetObjectItem(config.get(), key.c_str());
}
static std::string item_to_str(WINPR_JSON* item, const std::string& fallback = "")
{
if (!item || !WINPR_JSON_IsString(item))
return fallback;
auto str = WINPR_JSON_GetStringValue(item);
if (!str)
return {};
return str;
}
#endif
std::string sdl_get_pref_string(const std::string& key, const std::string& fallback)
{
#if defined(WITH_WINPR_JSON)
auto item = get_item(key);
return item_to_str(item, fallback);
#else
return fallback;
#endif
}
bool sdl_get_pref_bool(const std::string& key, bool fallback)
{
#if defined(WITH_WINPR_JSON)
auto item = get_item(key);
if (!item || !WINPR_JSON_IsBool(item))
return fallback;
return WINPR_JSON_IsTrue(item);
#else
return fallback;
#endif
}
int64_t sdl_get_pref_int(const std::string& key, int64_t fallback)
{
#if defined(WITH_WINPR_JSON)
auto item = get_item(key);
if (!item || !WINPR_JSON_IsNumber(item))
return fallback;
auto val = WINPR_JSON_GetNumberValue(item);
return static_cast<int64_t>(val);
#else
return fallback;
#endif
}
std::vector<std::string> sdl_get_pref_array(const std::string& key,
const std::vector<std::string>& fallback)
{
#if defined(WITH_WINPR_JSON)
auto item = get_item(key);
if (!item || !WINPR_JSON_IsArray(item))
return fallback;
std::vector<std::string> values;
for (int x = 0; x < WINPR_JSON_GetArraySize(item); x++)
{
auto cur = WINPR_JSON_GetArrayItem(item, x);
values.push_back(item_to_str(cur));
}
return values;
#else
return fallback;
#endif
}
std::string sdl_get_pref_dir()
{
using CStringPtr = std::unique_ptr<char, decltype(&free)>;
CStringPtr path(GetKnownPath(KNOWN_PATH_XDG_CONFIG_HOME), free);
if (!path)
return {};
fs::path config{ path.get() };
config /= FREERDP_VENDOR;
config /= FREERDP_PRODUCT;
return config.string();
}
std::string sdl_get_pref_file()
{
fs::path config{ sdl_get_pref_dir() };
config /= "sdl-freerdp.json";
return config.string();
}

32
client/SDL/sdl_prefs.hpp Normal file
View File

@@ -0,0 +1,32 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Prefs
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* 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.
*/
#pragma once
#include <string>
#include <vector>
std::string sdl_get_pref_dir();
std::string sdl_get_pref_file();
std::string sdl_get_pref_string(const std::string& key, const std::string& fallback = "");
int64_t sdl_get_pref_int(const std::string& key, int64_t fallback = 0);
bool sdl_get_pref_bool(const std::string& key, bool fallback = false);
std::vector<std::string> sdl_get_pref_array(const std::string& key,
const std::vector<std::string>& fallback = {});

View File

@@ -17,17 +17,6 @@
* limitations under the License.
*/
#include <fstream>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#elif __has_include(<experimental/filesystem>)
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#else
#error Could not find system header "<filesystem>" or "<experimental/filesystem>"
#endif
#include <cassert>
#include "sdl_utils.hpp"
@@ -35,11 +24,7 @@ namespace fs = std::experimental::filesystem;
#include <SDL.h>
#include <winpr/path.h>
#include <freerdp/version.h>
#if defined(CJSON_FOUND)
#include <cjson/cJSON.h>
#endif
const char* sdl_event_type_str(Uint32 type)
{
@@ -354,112 +339,3 @@ std::string sdl_window_event_str(Uint8 ev)
return "SDL_WINDOWEVENT_UNKNOWN";
}
}
#if defined(CJSON_FOUND)
using cJSONPtr = std::unique_ptr<cJSON, decltype(&cJSON_Delete)>;
static cJSONPtr get()
{
auto config = sdl_get_pref_file();
std::ifstream ifs(config);
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
return { cJSON_ParseWithLength(content.c_str(), content.size()), cJSON_Delete };
}
static cJSON* get_item(const std::string& key)
{
static cJSONPtr config{ nullptr, cJSON_Delete };
if (!config)
config = get();
if (!config)
return nullptr;
return cJSON_GetObjectItem(config.get(), key.c_str());
}
static std::string item_to_str(cJSON* item, const std::string& fallback = "")
{
if (!item || !cJSON_IsString(item))
return fallback;
auto str = cJSON_GetStringValue(item);
if (!str)
return {};
return str;
}
#endif
std::string sdl_get_pref_string(const std::string& key, const std::string& fallback)
{
#if defined(CJSON_FOUND)
auto item = get_item(key);
return item_to_str(item, fallback);
#else
return fallback;
#endif
}
bool sdl_get_pref_bool(const std::string& key, bool fallback)
{
#if defined(CJSON_FOUND)
auto item = get_item(key);
if (!item || !cJSON_IsBool(item))
return fallback;
return cJSON_IsTrue(item);
#else
return fallback;
#endif
}
int64_t sdl_get_pref_int(const std::string& key, int64_t fallback)
{
#if defined(CJSON_FOUND)
auto item = get_item(key);
if (!item || !cJSON_IsNumber(item))
return fallback;
auto val = cJSON_GetNumberValue(item);
return static_cast<int64_t>(val);
#else
return fallback;
#endif
}
std::vector<std::string> sdl_get_pref_array(const std::string& key,
const std::vector<std::string>& fallback)
{
#if defined(CJSON_FOUND)
auto item = get_item(key);
if (!item || !cJSON_IsArray(item))
return fallback;
std::vector<std::string> values;
for (int x = 0; x < cJSON_GetArraySize(item); x++)
{
auto cur = cJSON_GetArrayItem(item, x);
values.push_back(item_to_str(cur));
}
return values;
#else
return fallback;
#endif
}
std::string sdl_get_pref_dir()
{
using CStringPtr = std::unique_ptr<char, decltype(&free)>;
CStringPtr path(GetKnownPath(KNOWN_PATH_XDG_CONFIG_HOME), free);
if (!path)
return {};
fs::path config{ path.get() };
config /= FREERDP_VENDOR;
config /= FREERDP_PRODUCT;
return config.string();
}
std::string sdl_get_pref_file()
{
fs::path config{ sdl_get_pref_dir() };
config /= "sdl-freerdp.json";
return config.string();
}

View File

@@ -19,8 +19,6 @@
#pragma once
#include <string>
#include <winpr/synch.h>
#include <winpr/wlog.h>
@@ -102,12 +100,3 @@ const char* sdl_error_string(Uint32 res);
#define sdl_log_error(res, log, what) sdl_log_error_ex(res, log, what, __FILE__, __LINE__, __func__)
BOOL sdl_log_error_ex(Uint32 res, wLog* log, const char* what, const char* file, size_t line,
const char* fkt);
std::string sdl_get_pref_dir();
std::string sdl_get_pref_file();
std::string sdl_get_pref_string(const std::string& key, const std::string& fallback = "");
int64_t sdl_get_pref_int(const std::string& key, int64_t fallback = 0);
bool sdl_get_pref_bool(const std::string& key, bool fallback = false);
std::vector<std::string> sdl_get_pref_array(const std::string& key,
const std::vector<std::string>& fallback = {});

27
cmake/FindJSONC.cmake Normal file
View File

@@ -0,0 +1,27 @@
# - Try to find JSON-C
# Once done this will define
#
# JSONC_FOUND - JSON-C was found
# JSONC_INCLUDE_DIRS - JSON-C include directories
# JSONC_LIBRARIES - libraries needed for linking
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_JSONC json-c)
endif()
find_path(JSONC_INCLUDE_DIR NAMES json.h
HINTS ${PC_JSONC_INCLUDE_DIRS}
PATH_SUFFIXES json-c)
find_library(JSONC_LIBRARY NAMES json-c
HINTS ${PC_JSONC_LIBRARY_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JSONC DEFAULT_MSG JSONC_LIBRARY JSONC_INCLUDE_DIR)
if(JSONC_FOUND)
set(JSONC_LIBRARIES ${JSONC_LIBRARY})
set(JSONC_INCLUDE_DIRS ${JSONC_INCLUDE_DIR})
endif()
mark_as_advanced(JSONC_LIBRARY JSONC_INCLUDE_DIR)

View File

@@ -1,8 +1,8 @@
# - Try to find lodepng
# Once done this will define
# lodepng_FOUND - cJSON was found
# lodepng_INCLUDE_DIRS - cJSON include directories
# lodepng_LIBRARIES - cJSON libraries for linking
# lodepng_FOUND - lodepng was found
# lodepng_INCLUDE_DIRS - lodepng include directories
# lodepng_LIBRARIES - lodepng libraries for linking
find_path(lodepng_INCLUDE_DIR
NAMES lodepng.h)

49
cmake/JsonDetect.cmake Normal file
View File

@@ -0,0 +1,49 @@
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)
find_package(cJSON)
# Fallback detection:
# older ubuntu releases did not ship CMake or pkg-config files
# for cJSON. Be optimistic and try pkg-config and as last resort
# try manual detection
if (NOT CJSON_FOUND)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(CJSON libcjson)
endif()
if (NOT CJSON_FOUND)
find_path(CJSON_INCLUDE_DIRS
NAMES cjson/cJSON.h
)
find_library(CJSON_LIBRARIES
NAMES cjson
)
if (NOT "${CJSON_LIBRARIES}" EQUAL "CJSON_LIBRARIES-NOTFOUND" AND NOT "${CJSON_INCLUDE_DIRS}" EQUAL "CJSON_INCLUDE_DIRS-NOTFOUND")
set(CJSON_FOUND ON)
endif()
endif()
endif()
if (WITH_CJSON_REQUIRED)
if (NOT CJSON_FOUND)
message(FATAL_ERROR "cJSON was requested but not found")
endif()
endif()
if (WITH_JSONC_REQUIRED)
find_package(JSONC REQUIRED)
else()
find_package(JSONC)
endif()
if (NOT JSONC_FOUND AND NOT CJSON_FOUND)
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()

View File

@@ -248,23 +248,9 @@ if(FAAC_FOUND)
endif()
if (WITH_AAD)
if (NOT cJSON_FOUND)
find_package(PkgConfig REQUIRED)
pkg_check_modules(CJSON libcjson)
endif()
if (NOT CJSON_LIBRARIES OR NOT CJSON_INCLUDE_DIRS)
find_path(CJSON_INCLUDE_DIRS
NAMES cjson/cJSON.h
REQUIRED
)
find_library(CJSON_LIBRARIES
NAMES cjson
REQUIRED
)
endif()
freerdp_library_add(${CJSON_LIBRARIES})
include_directories(${CJSON_INCLUDE_DIRS})
if (NOT WITH_WINPR_JSON)
message(FATAL_ERROR "Trying to build -DWITH_AAD=ON but WITH_WINPR_JSON is not defined")
endif()
endif()
if(WITH_NEON)
@@ -424,10 +410,7 @@ set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
include(pkg-config-install-prefix)
set(FREERDP_REQUIRES_PRIVATE "")
if(cJSON_FOUND)
string(APPEND FREERDP_REQUIRES_PRIVATE " libcjson")
list(APPEND FREERDP_PC_PRIVATE_LIBS "-lcjson")
endif()
if(WITH_SMARTCARD_EMULATE)
string(APPEND FREERDP_REQUIRES_PRIVATE " zlib")
list(APPEND FREERDP_PC_PRIVATE_LIBS "-lz")

View File

@@ -1,8 +1,6 @@
include(CMakeFindDependencyMacro)
find_dependency(WinPR @FREERDP_VERSION@)
if("@cJSON_FOUND@" AND NOT "@BUILD_SHARED_LIBS@")
find_dependency(cJSON)
endif()
if("@WITH_SMARTCARD_EMULATE@" AND NOT "@BUILD_SHARED_LIBS@")
find_dependency(ZLIB)
endif()

View File

@@ -29,6 +29,7 @@
#include <freerdp/utils/aad.h>
#include <winpr/crypto.h>
#include <winpr/json.h>
#include "transport.h"
@@ -78,18 +79,18 @@ static SSIZE_T stream_sprintf(wStream* s, WINPR_FORMAT_ARG const char* fmt, ...)
return rc2;
}
static BOOL json_get_object(wLog* wlog, cJSON* json, const char* key, cJSON** obj)
static BOOL json_get_object(wLog* wlog, WINPR_JSON* json, const char* key, WINPR_JSON** obj)
{
WINPR_ASSERT(json);
WINPR_ASSERT(key);
if (!cJSON_HasObjectItem(json, key))
if (!WINPR_JSON_HasObjectItem(json, key))
{
WLog_Print(wlog, WLOG_ERROR, "[json] does not contain a key '%s'", key);
return FALSE;
}
cJSON* prop = cJSON_GetObjectItem(json, key);
WINPR_JSON* prop = WINPR_JSON_GetObjectItem(json, key);
if (!prop)
{
WLog_Print(wlog, WLOG_ERROR, "[json] object for key '%s' is NULL", key);
@@ -99,80 +100,45 @@ static BOOL json_get_object(wLog* wlog, cJSON* json, const char* key, cJSON** ob
return TRUE;
}
#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
}
#endif
static BOOL json_get_number(wLog* wlog, cJSON* json, const char* key, double* result)
static BOOL json_get_number(wLog* wlog, WINPR_JSON* json, const char* key, double* result)
{
BOOL rc = FALSE;
cJSON* prop = NULL;
WINPR_JSON* prop = NULL;
if (!json_get_object(wlog, json, key, &prop))
return FALSE;
if (!cJSON_IsNumber(prop))
if (!WINPR_JSON_IsNumber(prop))
{
WLog_Print(wlog, WLOG_ERROR, "[json] object for key '%s' is NOT a NUMBER", key);
goto fail;
}
*result = cJSON_GetNumberValue(prop);
*result = WINPR_JSON_GetNumberValue(prop);
rc = TRUE;
fail:
return rc;
}
static BOOL json_get_const_string(wLog* wlog, cJSON* json, const char* key, const char** result)
static BOOL json_get_const_string(wLog* wlog, WINPR_JSON* json, const char* key,
const char** result)
{
BOOL rc = FALSE;
WINPR_ASSERT(result);
*result = NULL;
cJSON* prop = NULL;
WINPR_JSON* prop = NULL;
if (!json_get_object(wlog, json, key, &prop))
return FALSE;
if (!cJSON_IsString(prop))
if (!WINPR_JSON_IsString(prop))
{
WLog_Print(wlog, WLOG_ERROR, "[json] object for key '%s' is NOT a STRING", key);
goto fail;
}
const char* str = cJSON_GetStringValue(prop);
const char* str = WINPR_JSON_GetStringValue(prop);
if (!str)
WLog_Print(wlog, WLOG_ERROR, "[json] object for key '%s' is NULL", key);
*result = str;
@@ -182,7 +148,7 @@ fail:
return rc;
}
static BOOL json_get_string_alloc(wLog* wlog, cJSON* json, const char* key, char** result)
static BOOL json_get_string_alloc(wLog* wlog, WINPR_JSON* json, const char* key, char** result)
{
const char* str = NULL;
if (!json_get_const_string(wlog, json, key, &str))
@@ -194,20 +160,6 @@ static BOOL json_get_string_alloc(wLog* wlog, cJSON* json, const char* key, char
return *result != NULL;
}
#if defined(USE_CJSON_COMPAT)
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
static INLINE const char* aad_auth_result_to_string(DWORD code)
{
#define ERROR_CASE(cd, x) \
@@ -232,7 +184,7 @@ static BOOL aad_get_nonce(rdpAad* aad)
BYTE* response = NULL;
long resp_code = 0;
size_t response_length = 0;
cJSON* json = NULL;
WINPR_JSON* json = NULL;
if (!freerdp_http_request("https://login.microsoftonline.com/common/oauth2/v2.0/token",
"grant_type=srv_challenge", &resp_code, &response, &response_length))
@@ -250,7 +202,7 @@ static BOOL aad_get_nonce(rdpAad* aad)
goto fail;
}
json = cJSON_ParseWithLength((const char*)response, response_length);
json = WINPR_JSON_ParseWithLength((const char*)response, response_length);
if (!json)
{
WLog_Print(aad->log, WLOG_ERROR, "Failed to parse nonce response");
@@ -264,7 +216,7 @@ static BOOL aad_get_nonce(rdpAad* aad)
fail:
free(response);
cJSON_Delete(json);
WINPR_JSON_Delete(json);
return ret;
}
@@ -536,12 +488,12 @@ static int aad_parse_state_initial(rdpAad* aad, wStream* s)
const size_t jlen = Stream_GetRemainingLength(s);
const char* ts_nonce = NULL;
int ret = -1;
cJSON* json = NULL;
WINPR_JSON* json = NULL;
if (!Stream_SafeSeek(s, jlen))
goto fail;
json = cJSON_ParseWithLength(jstr, jlen);
json = WINPR_JSON_ParseWithLength(jstr, jlen);
if (!json)
goto fail;
@@ -550,7 +502,7 @@ static int aad_parse_state_initial(rdpAad* aad, wStream* s)
ret = aad_send_auth_request(aad, ts_nonce);
fail:
cJSON_Delete(json);
WINPR_JSON_Delete(json);
return ret;
}
@@ -559,14 +511,14 @@ static int aad_parse_state_auth(rdpAad* aad, wStream* s)
int rc = -1;
double result = 0;
DWORD error_code = 0;
cJSON* json = NULL;
WINPR_JSON* json = NULL;
const char* jstr = Stream_PointerAs(s, char);
const size_t jlength = Stream_GetRemainingLength(s);
if (!Stream_SafeSeek(s, jlength))
goto fail;
json = cJSON_ParseWithLength(jstr, jlength);
json = WINPR_JSON_ParseWithLength(jstr, jlength);
if (!json)
goto fail;
@@ -583,7 +535,7 @@ static int aad_parse_state_auth(rdpAad* aad, wStream* s)
aad->state = AAD_STATE_FINAL;
rc = 1;
fail:
cJSON_Delete(json);
WINPR_JSON_Delete(json);
return rc;
}
@@ -846,10 +798,10 @@ BOOL aad_is_supported(void)
char* freerdp_utils_aad_get_access_token(wLog* log, const char* data, size_t length)
{
char* token = NULL;
cJSON* access_token_prop = NULL;
WINPR_JSON* access_token_prop = NULL;
const char* access_token_str = NULL;
cJSON* json = cJSON_ParseWithLength(data, length);
WINPR_JSON* json = WINPR_JSON_ParseWithLength(data, length);
if (!json)
{
WLog_Print(log, WLOG_ERROR, "Failed to parse access token response [got %" PRIuz " bytes",
@@ -857,14 +809,14 @@ char* freerdp_utils_aad_get_access_token(wLog* log, const char* data, size_t len
goto cleanup;
}
access_token_prop = cJSON_GetObjectItem(json, "access_token");
access_token_prop = WINPR_JSON_GetObjectItem(json, "access_token");
if (!access_token_prop)
{
WLog_Print(log, WLOG_ERROR, "Response has no \"access_token\" property");
goto cleanup;
}
access_token_str = cJSON_GetStringValue(access_token_prop);
access_token_str = WINPR_JSON_GetStringValue(access_token_prop);
if (!access_token_str)
{
WLog_Print(log, WLOG_ERROR, "Invalid value for \"access_token\"");
@@ -874,7 +826,7 @@ char* freerdp_utils_aad_get_access_token(wLog* log, const char* data, size_t len
token = _strdup(access_token_str);
cleanup:
cJSON_Delete(json);
WINPR_JSON_Delete(json);
return token;
}
#endif

View File

@@ -32,18 +32,6 @@ typedef enum
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#ifdef WITH_AAD
#include <cjson/cJSON.h>
#if CJSON_VERSION_MAJOR == 1
#if CJSON_VERSION_MINOR <= 7
#if CJSON_VERSION_PATCH < 13
#define USE_CJSON_COMPAT
#endif
#endif
#endif
#endif
FREERDP_LOCAL BOOL aad_is_supported(void);
FREERDP_LOCAL int aad_client_begin(rdpAad* aad);
@@ -56,8 +44,4 @@ FREERDP_LOCAL void aad_free(rdpAad* aad);
WINPR_ATTR_MALLOC(aad_free, 1)
FREERDP_LOCAL rdpAad* aad_new(rdpContext* context, rdpTransport* transport);
#if defined(USE_CJSON_COMPAT)
FREERDP_API cJSON* cJSON_ParseWithLength(const char* value, size_t buffer_length);
#endif
#endif /* FREERDP_LIB_CORE_AAD_H */

View File

@@ -53,10 +53,7 @@
#include "../utils.h"
#include "../redirection.h"
//#define WITH_AAD
#ifdef WITH_AAD
#include <cjson/cJSON.h>
#endif
#include <winpr/json.h>
#include <string.h>
@@ -296,10 +293,10 @@ static char* arm_create_request_json(rdpArm* arm)
WINPR_ASSERT(arm);
cJSON* json = cJSON_CreateObject();
WINPR_JSON* json = WINPR_JSON_CreateObject();
if (!json)
goto arm_create_cleanup;
cJSON_AddStringToObject(
WINPR_JSON_AddStringToObject(
json, "application",
freerdp_settings_get_string(arm->context->settings, FreeRDP_RemoteApplicationProgram));
@@ -313,14 +310,14 @@ static char* arm_create_request_json(rdpArm* arm)
freerdp_settings_get_uint32(arm->context->settings, FreeRDP_LoadBalanceInfoLength);
memcpy(lbi, freerdp_settings_get_pointer(arm->context->settings, FreeRDP_LoadBalanceInfo), len);
cJSON_AddStringToObject(json, "loadBalanceInfo", lbi);
cJSON_AddNullToObject(json, "LogonToken");
cJSON_AddNullToObject(json, "gatewayLoadBalancerToken");
WINPR_JSON_AddStringToObject(json, "loadBalanceInfo", lbi);
WINPR_JSON_AddNullToObject(json, "LogonToken");
WINPR_JSON_AddNullToObject(json, "gatewayLoadBalancerToken");
message = cJSON_PrintUnformatted(json);
message = WINPR_JSON_PrintUnformatted(json);
arm_create_cleanup:
if (json)
cJSON_Delete(json);
WINPR_JSON_Delete(json);
free(lbi);
return message;
}
@@ -529,17 +526,17 @@ out:
* base64.b64decode( base64.b64decode(input).decode('utf-16') )
* in python
*/
static BOOL arm_pick_base64Utf16Field(const cJSON* json, const char* name, BYTE** poutput,
static BOOL arm_pick_base64Utf16Field(const WINPR_JSON* json, const char* name, BYTE** poutput,
size_t* plen)
{
*poutput = NULL;
*plen = 0;
const cJSON* node = cJSON_GetObjectItemCaseSensitive(json, name);
if (!node || !cJSON_IsString(node))
WINPR_JSON* node = WINPR_JSON_GetObjectItemCaseSensitive(json, name);
if (!node || !WINPR_JSON_IsString(node))
return TRUE;
char* nodeValue = cJSON_GetStringValue(node);
const char* nodeValue = WINPR_JSON_GetStringValue(node);
if (!nodeValue)
return TRUE;
@@ -600,27 +597,27 @@ static BOOL arm_pick_base64Utf16Field(const cJSON* json, const char* name, BYTE*
static BOOL arm_treat_azureInstanceNetworkMetadata(const char* metadata, rdpSettings* settings)
{
BOOL ret = FALSE;
cJSON* json = cJSON_Parse(metadata);
WINPR_JSON* json = WINPR_JSON_Parse(metadata);
if (!json)
{
WLog_ERR(TAG, "invalid azureInstanceNetworkMetadata");
return FALSE;
}
const cJSON* iface = cJSON_GetObjectItem(json, "interface");
WINPR_JSON* iface = WINPR_JSON_GetObjectItem(json, "interface");
if (!iface)
{
ret = TRUE;
goto out;
}
if (!cJSON_IsArray(iface))
if (!WINPR_JSON_IsArray(iface))
{
WLog_ERR(TAG, "expecting interface to be an Array");
goto out;
}
int interfaceSz = cJSON_GetArraySize(iface);
size_t interfaceSz = WINPR_JSON_GetArraySize(iface);
if (interfaceSz == 0)
{
WLog_WARN(TAG, "no addresses in azure instance metadata");
@@ -628,32 +625,32 @@ static BOOL arm_treat_azureInstanceNetworkMetadata(const char* metadata, rdpSett
goto out;
}
for (int i = 0; i < interfaceSz; i++)
for (size_t i = 0; i < interfaceSz; i++)
{
const cJSON* interN = cJSON_GetArrayItem(iface, i);
WINPR_JSON* interN = WINPR_JSON_GetArrayItem(iface, i);
if (!interN)
continue;
const cJSON* ipv4 = cJSON_GetObjectItem(interN, "ipv4");
WINPR_JSON* ipv4 = WINPR_JSON_GetObjectItem(interN, "ipv4");
if (!ipv4)
continue;
const cJSON* ipAddress = cJSON_GetObjectItem(ipv4, "ipAddress");
if (!ipAddress || !cJSON_IsArray(ipAddress))
WINPR_JSON* ipAddress = WINPR_JSON_GetObjectItem(ipv4, "ipAddress");
if (!ipAddress || !WINPR_JSON_IsArray(ipAddress))
continue;
int naddresses = cJSON_GetArraySize(ipAddress);
for (int j = 0; j < naddresses; j++)
size_t naddresses = WINPR_JSON_GetArraySize(ipAddress);
for (size_t j = 0; j < naddresses; j++)
{
const cJSON* adressN = cJSON_GetArrayItem(ipAddress, j);
WINPR_JSON* adressN = WINPR_JSON_GetArrayItem(ipAddress, j);
if (!adressN)
continue;
const cJSON* publicIpNode = cJSON_GetObjectItem(adressN, "publicIpAddress");
if (!publicIpNode || !cJSON_IsString(publicIpNode))
WINPR_JSON* publicIpNode = WINPR_JSON_GetObjectItem(adressN, "publicIpAddress");
if (!publicIpNode || !WINPR_JSON_IsString(publicIpNode))
continue;
char* publicIp = cJSON_GetStringValue(publicIpNode);
const char* publicIp = WINPR_JSON_GetStringValue(publicIpNode);
if (publicIp && strlen(publicIp) &&
freerdp_settings_set_string(settings, FreeRDP_RedirectionTargetFQDN, publicIp))
{
@@ -667,11 +664,11 @@ static BOOL arm_treat_azureInstanceNetworkMetadata(const char* metadata, rdpSett
ret = TRUE;
out:
cJSON_Delete(json);
WINPR_JSON_Delete(json);
return ret;
}
static BOOL arm_fill_rdstls(rdpArm* arm, rdpSettings* settings, const cJSON* json)
static BOOL arm_fill_rdstls(rdpArm* arm, rdpSettings* settings, const WINPR_JSON* json)
{
BOOL ret = TRUE;
BYTE* cert = NULL;
@@ -681,12 +678,12 @@ static BOOL arm_fill_rdstls(rdpArm* arm, rdpSettings* settings, const cJSON* jso
do
{
/* redirectedAuthGuid */
const cJSON* redirectedAuthGuidNode =
cJSON_GetObjectItemCaseSensitive(json, "redirectedAuthGuid");
if (!redirectedAuthGuidNode || !cJSON_IsString(redirectedAuthGuidNode))
WINPR_JSON* redirectedAuthGuidNode =
WINPR_JSON_GetObjectItemCaseSensitive(json, "redirectedAuthGuid");
if (!redirectedAuthGuidNode || !WINPR_JSON_IsString(redirectedAuthGuidNode))
break;
char* redirectedAuthGuid = cJSON_GetStringValue(redirectedAuthGuidNode);
const char* redirectedAuthGuid = WINPR_JSON_GetStringValue(redirectedAuthGuidNode);
if (!redirectedAuthGuid)
break;
@@ -750,34 +747,35 @@ static BOOL arm_fill_gateway_parameters(rdpArm* arm, const char* message, size_t
WINPR_ASSERT(arm->context);
WINPR_ASSERT(message);
cJSON* json = cJSON_ParseWithLength(message, len);
WINPR_JSON* json = WINPR_JSON_ParseWithLength(message, len);
BOOL status = FALSE;
if (!json)
return FALSE;
rdpSettings* settings = arm->context->settings;
const cJSON* gwurl = cJSON_GetObjectItemCaseSensitive(json, "gatewayLocation");
if (cJSON_IsString(gwurl) && (gwurl->valuestring != NULL))
WINPR_JSON* gwurl = WINPR_JSON_GetObjectItemCaseSensitive(json, "gatewayLocation");
const char* gwurlstr = WINPR_JSON_GetStringValue(gwurl);
if (gwurlstr != NULL)
{
WLog_DBG(TAG, "extracted target url %s", gwurl->valuestring);
if (!freerdp_settings_set_string(settings, FreeRDP_GatewayUrl, gwurl->valuestring))
WLog_DBG(TAG, "extracted target url %s", gwurlstr);
if (!freerdp_settings_set_string(settings, FreeRDP_GatewayUrl, gwurlstr))
status = FALSE;
else
status = TRUE;
}
const cJSON* serverNameNode = cJSON_GetObjectItem(json, "redirectedServerName");
WINPR_JSON* serverNameNode = WINPR_JSON_GetObjectItem(json, "redirectedServerName");
if (serverNameNode)
{
char* serverName = cJSON_GetStringValue(serverNameNode);
const char* serverName = WINPR_JSON_GetStringValue(serverNameNode);
if (serverName)
status = freerdp_settings_set_string(settings, FreeRDP_ServerHostname, serverName);
}
const cJSON* azureMeta = cJSON_GetObjectItem(json, "azureInstanceNetworkMetadata");
if (azureMeta && cJSON_IsString(azureMeta))
WINPR_JSON* azureMeta = WINPR_JSON_GetObjectItem(json, "azureInstanceNetworkMetadata");
if (azureMeta && WINPR_JSON_IsString(azureMeta))
{
if (!arm_treat_azureInstanceNetworkMetadata(cJSON_GetStringValue(azureMeta), settings))
if (!arm_treat_azureInstanceNetworkMetadata(WINPR_JSON_GetStringValue(azureMeta), settings))
{
WLog_ERR(TAG, "error when treating azureInstanceNetworkMetadata");
}
@@ -791,7 +789,7 @@ static BOOL arm_fill_gateway_parameters(rdpArm* arm, const char* message, size_t
status = arm_fill_rdstls(arm, settings, json);
}
cJSON_Delete(json);
WINPR_JSON_Delete(json);
return status;
}
@@ -822,34 +820,34 @@ static BOOL arm_handle_bad_request(rdpArm* arm, const HttpResponse* response, BO
WLog_DBG(TAG, "Got HTTP Response data: %s", msg);
cJSON* json = cJSON_ParseWithLength(msg, len);
WINPR_JSON* json = WINPR_JSON_ParseWithLength(msg, len);
if (json == NULL)
{
const char* error_ptr = cJSON_GetErrorPtr();
const char* error_ptr = WINPR_JSON_GetErrorPtr();
if (error_ptr != NULL)
{
WLog_ERR(TAG, "NullPoException: %s", error_ptr);
return FALSE;
}
return FALSE;
}
const cJSON* gateway_code_str = cJSON_GetObjectItemCaseSensitive(json, "Code");
if (!cJSON_IsString(gateway_code_str) || (gateway_code_str->valuestring == NULL))
WINPR_JSON* gateway_code_obj = WINPR_JSON_GetObjectItemCaseSensitive(json, "Code");
const char* gw_code_str = WINPR_JSON_GetStringValue(gateway_code_obj);
if (gw_code_str == NULL)
{
WLog_ERR(TAG, "Response has no \"Code\" property");
http_response_log_error_status(WLog_Get(TAG), WLOG_ERROR, response);
goto fail;
}
if (strcmp(gateway_code_str->valuestring, "E_PROXY_ORCHESTRATION_LB_SESSIONHOST_DEALLOCATED") ==
0)
if (strcmp(gw_code_str, "E_PROXY_ORCHESTRATION_LB_SESSIONHOST_DEALLOCATED") == 0)
{
*retry = TRUE;
const cJSON* message = cJSON_GetObjectItemCaseSensitive(json, "Message");
if (!cJSON_IsString(message) || !message->valuestring)
WINPR_JSON* message = WINPR_JSON_GetObjectItemCaseSensitive(json, "Message");
const char* msgstr = WINPR_JSON_GetStringValue(message);
if (!msgstr)
WLog_WARN(TAG, "Starting your VM. It may take up to 5 minutes");
else
WLog_WARN(TAG, "%s", message->valuestring);
WLog_WARN(TAG, "%s", msgstr);
}
else
{
@@ -859,7 +857,7 @@ static BOOL arm_handle_bad_request(rdpArm* arm, const HttpResponse* response, BO
rc = TRUE;
fail:
cJSON_Delete(json);
WINPR_JSON_Delete(json);
return rc;
}

View File

@@ -47,6 +47,12 @@ if(WIN32)
freerdp_library_add(cfgmgr32)
endif()
CHECK_LIBRARY_EXISTS(m pow "" HAVE_LIB_M)
if (HAVE_LIB_M)
freerdp_library_add(m)
endif()
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -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@")

View File

@@ -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

View File

@@ -0,0 +1,93 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* JSON parser wrapper
*
* Copyright 2024 Armin Novak <anovak@thincast.com>
* 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 <winpr/winpr.h>
#include <winpr/string.h>
#include <winpr/wtypes.h>
#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

View File

@@ -16,6 +16,7 @@
# limitations under the License.
include(CheckFunctionExists)
include(JsonDetect)
set(WINPR_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(WINPR_SRCS "")

View File

@@ -16,25 +16,26 @@
# limitations under the License.
include(CheckFunctionExists)
include(CMakeDependentOption)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
option(WITH_LODEPNG "build WinPR with PNG support" OFF)
if (WITH_LODEPNG)
find_package(lodepng REQUIRED)
find_package(lodepng REQUIRED)
winpr_definition_add(-DWITH_LODEPNG)
set(WINPR_WITH_PNG ON CACHE BOOL "build cache")
winpr_definition_add(-DWITH_LODEPNG)
set(WINPR_WITH_PNG ON CACHE BOOL "build cache")
winpr_include_directory_add(${lodepng_INCLUDE_DIRS})
winpr_library_add_private(${lodepng_LIBRARIES})
winpr_include_directory_add(${lodepng_INCLUDE_DIRS})
winpr_library_add_private(${lodepng_LIBRARIES})
endif()
option(WINPR_UTILS_IMAGE_PNG "Add PNG <--> BMP conversion support to clipboard" OFF)
if (WINPR_UTILS_IMAGE_PNG)
find_package(PNG REQUIRED)
set(WINPR_WITH_PNG ON CACHE BOOL "build cache")
set(WINPR_WITH_PNG ON CACHE BOOL "build cache")
winpr_include_directory_add(${PNG_INCLUDE_DIRS})
winpr_library_add_private(${PNG_LIBRARIES})
endif()
@@ -50,11 +51,11 @@ endif()
option(WINPR_UTILS_IMAGE_JPEG "Add Jpeg <--> BMP conversion support to clipboard" OFF)
if (WINPR_UTILS_IMAGE_JPEG)
find_package(PkgConfig REQUIRED)
pkg_check_modules(JPEG libjpeg REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(JPEG libjpeg REQUIRED)
winpr_include_directory_add(${JPEG_INCLUDE_DIRS})
winpr_library_add_private(${JPEG_LIBRARIES})
winpr_include_directory_add(${JPEG_INCLUDE_DIRS})
winpr_library_add_private(${JPEG_LIBRARIES})
endif()
@@ -63,7 +64,7 @@ set(COLLECTIONS_SRCS
collections/Queue.c
collections/Stack.c
collections/PubSub.c
collections/BitStream.c
collections/BitStream.c
collections/ArrayList.c
collections/LinkedList.c
collections/HashTable.c
@@ -85,16 +86,16 @@ endif()
find_package(libsystemd)
option(WITH_SYSTEMD "allows to export wLog to systemd journal" ${libsystemd_FOUND})
if(WITH_LIBSYSTEMD)
find_package(libsystemd REQUIRED)
set(WINPR_HAVE_JOURNALD_H TRUE)
set(JOURNALD_SRCS
find_package(libsystemd REQUIRED)
set(WINPR_HAVE_JOURNALD_H TRUE)
set(JOURNALD_SRCS
wlog/JournaldAppender.c
wlog/JournaldAppender.h
)
)
winpr_include_directory_add(${LIBSYSTEMD_INCLUDE_DIR})
winpr_library_add_private(${LIBSYSTEMD_LIBRARY})
else()
unset(WINPR_HAVE_JOURNALD_H)
unset(WINPR_HAVE_JOURNALD_H)
endif()
set(WLOG_SRCS
@@ -147,44 +148,61 @@ set(SRCS
if (ANDROID)
list(APPEND SRCS android.h android.c)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
if (NOT WINPR_HAVE_UNWIND_H)
message("[backtrace] android NDK without unwind.h, falling back to corkscrew")
set(WINPR_HAVE_CORKSCREW 1)
endif()
if (NOT WINPR_HAVE_UNWIND_H)
message("[backtrace] android NDK without unwind.h, falling back to corkscrew")
set(WINPR_HAVE_CORKSCREW 1)
endif()
endif()
if (WINPR_HAVE_CORKSCREW)
list(APPEND SRCS
corkscrew/debug.c
corkscrew/debug.h)
list(APPEND SRCS
corkscrew/debug.c
corkscrew/debug.h)
endif()
if (WIN32)
list(APPEND SRCS
windows/debug.c
windows/debug.h)
list(APPEND SRCS
windows/debug.c
windows/debug.h)
endif()
if (WINPR_HAVE_EXECINFO_H)
option(USE_EXECINFO "Use execinfo.h to generate backtraces" ON)
if (USE_EXECINFO)
winpr_definition_add(-DUSE_EXECINFO)
list(APPEND SRCS
execinfo/debug.c
execinfo/debug.h)
endif()
option(USE_EXECINFO "Use execinfo.h to generate backtraces" ON)
if (USE_EXECINFO)
winpr_definition_add(-DUSE_EXECINFO)
list(APPEND SRCS
execinfo/debug.c
execinfo/debug.h)
endif()
endif()
if (WINPR_HAVE_UNWIND_H)
option(USE_UNWIND "Use unwind.h to generate backtraces" ON)
if (USE_UNWIND)
winpr_definition_add(-DUSE_UNWIND)
list(APPEND SRCS
unwind/debug.c
unwind/debug.h)
endif()
option(USE_UNWIND "Use unwind.h to generate backtraces" ON)
if (USE_UNWIND)
winpr_definition_add(-DUSE_UNWIND)
list(APPEND SRCS
unwind/debug.c
unwind/debug.h)
endif()
endif()
include(JsonDetect)
if (NOT WITH_JSON_DISABLED)
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")
endif()
endif()
winpr_module_add(json/json.c)
winpr_module_add(${SRCS}
${COLLECTIONS_SRCS}
${WLOG_SRCS}

View File

@@ -0,0 +1,651 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* JSON parser wrapper
*
* Copyright 2024 Armin Novak <anovak@thincast.com>
* 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 <math.h>
#include <winpr/json.h>
#include <winpr/assert.h>
#if defined(WITH_CJSON)
#include <cjson/cJSON.h>
#endif
#if defined(WITH_JSONC)
#include <json-c/json.h>
#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
}