[core,aad] migrate to cJSON parser library

This commit is contained in:
akallabeth 2023-03-08 15:18:00 +01:00 committed by akallabeth
parent c5406d79c5
commit 157d71e802
7 changed files with 130 additions and 870 deletions

View File

@ -1,64 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Simple JSON parser
*
* Copyright 2023 Isaac Klein <fifthdegree@protonmail.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.
*/
#ifndef FREERDP_UTILS_JSON_H
#define FREERDP_UTILS_JSON_H
#include <freerdp/api.h>
enum JSON_TYPE
{
JSON_TYPE_FALSE,
JSON_TYPE_NULL,
JSON_TYPE_TRUE,
JSON_TYPE_OBJECT,
JSON_TYPE_ARRAY,
JSON_TYPE_NUMBER,
JSON_TYPE_STRING
};
typedef struct JSON JSON;
#ifdef __cplusplus
extern "C"
{
#endif
FREERDP_API JSON* json_parse(const char* str);
FREERDP_API JSON* json_new(enum JSON_TYPE type);
FREERDP_API void json_free(JSON* json);
FREERDP_API enum JSON_TYPE json_get_type(JSON* json);
FREERDP_API int json_object_set_prop(JSON* object, const char* prop, JSON* value);
FREERDP_API int json_array_add(JSON* array, JSON* value);
FREERDP_API int json_number_set(JSON* json, double value);
FREERDP_API int json_string_set(JSON* json, const char* value);
FREERDP_API int json_object_get_prop(JSON* object, const char* prop, JSON** value);
FREERDP_API int json_array_get(JSON* array, size_t index, JSON** value);
FREERDP_API int json_number_get(JSON* json, double* value);
FREERDP_API int json_string_get(JSON* json, const char** value);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_UTILS_JSON_H */

View File

@ -18,6 +18,11 @@
set(MODULE_NAME "freerdp-core")
set(MODULE_PREFIX "FREERDP_CORE")
find_package(cJSON REQUIRED)
freerdp_include_directory_add(${CJSON_INCLUDE_DIRS})
freerdp_library_add(${CJSON_LIBRARIES})
freerdp_definition_add(-DEXT_PATH="${FREERDP_EXTENSION_PATH}")
freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR})

View File

