add new qloud-c-sdk component
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
file(GLOB src ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
|
||||
set(inc ${CMAKE_CURRENT_SOURCE_DIR}/inc/)
|
||||
|
||||
set(src_common ${src_common} ${src} PARENT_SCOPE)
|
||||
set(inc_common ${inc_common} ${inc} PARENT_SCOPE)
|
||||
|
||||
if( ${CONFIG_IOT_TEST} STREQUAL "ON")
|
||||
file(GLOB src_unit_test ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cc)
|
||||
set(src_test ${src_test} ${src_unit_test} PARENT_SCOPE)
|
||||
endif()
|
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file utils_downloader.h
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-10-20
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-10-20 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_DOWNLOADER_H_
|
||||
#define IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_DOWNLOADER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* @brief Downloader status.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
UTILS_DOWNLOADER_STATUS_SUCCESS = 0,
|
||||
UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED,
|
||||
UTILS_DOWNLOADER_STATUS_DATA_DOWNLOAD_FAILED,
|
||||
UTILS_DOWNLOADER_STATUS_NETWORK_FAILED
|
||||
} UtilsDownloaderStatus;
|
||||
|
||||
/**
|
||||
* @brief Downloader function.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
// memory
|
||||
void* (*downloader_malloc)(size_t len); /**< user malloc */
|
||||
void (*downloader_free)(void* val); /**< user free */
|
||||
|
||||
// break point
|
||||
int (*break_point_init)(void* usr_data); /**< init break point, read from flash or file */
|
||||
void (*break_point_deinit)(void* usr_data); /**< deinit break point */
|
||||
int (*break_point_set)(void* usr_data); /**< set break point structure */
|
||||
int (*break_point_save)(void* usr_data); /**< save break point in flash or file */
|
||||
int (*break_point_check)(void* usr_data); /**< check break point valid */
|
||||
int (*break_point_restore)(void* usr_data); /**< restore break point */
|
||||
|
||||
// data download
|
||||
int (*data_download_init)(void* usr_data); /**< init data download, such as http connect */
|
||||
void (*data_download_deinit)(void* usr_data); /**< deinit data download, such as http disconnect */
|
||||
|
||||
int (*data_download_is_over)(void* usr_data); /**< check if download finish */
|
||||
int (*data_download_recv)(void* usr_data); /**< recv data, such as http recv */
|
||||
int (*data_download_save)(void* usr_data); /**< save data, such as write firmware to flash */
|
||||
int (*data_download_finish)(void* usr_data, UtilsDownloaderStatus status); /**< process result */
|
||||
} UtilsDownloaderFunction;
|
||||
|
||||
/**
|
||||
* @brief Init downloader.
|
||||
*
|
||||
* @param[in] func download function should implement
|
||||
* @param[in] usr_data user data using in function
|
||||
* @return pointer to downloader
|
||||
*/
|
||||
void* utils_downloader_init(UtilsDownloaderFunction func, void* usr_data);
|
||||
|
||||
/**
|
||||
* @brief Process download using function.
|
||||
*
|
||||
* @param[in,out] handle pointer to downloader
|
||||
* @return -1 for fail, others see data_download_finish
|
||||
*/
|
||||
int utils_downloader_process(void* handle);
|
||||
|
||||
/**
|
||||
* @brief Deinit downloader.
|
||||
*
|
||||
* @param[in,out] handle pointer to downloader
|
||||
*/
|
||||
void utils_downloader_deinit(void* handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_DOWNLOADER_H_
|
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file utils_json.h
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-07-24
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-07-24 <td>1.0 <td>fancyxu <td>first commit
|
||||
* <tr><td>2021-07-29 <td>1.1 <td>fancyxu <td>fix bug and add utils_json_value_data_get
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_JSON_H_
|
||||
#define IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_JSON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* @brief Json value type
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
UTILS_JSON_VALUE_TYPE_INT32 = 0,
|
||||
UTILS_JSON_VALUE_TYPE_INT64,
|
||||
UTILS_JSON_VALUE_TYPE_UINT32,
|
||||
UTILS_JSON_VALUE_TYPE_UINT64,
|
||||
UTILS_JSON_VALUE_TYPE_FLOAT,
|
||||
UTILS_JSON_VALUE_TYPE_DOUBLE,
|
||||
UTILS_JSON_VALUE_TYPE_BOOLEAN,
|
||||
} UtilsJsonValueType;
|
||||
|
||||
/**
|
||||
* @brief Json value
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
const char *value;
|
||||
int value_len;
|
||||
} UtilsJsonValue;
|
||||
|
||||
/**
|
||||
* @brief Get value from json string. Not strict, just for iot scene, we suppose all the string is valid json.
|
||||
*
|
||||
* @param[in] key key in json, support nesting with '.'
|
||||
* @param[in] key_len key len
|
||||
* @param[in] src json string
|
||||
* @param[in] src_len src length
|
||||
* @param[out] value value
|
||||
* @return 0 for success
|
||||
*/
|
||||
int utils_json_value_get(const char *key, int key_len, const char *src, int src_len, UtilsJsonValue *value);
|
||||
|
||||
/**
|
||||
* @brief Get data of value with type.
|
||||
*
|
||||
* @param[in] value @see UtilsJsonValue
|
||||
* @param[in] type value type, string can use value directly @see UtilsJsonValueType
|
||||
* @param[out] data data pointer, user should match the type
|
||||
* @return 0 for success
|
||||
*/
|
||||
int utils_json_value_data_get(UtilsJsonValue value, UtilsJsonValueType type, void *data);
|
||||
|
||||
/**
|
||||
* @brief Return unsigned int value of key in json.
|
||||
*
|
||||
* @return 0 for success
|
||||
*/
|
||||
int utils_json_get_uint32(const char *key, int key_len, const char *src, int src_len, uint32_t *data);
|
||||
|
||||
/**
|
||||
* @brief Remove '\\' in json string.
|
||||
*
|
||||
* @param[in,out] src string to transfer
|
||||
* @param[in] src_len string len
|
||||
* @return length after transfer
|
||||
*/
|
||||
int utils_json_strip_transfer(char *src, int src_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_JSON_H_
|
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file utils_list.h
|
||||
* @brief header file for utils list
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-05-25
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-05-25 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LIST_H_
|
||||
#define IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LIST_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief ListNode iterator direction.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
LIST_HEAD,
|
||||
LIST_TAIL,
|
||||
} UtilsListDirection;
|
||||
|
||||
/**
|
||||
* @brief ListNode process result of OnNodeProcessHandle.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
LIST_TRAVERSE_CONTINUE,
|
||||
LIST_TRAVERSE_BREAK,
|
||||
} UtilsListResult;
|
||||
|
||||
/**
|
||||
* @brief Utils list function.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
void *(*list_malloc)(size_t len);
|
||||
void (*list_free)(void *val);
|
||||
|
||||
void *(*list_lock_init)(void);
|
||||
void (*list_lock)(void *lock);
|
||||
void (*list_unlock)(void *lock);
|
||||
void (*list_lock_deinit)(void *lock);
|
||||
} UtilsListFunc;
|
||||
|
||||
/**
|
||||
* @brief Node process handle called by utils_list_process.
|
||||
*
|
||||
*/
|
||||
typedef UtilsListResult (*OnNodeProcessHandle)(void *list, void *node, void *val, void *usr_data);
|
||||
|
||||
/**
|
||||
* @brief Create list with max len, return NULL if fail.
|
||||
*
|
||||
* @param[in] func function needed by list
|
||||
* @param[in] max_len max_len of list
|
||||
* @return pointer to list, NULL for failed
|
||||
*/
|
||||
void *utils_list_create(UtilsListFunc func, int max_len);
|
||||
|
||||
/**
|
||||
* @brief Destroy list.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
*/
|
||||
void utils_list_destroy(void *list);
|
||||
|
||||
/**
|
||||
* @brief Get list len.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @return len of list
|
||||
*/
|
||||
int utils_list_len_get(void *list);
|
||||
|
||||
/**
|
||||
* @brief Push the node to list tail, return NULL if node invalid.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @param[in] val value needed to push to list
|
||||
* @return pointer to node, NULL for failed
|
||||
*/
|
||||
void *utils_list_push(void *list, void *val);
|
||||
|
||||
/**
|
||||
* @brief Pop the val from list head, return NULL if list empty.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @return val in the head node
|
||||
*/
|
||||
void *utils_list_pop(void *list);
|
||||
|
||||
/**
|
||||
* @brief Delete the node in list and release the resource.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @param[in] node pointer to node needed remove
|
||||
*/
|
||||
void utils_list_remove(void *list, void *node);
|
||||
|
||||
/**
|
||||
* @brief Process list using handle function.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @param[in] direction direction to traverse
|
||||
* @param[in] handle process function @see OnNodeProcessHandle
|
||||
* @param[in,out] usr_data usr data to pass to OnNodeProcessHandle
|
||||
*/
|
||||
void utils_list_process(void *list, uint8_t direction, OnNodeProcessHandle handle, void *usr_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LIST_H_
|
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file utils_log.h
|
||||
* @brief header file for utils log
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-05-28
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-05-28 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LOG_H_
|
||||
#define IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LOG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief SDK log print/upload level.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
LOG_LEVEL_DISABLE = 0, /**< disable log print/upload */
|
||||
LOG_LEVEL_ERROR = 1, /**< error log level */
|
||||
LOG_LEVEL_WARN = 2, /**< warning log level */
|
||||
LOG_LEVEL_INFO = 3, /**< info log level */
|
||||
LOG_LEVEL_DEBUG = 4, /**< debug log level */
|
||||
} LogLevel;
|
||||
|
||||
/**
|
||||
* @brief User's self defined log handler callback.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
void *(*log_malloc)(size_t len);
|
||||
void (*log_free)(void *val);
|
||||
void (*log_handle)(const char *message);
|
||||
void (*log_upload)(int log_level, const char *message);
|
||||
void (*log_printf)(const char *fmt, ...);
|
||||
char *(*log_get_current_time_str)(void);
|
||||
void *(*log_mutex_create)(void);
|
||||
void (*log_mutex_lock)(void *mutex);
|
||||
void (*log_mutex_unlock)(void *mutex);
|
||||
void (*log_mutex_destroy)(void *mutex);
|
||||
} LogHandleFunc;
|
||||
|
||||
/**
|
||||
* @brief Init log with func, log level, max log size.
|
||||
*
|
||||
* @param[in] func function should be implement for utils log
|
||||
* @param[in] log_level @see LogLevel
|
||||
* @param[in] max_log_size max size of log to print
|
||||
* @return 0 for success
|
||||
*/
|
||||
int utils_log_init(LogHandleFunc func, LogLevel log_level, int max_log_size);
|
||||
|
||||
/**
|
||||
* @brief Deinit log.
|
||||
*
|
||||
*/
|
||||
void utils_log_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Set log level.
|
||||
*
|
||||
* @param log_level @see LogLevel
|
||||
*/
|
||||
void utils_log_set_level(LogLevel log_level);
|
||||
|
||||
/**
|
||||
* @brief Get log level.
|
||||
*
|
||||
* @return @see LogLevel
|
||||
*/
|
||||
LogLevel utils_log_get_level(void);
|
||||
|
||||
/**
|
||||
* @brief Generate log if level higher than set.
|
||||
*
|
||||
* @param[in] file file path
|
||||
* @param[in] func function where generate log
|
||||
* @param[in] line line of source file where genertate log
|
||||
* @param[in] level @see LogLevel
|
||||
* @param[in] fmt format of log content
|
||||
*/
|
||||
void utils_log_gen(const char *file, const char *func, const int line, const int level, const char *fmt, ...);
|
||||
|
||||
// Simple APIs for log generation in different level
|
||||
#define Log_d(fmt, ...) utils_log_gen(__FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
|
||||
#define Log_i(fmt, ...) utils_log_gen(__FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
|
||||
#define Log_w(fmt, ...) utils_log_gen(__FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_WARN, fmt, ##__VA_ARGS__)
|
||||
#define Log_e(fmt, ...) utils_log_gen(__FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LOG_H_
|
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file utils_downloader.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-10-18
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-10-18 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "utils_downloader.h"
|
||||
|
||||
/**
|
||||
* @brief Downloader.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
UtilsDownloaderFunction func;
|
||||
void* usr_data;
|
||||
} UtilsDownloader;
|
||||
|
||||
/**
|
||||
* @brief Init downloader.
|
||||
*
|
||||
* @param[in] func download function should implement
|
||||
* @param[in] usr_data user data using in function
|
||||
* @return pointer to downloader
|
||||
*/
|
||||
void* utils_downloader_init(UtilsDownloaderFunction func, void* usr_data)
|
||||
{
|
||||
if (!func.downloader_malloc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UtilsDownloader* handle = func.downloader_malloc(sizeof(UtilsDownloader));
|
||||
|
||||
if (!handle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
handle->func = func;
|
||||
handle->usr_data = usr_data;
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Process download using function.
|
||||
*
|
||||
* @param[in,out] handle pointer to downloader
|
||||
* @return -1 for fail, others see data_download_finish
|
||||
*/
|
||||
int utils_downloader_process(void* handle)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
UtilsDownloader* downloader = handle;
|
||||
UtilsDownloaderStatus status = UTILS_DOWNLOADER_STATUS_SUCCESS;
|
||||
|
||||
if (!handle) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = downloader->func.break_point_init(downloader->usr_data);
|
||||
if (rc) {
|
||||
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// if check ok, restore from break point, otherwise set break point
|
||||
rc = downloader->func.break_point_check(downloader->usr_data)
|
||||
? downloader->func.break_point_set(downloader->usr_data)
|
||||
: downloader->func.break_point_restore(downloader->usr_data);
|
||||
if (rc) {
|
||||
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = downloader->func.data_download_init(downloader->usr_data);
|
||||
if (rc) {
|
||||
status = UTILS_DOWNLOADER_STATUS_DATA_DOWNLOAD_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while (!downloader->func.data_download_is_over(downloader->usr_data)) {
|
||||
rc = downloader->func.data_download_recv(downloader->usr_data);
|
||||
if (rc < 0) {
|
||||
status = UTILS_DOWNLOADER_STATUS_NETWORK_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = downloader->func.data_download_save(downloader->usr_data);
|
||||
if (rc) {
|
||||
status = UTILS_DOWNLOADER_STATUS_DATA_DOWNLOAD_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = downloader->func.break_point_save(downloader->usr_data);
|
||||
if (rc) {
|
||||
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
rc = downloader->func.data_download_finish(downloader->usr_data, status);
|
||||
downloader->func.break_point_deinit(downloader->usr_data);
|
||||
downloader->func.data_download_deinit(downloader->usr_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deinit downloader.
|
||||
*
|
||||
* @param[in,out] handle pointer to downloader
|
||||
*/
|
||||
void utils_downloader_deinit(void* handle)
|
||||
{
|
||||
UtilsDownloader* downloader = handle;
|
||||
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
downloader->func.downloader_free(handle);
|
||||
}
|
@@ -0,0 +1,577 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file utils_json.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-07-25
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-07-25 <td>1.0 <td>fancyxu <td>first commit
|
||||
* <tr><td>2021-07-29 <td>1.1 <td>fancyxu <td>fix bug and add utils_json_value_data_get
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "utils_json.h"
|
||||
|
||||
/**
|
||||
* @brief Delimiter of json
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
JSON_DELIMITER_ARRAY_BEGIN = '[',
|
||||
JSON_DELIMITER_ARRAY_END = ']',
|
||||
JSON_DELIMITER_OBJECT_BEGIN = '{',
|
||||
JSON_DELIMITER_OBJECT_END = '}',
|
||||
JSON_DELIMITER_KEY = '"',
|
||||
JSON_DELIMITER_VALUE = ':',
|
||||
JSON_DELIMITER_ELEMENT_END = ',',
|
||||
JSON_DELIMITER_TYPE_STRING = '"',
|
||||
JSON_DELIMITER_TYPE_BOOLEAN_TRUE_UPPER = 'T',
|
||||
JSON_DELIMITER_TYPE_BOOLEAN_TRUE_LOWER = 't',
|
||||
JSON_DELIMITER_TYPE_BOOLEAN_FALSE_UPPER = 'F',
|
||||
JSON_DELIMITER_TYPE_BOOLEAN_FALSE_LOWER = 'f',
|
||||
JSON_DELIMITER_TYPE_NULL_UPPER = 'N',
|
||||
JSON_DELIMITER_TYPE_NULL_LOWER = 'n',
|
||||
JSON_DELIMITER_SPACE = ' ',
|
||||
JSON_DELIMITER_NONE = 0,
|
||||
} JsonDelimiter;
|
||||
|
||||
/**
|
||||
* @brief Element type support
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
JSON_ELEMENT_ARRAY = 0,
|
||||
JSON_ELEMENT_OBJECT,
|
||||
JSON_ELEMENT_VALUE_STRING,
|
||||
JSON_ELEMENT_VALUE_NUMBER,
|
||||
JSON_ELEMENT_VALUE_BOOLEAN,
|
||||
JSON_ELEMENT_VALUE_NULL,
|
||||
JSON_ELEMENT_KEY,
|
||||
} JsonElementType;
|
||||
|
||||
/**
|
||||
* @brief Json Element
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
JsonElementType type;
|
||||
char *pos_begin;
|
||||
char *pos_end;
|
||||
int element_len;
|
||||
} JsonElement;
|
||||
|
||||
#define json_key JsonElement
|
||||
#define json_value JsonElement
|
||||
|
||||
/**
|
||||
* @brief Is delimiter begin or end matched
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
int (*is_begin_matched)(char *str);
|
||||
int (*is_end_matched)(char *str, int *offset);
|
||||
} IsDelimiterMatched;
|
||||
|
||||
/**
|
||||
* @brief For array type, when meets '[', means depth++
|
||||
*
|
||||
* @param[in] str pointer to char
|
||||
* @return true for matched
|
||||
*/
|
||||
static int _is_array_begin_matched(char *str)
|
||||
{
|
||||
return *str == JSON_DELIMITER_ARRAY_BEGIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For array type, when meets ']', means depth--
|
||||
*
|
||||
* @param[in] str pointer to char
|
||||
* @param[out] offset offset for pointer to move
|
||||
* @return true for matched
|
||||
*/
|
||||
static int _is_array_end_matched(char *str, int *offset)
|
||||
{
|
||||
return *str == JSON_DELIMITER_ARRAY_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For object type, when meets '{', means depth++
|
||||
*
|
||||
* @param[in] str pointer to char
|
||||
* @return true for matched
|
||||
*/
|
||||
static int _is_object_begin_matched(char *str)
|
||||
{
|
||||
return *str == JSON_DELIMITER_OBJECT_BEGIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For object type, when meets '}', means depth--
|
||||
*
|
||||
* @param[in] str pointer to char
|
||||
* @param[out] offset offset for pointer to move
|
||||
* @return true for matched
|
||||
*/
|
||||
static int _is_object_end_matched(char *str, int *offset)
|
||||
{
|
||||
return *str == JSON_DELIMITER_OBJECT_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For string type, when meets '"', but not "\"", means the end
|
||||
*
|
||||
* @param[in] str pointer to char
|
||||
* @param[out] offset offset for pointer to move
|
||||
* @return true for matched
|
||||
*/
|
||||
static int _is_string_end_matched(char *str, int *offset)
|
||||
{
|
||||
return *str == '"' && *(str - 1) != '\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For number type, when meets not '0~9', '.' or 'f' for float, means the end
|
||||
*
|
||||
* @param[in] str pointer to char
|
||||
* @param[out] offset offset for pointer to move
|
||||
* @return true for matched
|
||||
*/
|
||||
static int _is_number_end_matched(char *str, int *offset)
|
||||
{
|
||||
return (*str < '0' || *str > '9') && *str != '.' && *str != 'f' && *str != '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For boolen type, when meets "true", "True", "false" or "False", means the end
|
||||
*
|
||||
* @param[in] str pointer to char
|
||||
* @param[out] offset offset for pointer to move, -1 means error
|
||||
* @return true for matched
|
||||
*/
|
||||
static int _is_boolean_end_matched(char *str, int *offset)
|
||||
{
|
||||
*offset = !strncmp(str, "true", 4) || !strncmp(str, "TRUE", 4) ? 4 : *offset;
|
||||
*offset = !strncmp(str, "false", 5) || !strncmp(str, "FALSE", 5) ? 5 : *offset;
|
||||
if (*offset == 0) {
|
||||
*offset = -1; // -1 means error
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For boolen type, when meets "null", "NULL", means the end
|
||||
*
|
||||
* @param[in] str pointer to char
|
||||
* @param[out] offset offset for pointer to move, -1 means error
|
||||
* @return true for matched
|
||||
*/
|
||||
static int _is_null_end_matched(char *str, int *offset)
|
||||
{
|
||||
*offset = !strncmp(str, "null", 4) || !strncmp(str, "NULL", 4) ? 4 : 0;
|
||||
if (*offset == 0) {
|
||||
*offset = -1; // -1 means error
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Table of matched function of elements
|
||||
*
|
||||
*/
|
||||
static IsDelimiterMatched sg_element_matched_func[] = {
|
||||
{_is_array_begin_matched, _is_array_end_matched}, // JSON_ELEMENT_ARRAY
|
||||
{_is_object_begin_matched, _is_object_end_matched}, // JSON_ELEMENT_OBJECT
|
||||
{NULL, _is_string_end_matched}, // JSON_ELEMENT_VALUE_STRING
|
||||
{NULL, _is_number_end_matched}, // JSON_ELEMENT_VALUE_NUMBER
|
||||
{NULL, _is_boolean_end_matched}, // JSON_ELEMENT_VALUE_BOOLEAN
|
||||
{NULL, _is_null_end_matched}, // JSON_ELEMENT_VALUE_NULL
|
||||
{NULL, NULL}, // JSON_ELEMENT_KEY
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Increase pos and decrease remain len
|
||||
*
|
||||
* @param[in,out] pos current pos
|
||||
* @param[in,out] len current len
|
||||
*/
|
||||
static void _increase_pos(char **pos, int *len)
|
||||
{
|
||||
(*pos)++;
|
||||
(*len)--;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Find delimiter and return pos
|
||||
*
|
||||
* @param[in] ch delimiter character
|
||||
* @param[in] spilt_char if 0 then spilt nothing but delimiter
|
||||
* @param[in] str input string
|
||||
* @param[in,out] remain_len remaining length
|
||||
* @return NULL for failed
|
||||
*/
|
||||
static char *_find_json_delimiter(JsonDelimiter ch, char spilt_char, char *str, int *remain_len)
|
||||
{
|
||||
char *pos = NULL;
|
||||
|
||||
while ((*remain_len) > 0 && str && *str) {
|
||||
if ((!spilt_char && *str != ch) || (spilt_char && *str == spilt_char)) {
|
||||
_increase_pos(&str, remain_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
pos = (*str == ch) ? str : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find element end
|
||||
*
|
||||
* @param[in] is_begin_matched using in nesting
|
||||
* @param[in] is_end_matched match end
|
||||
* @param[in] str input string
|
||||
* @param[in,out] remain_len remaining length
|
||||
* @return NULL for failed
|
||||
*/
|
||||
static char *_find_json_value_element_end(int (*is_begin_matched)(char *), int (*is_end_matched)(char *, int *),
|
||||
char *str, int *remain_len)
|
||||
{
|
||||
int offset = 0;
|
||||
int depth = 0;
|
||||
char *pos = NULL;
|
||||
|
||||
while (str && *str) {
|
||||
offset = 0;
|
||||
|
||||
if (*remain_len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_begin_matched) {
|
||||
if (is_begin_matched(str)) {
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_end_matched(str, &offset)) {
|
||||
if (!depth) {
|
||||
if (offset < 0) {
|
||||
break; // failed
|
||||
}
|
||||
pos = str + offset;
|
||||
(*remain_len) -= offset;
|
||||
break;
|
||||
}
|
||||
|
||||
if (depth > 0) {
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
|
||||
str++;
|
||||
(*remain_len)--;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get json key from string
|
||||
*
|
||||
* @param[in] node_begin string begin
|
||||
* @param[in,out] remain_len remaining length
|
||||
* @param[out] key key node
|
||||
* @return 0 for success
|
||||
*/
|
||||
static int _get_json_key(char *node_begin, int *remain_len, json_key *key)
|
||||
{
|
||||
char *key_begin = _find_json_delimiter(JSON_DELIMITER_KEY, JSON_DELIMITER_SPACE, node_begin, remain_len);
|
||||
if (!key_begin) {
|
||||
return -1;
|
||||
}
|
||||
_increase_pos(&key_begin, remain_len);
|
||||
|
||||
char *key_end = _find_json_delimiter(JSON_DELIMITER_KEY, JSON_DELIMITER_NONE, key_begin, remain_len);
|
||||
if (!key_end) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
key->type = JSON_ELEMENT_KEY;
|
||||
key->pos_begin = key_begin;
|
||||
key->pos_end = key_end;
|
||||
key->element_len = key_end - key_begin;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get json value from key end
|
||||
*
|
||||
* @param[in] key_end end of key
|
||||
* @param[in,out] remain_len remaining length
|
||||
* @param[out] value value node
|
||||
* @return 0 for success
|
||||
*/
|
||||
static int _get_json_value(char *key_end, int *remain_len, json_value *value)
|
||||
{
|
||||
char *value_begin = _find_json_delimiter(JSON_DELIMITER_VALUE, JSON_DELIMITER_SPACE, key_end, remain_len);
|
||||
if (!value_begin) {
|
||||
return -1;
|
||||
}
|
||||
_increase_pos(&value_begin, remain_len);
|
||||
|
||||
// filter all the space
|
||||
while (*value_begin == ' ') {
|
||||
value_begin++;
|
||||
(*remain_len)--;
|
||||
if (*remain_len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
JsonElementType type;
|
||||
|
||||
char *value_end = NULL;
|
||||
|
||||
switch (*value_begin) {
|
||||
case JSON_DELIMITER_ARRAY_BEGIN:
|
||||
// should + 1 for escape first [
|
||||
_increase_pos(&value_begin, remain_len);
|
||||
type = JSON_ELEMENT_ARRAY;
|
||||
break;
|
||||
case JSON_DELIMITER_OBJECT_BEGIN:
|
||||
// should + 1 for escape first {
|
||||
_increase_pos(&value_begin, remain_len);
|
||||
type = JSON_ELEMENT_OBJECT;
|
||||
break;
|
||||
case JSON_DELIMITER_TYPE_STRING:
|
||||
// should + 1 for escape first "
|
||||
_increase_pos(&value_begin, remain_len);
|
||||
type = JSON_ELEMENT_VALUE_STRING;
|
||||
break;
|
||||
case JSON_DELIMITER_TYPE_BOOLEAN_TRUE_UPPER:
|
||||
case JSON_DELIMITER_TYPE_BOOLEAN_TRUE_LOWER:
|
||||
case JSON_DELIMITER_TYPE_BOOLEAN_FALSE_UPPER:
|
||||
case JSON_DELIMITER_TYPE_BOOLEAN_FALSE_LOWER:
|
||||
type = JSON_ELEMENT_VALUE_BOOLEAN;
|
||||
break;
|
||||
case JSON_DELIMITER_TYPE_NULL_UPPER:
|
||||
case JSON_DELIMITER_TYPE_NULL_LOWER:
|
||||
type = JSON_ELEMENT_VALUE_NULL;
|
||||
break;
|
||||
default:
|
||||
type = JSON_ELEMENT_VALUE_NUMBER;
|
||||
break;
|
||||
}
|
||||
|
||||
value_end = _find_json_value_element_end(sg_element_matched_func[type].is_begin_matched,
|
||||
sg_element_matched_func[type].is_end_matched, value_begin, remain_len);
|
||||
if (!value_end) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int is_object_or_array = (type == JSON_ELEMENT_ARRAY || type == JSON_ELEMENT_OBJECT);
|
||||
int is_object_or_array_or_string = (is_object_or_array || type == JSON_ELEMENT_VALUE_STRING);
|
||||
|
||||
value->type = type;
|
||||
value->pos_begin = value_begin - is_object_or_array; // include '[' or '{'
|
||||
value->element_len = value_end - value->pos_begin + is_object_or_array; // include ']' or '}'
|
||||
value->pos_end = value_end + is_object_or_array_or_string; // filter '"' , ']' or '}'
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get value by key from json string
|
||||
*
|
||||
* @param[in] str json string
|
||||
* @param[in] str_len strign length
|
||||
* @param[in] key key
|
||||
* @param[in] key_len key length
|
||||
* @param[out] value value
|
||||
* @return 0 for success
|
||||
*/
|
||||
int json_get_value_by_key(const char *str, int str_len, const char *key, int key_len, json_value *value)
|
||||
{
|
||||
int rc = 0;
|
||||
char *object_begin = NULL;
|
||||
json_key key_found = {JSON_ELEMENT_KEY, 0, 0, 0};
|
||||
|
||||
object_begin = _find_json_delimiter(JSON_DELIMITER_OBJECT_BEGIN, JSON_DELIMITER_SPACE, (char *)str, &str_len);
|
||||
if (!object_begin) {
|
||||
return -1;
|
||||
}
|
||||
_increase_pos(&object_begin, &str_len);
|
||||
|
||||
do {
|
||||
rc = _get_json_key(object_begin, &str_len, &key_found);
|
||||
if (rc) {
|
||||
break;
|
||||
}
|
||||
_increase_pos(&key_found.pos_end, &str_len);
|
||||
|
||||
rc = _get_json_value(key_found.pos_end, &str_len, value);
|
||||
if (rc) {
|
||||
break;
|
||||
}
|
||||
|
||||
// NULL of object begin can be ok for reach the end of str
|
||||
object_begin = _find_json_delimiter(JSON_DELIMITER_ELEMENT_END, JSON_DELIMITER_SPACE, value->pos_end, &str_len);
|
||||
if (object_begin) {
|
||||
_increase_pos(&object_begin, &str_len);
|
||||
}
|
||||
} while (key_len != key_found.element_len || strncmp(key, key_found.pos_begin, key_found.element_len));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get value from json string. Not strict, just for iot scene, we suppose all the string is valid json.
|
||||
*
|
||||
* @param[in] key key in json, support nesting with '.'
|
||||
* @param[in] key_len key len
|
||||
* @param[in] src json string
|
||||
* @param[in] src_len src length
|
||||
* @param[out] value value
|
||||
* @return 0 for success
|
||||
*/
|
||||
int utils_json_value_get(const char *key, int key_len, const char *src, int src_len, UtilsJsonValue *value)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
char *delim = NULL;
|
||||
char *src_iter = (char *)src;
|
||||
int src_iter_len = src_len;
|
||||
char *key_iter = (char *)key;
|
||||
char *key_next = NULL;
|
||||
int key_next_len = 0;
|
||||
|
||||
json_value value_tmp;
|
||||
|
||||
// key can be separated by '.', such as: outer_key.(.......).inner_key
|
||||
while ((delim = strchr(key_iter, '.'))) {
|
||||
key_next = key_iter;
|
||||
key_next_len = delim - key_iter;
|
||||
|
||||
rc = json_get_value_by_key(src_iter, src_iter_len, key_next, key_next_len, &value_tmp);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
src_iter = value_tmp.pos_begin;
|
||||
src_iter_len = value_tmp.element_len;
|
||||
key_iter = delim + 1;
|
||||
}
|
||||
|
||||
// found inner key and get value
|
||||
rc = json_get_value_by_key(src_iter, src_iter_len, key_iter, key_len + key - key_iter, &value_tmp);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
value->value = value_tmp.pos_begin;
|
||||
value->value_len = value_tmp.element_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get data of value with type.
|
||||
*
|
||||
* @param[in] value @see UtilsJsonValue
|
||||
* @param[in] type value type, string can use value directly. @see UtilsJsonValueType
|
||||
* @param[out] data data pointer, user should
|
||||
* @return 0 for success
|
||||
*/
|
||||
int utils_json_value_data_get(UtilsJsonValue value, UtilsJsonValueType type, void *data)
|
||||
{
|
||||
char value_tmp[32] = {0};
|
||||
|
||||
if (value.value_len > sizeof(value_tmp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(value_tmp, value.value, value.value_len);
|
||||
|
||||
switch (type) {
|
||||
case UTILS_JSON_VALUE_TYPE_INT32:
|
||||
return !(sscanf(value_tmp, "%" SCNi32, (int32_t *)data) == 1);
|
||||
case UTILS_JSON_VALUE_TYPE_INT64:
|
||||
return !(sscanf(value_tmp, "%" SCNi64, (int64_t *)data) == 1);
|
||||
case UTILS_JSON_VALUE_TYPE_UINT32:
|
||||
return !(sscanf(value_tmp, "%" SCNu32, (uint32_t *)data) == 1);
|
||||
case UTILS_JSON_VALUE_TYPE_UINT64:
|
||||
return !(sscanf(value_tmp, "%" SCNu64, (uint64_t *)data) == 1);
|
||||
case UTILS_JSON_VALUE_TYPE_FLOAT:
|
||||
return !(sscanf(value_tmp, "%f", (float *)data) == 1);
|
||||
case UTILS_JSON_VALUE_TYPE_DOUBLE:
|
||||
return !(sscanf(value_tmp, "%lf", (double *)data) == 1);
|
||||
case UTILS_JSON_VALUE_TYPE_BOOLEAN:
|
||||
*(int *)data = strcmp(value_tmp, "false");
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return unsigned int value of key in json.
|
||||
*
|
||||
* @return 0 for success
|
||||
*/
|
||||
int utils_json_get_uint32(const char *key, int key_len, const char *src, int src_len, uint32_t *data)
|
||||
{
|
||||
int rc;
|
||||
UtilsJsonValue tmp;
|
||||
|
||||
rc = utils_json_value_get(key, key_len, src, src_len, &tmp);
|
||||
if (rc) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = utils_json_value_data_get(tmp, UTILS_JSON_VALUE_TYPE_UINT32, data);
|
||||
if (rc) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove '\\' in json string.
|
||||
*
|
||||
* @param[in,out] src string to transfer
|
||||
* @param[in] src_len string len
|
||||
* @return length after transfer
|
||||
*/
|
||||
int utils_json_strip_transfer(char *src, int src_len)
|
||||
{
|
||||
char *src_tmp = src;
|
||||
char *end = src + src_len;
|
||||
|
||||
while (src_tmp < end) {
|
||||
if (*src_tmp == '\\') {
|
||||
memmove(src_tmp, src_tmp + 1, end - src_tmp);
|
||||
end--;
|
||||
}
|
||||
src_tmp++;
|
||||
}
|
||||
return end - src;
|
||||
}
|
@@ -0,0 +1,326 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file utils_list.c
|
||||
* @brief utils list operation
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-05-25
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-05-28 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "utils_list.h"
|
||||
|
||||
/**
|
||||
* @brief Define list node.
|
||||
*
|
||||
*/
|
||||
typedef struct ListNode {
|
||||
struct ListNode *prev;
|
||||
struct ListNode *next;
|
||||
void * val;
|
||||
} ListNode;
|
||||
|
||||
/**
|
||||
* @brief Double Linked List.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
UtilsListFunc func;
|
||||
ListNode * head;
|
||||
ListNode * tail;
|
||||
void * lock;
|
||||
int len;
|
||||
int max_len;
|
||||
} List;
|
||||
|
||||
/**
|
||||
* @brief List iterator.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
List * list;
|
||||
ListNode * next;
|
||||
UtilsListDirection direction;
|
||||
} ListIterator;
|
||||
|
||||
/**
|
||||
* @brief Lock list.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
*/
|
||||
static inline void _list_lock(List *list)
|
||||
{
|
||||
if (list->lock) {
|
||||
list->func.list_lock(list->lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unlock list.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
*/
|
||||
static inline void _list_unlock(List *list)
|
||||
{
|
||||
if (list->lock) {
|
||||
list->func.list_unlock(list->lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete the node in list and release the resource.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @param[in] node pointer to node needed remove
|
||||
*/
|
||||
static void _list_remove(void *list, void *node)
|
||||
{
|
||||
List * self = (List *)list;
|
||||
ListNode *list_node = (ListNode *)node;
|
||||
|
||||
list_node->prev ? (list_node->prev->next = list_node->next) : (self->head = list_node->next);
|
||||
|
||||
list_node->next ? (list_node->next->prev = list_node->prev) : (self->tail = list_node->prev);
|
||||
|
||||
self->func.list_free(list_node->val);
|
||||
self->func.list_free(list_node);
|
||||
|
||||
if (self->len) {
|
||||
--self->len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create list with max len, return NULL if fail.
|
||||
*
|
||||
* @param[in] func function needed by list
|
||||
* @param[in] max_len max_len of list
|
||||
* @return pointer to list, NULL for failed
|
||||
*/
|
||||
void *utils_list_create(UtilsListFunc func, int max_len)
|
||||
{
|
||||
List *self;
|
||||
|
||||
if (max_len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self = (List *)func.list_malloc(sizeof(List));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(self, 0, sizeof(List));
|
||||
|
||||
if (func.list_lock_init) {
|
||||
self->lock = func.list_lock_init();
|
||||
if (!self->lock) {
|
||||
func.list_free(self);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
self->func = func;
|
||||
self->max_len = max_len;
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy list.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
*/
|
||||
void utils_list_destroy(void *list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
|
||||
List *self = (List *)list;
|
||||
|
||||
uint32_t len = self->len;
|
||||
|
||||
ListNode *next;
|
||||
ListNode *curr = self->head;
|
||||
|
||||
while (len--) {
|
||||
next = curr->next;
|
||||
self->func.list_free(curr->val);
|
||||
self->func.list_free(curr);
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if (self->lock) {
|
||||
self->func.list_lock_deinit(self->lock);
|
||||
}
|
||||
self->func.list_free(self);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get list len.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @return len of list
|
||||
*/
|
||||
int utils_list_len_get(void *list)
|
||||
{
|
||||
List *self = (List *)list;
|
||||
return self->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Push the node to list tail, return NULL if node invalid.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @param[in] val value needed to push to list
|
||||
* @return pointer to node, NULL for failed
|
||||
*/
|
||||
void *utils_list_push(void *list, void *val)
|
||||
{
|
||||
List *self = (List *)list;
|
||||
|
||||
_list_lock(self);
|
||||
|
||||
if (!val || self->len >= self->max_len) {
|
||||
_list_unlock(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ListNode *node;
|
||||
node = self->func.list_malloc(sizeof(ListNode));
|
||||
if (!node) {
|
||||
_list_unlock(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
node->val = val;
|
||||
|
||||
if (self->len) {
|
||||
node->prev = self->tail;
|
||||
node->next = NULL;
|
||||
self->tail->next = node;
|
||||
self->tail = node;
|
||||
} else {
|
||||
self->head = self->tail = node;
|
||||
node->prev = node->next = NULL;
|
||||
}
|
||||
|
||||
++self->len;
|
||||
|
||||
_list_unlock(self);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pop the value from list head, return NULL if list empty.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @return value in the head node
|
||||
*/
|
||||
void *utils_list_pop(void *list)
|
||||
{
|
||||
List * self = (List *)list;
|
||||
ListNode *node = NULL;
|
||||
|
||||
_list_lock(self);
|
||||
|
||||
if (!self->len) {
|
||||
_list_unlock(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = self->head;
|
||||
|
||||
if (--self->len) {
|
||||
(self->head = node->next)->prev = NULL;
|
||||
} else {
|
||||
self->head = self->tail = NULL;
|
||||
}
|
||||
|
||||
node->next = node->prev = NULL;
|
||||
|
||||
_list_unlock(self);
|
||||
|
||||
void *val = node->val;
|
||||
self->func.list_free(node);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete the node in list and release the resource.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @param[in] node pointer to node needed remove
|
||||
*/
|
||||
void utils_list_remove(void *list, void *node)
|
||||
{
|
||||
List *self = (List *)list;
|
||||
_list_lock(self);
|
||||
_list_remove(self, node);
|
||||
_list_unlock(self);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Process list using handle function.
|
||||
*
|
||||
* @param[in] list pointer to list
|
||||
* @param[in] direction direction to traverse
|
||||
* @param[in] handle process function @see OnNodeProcessHandle
|
||||
* @param[in,out] usr_data usr data to pass to OnNodeProcessHandle
|
||||
*/
|
||||
void utils_list_process(void *list, uint8_t direction, OnNodeProcessHandle handle, void *usr_data)
|
||||
{
|
||||
int rc;
|
||||
ListNode *node = NULL;
|
||||
List * self = (List *)list;
|
||||
|
||||
_list_lock(self);
|
||||
|
||||
if (!utils_list_len_get(list)) {
|
||||
_list_unlock(self);
|
||||
return;
|
||||
}
|
||||
|
||||
ListIterator iterator = {
|
||||
.direction = direction,
|
||||
.list = self,
|
||||
.next = direction == LIST_HEAD ? self->head : self->tail,
|
||||
};
|
||||
|
||||
// traverse list to process
|
||||
while ((node = iterator.next)) {
|
||||
iterator.next = iterator.direction == LIST_HEAD ? node->next : node->prev;
|
||||
if (!node->val) {
|
||||
_list_remove(list, node);
|
||||
continue;
|
||||
}
|
||||
// process node and val
|
||||
if (handle) {
|
||||
rc = handle(list, node, node->val, usr_data);
|
||||
if (rc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_list_unlock(list);
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file utils_log.c
|
||||
* @brief different level log generator
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-05-28
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-05-28 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "utils_log.h"
|
||||
|
||||
static const char *LEVEL_STR[] = {"DIS", "ERR", "WRN", "INF", "DBG"};
|
||||
static LogHandleFunc sg_log_handle_func;
|
||||
static char *sg_log_buffer;
|
||||
static int sg_log_max_size;
|
||||
static void *sg_log_mutex;
|
||||
static LogLevel sg_log_print_level = LOG_LEVEL_DEBUG;
|
||||
extern LogLevel sg_log_upload_level;
|
||||
|
||||
/**
|
||||
* @brief Get file name form path.
|
||||
*
|
||||
* @param[in] path file path
|
||||
* @return file name
|
||||
*/
|
||||
static const char *_get_filename(const char *path)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char ch = '\\';
|
||||
#else
|
||||
char ch = '/';
|
||||
#endif
|
||||
const char *q = strrchr(path, ch);
|
||||
if (!q) {
|
||||
q = path;
|
||||
} else {
|
||||
q++;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init log with func, log level, max log size.
|
||||
*
|
||||
* @param[in] func function should be implement for utils log
|
||||
* @param[in] log_level @see LogLevel
|
||||
* @param[in] max_log_size max size of log to print
|
||||
* @return 0 for success
|
||||
*/
|
||||
int utils_log_init(LogHandleFunc func, LogLevel log_level, int max_log_size)
|
||||
{
|
||||
sg_log_handle_func = func;
|
||||
sg_log_print_level = log_level;
|
||||
sg_log_max_size = max_log_size;
|
||||
if (func.log_mutex_create) {
|
||||
sg_log_mutex = func.log_mutex_create();
|
||||
if (!sg_log_mutex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (func.log_malloc) {
|
||||
sg_log_buffer = func.log_malloc(max_log_size);
|
||||
if (!sg_log_buffer) {
|
||||
if (sg_log_mutex) {
|
||||
func.log_mutex_destroy(sg_log_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return !sg_log_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deinit log.
|
||||
*
|
||||
*/
|
||||
void utils_log_deinit(void)
|
||||
{
|
||||
sg_log_handle_func.log_free(sg_log_buffer);
|
||||
if (sg_log_mutex) {
|
||||
sg_log_handle_func.log_mutex_destroy(sg_log_mutex);
|
||||
}
|
||||
sg_log_mutex = NULL;
|
||||
sg_log_buffer = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set log level.
|
||||
*
|
||||
* @param log_level @see LogLevel
|
||||
*/
|
||||
void utils_log_set_level(LogLevel log_level)
|
||||
{
|
||||
sg_log_print_level = log_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get log level.
|
||||
*
|
||||
* @return @see LogLevel
|
||||
*/
|
||||
LogLevel utils_log_get_level(void)
|
||||
{
|
||||
return sg_log_print_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate log if level higher than set.
|
||||
*
|
||||
* @param[in] file file path
|
||||
* @param[in] func function where generate log
|
||||
* @param[in] line line of source file where genertate log
|
||||
* @param[in] level @see LogLevel
|
||||
* @param[in] fmt format of log content
|
||||
*/
|
||||
void utils_log_gen(const char *file, const char *func, const int line, const int level, const char *fmt, ...)
|
||||
{
|
||||
if (level > sg_log_print_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sg_log_mutex) {
|
||||
sg_log_handle_func.log_mutex_lock(sg_log_mutex);
|
||||
}
|
||||
|
||||
/* format log content */
|
||||
const char *file_name = _get_filename(file);
|
||||
char *o = sg_log_buffer;
|
||||
|
||||
memset(sg_log_buffer, 0, sg_log_max_size);
|
||||
|
||||
o += snprintf(sg_log_buffer, sg_log_max_size, "%s|%s|%s|%s(%d): ", LEVEL_STR[level],
|
||||
sg_log_handle_func.log_get_current_time_str(), file_name, func, line);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(o, sg_log_max_size - 2 - strlen(sg_log_buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
strncat(sg_log_buffer, "\r\n", sg_log_max_size - strlen(sg_log_buffer) - 1);
|
||||
|
||||
if (level <= sg_log_print_level) {
|
||||
if (sg_log_handle_func.log_handle) {
|
||||
sg_log_handle_func.log_handle(sg_log_buffer);
|
||||
}
|
||||
sg_log_handle_func.log_printf("%s", sg_log_buffer);
|
||||
}
|
||||
|
||||
/* append to upload buffer */
|
||||
if (sg_log_handle_func.log_upload) {
|
||||
sg_log_handle_func.log_upload(level, sg_log_buffer);
|
||||
}
|
||||
|
||||
if (sg_log_mutex) {
|
||||
sg_log_handle_func.log_mutex_unlock(sg_log_mutex);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 120
|
||||
DerivePointerAlignment: true
|
||||
PointerAlignment: Left
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Preserve
|
||||
IndentPPDirectives: AfterHash
|
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file test_utils.cc
|
||||
* @brief unittest for utils
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-07-07
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-07-07 <td>1.0 <td>fancyxu <td>first commit
|
||||
* <tr><td>2021-07-27 <td>1.1 <td>fancyxu <td>support utils json
|
||||
* <tr><td>2021-07-29 <td>1.1 <td>fancyxu <td>rename HAL_Timer and add utils json test
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "qcloud_iot_platform.h"
|
||||
#include "utils_json.h"
|
||||
#include "utils_list.h"
|
||||
#include "utils_log.h"
|
||||
|
||||
namespace utils_unittest {
|
||||
|
||||
/**
|
||||
* @brief test fixture of utils list
|
||||
*
|
||||
*/
|
||||
class UtilsListTest : public testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
UtilsListFunc func = {
|
||||
.list_malloc = HAL_Malloc,
|
||||
.list_free = HAL_Free,
|
||||
.list_lock_init = HAL_MutexCreate,
|
||||
.list_lock = HAL_MutexLock,
|
||||
.list_unlock = HAL_MutexUnlock,
|
||||
.list_lock_deinit = HAL_MutexDestroy,
|
||||
};
|
||||
|
||||
self_list = utils_list_create(func, 10);
|
||||
ASSERT_NE(self_list, nullptr);
|
||||
|
||||
for (int i = 0; i < 10;) {
|
||||
int *val = reinterpret_cast<int *>(HAL_Malloc(sizeof(int)));
|
||||
*val = i++;
|
||||
ASSERT_NE(utils_list_push(self_list, reinterpret_cast<void *>(val)), nullptr);
|
||||
ASSERT_EQ(utils_list_len_get(self_list), i);
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown() override { utils_list_destroy(self_list); }
|
||||
|
||||
void *self_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Test list.
|
||||
*
|
||||
*/
|
||||
TEST_F(UtilsListTest, list) {
|
||||
ASSERT_EQ(utils_list_push(self_list, reinterpret_cast<void *>(1)), nullptr);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_EQ(utils_list_len_get(self_list), 10 - i);
|
||||
int *val = reinterpret_cast<int *>(utils_list_pop(self_list));
|
||||
ASSERT_EQ(*val, i);
|
||||
HAL_Free(val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test remove list node
|
||||
*
|
||||
* @param[in,out] list pointer to list
|
||||
* @param[in,out] node pointer to node
|
||||
* @param[in,out] val pointer to val
|
||||
* @param[in,out] usr_data pointer to usr data
|
||||
* @return @see UtilsListResult
|
||||
*/
|
||||
static UtilsListResult list_process_remove(void *list, void *node, void *val, void *usr_data) {
|
||||
static int i = 0;
|
||||
if (*reinterpret_cast<int *>(val) != i++) {
|
||||
return LIST_TRAVERSE_BREAK;
|
||||
}
|
||||
utils_list_remove(list, node);
|
||||
return LIST_TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test list process.
|
||||
*
|
||||
*/
|
||||
TEST_F(UtilsListTest, list_process) {
|
||||
utils_list_process(self_list, LIST_HEAD, list_process_remove, NULL);
|
||||
ASSERT_EQ(utils_list_len_get(self_list), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test log.
|
||||
*
|
||||
*/
|
||||
TEST(UtilsLogTest, log) {
|
||||
LogHandleFunc func = {0};
|
||||
|
||||
func.log_malloc = HAL_Malloc;
|
||||
func.log_free = HAL_Free;
|
||||
func.log_get_current_time_str = HAL_Timer_Current;
|
||||
func.log_printf = HAL_Printf;
|
||||
ASSERT_EQ(utils_log_init(func, LOG_LEVEL_DEBUG, 2048), 0);
|
||||
Log_d("Here is a debug level log test!");
|
||||
Log_i("Here is a info level log test!");
|
||||
Log_w("Here is a warning level log test!");
|
||||
Log_e("Here is a error level log test!");
|
||||
utils_log_deinit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test json.
|
||||
*
|
||||
*/
|
||||
TEST(UtilsJsonTest, json) {
|
||||
char test_json[] =
|
||||
"{\"str_test\":\"test\",\"int_test\":100,\"float_test\":1.210f,\"bool_test\":true,"
|
||||
"\"bool_false_test\":false,\"null_test\":null}";
|
||||
|
||||
UtilsJsonValue value;
|
||||
|
||||
int data_int = 0;
|
||||
ASSERT_EQ(utils_json_value_get("int_test", strlen("int_test"), test_json, strlen(test_json), &value), 0);
|
||||
ASSERT_EQ(utils_json_value_data_get(value, UTILS_JSON_VALUE_TYPE_INT32, &data_int), 0);
|
||||
ASSERT_EQ(data_int, 100);
|
||||
|
||||
float data_float = 0.0;
|
||||
ASSERT_EQ(utils_json_value_get("float_test", strlen("float_test"), test_json, strlen(test_json), &value), 0);
|
||||
ASSERT_EQ(utils_json_value_data_get(value, UTILS_JSON_VALUE_TYPE_FLOAT, &data_float), 0);
|
||||
ASSERT_EQ(data_float, 1.210f);
|
||||
|
||||
ASSERT_EQ(utils_json_value_get("bool_test", strlen("bool_test"), test_json, strlen(test_json), &value), 0);
|
||||
ASSERT_EQ(strncmp(value.value, "true", value.value_len), 0);
|
||||
|
||||
ASSERT_EQ(utils_json_value_get("bool_false_test", strlen("bool_false_test"), test_json, strlen(test_json), &value),
|
||||
0);
|
||||
ASSERT_EQ(strncmp(value.value, "false", value.value_len), 0);
|
||||
|
||||
ASSERT_EQ(utils_json_value_get("null_test", strlen("null_test"), test_json, strlen(test_json), &value), 0);
|
||||
ASSERT_EQ(strncmp(value.value, "null", value.value_len), 0);
|
||||
|
||||
ASSERT_EQ(utils_json_value_get("str_test", strlen("str_test"), test_json, strlen(test_json), &value), 0);
|
||||
ASSERT_EQ(strncmp(value.value, "test", value.value_len), 0);
|
||||
|
||||
char test_json_depth[] = "{\"depth_test\": {\"test\":\"test1\"}}";
|
||||
ASSERT_EQ(utils_json_value_get("depth_test.test", strlen("depth_test.test"), test_json_depth, strlen(test_json_depth),
|
||||
&value),
|
||||
0);
|
||||
ASSERT_EQ(strncmp(value.value, "test1", value.value_len), 0);
|
||||
|
||||
char test_json_before_strip[] =
|
||||
"{\\\"str_test\":\\\"test\\\",\\\"int_test\\\":100,\\\"float_test\\\":1.210f,\\\"bool_test\\\":true,"
|
||||
"\\\"bool_false_test\\\":false,\\\"null_test\\\":null}";
|
||||
ASSERT_EQ(utils_json_strip_transfer(test_json_before_strip, strlen(test_json_before_strip)), strlen(test_json));
|
||||
ASSERT_EQ(strncmp(test_json_before_strip, test_json, strlen(test_json_before_strip)), 0);
|
||||
}
|
||||
|
||||
} // namespace utils_unittest
|
Reference in New Issue
Block a user