@ -22,7 +22,9 @@
#include <stdio.h>
#include <freerdp/crypto/crypto.h>
#include <freerdp/utils/json.h>
#include <cjson/cJSON.h>
#include <winpr/crypto.h>
#include <openssl/ssl.h>
@ -124,6 +126,58 @@ rdpAad* aad_new(rdpContext* context, rdpTransport* transport)
return aad;
}
static BOOL json_get_number(cJSON* json, const char* key, double* result)
{
WINPR_ASSERT(json);
WINPR_ASSERT(key);
WINPR_ASSERT(result);
if (!cJSON_HasObjectItem(json, key))
return FALSE;
cJSON* prop = cJSON_GetObjectItem(json, key);
if (!prop)
return FALSE;
if (!cJSON_IsNumber(prop))
return FALSE;
*result = cJSON_GetNumberValue(prop);
return TRUE;
}
static BOOL json_get_const_string(cJSON* json, const char* key, const char** result)
{
WINPR_ASSERT(json);
WINPR_ASSERT(key);
WINPR_ASSERT(result);
*result = NULL;
if (!cJSON_HasObjectItem(json, key))
return FALSE;
cJSON* prop = cJSON_GetObjectItem(json, key);
if (!prop)
return FALSE;
if (!cJSON_IsString(prop))
return FALSE;
const char* str = cJSON_GetStringValue(prop);
*result = str;
return *result != NULL;
}
static BOOL json_get_string_alloc(cJSON* json, const char* key, char** result)
{
const char* str = NULL;
if (!json_get_const_string(json, key, &str))
return FALSE;
free(*result);
*result = _strdup(str);
return *result != NULL;
}
int aad_client_begin(rdpAad* aad)
{
int ret = -1;
@ -136,8 +190,8 @@ int aad_client_begin(rdpAad* aad)
char* p = NULL;
const char* token = NULL;
long status_code;
JSON* json = NULL;
JSON* prop = NULL;
cJSON* json = NULL;
cJSON* prop = NULL;
WINPR_ASSERT(aad);
WINPR_ASSERT(aad->rdpcontext);
@ -205,15 +259,15 @@ int aad_client_begin(rdpAad* aad)
LOG_ERROR_AND_GOTO(fail, "Received status code: %li", status_code);
/* Extract the access token from the JSON response */
if (!(json = json_parse(buffer)))
json = cJSON_ParseWithLength(buffer, length);
if (!json)
LOG_ERROR_AND_GOTO(fail, "Failed to parse JSON response");
if (!json_object_get_prop(json, "access_token", &prop) || !json_string_get(prop, &token))
if (!json_get_string_alloc(json, "access_token", &aad->access_token))
LOG_ERROR_AND_GOTO(fail, "Could not find \"access_token\" property in JSON response");
if (!(aad->access_token = _strdup(token)))
goto fail;
XFREE(buffer);
json_free(json);
cJSON_free(json);
json = NULL;
/* Send the nonce request message */
@ -235,17 +289,17 @@ int aad_client_begin(rdpAad* aad)
LOG_ERROR_AND_GOTO(fail, "Received status code: %li", status_code);
/* Extract the nonce from the response */
if (!(json = json_parse(buffer)))
json = cJSON_ParseWithLength(buffer, length);
if (!json)
LOG_ERROR_AND_GOTO(fail, "Failed to parse JSON response");
if (!json_object_get_prop(json, "Nonce", &prop) || !json_string_get(prop, &token))
if (!json_get_string_alloc(json, "Nonce", &aad->nonce))
LOG_ERROR_AND_GOTO(fail, "Could not find \"Nonce\" property in JSON response");
if (!(aad->nonce = _strdup(token)))
goto fail;
ret = 1;
fail:
json_free(json);
cJSON_free(json);
free(buffer);
free(req_body);
free(req_header);
@ -354,60 +408,70 @@ fail:
return ret;
}
static int aad_parse_state_initial(rdpAad* aad, wStream* s)
{
const char* jstr = Stream_PointerAs(s, char);
const size_t jlen = Stream_GetRemainingLength(s);
const char* ts_nonce = NULL;
int ret = -1;
cJSON* json = NULL;
if (!Stream_SafeSeek(s, jlen))
goto fail;
json = cJSON_ParseWithLength(jstr, jlen);
if (!json)
goto fail;
if (!json_get_const_string(json, "ts_nonce", &ts_nonce))
goto fail;
ret = aad_send_auth_request(aad, ts_nonce);
fail:
cJSON_free(json);
return ret;
}
static int aad_parse_state_auth(rdpAad* aad, wStream* s)
{
int rc = -1;
double result = 0;
cJSON* 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);
if (!json)
goto fail;
if (!json_get_number(json, "authentication_result", &result))
goto fail;
rc = 1;
fail:
cJSON_free(json);
if (result != 0.0)
LOG_ERROR_AND_RETURN(-1, "Authentication result: %d", (int)result);
aad->state = AAD_STATE_FINAL;
return rc;
}
int aad_recv(rdpAad* aad, wStream* s)
{
JSON* json;
JSON* prop;
cJSON* json;
cJSON* prop;
WINPR_ASSERT(aad);
WINPR_ASSERT(s);
if (aad->state == AAD_STATE_INITIAL)
{
const char* ts_nonce = NULL;
int ret = 0;
if (!(json = json_parse(Stream_PointerAs(s, char))))
LOG_ERROR_AND_RETURN(-1, "Failed to parse Server Nonce PDU");
if (!json_object_get_prop(json, "ts_nonce", &prop) || !json_string_get(prop, &ts_nonce))
{
json_free(json);
WLog_ERR(TAG, "Failed to find ts_nonce in PDU");
return -1;
}
Stream_Seek(s, Stream_Length(s));
ret = aad_send_auth_request(aad, ts_nonce);
json_free(json);
return ret;
}
return aad_parse_state_initial(aad, s);
else if (aad->state == AAD_STATE_AUTH)
{
double result = 0;
if (!(json = json_parse(Stream_PointerAs(s, char))))
LOG_ERROR_AND_RETURN(-1, "Failed to parse Authentication Result PDU");
if (!json_object_get_prop(json, "authentication_result", &prop) ||
!json_number_get(prop, &result))
{
json_free(json);
WLog_ERR(TAG, "Failed to find authentication_result in PDU");
return -1;
}
json_free(json);
Stream_Seek(s, Stream_Length(s));
if (result != 0)
LOG_ERROR_AND_RETURN(-1, "Authentication result: %d", (int)result);
aad->state = AAD_STATE_FINAL;
return 1;
}
return aad_parse_state_auth(aad, s);
else
LOG_ERROR_AND_RETURN(-1, "Invalid state");
}

View File

@ -33,7 +33,7 @@ set(${MODULE_PREFIX}_SRCS
smartcard_pack.c
smartcard_call.c
stopwatch.c
json.c)
)
freerdp_module_add(${${MODULE_PREFIX}_SRCS})

View File

@ -1,663 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Simple JSON parser
*
* Copyright 2023 Isaac Klein <fifthdegree@protonmail.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 <freerdp/utils/json.h>
#include <winpr/assert.h>
#include <winpr/string.h>
#include <ctype.h>
const char* whitespace = " \t\n\r";
struct JSON_OBJECT
{
struct JSON_PROP** props;
size_t count;
size_t capacity;
};
struct JSON_PROP
{
char* name;
struct JSON* value;
};
struct JSON_ARRAY
{
struct JSON** values;
size_t count;
size_t capacity;
};
struct JSON
{
enum JSON_TYPE type;
union
{
struct JSON_OBJECT object;
struct JSON_ARRAY array;
double number;
char* string;
} value;
};
static JSON* json_parse_value(const char* ptr, const char** tailptr);
static JSON* json_parse_object(const char* ptr, const char** tailptr);
static JSON* json_parse_array(const char* ptr, const char** tailptr);
static JSON* json_parse_number(const char* ptr, const char** tailptr);
static JSON* json_parse_string(const char* ptr, const char** tailptr);
static char* json_parse_raw_string(const char* str, const char** tailptr);
JSON* json_parse(const char* str)
{
JSON* json = NULL;
if (!str)
return NULL;
/* A JSON text is a single value surrounded by optional whitespace */
str = str + strspn(str, whitespace);
json = json_parse_value(str, &str);
str = str + strspn(str, whitespace);
/* Text must be fully consumed */
if (*str != '\0')
{
json_free(json);
return NULL;
}
return json;
}
JSON* json_new(enum JSON_TYPE type)
{
struct JSON* json = calloc(1, sizeof(struct JSON));
if (json)
json->type = type;
if (type == JSON_TYPE_OBJECT)
{
json->value.object.props = malloc(4 * sizeof(struct JSON_PROP*));
if (!json->value.object.props)
{
free(json);
return NULL;
}
json->value.object.capacity = 4;
}
else if (type == JSON_TYPE_ARRAY)
{
json->value.array.values = malloc(4 * sizeof(struct JSON_OBJECT*));
if (!json->value.array.values)
{
free(json);
return NULL;
}
json->value.array.capacity = 4;
}
else if (type == JSON_TYPE_STRING)
{
json->value.string = _strdup("");
if (!json->value.string)
{
free(json);
return NULL;
}
}
return json;
}
void json_free(struct JSON* json)
{
if (!json)
return;
if (json->type == JSON_TYPE_OBJECT)
{
for (size_t i = 0; i < json->value.object.count; i++)
{
free(json->value.object.props[i]->name);
json_free(json->value.object.props[i]->value);
free(json->value.object.props[i]);
}
free(json->value.object.props);
}
else if (json->type == JSON_TYPE_ARRAY)
{
for (size_t i = 0; i < json->value.array.count; i++)
json_free(json->value.array.values[i]);
free(json->value.array.values);
}
else if (json->type == JSON_TYPE_STRING)
{
free(json->value.string);
}
free(json);
}
enum JSON_TYPE json_get_type(struct JSON* json)
{
if (!json)
return JSON_TYPE_NULL;
return json->type;
}
int json_object_set_prop(struct JSON* json, const char* name, JSON* value)
{
struct JSON_OBJECT* object;
struct JSON_PROP* new_prop;
if (!json || !name || !value || json->type != JSON_TYPE_OBJECT)
return 0;
object = &json->value.object;
/* If we reached capacity, double it */
if (object->capacity <= object->count)
{
size_t new_size = object->capacity * 2;
struct JSON_PROP** tmp = realloc(object->props, new_size * sizeof(struct JSON_PROP*));
if (!tmp)
return 0;
object->capacity = new_size;
object->props = tmp;
}
new_prop = calloc(1, sizeof(struct JSON_PROP));
if (!new_prop)
return 0;
new_prop->name = _strdup(name);
if (!new_prop->name)
{
free(new_prop);
return 0;
}
new_prop->value = value;
object->props[object->count++] = new_prop;
return 1;
}
int json_array_add(JSON* json, JSON* value)
{
struct JSON_ARRAY* array;
if (!json || !value || json->type != JSON_TYPE_ARRAY)
return 0;
array = &json->value.array;
/* If we reached capacity, double it */
if (array->capacity <= array->count)
{
size_t new_size = array->capacity * 2;
struct JSON** tmp = realloc(array->values, new_size * sizeof(struct JSON*));
if (!tmp)
return 0;
array->capacity = new_size;
array->values = tmp;
}
array->values[array->count++] = value;
return 1;
}
int json_number_set(struct JSON* json, double value)
{
if (!json || json->type != JSON_TYPE_NUMBER)
return 0;
json->value.number = value;
return 1;
}
int json_string_set(struct JSON* json, const char* value)
{
char* tmp;
if (!json || json->type != JSON_TYPE_STRING)
return 0;
tmp = _strdup(value);
if (!tmp)
return 0;
free(json->value.string);
json->value.string = tmp;
return 1;
}
int json_object_get_prop(struct JSON* json, const char* name, JSON** value)
{
struct JSON_OBJECT* object;
if (!json || !name || !value || json->type != JSON_TYPE_OBJECT)
return 0;
object = &json->value.object;
for (size_t i = 0; i < object->count; i++)
{
if (strcmp(object->props[i]->name, name) == 0)
{
*value = object->props[i]->value;
return 1;
}
}
return 0;
}
int json_array_get(struct JSON* json, size_t index, JSON** value)
{
struct JSON_ARRAY* array;
if (!json || !value)
return 0;
array = &json->value.array;
if (index >= array->count)
return 0;
*value = array->values[index];
return 1;
}
int json_number_get(struct JSON* json, double* value)
{
if (!json || !value)
return 0;
*value = json->value.number;
return 1;
}
int json_string_get(struct JSON* json, const char** value)
{
if (!json || !value)
return 0;
*value = json->value.string;
return 1;
}
static JSON* json_parse_value(const char* ptr, const char** tailptr)
{
struct JSON* json = NULL;
if (!ptr)
return NULL;
/* Check what type of value to expect */
if (*ptr == '{')
{
json = json_parse_object(ptr, &ptr);
}
else if (*ptr == '[')
{
json = json_parse_array(ptr, &ptr);
}
else if (*ptr == '"')
{
json = json_parse_string(ptr, &ptr);
}
else if (isdigit(*ptr) || *ptr == '-')
{
json = json_parse_number(ptr, &ptr);
}
else if (strncmp(ptr, "false", 5) == 0)
{
json = json_new(JSON_TYPE_FALSE);
ptr += 5;
}
else if (strncmp(ptr, "null", 4) == 0)
{
json = json_new(JSON_TYPE_NULL);
ptr += 4;
}
else if (strncmp(ptr, "true", 4) == 0)
{
json = json_new(JSON_TYPE_TRUE);
ptr += 4;
}
/* If all these checks fail json remains null */
if (tailptr)
*tailptr = ptr;
return json;
}
static JSON* json_parse_object(const char* ptr, const char** tailptr)
{
struct JSON* json;
char* prop_name = NULL;
if (!ptr)
return NULL;
/* Objects begin with a '{' character surrounded by optional whitespace */
ptr += strspn(ptr, whitespace);
if (*ptr++ != '{')
return NULL;
ptr += strspn(ptr, whitespace);
json = json_new(JSON_TYPE_OBJECT);
if (!json)
return NULL;
/* Objects can be empty */
/* Any leading whitespace has been consumed together with trailing whitespace of '{' above */
if (*ptr == '}')
{
/* Consume '}' and any trailing whitespace */
ptr++;
if (tailptr)
*tailptr = ptr + strspn(ptr, whitespace);
return json;
}
while (*ptr)
{
const char* cur;
prop_name = json_parse_raw_string(ptr, &ptr);
if (!prop_name)
break;
/* Property names must be followd by a ':' character with optional surrounding whitespace */
ptr += strspn(ptr, whitespace);
if (*ptr++ != ':')
break;
ptr += strspn(ptr, whitespace);
if (!json_object_set_prop(json, prop_name, json_parse_value(ptr, &ptr)))
break;
free(prop_name);
prop_name = NULL;
/* Consume any whitespace before either a '}' or ',' character */
ptr += strspn(ptr, whitespace);
cur = ptr++;
if (*cur == '}')
{
/* Consume any space following '}' and parsing is complete */
if (tailptr)
*tailptr = ptr + strspn(ptr, whitespace);
return json;
}
else if (*cur == ',')
{
/* Consume any space following ',' and continue to the next property */
ptr += strspn(ptr, whitespace);
continue;
}
else
break;
}
/* If we got here, something failed */
free(prop_name);
json_free(json);
return NULL;
}
static JSON* json_parse_array(const char* ptr, const char** tailptr)
{
struct JSON* json;
if (!ptr)
return NULL;
/* Arrays start with '[', with optional surrounding whitespace */
ptr += strspn(ptr, whitespace);
if (*ptr++ != '[')
return NULL;
ptr += strspn(ptr, whitespace);
json = json_new(JSON_TYPE_ARRAY);
if (!json)
return NULL;
/* Arrays can be empty */
/* Any leading whitespace has been consumed together with trailing whitespace of '[' above */
if (*ptr == ']')
{
/* Consume ']' and any trailing whitespace */
ptr++;
if (tailptr)
*tailptr = ptr + strspn(ptr, whitespace);
return json;
}
while (*ptr)
{
const char* cur;
if (!json_array_add(json, json_parse_value(ptr, &ptr)))
break;
/* Consume any whitespace leading ']' or ',' */
ptr += strspn(ptr, whitespace);
cur = ptr++;
if (*cur == ']')
{
/* The array is completely parsed */
if (tailptr)
*tailptr = ptr + strspn(ptr, whitespace);
return json;
}
else if (*cur == ',')
{
ptr += strspn(ptr, whitespace);
continue;
}
else
break;
}
json_free(json);
return NULL;
}
static JSON* json_parse_number(const char* ptr, const char** tailptr)
{
struct JSON* json;
char* tail;
double value;
if (!ptr)
return NULL;
value = strtod(ptr, &tail);
if (tail == ptr)
return NULL;
json = json_new(JSON_TYPE_NUMBER);
if (!json)
return NULL;
json_number_set(json, value);
if (tailptr)
*tailptr = tail;
return json;
}
static JSON* json_parse_string(const char* ptr, const char** tailptr)
{
struct JSON* json;
char *string = NULL;
if (!ptr)
return NULL;
json = json_new(JSON_TYPE_STRING);
if (!json)
return NULL;
string = json_parse_raw_string(ptr, &ptr);
if (!json_string_set(json, string))
{
json_free(json);
json = NULL;
}
free(string);
if (tailptr)
*tailptr = ptr;
return json;
}
static uint16_t get_utf16_code_point(const char* str)
{
char hexdig[5] = { 0 };
char* tailptr;
uint16_t cp;
for (int i = 0; i < 4 && isxdigit(str[i]); i++)
hexdig[i] = str[i];
if (strlen(hexdig) != 4)
return 0;
cp = (uint16_t)strtoul(hexdig, &tailptr, 16);
if (tailptr != hexdig + 4)
return 0;
return cp;
}
static char* json_parse_raw_string(const char* str, const char** tailptr)
{
char* buffer;
char* ptr;
size_t str_len = strlen(str);
int escaped = 0;
/* Strings must begin with '"' */
if (!str || *str++ != '"')
return NULL;
/* The string cannot be longer than the rest of the JSON text */
if (!(buffer = malloc(str_len)))
return NULL;
ptr = buffer;
/* Read until we encounter an unescaped end-quote or we reach the end of the text */
while (*str && (escaped || *str != '"'))
{
if (escaped)
{
char cur = *str++;
if (cur == 'u')
{
uint32_t cp;
uint16_t surrogate;
cp = get_utf16_code_point(str);
if (cp == 0)
break;
str += 4;
/* Check if this might be the high surrogate of a pair */
if (cp >= 0xD800 && cp < 0xDC00 && str[0] == '\\' && str[1] == 'u')
{
surrogate = get_utf16_code_point(str + 2);
if (surrogate >= 0xDC00 && surrogate < 0xE000)
{
cp = (((cp & 0x3FF) << 10) & (surrogate & 0x3FF)) + 0x10000;
str += 6;
}
}
/* Encode the character as utf-8 */
if (cp < 0x80)
*ptr++ = cp;
else if (cp < 0x800)
{
*ptr++ = 0xC0 | (cp >> 6);
*ptr++ = 0x80 | (cp & 0x3F);
}
else if (cp < 0x10000)
{
*ptr++ = 0xE0 | (cp >> 12);
*ptr++ = 0x80 | ((cp >> 6) & 0x3F);
*ptr++ = 0x80 | (cp & 0x3F);
}
else
{
*ptr++ = 0xF0 | (cp >> 18);
*ptr++ = 0x80 | ((cp >> 12) & 0x3F);
*ptr++ = 0x80 | ((cp >> 6) & 0x3F);
*ptr++ = 0x80 | (cp & 0x3F);
}
}
else if (cur == '"')
*ptr++ = '"';
else if (cur == '\\')
*ptr++ = '\\';
else if (cur == '/')
*ptr++ = '/';
else if (cur == 'b')
*ptr++ = '\b';
else if (cur == 'f')
*ptr++ = '\f';
else if (cur == 'n')
*ptr++ = '\n';
else if (cur == 'r')
*ptr++ = '\r';
else if (cur == 't')
*ptr++ = '\t';
else
break;
escaped = 0;
}
else if (*str == '\\')
{
str++;
escaped = 1;
}
else
*ptr++ = *str++;
}
*ptr++ = '\0';
if (escaped || *str++ != '"')
{
free(buffer);
return NULL;
}
else
{
/* Try to not tie up a potentially large amount of unused memory */
char* tmp = realloc(buffer, ptr - buffer);
if (tmp)
buffer = tmp;
}
if (tailptr)
*tailptr = str;
return buffer;
}

View File

@ -7,7 +7,7 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestRingBuffer.c
TestPodArrays.c
TestJSON.c)
)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}

View File

@ -1,82 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* TestJSON
*
* Copyright 2023 Isaac Klein <fifthdegree@protonmail.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 <freerdp/utils/json.h>
const char* valid_json = " {\n\t\"string\" :\"two\\nlines \\\"with quotes\\\"\" , \"number\": "
"-12.3, \n \"true\" : true ,\"array\":[1,\"two\", {\"three\":3}]}";
int TestJSON(int argc, char* argv[])
{
JSON* j = NULL;
const char* s = NULL;
double n = 0;
JSON* a = NULL;
JSON* json = json_parse(valid_json);
if (!json)
return -1;
if (json_get_type(json) != JSON_TYPE_OBJECT)
return -2;
if (!json_object_get_prop(json, "string", &j))
return -3;
if (json_get_type(j) != JSON_TYPE_STRING)
return -4;
if (!json_string_get(j, &s))
return -5;
if (strcmp(s, "two\nlines \"with quotes\"") != 0)
return -6;
if (!json_object_get_prop(json, "number", &j))
return -7;
if (json_get_type(j) != JSON_TYPE_NUMBER)
return -8;
if (!json_number_get(j, &n))
return -9;
if (n != -12.3)
return -10;
if (!json_object_get_prop(json, "true", &j))
return -11;
if (json_get_type(j) != JSON_TYPE_TRUE)
return -12;
if (!json_object_get_prop(json, "array", &a))
return -13;
if (json_get_type(a) != JSON_TYPE_ARRAY)
return -14;
if (!json_array_get(a, 0, &j))
return -15;
if (json_get_type(j) != JSON_TYPE_NUMBER)
return -16;
if (json_array_get(a, 3, &j) != 0)
return -17;
if (json_object_get_prop(json, "notfound", &j) != 0)
return -18;
json_free(json);
return 0;
}