From 774cf2f613c2105fca017d2b66b2021645f5192c Mon Sep 17 00:00:00 2001 From: armatusmiles <akurotych@gmail.com> Date: Tue, 10 Jul 2018 23:10:09 +0300 Subject: [PATCH] delete client and http folders --- CMakeLists.txt | 17 +- client/CMakeLists.txt | 26 - client/client.pri | 15 - client/dap_client.c | 409 ------ client/dap_client.h | 111 -- client/dap_client_internal.c | 722 ----------- client/dap_client_internal.h | 73 -- client/dap_client_remote.c | 266 ---- client/dap_client_remote.h | 87 -- client/sxmlc/sxmlc.c | 2291 --------------------------------- client/sxmlc/sxmlc.h | 829 ------------ client/sxmlc/sxmlsearch.c | 639 --------- client/sxmlc/sxmlsearch.h | 232 ---- http/CMakeLists.txt | 18 - http/dap_http_client.c | 446 ------- http/dap_http_client.h | 103 -- http/dap_http_client_simple.c | 326 ----- http/dap_http_client_simple.h | 20 - http/dap_http_header.c | 193 --- http/dap_http_header.h | 49 - http/http.pri | 15 - libdap.c | 0 22 files changed, 1 insertion(+), 6886 deletions(-) delete mode 100644 client/CMakeLists.txt delete mode 100644 client/client.pri delete mode 100644 client/dap_client.c delete mode 100644 client/dap_client.h delete mode 100644 client/dap_client_internal.c delete mode 100644 client/dap_client_internal.h delete mode 100644 client/dap_client_remote.c delete mode 100644 client/dap_client_remote.h delete mode 100755 client/sxmlc/sxmlc.c delete mode 100755 client/sxmlc/sxmlc.h delete mode 100755 client/sxmlc/sxmlsearch.c delete mode 100755 client/sxmlc/sxmlsearch.h delete mode 100644 http/CMakeLists.txt delete mode 100644 http/dap_http_client.c delete mode 100644 http/dap_http_client.h delete mode 100644 http/dap_http_client_simple.c delete mode 100644 http/dap_http_client_simple.h delete mode 100644 http/dap_http_header.c delete mode 100644 http/dap_http_header.h delete mode 100644 http/http.pri delete mode 100644 libdap.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 77cbe49..7c15de0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,20 +3,5 @@ cmake_minimum_required(VERSION 2.8) add_subdirectory(core) add_subdirectory(crypto) -add_subdirectory(http) -add_subdirectory(client) -include_directories("${dap_core_INCLUDE_DIRS}") -include_directories("${dap_crypto_INCLUDE_DIRS}") -include_directories("${dap_http_INCLUDE_DIRS}") -include_directories("${dap_client_INCLUDE_DIRS}") - -add_definitions ("${dap_core_DEFINITIONS}") -add_definitions ("${dap_crypto_DEFINITIONS}") -add_definitions ("${dap_http_DEFINITIONS}") -add_definitions ("${dap_client_DEFINITIONS}") - -add_library(${PROJECT_NAME} STATIC IMPORTED libdap.c ) - -set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE) -set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE) +add_library(${PROJECT_NAME} STATIC IMPORTED) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt deleted file mode 100644 index b349940..0000000 --- a/client/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -project (dap_client) - -set(CMAKE_VERBOSE_MAKEFILE ON) -set(CMAKE_COLOR_MAKEFILE ON) -set (CMAKE_CXX_STANDARD 11) - -set(CLIENT_SRCS dap_client.c dap_client_internal.c dap_client_remote.c sxmlc/sxmlc.c sxmlc/sxmlsearch.c) - -add_library(${PROJECT_NAME} STATIC ${CLIENT_SRCS}) - -include_directories("${dap_core_INCLUDE_DIRS}") -include_directories("${dap_crypto_INCLUDE_DIRS}") -include_directories("${dap_http_INCLUDE_DIRS}") -include_directories("${dap_core_server_INCLUDE_DIRS}") -add_definitions ("${dap_core_DEFINITIONS}") -add_definitions ("${dap_crypto_DEFINITIONS}") -add_definitions ("${dap_http_DEFINITIONS}") -add_definitions ("${dap_core_server_DEFINITIONS}") - -set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE) - -set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE) - - - diff --git a/client/client.pri b/client/client.pri deleted file mode 100644 index 77b4320..0000000 --- a/client/client.pri +++ /dev/null @@ -1,15 +0,0 @@ -HEADERS += $$PWD/dap_client.h \ - $$PWD/dap_client_internal.h \ - $$PWD/dap_client_remote.h \ - $$PWD/sxmlc/sxmlc.h \ - $$PWD/sxmlc/sxmlsearch.h - - -SOURCES += $$PWD/dap_client.c \ - $$PWD/dap_client_internal.c \ - $$PWD/dap_client_remote.c \ - $$PWD/sxmlc/sxmlc.c \ - $$PWD/sxmlc/sxmlsearch.c - - -INCLUDEPATH += $$PWD diff --git a/client/dap_client.c b/client/dap_client.c deleted file mode 100644 index 0b39960..0000000 --- a/client/dap_client.c +++ /dev/null @@ -1,409 +0,0 @@ -#include <string.h> - -#include "dap_common.h" - -#include "dap_http_client.h" -#include "dap_http_client_simple.h" - -#include "dap_client.h" -#include "dap_client_internal.h" -#include "dap_enc_key.h" - - -#define LOG_TAG "dap_client" - -void m_stage_fsm_operator(dap_client_t * a_client, void * a_arg); - -/** - * @brief dap_client_init - * @return - */ -int dap_client_init() -{ - static bool s_is_first_time=true; - if (s_is_first_time ){ - log_it(L_INFO, "Init DAP client module"); - dap_http_client_init(); - dap_http_client_simple_init(); - dap_client_internal_init(); - s_is_first_time = false; - } - return 0; -} - -/** - * @brief dap_client_deinit - */ -void dap_client_deinit() -{ - dap_client_internal_deinit(); - dap_http_client_deinit(); - log_it(L_INFO, "Deinit DAP client module"); -} - -/** - * @brief dap_client_new - * @param a_stage_status_callback - * @param a_stage_status_error_callback - * @return - */ -dap_client_t * dap_client_new(dap_client_callback_t a_stage_status_callback - ,dap_client_callback_t a_stage_status_error_callback ) -{ - // ALLOC MEM FOR dap_client - dap_client_t *l_client = DAP_NEW_Z(dap_client_t); - if (!l_client) - goto MEM_ALLOC_ERR; - - l_client->_internal = DAP_NEW_Z(dap_client_internal_t); - if (!l_client->_internal) - goto MEM_ALLOC_ERR; - - // CONSTRUCT dap_client object - DAP_CLIENT_INTERNAL(l_client)->client = l_client; - DAP_CLIENT_INTERNAL(l_client)->stage_status_callback = a_stage_status_callback; - DAP_CLIENT_INTERNAL(l_client)->stage_status_error_callback = a_stage_status_error_callback; - - dap_client_internal_new(DAP_CLIENT_INTERNAL(l_client) ); - - return l_client; - -MEM_ALLOC_ERR: - log_it(L_ERROR, "dap_client_new can not allocate memory"); - if (l_client) - if(l_client->_internal) - free(l_client->_internal); - - if (l_client) - free (l_client); - return NULL; -} - -/** - * @brief sap_client_reset - * @param a_client - */ -void dap_client_reset(dap_client_t * a_client) -{ - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - if(l_client_internal->auth_cookie){ - free(l_client_internal->auth_cookie); - l_client_internal->auth_cookie = NULL; - } - - if(l_client_internal->session_key){ - dap_enc_key_delete(l_client_internal->session_key); - l_client_internal->session_key = NULL; - - } - if(l_client_internal->session_key_id){ - free(l_client_internal->session_key_id); - l_client_internal->session_key_id = NULL; - } - if ( l_client_internal->stream_key ){ - dap_enc_key_delete(l_client_internal->stream_key ); - l_client_internal->stream_key = NULL; - } - l_client_internal->es_stream = NULL; - - l_client_internal->stage = DAP_CLIENT_STAGE_BEGIN; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_DONE ; - l_client_internal->stage_target = DAP_CLIENT_STAGE_BEGIN ; -} - -/** - * @brief dap_client_delete - * @param a_client - */ -void dap_client_delete(dap_client_t * a_client) -{ - dap_client_internal_delete(DAP_CLIENT_INTERNAL(a_client)); - free(a_client); -} - -/** - * @brief dap_client_go_stage - * @param a_client - * @param a_stage_end - */ -void dap_client_go_stage(dap_client_t * a_client, dap_client_stage_t a_stage_target, dap_client_callback_t a_stage_end_callback) -{ - // ----- check parameters ----- - if(NULL == a_client) { - log_it(L_ERROR, "dap_client_go_stage, a_client == NULL"); - return; - } - if(NULL == a_stage_end_callback) { - log_it(L_ERROR, "dap_client_go_stage, a_stage_end_callback == NULL"); - return; - } - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - - l_client_internal->stage_target = a_stage_target; - l_client_internal->stage_target_done_callback = a_stage_end_callback; - - if(a_stage_target != l_client_internal->stage ){ // Going to stages downstairs - switch(l_client_internal->stage_status ){ - case DAP_CLIENT_STAGE_STATUS_ABORTING: - log_it(L_ERROR, "Already aborting the stage %s" - , dap_client_stage_str(l_client_internal->stage)); - break; - case DAP_CLIENT_STAGE_STATUS_IN_PROGRESS:{ - log_it(L_WARNING, "Aborting the stage %s" - , dap_client_stage_str(l_client_internal->stage)); - }break; - case DAP_CLIENT_STAGE_STATUS_DONE: - case DAP_CLIENT_STAGE_STATUS_ERROR: - default: { - log_it(L_DEBUG, "Start transitions chain to %",dap_client_stage_str(l_client_internal->stage_target) ); - int step = (a_stage_target > l_client_internal->stage)?1:-1; - dap_client_internal_stage_transaction_begin(l_client_internal,l_client_internal->stage+step,m_stage_fsm_operator); - } - } - }else{ // Same stage - log_it(L_ERROR,"We're already on stage %s",dap_client_stage_str(a_stage_target)); - } -} - -/** - * @brief m_stage_fsm_operator - * @param a_client - * @param a_arg - */ -void m_stage_fsm_operator(dap_client_t * a_client, void * a_arg) -{ - (void)a_arg; - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - if (l_client_internal->stage_target == l_client_internal->stage){ - log_it(L_WARNING, "FSM Op: current stage %s is same as target one, nothing to do", - dap_client_stage_str( l_client_internal->stage ) ); - l_client_internal->stage_status_done_callback = NULL; - - return; - } - - int step = (l_client_internal->stage_target > l_client_internal->stage)?1:-1; - dap_client_stage_t l_stage_next = l_client_internal->stage+step; - log_it(L_NOTICE, "FSM Op: current stage %s, go to %s (target %s)" - ,dap_client_stage_str(l_client_internal->stage), dap_client_stage_str(l_stage_next) - ,dap_client_stage_str(l_client_internal->stage_target)); - dap_client_internal_stage_transaction_begin(l_client_internal, - l_stage_next, m_stage_fsm_operator - ); - -} - -/** - * @brief dap_client_request_enc - * @param a_client - * @param a_path - * @param a_suburl - * @param a_query - * @param a_request - * @param a_request_size - * @param a_response_proc - * @param a_response_error - */ -void dap_client_request_enc(dap_client_t * a_client, const char * a_path, const char * a_suburl,const char* a_query, void * a_request, size_t a_request_size, - dap_client_callback_data_size_t a_response_proc, dap_client_callback_int_t a_response_error ) -{ - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - dap_client_internal_request_enc(l_client_internal, a_path, a_suburl, a_query,a_request,a_request_size, a_response_proc,a_response_error); -} - -/** - * @brief dap_client_set_uplink - * @param a_client - * @param a_addr - * @param a_port - */ -void dap_client_set_uplink(dap_client_t * a_client,const char* a_addr, uint16_t a_port) -{ - if(a_addr == NULL){ - log_it(L_ERROR,"Address is NULL"); - return; - } - DAP_CLIENT_INTERNAL(a_client)->uplink_addr = strdup(a_addr); - DAP_CLIENT_INTERNAL(a_client)->uplink_port = a_port; -} - -/** - * @brief dap_client_set_credentials - * @param a_client - * @param a_user - * @param a_password - */ -void dap_client_set_credentials(dap_client_t * a_client,const char* a_user, const char * a_password) -{ - if(a_user == NULL){ - log_it(L_ERROR,"Username is NULL"); - return; - } - if(a_password == NULL){ - log_it(L_ERROR,"Password is NULL"); - return; - } - DAP_CLIENT_INTERNAL(a_client)->uplink_user = strdup(a_user); -} - - -/** - * @brief dap_client_error_str - * @param a_client_error - * @return - */ -const char * dap_client_error_str(dap_client_error_t a_client_error) -{ - switch(a_client_error){ - case DAP_CLIENT_ERROR_ENC_NO_KEY: return "ENC_NO_KEY"; - case DAP_CLIENT_ERROR_ENC_WRONG_KEY: return "ENC_WRONG_KEY"; - case DAP_CLIENT_ERROR_AUTH_WRONG_REPLY: return "AUTH_WRONG_REPLY"; - case DAP_CLIENT_ERROR_AUTH_WRONG_COOKIE: return "AUTH_WRONG_COOKIE"; - case DAP_CLIENT_ERROR_AUTH_WRONG_CREDENTIALS: return "AUTH_WRONG_CREDENTIALS"; - case DAP_CLIENT_ERROR_NETWORK_CONNECTION_TIMEOUT: return "NETWORK_CONNECTION_TIMEOUT"; - case DAP_CLIENT_ERROR_NETWORK_CONNECTION_REFUSE: return "NETWORK_CONNECTION_REFUSE"; - case DAP_CLIENT_ERROR_NETWORK_DISCONNECTED: return "NETWORK_DISCONNECTED"; - case DAP_CLIENT_ERROR_STREAM_RESPONSE_WRONG: return "STREAM_RESPONSE_WRONG"; - case DAP_CLIENT_ERROR_STREAM_RESPONSE_TIMEOUT: return "STREAM_RESPONSE_TIMEOUT"; - case DAP_CLIENT_ERROR_STREAM_FREEZED: return "STREAM_FREEZED"; - case DAP_CLIENT_ERROR_STREAM_CTL_ERROR: return "STREAM_CTL_ERROR"; - case DAP_CLIENT_ERROR_STREAM_CTL_ERROR_AUTH: return "STREAM_CTL_ERROR_AUTH"; - case DAP_CLIENT_ERROR_STREAM_CTL_ERROR_RESPONSE_FORMAT: return "STREAM_CTL_ERROR_RESPONSE_FORMAT"; - - case DAP_CLIENT_ERROR_LICENSE: return "LICENSE_ERROR"; - default : return "UNDEFINED"; - } -} - -/** - * @brief dap_client_get_error_str - * @param a_client - * @return - */ -const char * dap_client_get_error_str(dap_client_t * a_client) -{ - return dap_client_error_str( DAP_CLIENT_INTERNAL(a_client)->last_error ); -} -/** - * @brief dap_client_get_stage - * @param a_client - * @return - */ -dap_client_stage_t dap_client_get_stage(dap_client_t * a_client) -{ - return DAP_CLIENT_INTERNAL(a_client)->stage; -} - -/** - * @brief dap_client_get_stage_status_str - * @param a_client - * @return - */ -const char * dap_client_get_stage_status_str(dap_client_t *a_client){ - return dap_client_stage_status_str(DAP_CLIENT_INTERNAL(a_client)->stage_status); -} - -/** - * @brief dap_client_stage_status_str - * @param a_stage_status - * @return - */ -const char * dap_client_stage_status_str(dap_client_stage_status_t a_stage_status) -{ - switch(a_stage_status){ - case DAP_CLIENT_STAGE_STATUS_NONE: return "NONE"; - case DAP_CLIENT_STAGE_STATUS_IN_PROGRESS: return "IN_PROGRESS"; - case DAP_CLIENT_STAGE_STATUS_ERROR: return "ERROR"; - case DAP_CLIENT_STAGE_STATUS_DONE: return "DONE"; - default: return "UNDEFINED"; - } -} - -/** - * @brief dap_client_get_stage_str - * @param a_client - * @return - */ -const char * dap_client_get_stage_str(dap_client_t *a_client) -{ - return dap_client_stage_str(DAP_CLIENT_INTERNAL(a_client)->stage); -} - -/** - * @brief dap_client_stage_str - * @param a_stage - * @return - */ -const char * dap_client_stage_str(dap_client_stage_t a_stage) -{ - switch(a_stage){ - case DAP_CLIENT_STAGE_BEGIN: return "BEGIN"; - case DAP_CLIENT_STAGE_ENC: return "ENC"; - case DAP_CLIENT_STAGE_AUTH: return "AUTH"; - case DAP_CLIENT_STAGE_STREAM_CTL: return "STREAM_CTL"; - case DAP_CLIENT_STAGE_STREAM: return "STREAM"; - case DAP_CLIENT_STAGE_NETCONF: return "NETCONF"; - case DAP_CLIENT_STAGE_TUNNEL: return "TUNNEL"; - default: return "UNDEFINED"; - } -} -/** - * @brief dap_client_get_stage_status - * @param a_client - * @return - */ -dap_client_stage_status_t dap_client_get_stage_status(dap_client_t * a_client) -{ - return DAP_CLIENT_INTERNAL(a_client)->stage_status; -} - -/** - * @brief dap_client_get_key_stream - * @param a_client - * @return - */ -dap_enc_key_t * dap_client_get_key_stream(dap_client_t * a_client){ - return DAP_CLIENT_INTERNAL(a_client)->stream_key; -} - -/** - * @brief sap_client_get_uplink_addr - * @param a_client - * @return - */ -const char* dap_client_get_uplink_addr(dap_client_t * a_client) -{ - return DAP_CLIENT_INTERNAL(a_client)->uplink_addr; -} - -/** - * @brief dap_client_get_uplink_port - * @param a_client - * @return - */ -uint16_t dap_client_get_uplink_port(dap_client_t * a_client) -{ - return DAP_CLIENT_INTERNAL(a_client)->uplink_port; -} - -/** - * @brief dap_client_get_auth_cookie - * @param a_client - * @return - */ -const char * dap_client_get_auth_cookie(dap_client_t * a_client) -{ - return DAP_CLIENT_INTERNAL(a_client)->auth_cookie; -} - -/** - * @brief dap_client_get_stream_id - * @param a_client - * @return - */ -const char * dap_client_get_stream_id(dap_client_t * a_client) -{ - return DAP_CLIENT_INTERNAL(a_client)->stream_id; -} - - diff --git a/client/dap_client.h b/client/dap_client.h deleted file mode 100644 index d83a887..0000000 --- a/client/dap_client.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _DAP_CLIENT_H_ -#define _DAP_CLIENT_H_ -#include <stdint.h> -#include <stddef.h> - -/** - * @brief The dap_client_stage enum. Top level of client's state machine - **/ - -typedef struct dap_enc_key dap_enc_key_t; - -typedef enum dap_client_stage { - DAP_CLIENT_STAGE_BEGIN=0, - DAP_CLIENT_STAGE_ENC=1, - DAP_CLIENT_STAGE_STREAM_CTL=2, - DAP_CLIENT_STAGE_STREAM=3, - DAP_CLIENT_STAGE_NETCONF=4, - DAP_CLIENT_STAGE_TUNNEL=5, - DAP_CLIENT_STAGE_AUTH=6 -} dap_client_stage_t; - -typedef enum dap_client_stage_status { - DAP_CLIENT_STAGE_STATUS_NONE=0, - // Enc init stage - DAP_CLIENT_STAGE_STATUS_IN_PROGRESS, - DAP_CLIENT_STAGE_STATUS_ABORTING, - DAP_CLIENT_STAGE_STATUS_ERROR, - DAP_CLIENT_STAGE_STATUS_DONE, -} dap_client_stage_status_t; - -typedef enum dap_client_error { - DAP_CLIENT_ERROR_NO = 0, - DAP_CLIENT_ERROR_ENC_NO_KEY, - DAP_CLIENT_ERROR_ENC_WRONG_KEY, - DAP_CLIENT_ERROR_AUTH_WRONG_REPLY, - DAP_CLIENT_ERROR_AUTH_WRONG_COOKIE, - DAP_CLIENT_ERROR_AUTH_WRONG_CREDENTIALS, - DAP_CLIENT_ERROR_NETWORK_CONNECTION_TIMEOUT, - DAP_CLIENT_ERROR_NETWORK_CONNECTION_REFUSE, - DAP_CLIENT_ERROR_NETWORK_DISCONNECTED, - DAP_CLIENT_ERROR_STREAM_CTL_ERROR, - DAP_CLIENT_ERROR_STREAM_CTL_ERROR_AUTH, - DAP_CLIENT_ERROR_STREAM_CTL_ERROR_RESPONSE_FORMAT, - DAP_CLIENT_ERROR_STREAM_RESPONSE_WRONG, - DAP_CLIENT_ERROR_STREAM_RESPONSE_TIMEOUT, - DAP_CLIENT_ERROR_STREAM_FREEZED, - DAP_CLIENT_ERROR_LICENSE, -} dap_client_error_t; - - -/** - * @brief The dap_client struct - */ -typedef struct dap_client{ - void * _internal; - void * _inheritor; -} dap_client_t; - -typedef void (*dap_client_callback_t) (dap_client_t *, void*); -typedef void (*dap_client_callback_int_t) (dap_client_t *, int); -typedef void (*dap_client_callback_data_size_t) (dap_client_t *, void *, size_t); - -#define DAP_UPLINK_PATH_ENC_INIT "1901248124123459" -#define DAP_UPLINK_PATH_DB "01094787531354" -#define DAP_UPLINK_PATH_STREAM_CTL "091348758013553" -#define DAP_UPLINK_PATH_STREAM "874751843144" -#define DAP_UPLINK_PATH_LICENSE "license" - -#ifdef __cplusplus -extern "C" { -#endif - -#define DAP_CLIENT_PROTOCOL_VERSION 20 - -int dap_client_init(); -void dap_client_deinit(); - -dap_client_t * dap_client_new(dap_client_callback_t a_stage_status_callback - , dap_client_callback_t a_stage_status_error_callback ); -void dap_client_delete(dap_client_t * a_client); - -void dap_client_set_uplink(dap_client_t * a_client,const char* a_addr, uint16_t a_port); -const char* sap_client_get_uplink_addr(dap_client_t * a_client); -uint16_t sap_client_get_uplink_port(dap_client_t * a_client); - -void dap_client_set_credentials(dap_client_t * a_client,const char* a_user, const char * a_password); -dap_enc_key_t * sap_client_get_key_stream(dap_client_t * a_client); - -void dap_client_go_stage(dap_client_t * a_client, dap_client_stage_t a_stage_end, dap_client_callback_t a_stage_end_callback); - -void dap_client_reset(dap_client_t * a_client); - -void dap_client_request_enc(dap_client_t * a_client, const char * a_path,const char * a_suburl,const char* a_query, void * a_request, size_t a_request_size, - dap_client_callback_data_size_t a_response_proc, dap_client_callback_int_t a_response_error); - -const char * dap_client_get_stage_str(dap_client_t * a_client); -const char * dap_client_stage_str(dap_client_stage_t a_stage); - -const char * dap_client_get_stage_status_str(dap_client_t * a_client); -const char * dap_client_stage_status_str(dap_client_stage_status_t a_stage_status); -const char * dap_client_error_str(dap_client_error_t a_client_error); -const char * dap_client_get_error_str(dap_client_t * a_client); - -dap_client_stage_t dap_client_get_stage(dap_client_t * a_client); -dap_client_stage_status_t dap_client_get_stage_status(dap_client_t * a_client); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/client/dap_client_internal.c b/client/dap_client_internal.c deleted file mode 100644 index ebbe7e0..0000000 --- a/client/dap_client_internal.c +++ /dev/null @@ -1,722 +0,0 @@ -#include "dap_client_internal.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#include "dap_enc_key.h" -#include "dap_enc.h" -#include "dap_enc_base64.h" -#include "dap_common.h" -#include "sxmlc/sxmlc.h" -#include "liboqs/kex_rlwe_msrln16/kex_rlwe_msrln16.h" -#include "liboqs/kex/kex.h" -#include "dap_enc_msrln16.h" - -#include "dap_http_client_simple.h" -#include "dap_client_internal.h" - -#define LOG_TAG "dap_client_internal" - -dap_enc_key_t * s_key_domain = NULL; -static void s_stage_status_after(dap_client_internal_t * a_client_internal); - -void m_enc_init_response(dap_client_t *, void *, size_t); -void m_enc_init_error(dap_client_t *, int); - -// AUTH stage callbacks -void m_auth_response(dap_client_t *, void *, size_t); -void m_auth_error(dap_client_t *, int); -int m_auth_response_parse(XMLEvent event, const XMLNode* node, SXML_CHAR* text, const int n, SAX_Data* sd); - -// STREAM_CTL stage callbacks -void m_stream_ctl_response(dap_client_t *, void *, size_t); -void m_stream_ctl_error(dap_client_t *, int); - -void m_request_response(void * a_response,size_t a_response_size,void * a_obj); -void m_request_error(int,void *); - -/** - * @brief dap_client_internal_init - * @return - */ -int dap_client_internal_init() -{ - OQS_RAND* rand = OQS_RAND_new(OQS_RAND_alg_urandom_chacha20); - s_key_domain = dap_enc_key_new_generate(DAP_ENC_KEY_TYPE_RLWE_MSRLN16,16); - dap_enc_msrln16_key_t* msrln16_key = DAP_ENC_KEY_TYPE_RLWE_MSRLN16(s_key_domain); - msrln16_key->kex = OQS_KEX_rlwe_msrln16_new(rand); - return 0; -} - -/** - * @brief dap_client_internal_deinit - */ -void dap_client_internal_deinit() -{ - dap_enc_key_delete(s_key_domain); - s_key_domain = NULL; -} - -/** - * @brief dap_client_internal_new - * @param a_client_internal - */ -void dap_client_internal_new(dap_client_internal_t * a_client_internal) -{ - a_client_internal->stage = DAP_CLIENT_STAGE_BEGIN; // start point of state machine - a_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_DONE; -} - -/** - * @brief dap_client_internal_delete - * @param a_client_internal - */ -void dap_client_internal_delete(dap_client_internal_t * a_client_internal) -{ - if(a_client_internal->uplink_addr) - free(a_client_internal->uplink_addr); - if(a_client_internal->uplink_user) - free(a_client_internal->uplink_user); - if(a_client_internal->uplink_password) - free(a_client_internal->uplink_password); - if(a_client_internal->session_key_id) - free(a_client_internal->session_key_id); -} - - -/** - * @brief s_client_internal_stage_status_proc - * @param a_client - */ -static void s_stage_status_after(dap_client_internal_t * a_client_internal) -{ - switch(a_client_internal->stage_status){ - case DAP_CLIENT_STAGE_STATUS_IN_PROGRESS:{ - switch( a_client_internal->stage){ - case DAP_CLIENT_STAGE_ENC:{ - log_it(L_INFO,"Go to stage ENC: prepare the request"); - //Stage 1 : generate private key and alice message - dap_enc_msrln16_key_t* msrln16_key = DAP_ENC_KEY_TYPE_RLWE_MSRLN16(s_key_domain); - uint8_t* out_msg = NULL; - size_t out_msg_size = 0; - OQS_KEX_rlwe_msrln16_alice_0(msrln16_key->kex,&msrln16_key->private_key,&out_msg,&out_msg_size); - - char *sendMsg = malloc(out_msg_size * 2 + 1024); - - char* encrypt_msg = malloc(out_msg_size * 2); - dap_enc_base64_encode(out_msg,out_msg_size, encrypt_msg,DAP_ENC_STANDARD_B64); - - strcat(sendMsg,encrypt_msg); - - dap_client_internal_request( a_client_internal, DAP_UPLINK_PATH_ENC_INIT "/gd4y5yh78w42aaagh", - sendMsg,strlen(sendMsg), m_enc_init_response, m_enc_init_error ); - - free(encrypt_msg); - free(sendMsg); - - }break; - case DAP_CLIENT_STAGE_AUTH:{ - log_it(L_INFO,"Go to stage AUTH: prepare the request"); - - /// uplink_user checks - if ( a_client_internal->uplink_user == NULL){ - log_it(L_ERROR,"Can't AUTH with NULL uplink user"); - a_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(a_client_internal); // be carefull to not to loop! - break; - }else if ( a_client_internal->uplink_user[0] == 0 ){ - log_it(L_ERROR,"Can't AUTH with empty uplink user"); - a_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(a_client_internal); // be carefull to not to loop! - break; - } - /// uplink_password checks - if ( a_client_internal->uplink_password == NULL){ - log_it(L_ERROR,"Can't AUTH with NULL uplink password"); - a_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(a_client_internal); // be carefull to not to loop! - break; - }else if ( a_client_internal->uplink_password[0] == 0 ){ - log_it(L_ERROR,"Can't AUTH with empty uplink password"); - a_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(a_client_internal); // be carefull to not to loop! - break; - } - - size_t l_request_size = strlen( a_client_internal->uplink_user) - + strlen( a_client_internal->uplink_password)+2+10; - char *l_request = DAP_NEW_Z_SIZE (char,l_request_size) ; - - snprintf(l_request, l_request_size,"%s %s %d",a_client_internal->uplink_user, - a_client_internal->uplink_password, DAP_CLIENT_PROTOCOL_VERSION); - log_it(L_DEBUG,"AUTH request size %u",strlen(l_request)); - - // If we was authorized before - reset it - if ( a_client_internal->auth_cookie ){ - DAP_DELETE (a_client_internal->auth_cookie ); - a_client_internal->auth_cookie = NULL; - } - // Until we haven't PROTO version before this step - we set the current one - a_client_internal->uplink_protocol_version = DAP_PROTOCOL_VERSION; - dap_client_internal_request_enc(a_client_internal, - DAP_UPLINK_PATH_DB, - "auth","login",l_request,l_request_size, - m_auth_response, m_auth_error); - - }break; - case DAP_CLIENT_STAGE_STREAM_CTL:{ - log_it(L_INFO,"Go to stage STREAM_CTL: prepare the request"); - - size_t l_request_size = strlen( a_client_internal->uplink_user) - + strlen( a_client_internal->uplink_password)+2+10; - char *l_request = DAP_NEW_Z_SIZE (char,l_request_size) ; - - snprintf(l_request, l_request_size,"%s %s %d",a_client_internal->uplink_user, - a_client_internal->uplink_password, DAP_CLIENT_PROTOCOL_VERSION); - log_it(L_DEBUG,"STREAM_CTL request size %u",strlen(l_request)); - - a_client_internal->uplink_protocol_version = DAP_PROTOCOL_VERSION; - - dap_client_internal_request_enc(a_client_internal, - DAP_UPLINK_PATH_STREAM_CTL, - "socket_forward","sf=1",l_request,l_request_size, - m_stream_ctl_response, m_stream_ctl_error); - }break; - case DAP_CLIENT_STAGE_STREAM:{ - log_it(L_INFO,"Go to stage STREAM: prepare the request"); - - size_t l_request_size = strlen( a_client_internal->uplink_user) - + strlen( a_client_internal->uplink_password)+2+10; - char *l_request = DAP_NEW_Z_SIZE (char,l_request_size) ; - - snprintf(l_request, l_request_size,"%s %s %d",a_client_internal->uplink_user, - a_client_internal->uplink_password, DAP_CLIENT_PROTOCOL_VERSION); - log_it(L_DEBUG,"STREAM request size %u",strlen(l_request)); - - dap_client_internal_request_enc(a_client_internal, - DAP_UPLINK_PATH_STREAM, - "socket_forward","sf=1",l_request,l_request_size, - m_stream_ctl_response, m_stream_ctl_error); - }break; - default:{ - log_it(L_ERROR,"Undefined proccessing actions for stage status %s", - dap_client_stage_status_str(a_client_internal->stage_status)); - a_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(a_client_internal); // be carefull to not to loop! - } - } - } break; - case DAP_CLIENT_STAGE_STATUS_ERROR:{ - log_it(L_ERROR, "Error state, doing callback if present"); - if( a_client_internal->stage_status_error_callback ){ - a_client_internal->stage_status_error_callback(a_client_internal->client,NULL); - // Expecting that its one-shot callback - //a_client_internal->stage_status_error_callback = NULL; - } - a_client_internal->stage = DAP_CLIENT_STAGE_ENC; - // Trying the step again - a_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_IN_PROGRESS; - s_stage_status_after(a_client_internal); - } break; - case DAP_CLIENT_STAGE_STATUS_DONE :{ - log_it(L_INFO, "Stage status %s is done", - dap_client_stage_str(a_client_internal->stage) ); - bool l_is_last_stage=( a_client_internal->stage == a_client_internal->stage_target ); - if( a_client_internal->stage_status_done_callback ){ - a_client_internal->stage_status_done_callback(a_client_internal->client,NULL); - // Expecting that its one-shot callback - //a_client_internal->stage_status_done_callback = NULL; - }else - log_it(L_WARNING,"Stage done callback is not present"); - - if (l_is_last_stage ){ - log_it(L_NOTICE, "Stage %s is achieved", - dap_client_stage_str(a_client_internal->stage)); - if( a_client_internal->stage_target_done_callback ){ - a_client_internal->stage_target_done_callback(a_client_internal->client,NULL); - // Expecting that its one-shot callback - a_client_internal->stage_target_done_callback = NULL; - } - } - }break; - default: log_it(L_ERROR,"Undefined proccessing actions for stage status %s", - dap_client_stage_status_str(a_client_internal->stage_status)); - } - - if( a_client_internal->stage_status_callback ) - a_client_internal->stage_status_callback( a_client_internal->client,NULL ); -} - - -/** - * @brief dap_client_internal_stage_transaction_begin - * @param a_client_internal - * @param a_stage_next - * @param a_done_callback - */ -void dap_client_internal_stage_transaction_begin(dap_client_internal_t * a_client_internal, dap_client_stage_t a_stage_next, - dap_client_callback_t a_done_callback) -{ - a_client_internal->stage_status_done_callback = a_done_callback; - a_client_internal->stage = a_stage_next; - a_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_IN_PROGRESS; - s_stage_status_after(a_client_internal); -} - -/** - * @brief dap_client_internal_request - * @param a_client_internal - * @param a_path - * @param a_request - * @param a_request_size - * @param a_response_proc - */ -void dap_client_internal_request(dap_client_internal_t * a_client_internal, const char * a_path, void * a_request, - size_t a_request_size, dap_client_callback_data_size_t a_response_proc, dap_client_callback_int_t a_response_error) -{ - a_client_internal->request_response_callback = a_response_proc; - a_client_internal->request_error_callback = a_response_error; - a_client_internal->is_encrypted = false; - char l_url[2048]; - if(a_path) - snprintf(l_url,1024,"http://%s:%u/%s",a_client_internal->uplink_addr, a_client_internal->uplink_port, a_path ); - else - snprintf(l_url,1024,"http://%s:%u",a_client_internal->uplink_addr, a_client_internal->uplink_port ); - - dap_http_client_simple_request(l_url, a_request?"POST":"GET","text/text", a_request, a_request_size,NULL, - m_request_response, m_request_error, a_client_internal,NULL); -} - -/** - * @brief dap_client_internal_request_enc - * @param a_client_internal - * @param a_path - * @param a_sub_url - * @param a_query - * @param a_request - * @param a_request_size - * @param a_response_proc - * @param a_response_error - */ -void dap_client_internal_request_enc(dap_client_internal_t * a_client_internal, const char * a_path, - const char * a_sub_url, const char * a_query - , void * a_request, size_t a_request_size - ,dap_client_callback_data_size_t a_response_proc - , dap_client_callback_int_t a_response_error) -{ - log_it(L_DEBUG,"Encrypted request: sub_url '%s' query '%s'",a_sub_url?a_sub_url:"", a_query?a_query:"" ); - size_t l_sub_url_size = a_sub_url?strlen(a_sub_url): 0; - size_t l_query_size = a_query?strlen(a_query):0; - size_t l_url_size; - - char l_url[1024]; - snprintf(l_url,1024,"http://%s:%u",a_client_internal->uplink_addr, a_client_internal->uplink_port ); - l_url_size = strlen(l_url); - - char *l_sub_url_enc = l_sub_url_size ? (char*) calloc(1,2*(l_sub_url_size+16) ): NULL; - char *l_query_enc = l_query_size ? (char*) calloc(1,(l_query_size+16)*2):NULL; - - size_t l_url_full_size_max = 2*l_sub_url_size + 2*(l_query_size+16) + 5 + l_url_size; - char * l_url_full = (char*) calloc(1, l_url_full_size_max); - - size_t l_request_enc_size_max = a_request_size ?a_request_size*2+16 : 0; - char * l_request_enc = a_request_size? (char*) calloc(1,l_request_enc_size_max ) : NULL; - size_t l_request_enc_size = 0; - - a_client_internal->request_response_callback = a_response_proc; - a_client_internal->request_error_callback = a_response_error; - a_client_internal->is_encrypted = true; - dap_enc_data_type_t l_enc_type; - - if( a_client_internal->uplink_protocol_version >= 21 ) - l_enc_type = DAP_ENC_DATA_TYPE_B64_URLSAFE; - else - l_enc_type = DAP_ENC_DATA_TYPE_B64; - - if ( l_sub_url_size ) - dap_enc_code(a_client_internal->session_key,a_sub_url,l_sub_url_size,l_sub_url_enc,l_enc_type); - - if ( l_query_size ) - dap_enc_code(a_client_internal->session_key,a_query,l_query_size,l_query_enc,l_enc_type); - - - if ( a_request_size ) - l_request_enc_size = dap_enc_code(a_client_internal->session_key, a_request, a_request_size - , l_request_enc, DAP_ENC_DATA_TYPE_RAW ); - - if (a_path){ - if( l_sub_url_size ){ - if( l_query_size ){ - snprintf(l_url_full,l_url_full_size_max-1,"%s/%s/%s?%s",l_url,a_path, l_sub_url_enc, l_query_enc ); - }else{ - snprintf(l_url_full,l_url_full_size_max-1,"%s/%s/%s",l_url,a_path, l_sub_url_enc); - } - }else{ - snprintf(l_url_full,l_url_full_size_max-1,"%s/%s",l_url,a_path); - } - }else{ - snprintf(l_url_full,l_url_full_size_max-1,"%s",l_url); - } - - char l_key_hdr_str[1024]; - snprintf(l_key_hdr_str,sizeof(l_key_hdr_str),"KeyID: %s",a_client_internal->session_key_id ); - if ( a_client_internal->auth_cookie){ - size_t l_cookie_hdr_str_size = strlen(a_client_internal->auth_cookie)+100; - char * l_cookie_hdr_str= DAP_NEW_Z_SIZE(char,l_cookie_hdr_str_size); - snprintf(l_cookie_hdr_str,l_cookie_hdr_str_size,"Cookie: %s",a_client_internal->auth_cookie ); - - dap_http_client_simple_request(l_url_full, a_request?"POST":"GET","text/text", - l_request_enc, l_request_enc_size, l_cookie_hdr_str, - m_request_response, m_request_error, a_client_internal, l_key_hdr_str); - DAP_DELETE(l_cookie_hdr_str); - }else - dap_http_client_simple_request(l_url_full, a_request?"POST":"GET","text/text", - l_request_enc, l_request_enc_size, NULL, - m_request_response, m_request_error, a_client_internal, l_key_hdr_str); - if( l_sub_url_enc ) - free(l_sub_url_enc); - - if( l_query_enc ) - free(l_query_enc); - - if( l_url_full ) - free(l_url_full); - - if( l_request_enc ) - free(l_request_enc); -} - -/** - * @brief m_request_error - * @param a_err_code - * @param a_obj - */ -void m_request_error(int a_err_code, void * a_obj) -{ - dap_client_internal_t * a_client_internal = (dap_client_internal_t *) a_obj; - a_client_internal->request_error_callback(a_client_internal->client, a_err_code ); -} - -/** - * @brief m_request_response - * @param a_response - * @param a_response_size - * @param a_obj - */ -void m_request_response(void * a_response,size_t a_response_size,void * a_obj) -{ - dap_client_internal_t * a_client_internal = (dap_client_internal_t *) a_obj; - if( a_client_internal->is_encrypted){ - size_t l_response_dec_size_max = a_response_size ?a_response_size*2+16 : 0; - char * l_response_dec = a_response_size? (char*) calloc(1,l_response_dec_size_max ) : NULL; - size_t l_response_dec_size = 0; - if ( a_response_size ) - l_response_dec_size = dap_enc_decode(a_client_internal->session_key, - a_response, a_response_size, l_response_dec, DAP_ENC_DATA_TYPE_RAW ); - - a_client_internal->request_response_callback(a_client_internal->client, l_response_dec, l_response_dec_size ); - - if( l_response_dec ) - free ( l_response_dec ); - }else{ - a_client_internal->request_response_callback(a_client_internal->client, a_response, a_response_size ); - } -} - - -/** - * @brief m_enc_init_response - * @param a_client - * @param a_response - * @param a_response_size - */ -void m_enc_init_response(dap_client_t * a_client, void * a_response,size_t a_response_size) -{ - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - if( a_response_size > 2000 && a_response_size < 4000){ - if( l_client_internal->stage == DAP_CLIENT_STAGE_ENC ){ - char *msg_index = strchr(a_response,' '); - int key_size = (void*)msg_index - a_response; - int msg_size = a_response_size - key_size - 1; - char* encoded_key = malloc(key_size); - memset(encoded_key,0,key_size); - uint8_t *encoded_msg = malloc(msg_size); - dap_enc_base64_decode(a_response,key_size,encoded_key,DAP_ENC_STANDARD_B64); - dap_enc_base64_decode(msg_index+1,msg_size,encoded_msg,DAP_ENC_STANDARD_B64); - dap_enc_msrln16_key_t* msrln16_key = DAP_ENC_KEY_TYPE_RLWE_MSRLN16(s_key_domain); - OQS_KEX_rlwe_msrln16_alice_1(msrln16_key->kex, msrln16_key->private_key, encoded_msg, 2048,&msrln16_key->public_key,&msrln16_key->public_length); - aes_key_from_msrln_pub(s_key_domain); - l_client_internal->session_key_id = (char*)malloc(33); - memcpy(l_client_internal->session_key_id,encoded_key,33); - l_client_internal->session_key_id[32] = 0; - l_client_internal->session_key = s_key_domain; - free(encoded_key); - free(encoded_msg); - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_DONE; - s_stage_status_after(l_client_internal); - } - else{ - log_it(L_WARNING,"Initialized encryption but current stage is %s (%s)", - dap_client_get_stage_str(a_client),dap_client_get_stage_status_str(a_client)); - } - }else if( a_response_size>1){ - s_stage_status_after(l_client_internal); - log_it(L_ERROR, "Wrong response (size %u data '%s')",a_response_size,(char*) a_response); - l_client_internal->last_error = DAP_CLIENT_ERROR_ENC_NO_KEY; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(l_client_internal); - }else{ - log_it(L_ERROR, "Wrong response (size %u)",a_response_size); - l_client_internal->last_error = DAP_CLIENT_ERROR_ENC_NO_KEY; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(l_client_internal); - } -} - -/** - * @brief m_enc_init_error - * @param a_client - * @param a_err_code - */ -void m_enc_init_error(dap_client_t * a_client, int a_err_code) -{ - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - //dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - log_it(L_ERROR,"Can't init ecnryption session, err code %d",a_err_code); - - l_client_internal->last_error = DAP_CLIENT_ERROR_NETWORK_CONNECTION_REFUSE ; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(l_client_internal); -} - -/** - * @brief m_auth_response Process AUTH response - * @param a_client - * @param a_data - * @param a_data_size - */ -void m_auth_response(dap_client_t * a_client, void * a_data, size_t a_data_size) -{ - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - - log_it(L_DEBUG, "AUTH response %u bytes length recieved", a_data_size); - char * l_response_str = DAP_NEW_Z_SIZE(char, a_data_size+1); - memcpy(l_response_str, a_data,a_data_size); - - if(a_data_size <10 ){ - log_it(L_ERROR, "AUTH Wrong reply: '%s'", l_response_str); - }else{ - XMLDoc l_doc; - XMLDoc_init(&l_doc); - - SAX_Callbacks l_sax; - SAX_Callbacks_init(&l_sax); - - l_sax.all_event = m_auth_response_parse; - - XMLDoc_parse_buffer_SAX( C2SX(l_response_str ), C2SX("auth"),&l_sax, a_client ); - XMLDoc_free(&l_doc); - - DAP_DELETE(l_response_str); - if ( l_client_internal->auth_cookie ){ - log_it(L_DEBUG, "Cookie is present in reply"); - if( l_client_internal->stage == DAP_CLIENT_STAGE_AUTH ){ // We are in proper stage - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_DONE; - s_stage_status_after(l_client_internal); - }else{ - log_it(L_WARNING,"Expected to be stage AUTH but current stage is %s (%s)", - dap_client_get_stage_str(a_client),dap_client_get_stage_status_str(a_client)); - - } - }else { - if( l_client_internal->last_error == DAP_CLIENT_ERROR_AUTH_WRONG_CREDENTIALS ){ - log_it (L_WARNING, "Wrong user or/and password"); - }else{ - log_it(L_WARNING, "Cookie is not present in reply!"); - l_client_internal->last_error = DAP_CLIENT_ERROR_AUTH_WRONG_COOKIE ; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - } - - s_stage_status_after(l_client_internal); - } - } -} - -/** - * @brief m_auth_response_parse Parse XML reply after authorization - * @param event - * @param node - * @param text - * @param n - * @param sd - * @return - */ -int m_auth_response_parse(XMLEvent event, const XMLNode* node, SXML_CHAR* text, const int n, SAX_Data* sd) -{ - (void)n; - dap_client_t * l_client = (dap_client_t *) sd->user; - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL( l_client ); - - switch (event) { - //case XML_EVENT_START_NODE: last_parsed_node = strdup ( node->text) return start_node(node, sd); - case XML_EVENT_TEXT: -// log_it(L_DEBUG, "Node text '%s'", text ); - if( l_client_internal->last_parsed_node ){ - free(l_client_internal->last_parsed_node); - l_client_internal->last_parsed_node = NULL; - } - l_client_internal->last_parsed_node = strdup(text); - return true; - break; - case XML_EVENT_END_NODE: { - if(node == NULL) - break; - // log_it(L_DEBUG,"Parsed <%s>%s</%s> tag", node->tag, l_client_internal->last_parsed_node - // ?l_client_internal->last_parsed_node:"(NULL)", node->tag); - if (strcmp(node->tag, "err_str") == 0 ){ - log_it(L_ERROR,"Error string in reply: '%s'", l_client_internal->last_parsed_node?l_client_internal->last_parsed_node: "(NULL))" ); - - l_client_internal->last_error = DAP_CLIENT_ERROR_AUTH_WRONG_CREDENTIALS ; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - }else if ( strcmp ( node->tag, "cookie") == 0 ){ - //log_it (L_DEBUG, "Cookie %s", l_client_internal->last_parsed_node?l_client_internal->last_parsed_node:"(NULL)"); - l_client_internal->auth_cookie = strdup (l_client_internal->last_parsed_node?l_client_internal->last_parsed_node:"(NULL)"); - }else if ( strcmp ( node->tag, "server_protocol_version" ) == 0 ){ - if( l_client_internal->last_parsed_node ) { - sscanf(l_client_internal->last_parsed_node,"%u",&l_client_internal->uplink_protocol_version); - if (l_client_internal->uplink_protocol_version == 0){ - log_it(L_WARNING, "No uplink protocol version, setting up the default, %u",DAP_PROTOCOL_VERSION); - } - log_it (L_NOTICE, "Uplink protocol version %u", l_client_internal->uplink_protocol_version); - } - - } - if( l_client_internal->last_parsed_node ){ - free(l_client_internal->last_parsed_node); - l_client_internal->last_parsed_node = NULL; - } - return true; - }break; - default: return true; - //case XML_EVENT_TEXT: return new_text(text, sd); - } - return true; -} - -/** - * @brief m_auth_error - * @param a_client - * @param a_error - */ -void m_auth_error(dap_client_t * a_client, int a_error) -{ - log_it(L_WARNING, "AUTH error %d", a_error); - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - - l_client_internal->last_error = DAP_CLIENT_ERROR_AUTH_WRONG_REPLY ; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(l_client_internal); -} - -/** - * @brief m_stream_ctl_response - * @param a_client - * @param a_data - * @param a_data_size - */ -void m_stream_ctl_response(dap_client_t * a_client, void * a_data, size_t a_data_size) -{ - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - - log_it(L_DEBUG, "STREAM_CTL response %u bytes length recieved", a_data_size); - char * l_response_str = DAP_NEW_Z_SIZE(char, a_data_size+1); - memcpy(l_response_str, a_data,a_data_size); - - if( a_data_size<4 ){ - log_it(L_ERROR, "STREAM_CTL Wrong reply: '%s'", l_response_str); - l_client_internal->last_error = DAP_CLIENT_ERROR_STREAM_CTL_ERROR_RESPONSE_FORMAT; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(l_client_internal); - }else if ( strcmp(l_response_str, "ERROR") == 0 ){ - log_it(L_WARNING, "STREAM_CTL Got ERROR from the remote site,expecting thats ERROR_AUTH"); - l_client_internal->last_error = DAP_CLIENT_ERROR_STREAM_CTL_ERROR_AUTH; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(l_client_internal); - }else { - int l_arg_count; - char l_stream_id[25]={0}; - char *l_stream_key = DAP_NEW_Z_SIZE(char,4096*3); - void * l_stream_key_raw = DAP_NEW_Z_SIZE(char,4096); - uint32_t l_remote_protocol_version; - - l_arg_count = sscanf(l_response_str,"%25s %4096s %u" - ,l_stream_id,l_stream_key,&l_remote_protocol_version ); - if (l_arg_count <2 ){ - log_it(L_WARNING, "STREAM_CTL Need at least 2 arguments in reply (got %d)",l_arg_count); - l_client_internal->last_error = DAP_CLIENT_ERROR_STREAM_CTL_ERROR_RESPONSE_FORMAT; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(l_client_internal); - }else{ - - if( l_arg_count >2){ - l_client_internal->uplink_protocol_version = l_remote_protocol_version; - log_it(L_DEBUG,"Uplink protocol version %u",l_remote_protocol_version); - }else - log_it(L_WARNING,"No uplink protocol version, use the default version %d" - ,l_client_internal->uplink_protocol_version = DAP_PROTOCOL_VERSION); - - if(strlen(l_stream_id)<13){ - //log_it(L_DEBUG, "Stream server id %s, stream key length(base64 encoded) %u" - // ,l_stream_id,strlen(l_stream_key) ); - log_it(L_DEBUG, "Stream server id %s, stream key '%s'" - ,l_stream_id,l_stream_key ); - - //l_stream_key_raw_size = enc_base64_decode(l_stream_key,strlen(l_stream_key),l_stream_key_raw); - // Delete old key if present - if(l_client_internal->stream_key) - dap_enc_key_delete(l_client_internal->stream_key); - - strncpy(l_client_internal->stream_id,l_stream_id,sizeof(l_client_internal->stream_id)-1); - l_client_internal->stream_key = dap_enc_key_new_from_str(DAP_ENC_KEY_TYPE_AES,l_stream_key); - - //streamSocket->connectToHost(SapSession::me()->address(),SapSession::me()->port().toUShort(),QIODevice::ReadWrite); - - if( l_client_internal->stage == DAP_CLIENT_STAGE_STREAM_CTL ){ // We are on the right stage - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_DONE; - s_stage_status_after(l_client_internal); - }else{ - log_it(L_WARNING,"Expected to be stage STREAM_CTL but current stage is %s (%s)", - dap_client_get_stage_str(a_client),dap_client_get_stage_status_str(a_client)); - - } - }else{ - log_it(L_WARNING,"Wrong stream id response"); - l_client_internal->last_error = DAP_CLIENT_ERROR_STREAM_CTL_ERROR_RESPONSE_FORMAT; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - s_stage_status_after(l_client_internal); - } - - } - DAP_DELETE(l_stream_key); - DAP_DELETE(l_stream_key_raw); - } -} - -/** - * @brief m_stream_ctl_error - * @param a_client - * @param a_error - */ -void m_stream_ctl_error(dap_client_t * a_client, int a_error) -{ - log_it(L_WARNING, "STREAM_CTL error %d",a_error); - - dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client); - - l_client_internal->last_error = DAP_CLIENT_ERROR_STREAM_CTL_ERROR; - l_client_internal->stage_status = DAP_CLIENT_STAGE_STATUS_ERROR; - - s_stage_status_after(l_client_internal); - -} diff --git a/client/dap_client_internal.h b/client/dap_client_internal.h deleted file mode 100644 index bc91491..0000000 --- a/client/dap_client_internal.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _DAP_CLIENT_INTERNAL_H_ -#define _DAP_CLIENT_INTERNAL_H_ - -#include <stdbool.h> -#include <stdint.h> -#include "dap_client.h" - -typedef struct dap_events_socket_t dap_events_socket_t; -typedef struct dap_enc_key dap_enc_key_t; -typedef struct dap_http_client dap_http_client_t; - -typedef struct dap_client_internal -{ - dap_client_t * client; - - dap_http_client_t * http_client; - - dap_events_socket_t * es_stream; - - dap_enc_key_t * session_key; - dap_enc_key_t * stream_key; - char stream_id[25]; - - char * session_key_id; - char * auth_cookie; - - char * uplink_addr; - uint16_t uplink_port; - char * uplink_user; - char * uplink_password; - - uint32_t uplink_protocol_version; - - char * last_parsed_node; - - - dap_client_stage_t stage_target; - dap_client_callback_t stage_target_done_callback; - - dap_client_stage_t stage; - dap_client_stage_status_t stage_status; - dap_client_error_t last_error; - - dap_client_callback_t stage_status_callback; - - dap_client_callback_t stage_status_done_callback; - dap_client_callback_t stage_status_error_callback; - - bool is_encrypted; - dap_client_callback_data_size_t request_response_callback; - dap_client_callback_int_t request_error_callback; -} dap_client_internal_t; - -#define DAP_CLIENT_INTERNAL(a) ((dap_client_internal_t*) a->_internal ) - - -int dap_client_internal_init(); -void dap_client_internal_deinit(); - -void dap_client_internal_stage_transaction_begin(dap_client_internal_t * dap_client_internal_t, dap_client_stage_t a_stage_next, - dap_client_callback_t a_done_callback); - -void dap_client_internal_request(dap_client_internal_t * a_client_internal, const char * a_path, void * a_request, - size_t a_request_size, dap_client_callback_data_size_t a_response_proc, dap_client_callback_int_t a_response_error); - -void dap_client_internal_request_enc(dap_client_internal_t * a_client_internal, const char * a_path, const char * a_sub_url, - const char * a_query, void * a_request, size_t a_request_size, - dap_client_callback_data_size_t a_response_proc, dap_client_callback_int_t a_error_proc); - -void dap_client_internal_new(dap_client_internal_t * a_client_internal); -void dap_client_internal_delete(dap_client_internal_t * a_client_internal); - -#endif diff --git a/client/dap_client_remote.c b/client/dap_client_remote.c deleted file mode 100644 index b66d46e..0000000 --- a/client/dap_client_remote.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DAP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <sys/epoll.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <unistd.h> -#include <string.h> - -#include <ev.h> - -#include "dap_common.h" -#include "dap_loop.h" -#include "dap_client_remote.h" - -#ifdef DAP_SERVER -#include "dap_server.h" -#endif - - - -#define LOG_TAG "dap_client_remote" - - -/** - * @brief dap_client_init Init clients module - * @return Zero if ok others if no - */ -int dap_client_remote_init() -{ - log_it(L_NOTICE,"Initialized socket client module"); - return 0; -} - -/** - * @brief dap_client_deinit Deinit clients module - */ -void dap_client_remote_deinit() -{ - -} - -/** - * @brief dap_client_remote_create Create new client and add it to the list - * @param sh Server instance - * @param s Client's socket - * @return Pointer to the new list's node - */ -dap_client_remote_t * dap_client_create(dap_server_t * sh, int s, ev_io* w_client) -{ -#ifdef DAP_SERVER - pthread_mutex_lock(&sh->mutex_on_hash); -#endif - log_it(L_DEBUG,"Client structure create"); - - dap_client_remote_t * ret=DAP_NEW_Z(dap_client_remote_t); - ret->socket=s; -#ifdef DAP_SERVER - ret->server=sh; -#endif - ret->watcher_client = w_client; - ret->_ready_to_read=true; - -#ifdef DAP_SERVER - HASH_ADD_INT( sh->clients, socket, ret); - if(sh->client_new_callback) - sh->client_new_callback(ret,NULL); // Init internal structure - - pthread_mutex_unlock(&sh->mutex_on_hash); -#endif - return ret; -} - -/** - * @brief dap_client_find - * @param sock - * @param sh - * @return - */ -dap_client_remote_t * dap_client_find(int sock, struct dap_server * sh) -{ - dap_client_remote_t * ret=NULL; -#ifdef DAP_SERVER - pthread_mutex_lock(&sh->mutex_on_hash); - HASH_FIND_INT(sh->clients,&sock,ret); - pthread_mutex_unlock(&sh->mutex_on_hash); -#endif - return ret; -} - -/** - * @brief dap_client_ready_to_read - * @param sc - * @param isReady - */ -void dap_client_ready_to_read(dap_client_remote_t * sc,bool is_ready) -{ - if(is_ready != sc->_ready_to_read) { - - uint32_t events = 0; - sc->_ready_to_read=is_ready; - - if(sc->_ready_to_read) - events |= EV_READ; - - if(sc->_ready_to_write) - events |= EV_WRITE; - - ev_io_set(sc->watcher_client, sc->socket, events ); - } -} - -/** - * @brief dap_client_ready_to_write - * @param sc - * @param isReady - */ -void dap_client_ready_to_write(dap_client_remote_t * sc,bool is_ready) -{ - if(is_ready != sc->_ready_to_write) { - - uint32_t events = 0; - sc->_ready_to_write=is_ready; - - if(sc->_ready_to_read) - events |= EV_READ; - - if(sc->_ready_to_write) - events |= EV_WRITE; - - ev_io_set(sc->watcher_client, sc->socket, events ); - } -} - - -/** - * @brief safe_client_remove Removes the client from the list - * @param sc Client instance - */ -void dap_client_remove(dap_client_remote_t *sc, struct dap_server * sh) -{ -#ifdef DAP_SERVER - pthread_mutex_lock(&sh->mutex_on_hash); - - log_it(L_DEBUG, "Client structure remove"); - HASH_DEL(sc->server->clients,sc); - - if(sc->server->client_delete_callback) - sc->server->client_delete_callback(sc,NULL); // Init internal structure - if(sc->_inheritor) - free(sc->_inheritor); - - if(sc->socket) - close(sc->socket); - free(sc); - pthread_mutex_unlock(&sh->mutex_on_hash); -#endif -} - -/** - * @brief dap_client_write Write data to the client - * @param sc Client instance - * @param data Pointer to data - * @param data_size Size of data to write - * @return Number of bytes that were placed into the buffer - */ -size_t dap_client_write(dap_client_remote_t *sc, const void * data, size_t data_size) -{ - data_size = ((sc->buf_out_size+data_size)<(sizeof(sc->buf_out)))?data_size:(sizeof(sc->buf_out)-sc->buf_out_size ); - memcpy(sc->buf_out+sc->buf_out_size,data,data_size); - sc->buf_out_size+=data_size; - return data_size; -} - -/** - * @brief dap_client_write_f Write formatted text to the client - * @param a_client Client instance - * @param a_format Format - * @return Number of bytes that were placed into the buffer - */ -size_t dap_client_write_f(dap_client_remote_t *a_client, const char * a_format,...) -{ - size_t max_data_size = sizeof(a_client->buf_out)-a_client->buf_out_size; - va_list ap; - va_start(ap,a_format); - int ret=vsnprintf(a_client->buf_out+a_client->buf_out_size,max_data_size,a_format,ap); - va_end(ap); - if(ret>0){ - a_client->buf_out_size+=ret; - return ret; - }else{ - log_it(L_ERROR,"Can't write out formatted data '%s'",a_format); - return 0; - } -} - -/** - * @brief dap_client_read Read data from input buffer - * @param sc Client instasnce - * @param data Pointer to memory where to store the data - * @param data_size Size of data to read - * @return Actual bytes number that were read - */ -size_t dap_client_read(dap_client_remote_t *sc, void * data, size_t data_size) -{ - - //log_it(L_DEBUG, "Size of package: %d\n", (int)data_size); - // - // hexdump(data, data_size); packet dump - - if (data_size < sc->buf_in_size) { - memcpy(data, sc->buf_in, data_size); - memmove(data, sc->buf_in + data_size, sc->buf_in_size - data_size); - } else { - if (data_size > sc->buf_in_size) { - data_size = sc->buf_in_size; - } - memcpy(data, sc->buf_in, data_size); - } - sc->buf_in_size -= data_size; - return data_size; -} - - -/** - * @brief shrink_client_buf_in Shrink input buffer (shift it left) - * @param cl Client instance - * @param shrink_size Size on wich we shrink the buffer with shifting it left - */ -void dap_client_shrink_buf_in(dap_client_remote_t * cl, size_t shrink_size) -{ - if((shrink_size==0)||(cl->buf_in_size==0) ){ - //log_it(L_WARNINGNG, "DBG_#003"); - return; - }else if(cl->buf_in_size>shrink_size){ - size_t buf_size=cl->buf_in_size-shrink_size; - void * buf = malloc(buf_size); - memcpy(buf,cl->buf_in+ shrink_size,buf_size ); - memcpy(cl->buf_in,buf,buf_size); - cl->buf_in_size=buf_size; - //log_it(L_WARNINGNG, "DBG_#004"); - free(buf); - }else { - //log_it(L_WARNINGNG, "DBG_#005"); - cl->buf_in_size=0; - } - -} diff --git a/client/dap_client_remote.h b/client/dap_client_remote.h deleted file mode 100644 index a5782db..0000000 --- a/client/dap_client_remote.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DAP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once -#ifndef _DAP_CLIENT_H -#define _DAP_CLIENT_H - -#include <stdint.h> -#include <stddef.h> -#include <stdbool.h> -#include "uthash.h" -#include <ev.h> - - -typedef struct dap_server dap_server_t; -struct dap_client_remote; - -typedef void (*dap_client_remote_callback_t) (struct dap_client_remote *,void * arg); // Callback for specific client operations - -#define DAP_CLIENT_REMOTE_BUF 100000 - -typedef struct dap_client_remote{ - int socket; - bool signal_close; - - bool _ready_to_write; - bool _ready_to_read; - - uint32_t buf_out_zero_count; - char buf_in[DAP_CLIENT_REMOTE_BUF+1]; // Internal buffer for input data - size_t buf_in_size; // size of data that is in the input buffer - - char buf_out[DAP_CLIENT_REMOTE_BUF+1]; // Internal buffer for output data - - char hostaddr[1024]; // Address - char service[128]; - - size_t buf_out_size; // size of data that is in the output buffer - - ev_io* watcher_client; - - struct dap_server * server; - - UT_hash_handle hh; - - void * _internal; - void * _inheritor; // Internal data to specific client type, usualy states for state machine -} dap_client_remote_t; // Node of bidirectional list of clients - - - -int dap_client_remote_init(); // Init clients module -void dap_client_remote_deinit(); // Deinit clients module - -dap_client_remote_t * dap_client_create(struct dap_server * sh, int s, ev_io* w_client); // Create new client and add it to the list -dap_client_remote_t * dap_client_find(int sock, struct dap_server * sh); // Find client by socket - -bool dap_client_is_ready_to_read(dap_client_remote_t * sc); -bool dap_client_is_ready_to_write(dap_client_remote_t * sc); -void dap_client_ready_to_read(dap_client_remote_t * sc,bool is_ready); -void dap_client_ready_to_write(dap_client_remote_t * sc,bool is_ready); - -size_t dap_client_write(dap_client_remote_t *sc, const void * data, size_t data_size); -size_t dap_client_write_f(dap_client_remote_t *a_client, const char * a_format,...); -size_t dap_client_read(dap_client_remote_t *sc, void * data, size_t data_size); - -void dap_client_remove(dap_client_remote_t *sc, struct dap_server * sh); // Removes the client from the list - -void dap_client_shrink_buf_in(dap_client_remote_t * cl, size_t shrink_size); - -#endif diff --git a/client/sxmlc/sxmlc.c b/client/sxmlc/sxmlc.c deleted file mode 100755 index 4852416..0000000 --- a/client/sxmlc/sxmlc.c +++ /dev/null @@ -1,2291 +0,0 @@ -/* - Copyright (c) 2010, Matthieu Labas - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - OF SUCH DAMAGE. - - The views and conclusions contained in the software and documentation are those of the - authors and should not be interpreted as representing official policies, either expressed - or implied, of the FreeBSD Project. -*/ -#if defined(WIN32) || defined(WIN64) -#pragma warning(disable : 4996) -#else -#ifndef strdup -#define _GNU_SOURCE -#endif -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include "sxmlc.h" - -/* - Struct defining "special" tags such as "<? ?>" or "<![CDATA[ ]]/>". - These tags are considered having a start and an end with some data in between that will - be stored in the 'tag' member of an XMLNode. - The 'tag_type' member is a constant that is associated to such tag. - All 'len_*' members are basically the "sx_strlen()" of 'start' and 'end' members. - */ -typedef struct _Tag { - TagType tag_type; - SXML_CHAR* start; - int len_start; - SXML_CHAR* end; - int len_end; -} _TAG; - -typedef struct _SpecialTag { - _TAG *tags; - int n_tags; -} SPECIAL_TAG; - -/* - List of "special" tags handled by sxmlc. - NB the "<!DOCTYPE" tag has a special handling because its 'end' changes according - to its content ('>' or ']>'). - */ -static _TAG _spec[] = { - { TAG_INSTR, C2SX("<?"), 2, C2SX("?>"), 2 }, - { TAG_COMMENT, C2SX("<!--"), 4, C2SX("-->"), 3 }, - { TAG_CDATA, C2SX("<![CDATA["), 9, C2SX("]]>"), 3 } -}; -static int NB_SPECIAL_TAGS = (int)(sizeof(_spec) / sizeof(_TAG)); /* Auto computation of number of special tags */ - -/* - User-registered tags. - */ -static SPECIAL_TAG _user_tags = { NULL, 0 }; - -int XML_register_user_tag(TagType tag_type, SXML_CHAR* start, SXML_CHAR* end) -{ - _TAG* p; - int i, n, le; - - if (tag_type < TAG_USER) - return -1; - - if (start == NULL || end == NULL || *start != C2SX('<')) - return -1; - - le = sx_strlen(end); - if (end[le-1] != C2SX('>')) - return -1; - - i = _user_tags.n_tags; - n = i + 1; - p = (_TAG*)__realloc(_user_tags.tags, n * sizeof(_TAG)); - if (p == NULL) - return -1; - - p[i].tag_type = tag_type; - p[i].start = start; - p[i].end = end; - p[i].len_start = sx_strlen(start); - p[i].len_end = le; - _user_tags.tags = p; - _user_tags.n_tags = n; - - return i; -} - -int XML_unregister_user_tag(int i_tag) -{ - _TAG* pt; - - if (i_tag < 0 || i_tag >= _user_tags.n_tags) - return -1; - - if (_user_tags.n_tags == 1) - pt = NULL; - else { - pt = (_TAG*)__malloc((_user_tags.n_tags - 1) * sizeof(_TAG)); - if (pt == NULL) - return -1; - } - - if (pt != NULL) { - memcpy(pt, _user_tags.tags, i_tag * sizeof(_TAG)); - memcpy(&pt[i_tag], &_user_tags.tags[i_tag + 1], (_user_tags.n_tags - i_tag - 1) * sizeof(_TAG)); - } - if (_user_tags.tags != NULL) - __free(_user_tags.tags); - _user_tags.tags = pt; - _user_tags.n_tags--; - - return _user_tags.n_tags; -} - -int XML_get_nb_registered_user_tags(void) -{ - return _user_tags.n_tags; -} - -int XML_get_registered_user_tag(TagType tag_type) -{ - int i; - - for (i = 0; i < _user_tags.n_tags; i++) - if (_user_tags.tags[i].tag_type == tag_type) - return i; - - return -1; -} - -/* --- XMLNode methods --- */ - -/* - Add 'node' to given '*children_array' of '*len_array' elements. - '*len_array' is overwritten with the number of elements in '*children_array' after its reallocation. - Return the index of the newly added 'node' in '*children_array', or '-1' for memory error. - */ -static int _add_node(XMLNode*** children_array, int* len_array, XMLNode* node) -{ - XMLNode** pt = (XMLNode**)__realloc(*children_array, (*len_array+1) * sizeof(XMLNode*)); - - if (pt == NULL) - return -1; - - pt[*len_array] = node; - *children_array = pt; - - return (*len_array)++; -} - -int XMLNode_init(XMLNode* node) -{ - if (node == NULL) - return false; - - if (node->init_value == XML_INIT_DONE) - return true; /*(void)XMLNode_free(node);*/ - - node->tag = NULL; - node->text = NULL; - - node->attributes = NULL; - node->n_attributes = 0; - - node->father = NULL; - node->children = NULL; - node->n_children = 0; - - node->tag_type = TAG_NONE; - node->active = true; - - node->init_value = XML_INIT_DONE; - - return true; -} - -XMLNode* XMLNode_allocN(int n) -{ - int i; - XMLNode* p; - - if (n <= 0) - return NULL; - - p = (XMLNode*)__calloc(n, sizeof(XMLNode)); - if (p == NULL) - return NULL; - - for (i = 0; i < n; i++) - (void)XMLNode_init(&p[i]); - - return p; -} - -XMLNode* XMLNode_dup(const XMLNode* node, int copy_children) -{ - XMLNode* n; - - if (node == NULL) - return NULL; - - n = (XMLNode*)__calloc(1, sizeof(XMLNode)); - if (n == NULL) - return NULL; - - XMLNode_init(n); - if (!XMLNode_copy(n, node, copy_children)) { - XMLNode_free(n); - - return NULL; - } - - return n; -} - -int XMLNode_free(XMLNode* node) -{ - if (node == NULL || node->init_value != XML_INIT_DONE) - return false; - - if (node->tag != NULL) { - __free(node->tag); - node->tag = NULL; - } - - XMLNode_remove_text(node); - XMLNode_remove_all_attributes(node); - XMLNode_remove_children(node); - - node->tag_type = TAG_NONE; - - return true; -} - -int XMLNode_copy(XMLNode* dst, const XMLNode* src, int copy_children) -{ - int i; - - if (dst == NULL || (src != NULL && src->init_value != XML_INIT_DONE)) - return false; - - (void)XMLNode_free(dst); /* 'dst' is freed first */ - - /* NULL 'src' resets 'dst' */ - if (src == NULL) - return true; - - /* Tag */ - if (src->tag != NULL) { - dst->tag = sx_strdup(src->tag); - if (dst->tag == NULL) goto copy_err; - } - - /* Text */ - if (dst->text != NULL) { - dst->text = sx_strdup(src->text); - if (dst->text == NULL) goto copy_err; - } - - /* Attributes */ - if (src->n_attributes > 0) { - dst->attributes = (XMLAttribute*)__calloc(src->n_attributes, sizeof(XMLAttribute)); - if (dst->attributes== NULL) goto copy_err; - dst->n_attributes = src->n_attributes; - for (i = 0; i < src->n_attributes; i++) { - dst->attributes[i].name = sx_strdup(src->attributes[i].name); - dst->attributes[i].value = sx_strdup(src->attributes[i].value); - if (dst->attributes[i].name == NULL || dst->attributes[i].value == NULL) goto copy_err; - dst->attributes[i].active = src->attributes[i].active; - } - } - - dst->tag_type = src->tag_type; - dst->father = src->father; - dst->user = src->user; - dst->active = src->active; - - /* Copy children if required (and there are any) */ - if (copy_children && src->n_children > 0) { - dst->children = (XMLNode**)__calloc(src->n_children, sizeof(XMLNode*)); - if (dst->children == NULL) goto copy_err; - dst->n_children = src->n_children; - for (i = 0; i < src->n_children; i++) { - if (!XMLNode_copy(dst->children[i], src->children[i], true)) goto copy_err; - } - } - - return true; - -copy_err: - (void)XMLNode_free(dst); - - return false; -} - -int XMLNode_set_active(XMLNode* node, int active) -{ - if (node == NULL || node->init_value != XML_INIT_DONE) - return false; - - node->active = active; - - return true; -} - -int XMLNode_set_tag(XMLNode* node, const SXML_CHAR* tag) -{ - SXML_CHAR* newtag; - if (node == NULL || tag == NULL || node->init_value != XML_INIT_DONE) - return false; - - newtag = sx_strdup(tag); - if (newtag == NULL) - return false; - if (node->tag != NULL) __free(node->tag); - node->tag = newtag; - - return true; -} - -int XMLNode_set_type(XMLNode* node, const TagType tag_type) -{ - if (node == NULL || node->init_value != XML_INIT_DONE) - return false; - - switch (tag_type) { - case TAG_ERROR: - case TAG_END: - case TAG_PARTIAL: - case TAG_NONE: - return false; - - default: - node->tag_type = tag_type; - return true; - } -} - -int XMLNode_set_attribute(XMLNode* node, const SXML_CHAR* attr_name, const SXML_CHAR* attr_value) -{ - XMLAttribute* pt; - int i; - - if (node == NULL || attr_name == NULL || attr_name[0] == NULC || node->init_value != XML_INIT_DONE) - return -1; - - i = XMLNode_search_attribute(node, attr_name, 0); - if (i >= 0) { /* Attribute found: update it */ - SXML_CHAR* value = NULL; - if (attr_value != NULL && (value = sx_strdup(attr_value)) == NULL) - return -1; - pt = node->attributes; - if (pt[i].value != NULL) - __free(pt[i].value); - pt[i].value = value; - } else { /* Attribute not found: add it */ - SXML_CHAR* name = sx_strdup(attr_name); - SXML_CHAR* value = (attr_value == NULL ? NULL : sx_strdup(attr_value)); - if (name == NULL || (value == NULL && attr_value != NULL)) { - if (value != NULL) - __free(value); - if (name != NULL) - __free(name); - return -1; - } - i = node->n_attributes; - pt = (XMLAttribute*)__realloc(node->attributes, (i+1) * sizeof(XMLAttribute)); - if (pt == NULL) { - if (value != NULL) - __free(value); - __free(name); - return -1; - } - - pt[i].name = name; - pt[i].value = value; - pt[i].active = true; - node->attributes = pt; - node->n_attributes = i + 1; - } - - return node->n_attributes; -} - -int XMLNode_get_attribute_with_default(XMLNode* node, const SXML_CHAR* attr_name, const SXML_CHAR** attr_value, const SXML_CHAR* default_attr_value) -{ - XMLAttribute* pt; - int i; - - if (node == NULL || attr_name == NULL || attr_name[0] == NULC || attr_value == NULL || node->init_value != XML_INIT_DONE) - return false; - - i = XMLNode_search_attribute(node, attr_name, 0); - if (i >= 0) { - pt = node->attributes; - if (pt[i].value != NULL) { - *attr_value = sx_strdup(pt[i].value); - if (*attr_value == NULL) - return false; - } else - *attr_value = NULL; /* NULL but returns 'true' as 'NULL' is the actual attribute value */ - } else if (default_attr_value != NULL) { - *attr_value = sx_strdup(default_attr_value); - if (*attr_value == NULL) - return false; - } else - *attr_value = NULL; - - return true; -} - -int XMLNode_get_attribute_count(const XMLNode* node) -{ - int i, n; - - if (node == NULL || node->init_value != XML_INIT_DONE) - return -1; - - for (i = n = 0; i < node->n_attributes; i++) - if (node->attributes[i].active) n++; - - return n; -} - -int XMLNode_search_attribute(const XMLNode* node, const SXML_CHAR* attr_name, int i_search) -{ - int i; - - if (node == NULL || attr_name == NULL || attr_name[0] == NULC || i_search < 0 || i_search >= node->n_attributes) - return -1; - - for (i = i_search; i < node->n_attributes; i++) - if (node->attributes[i].active && !sx_strcmp(node->attributes[i].name, attr_name)) - return i; - - return -1; -} - -int XMLNode_remove_attribute(XMLNode* node, int i_attr) -{ - XMLAttribute* pt; - if (node == NULL || node->init_value != XML_INIT_DONE || i_attr < 0 || i_attr >= node->n_attributes) - return -1; - - /* Before modifying first see if we run out of memory */ - if (node->n_attributes == 1) - pt = NULL; - else { - pt = (XMLAttribute*)__malloc((node->n_attributes - 1) * sizeof(XMLAttribute)); - if (pt == NULL) - return -1; - } - - /* Can't fail anymore, free item */ - if (node->attributes[i_attr].name != NULL) __free(node->attributes[i_attr].name); - if (node->attributes[i_attr].value != NULL) __free(node->attributes[i_attr].value); - - if (pt != NULL) { - memcpy(pt, node->attributes, i_attr * sizeof(XMLAttribute)); - memcpy(&pt[i_attr], &node->attributes[i_attr + 1], (node->n_attributes - i_attr - 1) * sizeof(XMLAttribute)); - } - if (node->attributes != NULL) - __free(node->attributes); - node->attributes = pt; - node->n_attributes--; - - return node->n_attributes; -} - -int XMLNode_remove_all_attributes(XMLNode* node) -{ - int i; - - if (node == NULL || node->init_value != XML_INIT_DONE) - return false; - - if (node->attributes != NULL) { - for (i = 0; i < node->n_attributes; i++) { - if (node->attributes[i].name != NULL) - __free(node->attributes[i].name); - if (node->attributes[i].value != NULL) - __free(node->attributes[i].value); - } - __free(node->attributes); - node->attributes = NULL; - } - node->n_attributes = 0; - - return true; -} - -int XMLNode_set_text(XMLNode* node, const SXML_CHAR* text) -{ - SXML_CHAR* p; - if (node == NULL || node->init_value != XML_INIT_DONE) - return false; - - if (text == NULL) { /* We want to remove it => free node text */ - if (node->text != NULL) { - __free(node->text); - node->text = NULL; - } - - return true; - } - - p = (SXML_CHAR*)__realloc(node->text, (sx_strlen(text) + 1)*sizeof(SXML_CHAR)); /* +1 for '\0' */ - if (p == NULL) - return false; - node->text = p; - - sx_strcpy(node->text, text); - - return true; -} - -int XMLNode_add_child(XMLNode* node, XMLNode* child) -{ - if (node == NULL || child == NULL || node->init_value != XML_INIT_DONE || child->init_value != XML_INIT_DONE) - return false; - - if (_add_node(&node->children, &node->n_children, child) >= 0) { - node->tag_type = TAG_FATHER; - child->father = node; - return true; - } else - return false; -} - -int XMLNode_get_children_count(const XMLNode* node) -{ - int i, n; - - if (node == NULL || node->init_value != XML_INIT_DONE) - return -1; - - for (i = n = 0; i < node->n_children; i++) - if (node->children[i]->active) n++; - - return n; -} - -XMLNode* XMLNode_get_child(const XMLNode* node, int i_child) -{ - int i; - - if (node == NULL || node->init_value != XML_INIT_DONE || i_child < 0 || i_child >= node->n_children) - return NULL; - - for (i = 0; i < node->n_children; i++) { - if (!node->children[i]->active) - i_child++; - else if (i == i_child) - return node->children[i]; - } - - return NULL; -} - -int XMLNode_remove_child(XMLNode* node, int i_child, int free_child) -{ - int i; - XMLNode** pt; - - if (node == NULL || node->init_value != XML_INIT_DONE || i_child < 0 || i_child >= node->n_children) - return -1; - - /* Lookup 'i_child'th active child */ - for (i = 0; i < node->n_children; i++) { - if (!node->children[i]->active) - i_child++; - else if (i == i_child) - break; - } - if (i >= node->n_children) - return -1; /* Children is not found */ - - /* Before modifying first see if we run out of memory */ - if (node->n_children == 1) - pt = NULL; - else { - pt = (XMLNode**)__malloc((node->n_children - 1) * sizeof(XMLNode*)); - if (pt == NULL) - return -1; - } - - /* Can't fail anymore, free item */ - (void)XMLNode_free(node->children[i_child]); - if (free_child) - __free(node->children[i_child]); - - if (pt != NULL) { - memcpy(pt, node->children, i_child * sizeof(XMLNode*)); - memcpy(&pt[i_child], &node->children[i_child + 1], (node->n_children - i_child - 1) * sizeof(XMLNode*)); - } - if (node->children != NULL) - __free(node->children); - node->children = pt; - node->n_children--; - if (node->n_children == 0) - node->tag_type = TAG_SELF; - - return node->n_children; -} - -int XMLNode_remove_children(XMLNode* node) -{ - int i; - - if (node == NULL || node->init_value != XML_INIT_DONE) - return false; - - if (node->children != NULL) { - for (i = 0; i < node->n_children; i++) - if (node->children[i] != NULL) { - (void)XMLNode_free(node->children[i]); - __free(node->children[i]); - } - __free(node->children); - node->children = NULL; - } - node->n_children = 0; - - return true; -} - -int XMLNode_equal(const XMLNode* node1, const XMLNode* node2) -{ - int i, j; - - if (node1 == node2) - return true; - - if (node1 == NULL || node2 == NULL || node1->init_value != XML_INIT_DONE || node2->init_value != XML_INIT_DONE) - return false; - - if (sx_strcmp(node1->tag, node2->tag)) - return false; - - /* Test all attributes from 'node1' */ - for (i = 0; i < node1->n_attributes; i++) { - if (!node1->attributes[i].active) - continue; - j = XMLNode_search_attribute(node2, node1->attributes[i].name, 0); - if (j < 0) - return false; - if (sx_strcmp(node1->attributes[i].value, node2->attributes[j].value)) - return false; - } - - /* Test other attributes from 'node2' that might not be in 'node1' */ - for (i = 0; i < node2->n_attributes; i++) { - if (!node2->attributes[i].active) - continue; - j = XMLNode_search_attribute(node1, node2->attributes[i].name, 0); - if (j < 0) - return false; - if (sx_strcmp(node2->attributes[i].name, node1->attributes[j].name)) - return false; - } - - return true; -} - -XMLNode* XMLNode_next_sibling(const XMLNode* node) -{ - int i; - XMLNode* father; - - if (node == NULL || node->init_value != XML_INIT_DONE || node->father == NULL) - return NULL; - - father = node->father; - for (i = 0; i < father->n_children && father->children[i] != node; i++) ; - i++; /* father->children[i] is now 'node' next sibling */ - - return i < father->n_children ? father->children[i] : NULL; -} - -static XMLNode* _XMLNode_next(const XMLNode* node, int in_children) -{ - XMLNode* node2; - - if (node == NULL || node->init_value != XML_INIT_DONE) - return NULL; - - /* Check first child */ - if (in_children && node->n_children > 0) - return node->children[0]; - - /* Check next sibling */ - if ((node2 = XMLNode_next_sibling(node)) != NULL) - return node2; - - /* Check next uncle */ - return _XMLNode_next(node->father, false); -} - -XMLNode* XMLNode_next(const XMLNode* node) -{ - return _XMLNode_next(node, true); -} - -/* --- XMLDoc methods --- */ - -int XMLDoc_init(XMLDoc* doc) -{ - if (doc == NULL) - return false; - - doc->filename[0] = NULC; -#ifdef SXMLC_UNICODE - memset(&doc->bom, 0, sizeof(doc->bom)); -#endif - doc->nodes = NULL; - doc->n_nodes = 0; - doc->i_root = -1; - doc->init_value = XML_INIT_DONE; - - return true; -} - -int XMLDoc_free(XMLDoc* doc) -{ - int i; - - if (doc == NULL || doc->init_value != XML_INIT_DONE) - return false; - - for (i = 0; i < doc->n_nodes; i++) { - (void)XMLNode_free(doc->nodes[i]); - __free(doc->nodes[i]); - } - __free(doc->nodes); - doc->nodes = NULL; - doc->n_nodes = 0; - doc->i_root = -1; - - return true; -} - -int XMLDoc_set_root(XMLDoc* doc, int i_root) -{ - if (doc == NULL || doc->init_value != XML_INIT_DONE || i_root < 0 || i_root >= doc->n_nodes) - return false; - - doc->i_root = i_root; - - return true; -} - -int XMLDoc_add_node(XMLDoc* doc, XMLNode* node) -{ - if (doc == NULL || node == NULL || doc->init_value != XML_INIT_DONE) - return -1; - - if (_add_node(&doc->nodes, &doc->n_nodes, node) < 0) - return -1; - - if (node->tag_type == TAG_FATHER) - doc->i_root = doc->n_nodes - 1; /* Main root node is the last father node */ - - return doc->n_nodes; -} - -int XMLDoc_remove_node(XMLDoc* doc, int i_node, int free_node) -{ - XMLNode** pt; - if (doc == NULL || doc->init_value != XML_INIT_DONE || i_node < 0 || i_node > doc->n_nodes) - return false; - - /* Before modifying first see if we run out of memory */ - if (doc->n_nodes == 1) - pt = NULL; - else { - pt = (XMLNode**)__malloc((doc->n_nodes - 1) * sizeof(XMLNode*)); - if (pt == NULL) - return false; - } - - /* Can't fail anymore, free item */ - (void)XMLNode_free(doc->nodes[i_node]); - if (free_node) __free(doc->nodes[i_node]); - - if (pt != NULL) { - memcpy(pt, &doc->nodes[i_node], i_node * sizeof(XMLNode*)); - memcpy(&pt[i_node], &doc->nodes[i_node + 1], (doc->n_nodes - i_node - 1) * sizeof(XMLNode*)); - } - - if (doc->nodes != NULL) - __free(doc->nodes); - doc->nodes = pt; - doc->n_nodes--; - - return true; -} - -/* - Helper functions to print formatting before a new tag. - Returns the new number of characters in the line. - */ -static int _count_new_char_line(const SXML_CHAR* str, int nb_char_tab, int cur_sz_line) -{ - for (; *str; str++) { - if (*str == C2SX('\n')) - cur_sz_line = 0; - else if (*str == C2SX('\t')) - cur_sz_line += nb_char_tab; - else - cur_sz_line++; - } - - return cur_sz_line; -} -static int _print_formatting(const XMLNode* node, FILE* f, const SXML_CHAR* tag_sep, const SXML_CHAR* child_sep, int nb_char_tab, int cur_sz_line) -{ - if (tag_sep != NULL) { - sx_fprintf(f, tag_sep); - cur_sz_line = _count_new_char_line(tag_sep, nb_char_tab, cur_sz_line); - } - if (child_sep != NULL) { - for (node = node->father; node != NULL; node = node->father) { - sx_fprintf(f, child_sep); - cur_sz_line = _count_new_char_line(child_sep, nb_char_tab, cur_sz_line); - } - } - - return cur_sz_line; -} - -static int _XMLNode_print_header(const XMLNode* node, FILE* f, const SXML_CHAR* tag_sep, const SXML_CHAR* child_sep, const SXML_CHAR* attr_sep, int sz_line, int cur_sz_line, int nb_char_tab) -{ - int i; - SXML_CHAR* p; - - if (node == NULL || f == NULL || !node->active || node->tag == NULL || node->tag[0] == NULC) - return -1; - - /* Special handling of DOCTYPE */ - if (node->tag_type == TAG_DOCTYPE) { - /* Search for an unescaped '[' in the DOCTYPE definition, in which case the end delimiter should be ']>' instead of '>' */ - for (p = sx_strchr(node->tag, C2SX('[')); p != NULL && *(p-1) == C2SX('\\'); p = sx_strchr(p+1, C2SX('['))) ; - cur_sz_line += sx_fprintf(f, C2SX("<!DOCTYPE%s%s>"), node->tag, p != NULL ? C2SX("]") : C2SX("")); - return cur_sz_line; - } - - /* Check for special tags first */ - for (i = 0; i < NB_SPECIAL_TAGS; i++) { - if (node->tag_type == _spec[i].tag_type) { - sx_fprintf(f, C2SX("%s%s%s"), _spec[i].start, node->tag, _spec[i].end); - cur_sz_line += sx_strlen(_spec[i].start) + sx_strlen(node->tag) + sx_strlen(_spec[i].end); - return cur_sz_line; - } - } - - /* Check for user tags */ - for (i = 0; i < _user_tags.n_tags; i++) { - if (node->tag_type == _user_tags.tags[i].tag_type) { - sx_fprintf(f, C2SX("%s%s%s"), _user_tags.tags[i].start, node->tag, _user_tags.tags[i].end); - cur_sz_line += sx_strlen(_user_tags.tags[i].start) + sx_strlen(node->tag) + sx_strlen(_user_tags.tags[i].end); - return cur_sz_line; - } - } - - /* Print tag name */ - cur_sz_line += sx_fprintf(f, C2SX("<%s"), node->tag); - - /* Print attributes */ - for (i = 0; i < node->n_attributes; i++) { - if (!node->attributes[i].active) - continue; - cur_sz_line += sx_strlen(node->attributes[i].name) + sx_strlen(node->attributes[i].value) + 3; - if (sz_line > 0 && cur_sz_line > sz_line) { - cur_sz_line = _print_formatting(node, f, tag_sep, child_sep, nb_char_tab, cur_sz_line); - /* Add extra separator, as if new line was a child of the previous one */ - if (child_sep != NULL) { - sx_fprintf(f, child_sep); - cur_sz_line = _count_new_char_line(child_sep, nb_char_tab, cur_sz_line); - } - } - /* Attribute name */ - if (attr_sep != NULL) { - sx_fprintf(f, attr_sep); - cur_sz_line = _count_new_char_line(attr_sep, nb_char_tab, cur_sz_line); - sx_fprintf(f, C2SX("%s="), node->attributes[i].name); - } else - sx_fprintf(f, C2SX(" %s="), node->attributes[i].name); - - /* Attribute value */ - (void)sx_fputc(XML_DEFAULT_QUOTE, f); - cur_sz_line += fprintHTML(f, node->attributes[i].value) + 2; - (void)sx_fputc(XML_DEFAULT_QUOTE, f); - } - - /* End the tag if there are no children and no text */ - if (node->n_children == 0 && (node->text == NULL || node->text[0] == NULC)) { - cur_sz_line += sx_fprintf(f, C2SX("/>")); - } else { - (void)sx_fputc(C2SX('>'), f); - cur_sz_line++; - } - - return cur_sz_line; -} - -int XMLNode_print_header(const XMLNode* node, FILE* f, int sz_line, int nb_char_tab) -{ - return _XMLNode_print_header(node, f, NULL, NULL, NULL, sz_line, 0, nb_char_tab) < 0 ? false : true; -} - -static int _XMLNode_print(const XMLNode* node, FILE* f, const SXML_CHAR* tag_sep, const SXML_CHAR* child_sep, const SXML_CHAR* attr_sep, int keep_text_spaces, int sz_line, int cur_sz_line, int nb_char_tab, int depth) -{ - int i; - SXML_CHAR* p; - - if (node != NULL && node->tag_type==TAG_TEXT) { /* Text has to be printed: check if it is only spaces */ - if (!keep_text_spaces) { - for (p = node->text; *p != NULC && sx_isspace(*p); p++) ; /* 'p' points to first non-space character, or to '\0' if only spaces */ - } else - p = node->text; /* '*p' won't be '\0' */ - if (*p != NULC) - cur_sz_line += fprintHTML(f, node->text); - return cur_sz_line; - } - - if (node == NULL || f == NULL || !node->active || node->tag == NULL || node->tag[0] == NULC) - return -1; - - if (nb_char_tab <= 0) - nb_char_tab = 1; - - /* Print formatting */ - if (depth < 0) /* UGLY HACK: 'depth' forced negative on very first line so we don't print an extra 'tag_sep' (usually "\n" when pretty-printing) */ - depth = 0; - else - cur_sz_line = _print_formatting(node, f, tag_sep, child_sep, nb_char_tab, cur_sz_line); - - _XMLNode_print_header(node, f, tag_sep, child_sep, attr_sep, sz_line, cur_sz_line, nb_char_tab); - - if (node->text != NULL && node->text[0] != NULC) { - /* Text has to be printed: check if it is only spaces */ - if (!keep_text_spaces) { - for (p = node->text; *p != NULC && sx_isspace(*p); p++) ; /* 'p' points to first non-space character, or to '\0' if only spaces */ - } else - p = node->text; /* '*p' won't be '\0' */ - if (*p != NULC) cur_sz_line += fprintHTML(f, node->text); - } else if (node->n_children <= 0) /* Everything has already been printed */ - return cur_sz_line; - - /* Recursively print children */ - for (i = 0; i < node->n_children; i++) - (void)_XMLNode_print(node->children[i], f, tag_sep, child_sep, attr_sep, keep_text_spaces, sz_line, cur_sz_line, nb_char_tab, depth+1); - - /* Print tag end after children */ - /* Print formatting */ - if (node->n_children > 0) - cur_sz_line = _print_formatting(node, f, tag_sep, child_sep, nb_char_tab, cur_sz_line); - cur_sz_line += sx_fprintf(f, C2SX("</%s>"), node->tag); - - return cur_sz_line; -} - -int XMLNode_print_attr_sep(const XMLNode* node, FILE* f, const SXML_CHAR* tag_sep, const SXML_CHAR* child_sep, const SXML_CHAR* attr_sep, int keep_text_spaces, int sz_line, int nb_char_tab) -{ - return _XMLNode_print(node, f, tag_sep, child_sep, attr_sep, keep_text_spaces, sz_line, 0, nb_char_tab, 0); -} - -int XMLDoc_print_attr_sep(const XMLDoc* doc, FILE* f, const SXML_CHAR* tag_sep, const SXML_CHAR* child_sep, const SXML_CHAR* attr_sep, int keep_text_spaces, int sz_line, int nb_char_tab) -{ - int i, depth, cur_sz_line; - - if (doc == NULL || f == NULL || doc->init_value != XML_INIT_DONE) - return false; - -#ifdef SXMLC_UNICODE - /* Write BOM if it exist */ - if (doc->sz_bom > 0) fwrite(doc->bom, sizeof(unsigned char), doc->sz_bom, f); -#endif - - depth = -1; /* UGLY HACK: 'depth' forced negative on very first line so we don't print an extra 'tag_sep' (usually "\n") */ - for (i = 0, cur_sz_line = 0; i < doc->n_nodes; i++) { - cur_sz_line = _XMLNode_print(doc->nodes[i], f, tag_sep, child_sep, attr_sep, keep_text_spaces, sz_line, cur_sz_line, nb_char_tab, depth); - depth = 0; - } - /* TODO: Find something more graceful than 'depth=-1', even though everyone knows I probably never will ;) */ - - return true; -} - -/* --- */ - -int XML_parse_attribute_to(const SXML_CHAR* str, int to, XMLAttribute* xmlattr) -{ - const SXML_CHAR *p; - int i, n0, n1, remQ = 0; - int ret = 1; - SXML_CHAR quote = '\0'; - - if (str == NULL || xmlattr == NULL) - return 0; - - if (to < 0) - to = sx_strlen(str) - 1; - - /* Search for the '=' */ - /* 'n0' is where the attribute name stops, 'n1' is where the attribute value starts */ - for (n0 = 0; n0 != to && str[n0] != C2SX('=') && !sx_isspace(str[n0]); n0++) ; /* Search for '=' or a space */ - for (n1 = n0; n1 != to && sx_isspace(str[n1]); n1++) ; /* Search for something not a space */ - if (str[n1] != C2SX('=')) - return 0; /* '=' not found: malformed string */ - for (n1++; n1 != to && sx_isspace(str[n1]); n1++) ; /* Search for something not a space */ - if (isquote(str[n1])) { /* Remove quotes */ - quote = str[n1]; - remQ = 1; - } - - xmlattr->name = (SXML_CHAR*)__malloc((n0+1)*sizeof(SXML_CHAR)); - xmlattr->value = (SXML_CHAR*)__malloc((to+1 - n1 - remQ + 1) * sizeof(SXML_CHAR)); - xmlattr->active = true; - if (xmlattr->name != NULL && xmlattr->value != NULL) { - /* Copy name */ - sx_strncpy(xmlattr->name, str, n0); - xmlattr->name[n0] = NULC; - /* (void)str_unescape(xmlattr->name); do not unescape the name */ - /* Copy value (p starts after the quote (if any) and stops at the end of 'str' - (skipping the quote if any, hence the '*(p+remQ)') */ - for (i = 0, p = str + n1 + remQ; i + n1 + remQ < to && *(p+remQ) != NULC; i++, p++) - xmlattr->value[i] = *p; - xmlattr->value[i] = NULC; - (void)html2str(xmlattr->value, NULL); /* Convert HTML escape sequences, do not str_unescape(xmlattr->value) */ - if (remQ && *p != quote) - ret = 2; /* Quote at the beginning but not at the end: probable presence of '>' inside attribute value, so we need to read more data! */ - } else - ret = 0; - - if (ret == 0) { - if (xmlattr->name != NULL) { - __free(xmlattr->name); - xmlattr->name = NULL; - } - if (xmlattr->value != NULL) { - __free(xmlattr->value); - xmlattr->value = NULL; - } - } - - return ret; -} - -static TagType _parse_special_tag(const SXML_CHAR* str, int len, _TAG* tag, XMLNode* node) -{ - if (sx_strncmp(str, tag->start, tag->len_start)) - return TAG_NONE; - - if (sx_strncmp(str + len - tag->len_end, tag->end, tag->len_end)) /* There probably is a '>' inside the tag */ - return TAG_PARTIAL; - - node->tag = (SXML_CHAR*)__malloc((len - tag->len_start - tag->len_end + 1)*sizeof(SXML_CHAR)); - if (node->tag == NULL) - return TAG_NONE; - sx_strncpy(node->tag, str + tag->len_start, len - tag->len_start - tag->len_end); - node->tag[len - tag->len_start - tag->len_end] = NULC; - node->tag_type = tag->tag_type; - - return node->tag_type; -} - -/* - Reads a string that is supposed to be an xml tag like '<tag (attribName="attribValue")* [/]>' or '</tag>'. - Fills the 'xmlnode' structure with the tag name and its attributes. - Returns 'TAG_ERROR' if an error occurred (malformed 'str' or memory). 'TAG_*' when string is recognized. - */ -TagType XML_parse_1string(const SXML_CHAR* str, XMLNode* xmlnode) -{ - SXML_CHAR *p; - XMLAttribute* pt; - int n, nn, len, rc, tag_end = 0; - - if (str == NULL || xmlnode == NULL) - return TAG_ERROR; - len = sx_strlen(str); - - /* Check for malformed string */ - if (str[0] != C2SX('<') || str[len-1] != C2SX('>')) - return TAG_ERROR; - - for (nn = 0; nn < NB_SPECIAL_TAGS; nn++) { - n = (int)_parse_special_tag(str, len, &_spec[nn], xmlnode); - switch (n) { - case TAG_NONE: break; /* Nothing found => do nothing */ - default: return (TagType)n; /* Tag found => return it */ - } - } - - /* "<!DOCTYPE" requires a special handling because it can end with "]>" instead of ">" if a '[' is found inside */ - if (str[1] == C2SX('!')) { - /* DOCTYPE */ - if (!sx_strncmp(str, C2SX("<!DOCTYPE"), 9)) { /* 9 = sizeof("<!DOCTYPE") */ - for (n = 9; str[n] && str[n] != C2SX('['); n++) ; /* Look for a '[' inside the DOCTYPE, which would mean that we should be looking for a "]>" tag end */ - nn = 0; - if (str[n]) { /* '[' was found */ - if (sx_strncmp(str+len-2, C2SX("]>"), 2)) /* There probably is a '>' inside the DOCTYPE */ - return TAG_PARTIAL; - nn = 1; - } - xmlnode->tag = (SXML_CHAR*)__malloc((len - 9 - nn)*sizeof(SXML_CHAR)); /* 'len' - "<!DOCTYPE" and ">" + '\0' */ - if (xmlnode->tag == NULL) - return TAG_ERROR; - sx_strncpy(xmlnode->tag, &str[9], len - 10 - nn); - xmlnode->tag[len - 10 - nn] = NULC; - xmlnode->tag_type = TAG_DOCTYPE; - - return TAG_DOCTYPE; - } - } - - /* Test user tags */ - for (nn = 0; nn < _user_tags.n_tags; nn++) { - n = _parse_special_tag(str, len, &_user_tags.tags[nn], xmlnode); - switch (n) { - case TAG_ERROR: return TAG_NONE; /* Error => exit */ - case TAG_NONE: break; /* Nothing found => do nothing */ - default: return (TagType)n; /* Tag found => return it */ - } - } - - if (str[1] == C2SX('/')) - tag_end = 1; - - /* tag starts at index 1 (or 2 if tag end) and ends at the first space or '/>' */ - for (n = 1 + tag_end; str[n] != NULC && str[n] != C2SX('>') && str[n] != C2SX('/') && !sx_isspace(str[n]); n++) ; - xmlnode->tag = (SXML_CHAR*)__malloc((n - tag_end)*sizeof(SXML_CHAR)); - if (xmlnode->tag == NULL) - return TAG_ERROR; - sx_strncpy(xmlnode->tag, &str[1 + tag_end], n - 1 - tag_end); - xmlnode->tag[n - 1 - tag_end] = NULC; - if (tag_end) { - xmlnode->tag_type = TAG_END; - return TAG_END; - } - - /* Here, 'n' is the position of the first space after tag name */ - while (n < len) { - /* Skips spaces */ - while (sx_isspace(str[n])) n++; - - /* Check for XML end ('>' or '/>') */ - if (str[n] == C2SX('>')) { /* Tag with children */ - int type = (str[n-1] == '/' ? TAG_SELF : TAG_FATHER); // TODO: Find something better to cope with <tag attr=v/> - xmlnode->tag_type = type; - return type; - } - if (!sx_strcmp(str+n, C2SX("/>"))) { /* Tag without children */ - xmlnode->tag_type = TAG_SELF; - return TAG_SELF; - } - - /* New attribute found */ - p = sx_strchr(str+n, C2SX('=')); - if (p == NULL) goto parse_err; - pt = (XMLAttribute*)__realloc(xmlnode->attributes, (xmlnode->n_attributes + 1) * sizeof(XMLAttribute)); - if (pt == NULL) goto parse_err; - - pt[xmlnode->n_attributes].name = NULL; - pt[xmlnode->n_attributes].value = NULL; - pt[xmlnode->n_attributes].active = false; - xmlnode->n_attributes++; - xmlnode->attributes = pt; - while (*p != NULC && sx_isspace(*++p)) ; /* Skip spaces */ - if (isquote(*p)) { /* Attribute value starts with a quote, look for next one, ignoring protected ones with '\' */ - for (nn = p-str+1; str[nn] && str[nn] != *p; nn++) { // CHECK UNICODE "nn = p-str+1" - /* if (str[nn] == C2SX('\\')) nn++; [bugs:#7]: '\' is valid in values */ - } - } else { /* Attribute value stops at first space or end of XML string */ - for (nn = p-str+1; str[nn] != NULC && !sx_isspace(str[nn]) && str[nn] != C2SX('/') && str[nn] != C2SX('>'); nn++) ; /* Go to the end of the attribute value */ // CHECK UNICODE - } - - /* Here 'str[nn]' is the character after value */ - /* the attribute definition ('attrName="attrVal"') is between 'str[n]' and 'str[nn]' */ - rc = XML_parse_attribute_to(&str[n], nn - n, &xmlnode->attributes[xmlnode->n_attributes - 1]); - if (!rc) goto parse_err; - if (rc == 2) { /* Probable presence of '>' inside attribute value, which is legal XML. Remove attribute to re-parse it later */ - XMLNode_remove_attribute(xmlnode, xmlnode->n_attributes - 1); - return TAG_PARTIAL; - } - - n = nn + 1; - } - - sx_fprintf(stderr, C2SX("\nWE SHOULD NOT BE HERE!\n[%s]\n\n"), str); - -parse_err: - (void)XMLNode_free(xmlnode); - - return TAG_ERROR; -} - -static int _parse_data_SAX(void* in, const DataSourceType in_type, const SAX_Callbacks* sax, SAX_Data* sd) -{ - SXML_CHAR *line = NULL, *txt_end, *p; - XMLNode node; - int ret, exit, sz, n0, ncr; - TagType tag_type; - int (*meos)(void* ds) = (in_type == DATA_SOURCE_BUFFER ? (int(*)(void*))_beob : (int(*)(void*))sx_feof); - - if (sax->start_doc != NULL && !sax->start_doc(sd)) - return true; - if (sax->all_event != NULL && !sax->all_event(XML_EVENT_START_DOC, NULL, (SXML_CHAR*)sd->name, 0, sd)) - return true; - - ret = true; - exit = false; - sd->line_num = 1; /* Line counter, starts at 1 */ - sz = 0; /* 'line' buffer size */ - node.init_value = 0; - (void)XMLNode_init(&node); - while ((n0 = read_line_alloc(in, in_type, &line, &sz, 0, NULC, C2SX('>'), true, C2SX('\n'), &ncr)) != 0) { - (void)XMLNode_free(&node); - for (p = line; *p != NULC && sx_isspace(*p); p++) ; /* Checks if text is only spaces */ - if (*p == NULC) - break; - sd->line_num += ncr; - - /* Get text for 'father' (i.e. what is before '<') */ - while ((txt_end = sx_strchr(line, C2SX('<'))) == NULL) { /* '<' was not found, indicating a probable '>' inside text (should have been escaped with '>' but we'll handle that ;) */ - int n1 = read_line_alloc(in, in_type, &line, &sz, n0, 0, C2SX('>'), true, C2SX('\n'), &ncr); /* Go on reading the file from current position until next '>' */ - sd->line_num += ncr; - if (n1 <= n0) { - ret = false; - if (sax->on_error == NULL && sax->all_event == NULL) - sx_fprintf(stderr, C2SX("%s:%d: MEMORY ERROR.\n"), sd->name, sd->line_num); - else { - if (sax->on_error != NULL && !sax->on_error(PARSE_ERR_MEMORY, sd->line_num, sd)) - break; - if (sax->all_event != NULL && !sax->all_event(XML_EVENT_ERROR, NULL, (SXML_CHAR*)sd->name, PARSE_ERR_MEMORY, sd)) - break; - } - break; /* 'txt_end' is still NULL here so we'll display the syntax error below */ - } - n0 = n1; - } - if (txt_end == NULL) { /* Missing tag start */ - ret = false; - if (sax->on_error == NULL && sax->all_event == NULL) - sx_fprintf(stderr, C2SX("%s:%d: ERROR: Unexpected end character '>', without matching '<'!\n"), sd->name, sd->line_num); - else { - if (sax->on_error != NULL && !sax->on_error(PARSE_ERR_UNEXPECTED_TAG_END, sd->line_num, sd)) - break; - if (sax->all_event != NULL && !sax->all_event(XML_EVENT_ERROR, NULL, (SXML_CHAR*)sd->name, PARSE_ERR_UNEXPECTED_TAG_END, sd)) - break; - } - break; - } - /* First part of 'line' (before '<') is to be added to 'father->text' */ - *txt_end = NULC; /* Have 'line' be the text for 'father' */ - if (*line != NULC && (sax->new_text != NULL || sax->all_event != NULL)) { - if (sax->new_text != NULL && (exit = !sax->new_text(line, sd))) /* no str_unescape(line) */ - break; - if (sax->all_event != NULL && (exit = !sax->all_event(XML_EVENT_TEXT, NULL, line, sd->line_num, sd))) - break; - } - *txt_end = '<'; /* Restores tag start */ - - switch (tag_type = XML_parse_1string(txt_end, &node)) { - case TAG_ERROR: /* Memory error */ - ret = false; - if (sax->on_error == NULL && sax->all_event == NULL) - sx_fprintf(stderr, C2SX("%s:%d: MEMORY ERROR.\n"), sd->name, sd->line_num); - else { - if (sax->on_error != NULL && (exit = !sax->on_error(PARSE_ERR_MEMORY, sd->line_num, sd))) - break; - if (sax->all_event != NULL && (exit = !sax->all_event(XML_EVENT_ERROR, NULL, (SXML_CHAR*)sd->name, PARSE_ERR_MEMORY, sd))) - break; - } - break; - - case TAG_NONE: /* Syntax error */ - ret = false; - p = sx_strchr(txt_end, C2SX('\n')); - if (p != NULL) - *p = NULC; - if (sax->on_error == NULL && sax->all_event == NULL) { - sx_fprintf(stderr, C2SX("%s:%d: SYNTAX ERROR (%s%s).\n"), sd->name, sd->line_num, txt_end, p == NULL ? C2SX("") : C2SX("...")); - if (p != NULL) - *p = C2SX('\n'); - } else { - if (sax->on_error != NULL && (exit = !sax->on_error(PARSE_ERR_SYNTAX, sd->line_num, sd))) - break; - if (sax->all_event != NULL && (exit = !sax->all_event(XML_EVENT_ERROR, NULL, (SXML_CHAR*)sd->name, PARSE_ERR_SYNTAX, sd))) - break; - } - break; - - case TAG_END: - if (sax->end_node != NULL || sax->all_event != NULL) { - if (sax->end_node != NULL && (exit = !sax->end_node(&node, sd))) - break; - if (sax->all_event != NULL && (exit = !sax->all_event(XML_EVENT_END_NODE, &node, NULL, sd->line_num, sd))) - break; - } - break; - - default: /* Add 'node' to 'father' children */ - /* If the line looks like a comment (or CDATA) but is not properly finished, loop until we find the end. */ - while (tag_type == TAG_PARTIAL) { - int n1 = read_line_alloc(in, in_type, &line, &sz, n0, NULC, C2SX('>'), true, C2SX('\n'), &ncr); /* Go on reading the file from current position until next '>' */ - sd->line_num += ncr; - if (n1 <= n0) { - ret = false; - if (sax->on_error == NULL && sax->all_event == NULL) - sx_fprintf(stderr, C2SX("%s:%d: SYNTAX ERROR.\n"), sd->name, sd->line_num); - else { - if (sax->on_error != NULL && (exit = !sax->on_error(meos(in) ? PARSE_ERR_EOF : PARSE_ERR_MEMORY, sd->line_num, sd))) - break; - if (sax->all_event != NULL && (exit = !sax->all_event(XML_EVENT_ERROR, NULL, (SXML_CHAR*)sd->name, meos(in) ? PARSE_ERR_EOF : PARSE_ERR_MEMORY, sd))) - break; - } - break; - } - n0 = n1; - txt_end = sx_strchr(line, C2SX('<')); /* In case 'line' has been moved by the '__realloc' in 'read_line_alloc' */ - tag_type = XML_parse_1string(txt_end, &node); - if (tag_type == TAG_ERROR) { - ret = false; - if (sax->on_error == NULL && sax->all_event == NULL) - sx_fprintf(stderr, C2SX("%s:%d: PARSE ERROR.\n"), sd->name, sd->line_num); - else { - if (sax->on_error != NULL && (exit = !sax->on_error(meos(in) ? PARSE_ERR_EOF : PARSE_ERR_SYNTAX, sd->line_num, sd))) - break; - if (sax->all_event != NULL && (exit = !sax->all_event(XML_EVENT_ERROR, NULL, (SXML_CHAR*)sd->name, meos(in) ? PARSE_ERR_EOF : PARSE_ERR_SYNTAX, sd))) - break; - } - break; - } - } - if (ret == false) - break; - if (sax->start_node != NULL && (exit = !sax->start_node(&node, sd))) - break; - if (sax->all_event != NULL && (exit = !sax->all_event(XML_EVENT_START_NODE, &node, NULL, sd->line_num, sd))) - break; - if (node.tag_type != TAG_FATHER && (sax->end_node != NULL || sax->all_event != NULL)) { - if (sax->end_node != NULL && (exit = !sax->end_node(&node, sd))) - break; - if (sax->all_event != NULL && (exit = !sax->all_event(XML_EVENT_END_NODE, &node, NULL, sd->line_num, sd))) - break; - } - break; - } - if (exit == true || ret == false || meos(in)) - break; - } - __free(line); - (void)XMLNode_free(&node); - - if (sax->end_doc != NULL && !sax->end_doc(sd)) - return ret; - if (sax->all_event != NULL) - (void)sax->all_event(XML_EVENT_END_DOC, NULL, (SXML_CHAR*)sd->name, sd->line_num, sd); - - return ret; -} - -int SAX_Callbacks_init(SAX_Callbacks* sax) -{ - if (sax == NULL) - return false; - - sax->start_doc = NULL; - sax->start_node = NULL; - sax->end_node = NULL; - sax->new_text = NULL; - sax->on_error = NULL; - sax->end_doc = NULL; - sax->all_event = NULL; - - return true; -} - -int DOMXMLDoc_doc_start(SAX_Data* sd) -{ - DOM_through_SAX* dom = (DOM_through_SAX*)sd->user; - - dom->current = NULL; - dom->error = PARSE_ERR_NONE; - dom->line_error = 0; - - return true; -} - -int DOMXMLDoc_node_start(const XMLNode* node, SAX_Data* sd) -{ - DOM_through_SAX* dom = (DOM_through_SAX*)sd->user; - XMLNode* new_node; - int i; - - if ((new_node = XMLNode_dup(node, true)) == NULL) goto node_start_err; /* No real need to put 'true' for 'XMLNode_dup', but cleaner */ - - if (dom->current == NULL) { - if ((i = _add_node(&dom->doc->nodes, &dom->doc->n_nodes, new_node)) < 0) goto node_start_err; - - if (dom->doc->i_root < 0 && (node->tag_type == TAG_FATHER || node->tag_type == TAG_SELF)) - dom->doc->i_root = i; - } else { - if (_add_node(&dom->current->children, &dom->current->n_children, new_node) < 0) goto node_start_err; - } - - new_node->father = dom->current; - dom->current = new_node; - - return true; - -node_start_err: - dom->error = PARSE_ERR_MEMORY; - dom->line_error = sd->line_num; - (void)XMLNode_free(new_node); - __free(new_node); - - return false; -} - -int DOMXMLDoc_node_end(const XMLNode* node, SAX_Data* sd) -{ - DOM_through_SAX* dom = (DOM_through_SAX*)sd->user; - - if (dom->current == NULL || sx_strcmp(dom->current->tag, node->tag)) { - sx_fprintf(stderr, C2SX("%s:%d: ERROR - End tag </%s> was unexpected"), sd->name, sd->line_num, node->tag); - if (dom->current != NULL) - sx_fprintf(stderr, C2SX(" (</%s> was expected)\n"), dom->current->tag); - else - sx_fprintf(stderr, C2SX(" (no node to end)\n")); - - dom->error = PARSE_ERR_UNEXPECTED_NODE_END; - dom->line_error = sd->line_num; - - return false; - } - - dom->current = dom->current->father; - - return true; -} - -int DOMXMLDoc_node_text(SXML_CHAR* text, SAX_Data* sd) -{ - SXML_CHAR* p = text; - DOM_through_SAX* dom = (DOM_through_SAX*)sd->user; - - /* Keep text, even if it is only spaces */ -#if 0 - while(*p != NULC && sx_isspace(*p++)) ; - if (*p == NULC) return true; /* Only spaces */ -#endif - - /* If there is no current node to add text to, raise an error, except if text is only spaces, in which case it is probably just formatting */ - if (dom->current == NULL) { - while(*p != NULC && sx_isspace(*p++)) ; - if (*p == NULC) /* Only spaces => probably pretty-printing */ - return true; - dom->error = PARSE_ERR_TEXT_OUTSIDE_NODE; - dom->line_error = sd->line_num; - return false; /* There is some "real" text => raise an error */ - } - - if (dom->text_as_nodes) { - XMLNode* new_node = XMLNode_allocN(1); - if (new_node == NULL || (new_node->text = sx_strdup(text)) == NULL - || _add_node(&dom->current->children, &dom->current->n_children, new_node) < 0) { - dom->error = PARSE_ERR_MEMORY; - dom->line_error = sd->line_num; - (void)XMLNode_free(new_node); - __free(new_node); - return false; - } - new_node->tag_type = TAG_TEXT; - new_node->father = dom->current; - //dom->current->tag_type = TAG_FATHER; // OS: should parent field be forced to be TAG_FATHER? now it has at least one TAG_TEXT child. I decided not to enforce this to enforce backward-compatibility related to tag_types - return true; - } else { /* Old behaviour: concatenate text to the previous one */ - /* 'p' will point at the new text */ - if (dom->current->text == NULL) { - p = sx_strdup(text); - } else { - p = (SXML_CHAR*)__realloc(dom->current->text, (sx_strlen(dom->current->text) + sx_strlen(text) + 1)*sizeof(SXML_CHAR)); - if (p != NULL) - sx_strcat(p, text); - } - if (p == NULL) { - dom->error = PARSE_ERR_MEMORY; - dom->line_error = sd->line_num; - return false; - } - - dom->current->text = p; - } - - return true; -} - -int DOMXMLDoc_parse_error(ParseError error_num, int line_number, SAX_Data* sd) -{ - DOM_through_SAX* dom = (DOM_through_SAX*)sd->user; - - dom->error = error_num; - dom->line_error = line_number; - - /* Complete error message will be displayed in 'DOMXMLDoc_doc_end' callback */ - - return false; /* Stop on error */ -} - -int DOMXMLDoc_doc_end(SAX_Data* sd) -{ - DOM_through_SAX* dom = (DOM_through_SAX*)sd->user; - - if (dom->error != PARSE_ERR_NONE) { - SXML_CHAR* msg; - - switch (dom->error) { - case PARSE_ERR_MEMORY: msg = C2SX("MEMORY"); break; - case PARSE_ERR_UNEXPECTED_TAG_END: msg = C2SX("UNEXPECTED_TAG_END"); break; - case PARSE_ERR_SYNTAX: msg = C2SX("SYNTAX"); break; - case PARSE_ERR_EOF: msg = C2SX("UNEXPECTED_END_OF_FILE"); break; - case PARSE_ERR_TEXT_OUTSIDE_NODE: msg = C2SX("TEXT_OUTSIDE_NODE"); break; - case PARSE_ERR_UNEXPECTED_NODE_END: msg = C2SX("UNEXPECTED_NODE_END"); break; - default: msg = C2SX("UNKNOWN"); break; - } - sx_fprintf(stderr, C2SX("%s:%d: An error was found (%s), loading aborted...\n"), sd->name, dom->line_error, msg); - dom->current = NULL; - (void)XMLDoc_free(dom->doc); - dom->doc = NULL; - } - - return true; -} - -int SAX_Callbacks_init_DOM(SAX_Callbacks* sax) -{ - if (sax == NULL) - return false; - - sax->start_doc = DOMXMLDoc_doc_start; - sax->start_node = DOMXMLDoc_node_start; - sax->end_node = DOMXMLDoc_node_end; - sax->new_text = DOMXMLDoc_node_text; - sax->on_error = DOMXMLDoc_parse_error; - sax->end_doc = DOMXMLDoc_doc_end; - sax->all_event = NULL; - - return true; -} - -int XMLDoc_parse_file_SAX(const SXML_CHAR* filename, const SAX_Callbacks* sax, void* user) -{ - FILE* f; - int ret; - SAX_Data sd; - SXML_CHAR* fmode = -#ifndef SXMLC_UNICODE - C2SX("rt"); -#else - C2SX("rb"); /* In Unicode, open the file as binary so that further 'fgetwc' read all bytes */ - BOM_TYPE bom; -#endif - - - if (sax == NULL || filename == NULL || filename[0] == NULC) - return false; - - f = sx_fopen(filename, fmode); - if (f == NULL) - return false; - /* Microsoft' 'ftell' returns invalid position for Unicode text files - (see http://connect.microsoft.com/VisualStudio/feedback/details/369265/ftell-ftell-nolock-incorrectly-handling-unicode-text-translation) - However, we're opening the file as binary in Unicode so we don't fall into that case... - */ - #if defined(SXMLC_UNICODE) && (defined(WIN32) || defined(WIN64)) - //setvbuf(f, NULL, _IONBF, 0); - #endif - - sd.name = (SXML_CHAR*)filename; - sd.user = user; -#ifdef SXMLC_UNICODE - bom = freadBOM(f, NULL, NULL); /* Skip BOM, if any */ - /* In Unicode, re-open the file in text-mode if there is no BOM (or UTF-8) as we assume that - the file is "plain" text (i.e. 1 byte = 1 character). If opened in binary mode, 'fgetwc' - would read 2 bytes for 1 character, which would not work on "plain" files. */ - if (bom == BOM_NONE || bom == BOM_UTF_8) { - sx_fclose(f); - f = sx_fopen(filename, C2SX("rt")); - if (f == NULL) - return false; - if (bom == BOM_UTF_8) - freadBOM(f, NULL, NULL); /* Skip the UTF-8 BOM that was found */ - } -#endif - ret = _parse_data_SAX((void*)f, DATA_SOURCE_FILE, sax, &sd); - (void)sx_fclose(f); - - return ret; -} - -int XMLDoc_parse_buffer_SAX(const SXML_CHAR* buffer, const SXML_CHAR* name, const SAX_Callbacks* sax, void* user) -{ - DataSourceBuffer dsb = { buffer, 0 }; - SAX_Data sd; - - if (sax == NULL || buffer == NULL) - return false; - - sd.name = name; - sd.user = user; - return _parse_data_SAX((void*)&dsb, DATA_SOURCE_BUFFER, sax, &sd); -} - -int XMLDoc_parse_file_DOM_text_as_nodes(const SXML_CHAR* filename, XMLDoc* doc, int text_as_nodes) -{ - DOM_through_SAX dom; - SAX_Callbacks sax; - - if (doc == NULL || filename == NULL || filename[0] == NULC || doc->init_value != XML_INIT_DONE) - return false; - - sx_strncpy(doc->filename, filename, SXMLC_MAX_PATH - 1); - doc->filename[SXMLC_MAX_PATH - 1] = NULC; - - /* Read potential BOM on file, only when unicode is defined */ -#ifdef SXMLC_UNICODE - { - /* In Unicode, open the file as binary so that further 'fgetwc' read all bytes */ - FILE* f = sx_fopen(filename, C2SX("rb")); - if (f != NULL) { - #if defined(SXMLC_UNICODE) && (defined(WIN32) || defined(WIN64)) - //setvbuf(f, NULL, _IONBF, 0); - #endif - doc->bom_type = freadBOM(f, doc->bom, &doc->sz_bom); - sx_fclose(f); - } - } -#endif - - dom.doc = doc; - dom.current = NULL; - dom.text_as_nodes = text_as_nodes; - SAX_Callbacks_init_DOM(&sax); - - if (!XMLDoc_parse_file_SAX(filename, &sax, &dom)) { - (void)XMLDoc_free(doc); - dom.doc = NULL; - return false; - } - - return true; -} - -int XMLDoc_parse_buffer_DOM_text_as_nodes(const SXML_CHAR* buffer, const SXML_CHAR* name, XMLDoc* doc, int text_as_nodes) -{ - DOM_through_SAX dom; - SAX_Callbacks sax; - - if (doc == NULL || buffer == NULL || doc->init_value != XML_INIT_DONE) - return false; - - dom.doc = doc; - dom.current = NULL; - dom.text_as_nodes = text_as_nodes; - SAX_Callbacks_init_DOM(&sax); - - return XMLDoc_parse_buffer_SAX(buffer, name, &sax, &dom) ? true : XMLDoc_free(doc); -} - - - -/* --- Utility functions (ex sxmlutils.c) --- */ - -#ifdef DBG_MEM -static int nb_alloc = 0, nb_free = 0; - -void* __malloc(size_t sz) -{ - void* p = malloc(sz); - if (p != NULL) - nb_alloc++; - printf("0x%x: MALLOC (%d) - NA %d - NF %d = %d\n", p, sz, nb_alloc, nb_free, nb_alloc - nb_free); - return p; -} - -void* __calloc(size_t count, size_t sz) -{ - void* p = calloc(count, sz); - if (p != NULL) - nb_alloc++; - printf("0x%x: CALLOC (%d, %d) - NA %d - NF %d = %d\n", p, count, sz, nb_alloc, nb_free, nb_alloc - nb_free); - return p; -} - -void* __realloc(void* mem, size_t sz) -{ - void* p = realloc(mem, sz); - if (mem == NULL && p != NULL) - nb_alloc++; - else if (mem != NULL && sz == 0) - nb_free++; - printf("0x%x: REALLOC 0x%x (%d)", p, mem, sz); - if (mem == NULL) - printf(" - NA %d - NF %d = %d", nb_alloc, nb_free, nb_alloc - nb_free); - printf("\n"); - return p; -} - -void __free(void* mem) -{ - nb_free++; - printf("0x%x: FREE - NA %d - NF %d = %d\n", mem, nb_alloc, nb_free, nb_alloc - nb_free); - free(mem); -} - -char* __sx_strdup(const char* s) -{ -/* Mimic the behavior of sx_strdup(), as we can't use it directly here: DBG_MEM is defined - and sx_strdup is this function! (bug #5) */ -#ifdef SXMLC_UNICODE - char* p = wcsdup(s); -#else - char* p = strdup(s); -#endif - if (p != NULL) - nb_alloc++; - printf("0x%x: STRDUP (%d) - NA %d - NF %d = %d\n", p, sx_strlen(s), nb_alloc, nb_free, nb_alloc - nb_free); - return p; -} -#endif - -/* Dictionary of special characters and their HTML equivalent */ -static struct _html_special_dict { - SXML_CHAR chr; /* Original character */ - SXML_CHAR* html; /* Equivalent HTML string */ - int html_len; /* 'sx_strlen(html)' */ -} HTML_SPECIAL_DICT[] = { - { C2SX('<'), C2SX("<"), 4 }, - { C2SX('>'), C2SX(">"), 4 }, - { C2SX('"'), C2SX("""), 6 }, - { C2SX('\''), C2SX("'"), 6 }, - { C2SX('&'), C2SX("&"), 5 }, - { NULC, NULL, 0 }, /* Terminator */ -}; - -int _bgetc(DataSourceBuffer* ds) -{ - if (ds == NULL || ds->buf[ds->cur_pos] == NULC) - return EOF; - - return (int)(ds->buf[ds->cur_pos++]); -} - -int _beob(DataSourceBuffer* ds) -{ - - if (ds == NULL || ds->buf[ds->cur_pos] == NULC) - return true; - - return false; -} - -int read_line_alloc(void* in, DataSourceType in_type, SXML_CHAR** line, int* sz_line, int i0, SXML_CHAR from, SXML_CHAR to, int keep_fromto, SXML_CHAR interest, int* interest_count) -{ - int init_sz = 0; - SXML_CHAR ch, *pt; - int c; - int n, ret; - int (*mgetc)(void* ds) = (in_type == DATA_SOURCE_BUFFER ? (int(*)(void*))_bgetc : (int(*)(void*))sx_fgetc); - int (*meos)(void* ds) = (in_type == DATA_SOURCE_BUFFER ? (int(*)(void*))_beob : (int(*)(void*))sx_feof); - - if (in == NULL || line == NULL) - return 0; - - if (to == NULC) - to = C2SX('\n'); - /* Search for character 'from' */ - if (interest_count != NULL) - *interest_count = 0; - while (true) { - /* Reaching EOF before 'to' char is not an error but should trigger 'line' alloc and init to '' */ - c = mgetc(in); - ch = (SXML_CHAR)c; - if (c == EOF) - break; - if (interest_count != NULL && ch == interest) - (*interest_count)++; - /* If 'from' is '\0', we stop here */ - if (ch == from || from == NULC) - break; - } - - if (sz_line == NULL) - sz_line = &init_sz; - - if (*line == NULL || *sz_line == 0) { - if (*sz_line == 0) *sz_line = MEM_INCR_RLA; - *line = (SXML_CHAR*)__malloc(*sz_line*sizeof(SXML_CHAR)); - if (*line == NULL) - return 0; - } - if (i0 < 0) - i0 = 0; - if (i0 > *sz_line) - return 0; - - n = i0; - if (c == CEOF) { /* EOF reached before 'to' char => return the empty string */ - (*line)[n] = NULC; - return meos(in) ? n : 0; /* Error if not EOF */ - } - if (ch != from || keep_fromto) - (*line)[n++] = ch; - (*line)[n] = NULC; - ret = 0; - while (true) { - if ((c = mgetc(in)) == CEOF) { /* EOF or error */ - (*line)[n] = NULC; - ret = meos(in) ? n : 0; - break; - } - ch = (SXML_CHAR)c; - if (interest_count != NULL && ch == interest) - (*interest_count)++; - (*line)[n] = ch; - if (ch != to || (keep_fromto && to != NULC && ch == to)) /* If we reached the 'to' character and we keep it, we still need to add the extra '\0' */ - n++; - if (n >= *sz_line) { /* Too many characters for our line => realloc some more */ - *sz_line += MEM_INCR_RLA; - pt = (SXML_CHAR*)__realloc(*line, *sz_line*sizeof(SXML_CHAR)); - if (pt == NULL) { - ret = 0; - break; - } else - *line = pt; - } - (*line)[n] = NULC; /* If we reached the 'to' character and we want to strip it, 'n' hasn't changed and 'line[n]' (which is 'to') will be replaced by '\0' */ - if (ch == to) { - ret = n; - break; - } - } - -#if 0 /* Automatic buffer resize is deactivated */ - /* Resize line to the exact size */ - pt = (SXML_CHAR*)__realloc(*line, (n+1)*sizeof(SXML_CHAR)); - if (pt != NULL) - *line = pt; -#endif - - return ret; -} - -/* --- */ - -SXML_CHAR* strcat_alloc(SXML_CHAR** src1, const SXML_CHAR* src2) -{ - SXML_CHAR* cat; - int n; - - /* Do not concatenate '*src1' with itself */ - if (src1 == NULL || *src1 == src2) - return NULL; - - /* Concatenate a NULL or empty string */ - if (src2 == NULL || *src2 == NULC) - return *src1; - - n = (*src1 == NULL ? 0 : sx_strlen(*src1)) + sx_strlen(src2) + 1; - cat = (SXML_CHAR*)__realloc(*src1, n*sizeof(SXML_CHAR)); - if (cat == NULL) - return NULL; - if (*src1 == NULL) - *cat = NULC; - *src1 = cat; - sx_strcat(*src1, src2); - - return *src1; -} - -SXML_CHAR* strip_spaces(SXML_CHAR* str, SXML_CHAR repl_sq) -{ - SXML_CHAR* p; - int i, len; - - /* 'p' to the first non-space */ - for (p = str; *p != NULC && sx_isspace(*p); p++) ; /* No need to search for 'protect' as it is not a space */ - len = sx_strlen(str); - for (i = len-1; sx_isspace(str[i]); i--) ; - if (str[i] == C2SX('\\')) /* If last non-space is the protection, keep the last space */ - i++; - str[i+1] = NULC; /* New end of string to last non-space */ - - if (repl_sq == NULC) { - if (p == str && i == len) - return str; /* Nothing to do */ - for (i = 0; (str[i] = *p) != NULC; i++, p++) ; /* Copy 'p' to 'str' */ - return str; - } - - /* Squeeze all spaces with 'repl_sq' */ - i = 0; - while (*p != NULC) { - if (sx_isspace(*p)) { - str[i++] = repl_sq; - while (sx_isspace(*++p)) ; /* Skips all next spaces */ - } else { - if (*p == C2SX('\\')) - p++; - str[i++] = *p++; - } - } - str[i] = NULC; - - return str; -} - -SXML_CHAR* str_unescape(SXML_CHAR* str) -{ - int i, j; - - if (str == NULL) - return NULL; - - for (i = j = 0; str[j]; j++) { - if (str[j] == C2SX('\\')) - j++; - str[i++] = str[j]; - } - - return str; -} - -int split_left_right(SXML_CHAR* str, SXML_CHAR sep, int* l0, int* l1, int* i_sep, int* r0, int* r1, int ignore_spaces, int ignore_quotes) -{ - int n0, n1, is; - SXML_CHAR quote = '\0'; - - if (str == NULL) - return false; - - if (i_sep != NULL) - *i_sep = -1; - - if (!ignore_spaces) /* No sense of ignore quotes if spaces are to be kept */ - ignore_quotes = false; - - /* Parse left part */ - - if (ignore_spaces) { - for (n0 = 0; str[n0] != NULC && sx_isspace(str[n0]); n0++) ; /* Skip head spaces, n0 points to first non-space */ - if (ignore_quotes && isquote(str[n0])) { /* If quote is found, look for next one */ - quote = str[n0++]; /* Quote can be '\'' or '"' */ - for (n1 = n0; str[n1] != NULC && str[n1] != quote; n1++) { - if (str[n1] == C2SX('\\') && str[++n1] == NULC) - break; /* Escape character (can be the last) */ - } - for (is = n1 + 1; str[is] != NULC && sx_isspace(str[is]); is++) ; /* '--' not to take quote into account */ - } else { - for (n1 = n0; str[n1] != NULC && str[n1] != sep && !sx_isspace(str[n1]); n1++) ; /* Search for separator or a space */ - for (is = n1; str[is] != NULC && sx_isspace(str[is]); is++) ; - } - } else { - n0 = 0; - for (n1 = 0; str[n1] != NULC && str[n1] != sep; n1++) ; /* Search for separator only */ - if (str[n1] != sep) /* Separator not found: malformed string */ - return false; - is = n1; - } - - /* Here 'n0' is the start of left member, 'n1' is the character after the end of left member */ - - if (l0 != NULL) - *l0 = n0; - if (l1 != NULL) - *l1 = n1 - 1; - if (i_sep != NULL) - *i_sep = is; - if (str[is] == NULC || str[is+1] == NULC) { /* No separator => empty right member */ - if (r0 != NULL) - *r0 = is; - if (r1 != NULL) - *r1 = is-1; - if (i_sep != NULL) - *i_sep = (str[is] == NULC ? -1 : is); - return true; - } - - /* Parse right part */ - - n0 = is + 1; - if (ignore_spaces) { - for (; str[n0] != NULC && sx_isspace(str[n0]); n0++) ; - if (ignore_quotes && isquote(str[n0])) - quote = str[n0]; - } - - for (n1 = ++n0; str[n1]; n1++) { - if (ignore_quotes && str[n1] == quote) /* Quote was reached */ - break; - if (str[n1] == C2SX('\\') && str[++n1] == NULC) /* Escape character (can be the last) */ - break; - } - if (ignore_quotes && str[n1--] != quote) /* Quote is not the same than earlier, '--' is not to take it into account */ - return false; - if (!ignore_spaces) - while (str[++n1]) ; /* Jump down the end of the string */ - - if (r0 != NULL) - *r0 = n0; - if (r1 != NULL) - *r1 = n1; - - return true; -} - -BOM_TYPE freadBOM(FILE* f, unsigned char* bom, int* sz_bom) -{ - unsigned char c1, c2; - long pos; - - if (f == NULL) - return BOM_NONE; - - /* Save position and try to read and skip BOM if found. If not, go back to save position. */ - pos = ftell(f); - if (pos < 0) - return BOM_NONE; - if (fread(&c1, sizeof(char), 1, f) != 1 || fread(&c2, sizeof(char), 1, f) != 1) { - fseek(f, pos, SEEK_SET); - return BOM_NONE; - } - if (bom != NULL) { - bom[0] = c1; - bom[1] = c2; - bom[2] = '\0'; - if (sz_bom != NULL) - *sz_bom = 2; - } - switch ((unsigned short)(c1 << 8) | c2) { - case (unsigned short)0xfeff: - return BOM_UTF_16BE; - - case (unsigned short)0xfffe: - pos = ftell(f); /* Save current position to get it back if BOM is not UTF-32LE */ - if (pos < 0) - return BOM_UTF_16LE; - if (fread(&c1, sizeof(char), 1, f) != 1 || fread(&c2, sizeof(char), 1, f) != 1) { - fseek(f, pos, SEEK_SET); - return BOM_UTF_16LE; - } - if (c1 == 0x00 && c2 == 0x00) { - if (bom != NULL) - bom[2] = bom[3] = bom[4] = '\0'; - if (sz_bom != NULL) - *sz_bom = 4; - return BOM_UTF_32LE; - } - fseek(f, pos, SEEK_SET); /* fseek(f, -2, SEEK_CUR) is not garanteed on Windows (and actually fail in Unicode...) */ - return BOM_UTF_16LE; - - case (unsigned short)0x0000: - if (fread(&c1, sizeof(char), 1, f) == 1 && fread(&c2, sizeof(char), 1, f) == 1 - && c1 == 0xfe && c2 == 0xff) { - bom[2] = c1; - bom[3] = c2; - bom[4] = '\0'; - if (sz_bom != NULL) - *sz_bom = 4; - return BOM_UTF_32BE; - } - fseek(f, pos, SEEK_SET); - return BOM_NONE; - - case (unsigned short)0xefbb: /* UTF-8? */ - if (fread(&c1, sizeof(char), 1, f) != 1 || c1 != 0xbf) { /* Not UTF-8 */ - fseek(f, pos, SEEK_SET); - if (bom != NULL) - bom[0] = '\0'; - if (sz_bom != NULL) - *sz_bom = 0; - return BOM_NONE; - } - if (bom != NULL) { - bom[2] = c1; - bom[3] = '\0'; - } - if (sz_bom != NULL) - *sz_bom = 3; - return BOM_UTF_8; - - default: /* No BOM, go back */ - fseek(f, pos, SEEK_SET); - if (bom != NULL) - bom[0] = '\0'; - if (sz_bom != NULL) - *sz_bom = 0; - return BOM_NONE; - } -} - -/* --- */ - -SXML_CHAR* html2str(SXML_CHAR* html, SXML_CHAR* str) -{ - SXML_CHAR *ps, *pd; - int i; - - if (html == NULL) return NULL; - - if (str == NULL) str = html; - - /* Look for '&' and matches it to any of the recognized HTML pattern. */ - /* If found, replaces the '&' by the corresponding char. */ - /* 'p2' is the char to analyze, 'p1' is where to insert it */ - for (pd = str, ps = html; *ps; ps++, pd++) { - if (*ps != C2SX('&')) { - if (pd != ps) - *pd = *ps; - continue; - } - - for (i = 0; HTML_SPECIAL_DICT[i].chr; i++) { - if (sx_strncmp(ps, HTML_SPECIAL_DICT[i].html, HTML_SPECIAL_DICT[i].html_len)) - continue; - - *pd = HTML_SPECIAL_DICT[i].chr; - ps += HTML_SPECIAL_DICT[i].html_len-1; - break; - } - /* If no string was found, simply copy the character */ - if (HTML_SPECIAL_DICT[i].chr == NULC && pd != ps) - *pd = *ps; - } - *pd = NULC; - - return str; -} - -/* TODO: Allocate 'html'? */ -SXML_CHAR* str2html(SXML_CHAR* str, SXML_CHAR* html) -{ - SXML_CHAR *ps, *pd; - int i; - - if (str == NULL) - return NULL; - - if (html == str) /* Not handled (yet) */ - return NULL; - - if (html == NULL) { /* Allocate 'html' to the correct size */ - html = __malloc(strlen_html(str) * sizeof(SXML_CHAR)); - if (html == NULL) - return NULL; - } - - for (ps = str, pd = html; *ps; ps++, pd++) { - for (i = 0; HTML_SPECIAL_DICT[i].chr; i++) { - if (*ps == HTML_SPECIAL_DICT[i].chr) { - sx_strcpy(pd, HTML_SPECIAL_DICT[i].html); - pd += HTML_SPECIAL_DICT[i].html_len - 1; - break; - } - } - if (HTML_SPECIAL_DICT[i].chr == NULC && pd != ps) - *pd = *ps; - } - *pd = NULC; - - return html; -} - -int strlen_html(SXML_CHAR* str) -{ - int i, j, n; - - if (str == NULL) - return 0; - - n = 0; - for (i = 0; str[i] != NULC; i++) { - for (j = 0; HTML_SPECIAL_DICT[j].chr; j++) { - if (str[i] == HTML_SPECIAL_DICT[j].chr) { - n += HTML_SPECIAL_DICT[j].html_len; - break; - } - } - if (HTML_SPECIAL_DICT[j].chr == NULC) - n++; - } - - return n; -} - -int fprintHTML(FILE* f, SXML_CHAR* str) -{ - SXML_CHAR* p; - int i, n; - - for (p = str, n = 0; *p != NULC; p++) { - for (i = 0; HTML_SPECIAL_DICT[i].chr; i++) { - if (*p != HTML_SPECIAL_DICT[i].chr) - continue; - sx_fprintf(f, HTML_SPECIAL_DICT[i].html); - n += HTML_SPECIAL_DICT[i].html_len; - break; - } - if (HTML_SPECIAL_DICT[i].chr == NULC) { - (void)sx_fputc(*p, f); - n++; - } - } - - return n; -} - -int regstrcmp(SXML_CHAR* str, SXML_CHAR* pattern) -{ - SXML_CHAR *p, *s; - - if (str == NULL && pattern == NULL) - return true; - - if (str == NULL || pattern == NULL) - return false; - - p = pattern; - s = str; - while (true) { - switch (*p) { - /* Any character matches, go to next one */ - case C2SX('?'): - p++; - s++; - break; - - /* Go to next character in pattern and wait until it is found in 'str' */ - case C2SX('*'): - for (; *p != NULC; p++) { /* Squeeze '**?*??**' to '*' */ - if (*p != C2SX('*') && *p != C2SX('?')) - break; - } - for (; *s != NULC; s++) { - if (*s == *p) - break; - } - break; - - /* NULL character on pattern has to be matched by 'str' */ - case 0: - return *s ? false : true; - - default: - if (*p == C2SX('\\')) /* Escape character */ - p++; - if (*p++ != *s++) /* Characters do not match */ - return false; - break; - } - } - - return false; -} diff --git a/client/sxmlc/sxmlc.h b/client/sxmlc/sxmlc.h deleted file mode 100755 index 91aef71..0000000 --- a/client/sxmlc/sxmlc.h +++ /dev/null @@ -1,829 +0,0 @@ -/* - Copyright (c) 2010, Matthieu Labas - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - OF SUCH DAMAGE. - - The views and conclusions contained in the software and documentation are those of the - authors and should not be interpreted as representing official policies, either expressed - or implied, of the FreeBSD Project. -*/ -#ifndef _SXML_H_ -#define _SXML_H_ - -#define SXMLC_VERSION "4.2.7" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdio.h> - -#ifdef SXMLC_UNICODE - typedef wchar_t SXML_CHAR; - #define C2SX(c) L ## c - #define CEOF WEOF - #define sx_strcmp wcscmp - #define sx_strncmp wcsncmp - #define sx_strlen wcslen - #define sx_strdup wcsdup - #define sx_strchr wcschr - #define sx_strrchr wcsrchr - #define sx_strcpy wcscpy - #define sx_strncpy wcsncpy - #define sx_strcat wcscat - #define sx_printf wprintf - #define sx_fprintf fwprintf - #define sx_sprintf swprintf - #define sx_fgetc fgetwc - #define sx_fputc fputwc - #define sx_isspace iswspace - #if defined(WIN32) || defined(WIN64) - #define sx_fopen _wfopen - #else - #define sx_fopen fopen - #endif - #define sx_fclose fclose - #define sx_feof feof -#else - typedef char SXML_CHAR; - #define C2SX(c) c - #define CEOF EOF - #define sx_strcmp strcmp - #define sx_strncmp strncmp - #define sx_strlen strlen - #define sx_strdup __sx_strdup - #define sx_strchr strchr - #define sx_strrchr strrchr - #define sx_strcpy strcpy - #define sx_strncpy strncpy - #define sx_strcat strcat - #define sx_printf printf - #define sx_fprintf fprintf - #define sx_sprintf sprintf - #define sx_fgetc fgetc - #define sx_fputc fputc - #define sx_isspace(ch) isspace((int)ch) - #define sx_fopen fopen - #define sx_fclose fclose - #define sx_feof feof -#endif - -#ifdef DBG_MEM - void* __malloc(size_t sz); - void* __calloc(size_t count, size_t sz); - void* __realloc(void* mem, size_t sz); - void __free(void* mem); - char* __sx_strdup(const char* s); -#else - #define __malloc malloc - #define __calloc calloc - #define __realloc realloc - #define __free free - #define __sx_strdup strdup -#endif - -#ifndef MEM_INCR_RLA -#define MEM_INCR_RLA (256*sizeof(SXML_CHAR)) /* Initial buffer size and increment for memory reallocations */ -#endif - -#ifndef false -#define false 0 -#endif - -#ifndef true -#define true 1 -#endif - -#define NULC ((SXML_CHAR)C2SX('\0')) -#define isquote(c) (((c) == C2SX('"')) || ((c) == C2SX('\''))) - -/* - Buffer data source used by 'read_line_alloc' when required. - 'buf' should be 0-terminated. - */ -typedef struct _DataSourceBuffer { - const SXML_CHAR* buf; - int cur_pos; -} DataSourceBuffer; - -typedef FILE* DataSourceFile; - -typedef enum _DataSourceType { - DATA_SOURCE_FILE = 0, - DATA_SOURCE_BUFFER, - DATA_SOURCE_MAX -} DataSourceType; - -#ifndef false -#define false 0 -#endif - -#ifndef true -#define true 1 -#endif - -/* Node types */ -typedef enum _TagType { - TAG_ERROR = -1, - TAG_NONE = 0, - TAG_PARTIAL, /* Node containing a legal '>' that stopped file reading */ - TAG_FATHER, /* <tag> - Next nodes will be children of this one. */ - TAG_SELF, /* <tag/> - Standalone node. */ - TAG_INSTR, /* <?prolog?> - Processing instructions, or prolog node. */ - TAG_COMMENT, /* <!--comment--> */ - TAG_CDATA, /* <![CDATA[ ]]> - CDATA node */ - TAG_DOCTYPE, /* <!DOCTYPE [ ]> - DOCTYPE node */ - TAG_END, /* </tag> - End of father node. */ - TAG_TEXT, /* text node*/ - - TAG_USER = 100 /* User-defined tag start */ -} TagType; - -/* TODO: Performance improvement with some fixed-sized strings ??? (e.g. XMLAttribute.name[64], XMLNode.tag[64]) */ - -typedef struct _XMLAttribute { - SXML_CHAR* name; - SXML_CHAR* value; - int active; -} XMLAttribute; - -/* Constant to know whether a struct has been initialized (XMLNode or XMLDoc) */ -#define XML_INIT_DONE 0x19770522 /* Happy Birthday ;) */ - -/* - An XML node. - */ -typedef struct _XMLNode { - SXML_CHAR* tag; /* Tag name */ - SXML_CHAR* text; /* Text inside the node */ - XMLAttribute* attributes; - int n_attributes; - - struct _XMLNode* father; /* NULL if root */ - struct _XMLNode** children; - int n_children; - - TagType tag_type; /* Node type ('TAG_FATHER', 'TAG_SELF' or 'TAG_END') */ - int active; /* 'true' to tell that node is active and should be displayed by 'XMLDoc_print' */ - - void* user; /* Pointer for user data associated to the node */ - - /* Keep 'init_value' as the last member */ - int init_value; /* Initialized to 'XML_INIT_DONE' to indicate that node has been initialized properly */ -} XMLNode; - -/* - An XML document. - */ -#ifndef SXMLC_MAX_PATH -#define SXMLC_MAX_PATH 256 -#endif -typedef struct _XMLDoc { - SXML_CHAR filename[SXMLC_MAX_PATH]; -#ifdef SXMLC_UNICODE - BOM_TYPE bom_type; - unsigned char bom[5]; /* First characters read that might be a BOM when unicode is used */ - int sz_bom; /* Number of bytes in BOM */ -#endif - XMLNode** nodes; /* Nodes of the document, including prolog, comments and root nodes */ - int n_nodes; /* Number of nodes in 'nodes' */ - int i_root; /* Index of first root node in 'nodes', -1 if document is empty */ - - /* Keep 'init_value' as the last member */ - int init_value; /* Initialized to 'XML_INIT_DONE' to indicate that document has been initialized properly */ -} XMLDoc; - -/* - Register an XML tag, giving its 'start' and 'end' string, which should include '<' and '>'. - The 'tag_type' is user-given and has to be less than or equal to 'TAG_USER'. It will be - returned as the 'tag_type' member of the XMLNode struct. Note that no test is performed - to check for an already-existing tag_type. - Return tag index in user tags table when successful, or '-1' if the 'tag_type' is invalid or - the new tag could not be registered (e.g. when 'start' does not start with '<' or 'end' does not end with '>'). - */ -int XML_register_user_tag(TagType tag_type, SXML_CHAR* start, SXML_CHAR* end); - -/* - Remove a registered user tag. - Return the new number of registered user tags or '-1' if 'i_tag' is invalid. - */ -int XML_unregister_user_tag(int i_tag); - -/* - Return the number of registered tags. - */ -int XML_get_nb_registered_user_tags(void); - -/* - Return the index of first occurrence of 'tag_type' in registered user tags, or '-1' if not found. - */ -int XML_get_registered_user_tag(TagType tag_type); - - -typedef enum _ParseError { - PARSE_ERR_NONE = 0, - PARSE_ERR_MEMORY = -1, - PARSE_ERR_UNEXPECTED_TAG_END = -2, - PARSE_ERR_SYNTAX = -3, - PARSE_ERR_EOF = -4, - PARSE_ERR_TEXT_OUTSIDE_NODE = -5, /* During DOM loading */ - PARSE_ERR_UNEXPECTED_NODE_END = -6 /* During DOM loading */ -} ParseError; - -/* - Events that can happen when loading an XML document. - These will be passed to the 'all_event' callback of the SAX parser. - */ -typedef enum _XMLEvent { - XML_EVENT_START_DOC, - XML_EVENT_START_NODE, - XML_EVENT_END_NODE, - XML_EVENT_TEXT, - XML_EVENT_ERROR, - XML_EVENT_END_DOC -} XMLEvent; - -/* - Structure given as an argument for SAX callbacks to retrieve information about - parsing status - */ -typedef struct _SAX_Data { - const SXML_CHAR* name; - int line_num; - void* user; -} SAX_Data; - -/* - User callbacks used for SAX parsing. Return values of these callbacks should be 0 to stop parsing. - Members can be set to NULL to disable handling of some events. - All parameters are pointers to structures that will no longer be available after callback returns. - It is recommended that the callback uses the information and stores it in its own data structure. - WARNING! SAX PARSING DOES NOT CHECK FOR XML INTEGRITY! e.g. a tag end without a matching tag start - will not be detected by the parser and should be detected by the callbacks instead. - */ -typedef struct _SAX_Callbacks { - /* - Callback called when parsing starts, before parsing the first node. - */ - int (*start_doc)(SAX_Data* sd); - - /* - Callback called when a new node starts (e.g. '<tag>' or '<tag/>'). - If any, attributes can be read from 'node->attributes'. - N.B. '<tag/>' will trigger an immediate call to the 'end_node' callback - after the 'start_node' callback. - */ - int (*start_node)(const XMLNode* node, SAX_Data* sd); - - /* - Callback called when a node ends (e.g. '</tag>' or '<tag/>'). - */ - int (*end_node)(const XMLNode* node, SAX_Data* sd); - - /* - Callback called when text has been found in the last node. - */ - int (*new_text)(SXML_CHAR* text, SAX_Data* sd); - - /* - Callback called when parsing is finished. - No other callbacks will be called after it. - */ - int (*end_doc)(SAX_Data* sd); - - /* - Callback called when an error occurs during parsing. - 'error_num' is the error number and 'line_number' is the line number in the stream - being read (file or buffer). - */ - int (*on_error)(ParseError error_num, int line_number, SAX_Data* sd); - - /* - Callback called when text has been found in the last node. - 'event' is the type of event for which the callback was called: - XML_EVENT_START_DOC: - 'node' is NULL. - 'text' is the file name if a file is being parsed, NULL if a buffer is being parsed. - 'n' is 0. - XML_EVENT_START_NODE: - 'node' is the node starting, with tag and all attributes initialized. - 'text' is NULL. - 'n' is the number of lines parsed. - XML_EVENT_END_NODE: - 'node' is the node ending, with tag, attributes and text initialized. - 'text' is NULL. - 'n' is the number of lines parsed. - XML_EVENT_TEXT: - 'node' is NULL. - 'text' is the text to be added to last node started and not finished. - 'n' is the number of lines parsed. - XML_EVENT_ERROR: - Everything is NULL. - 'n' is one of the 'PARSE_ERR_*'. - XML_EVENT_END_DOC: - 'node' is NULL. - 'text' is the file name if a file is being parsed, NULL if a buffer is being parsed. - 'n' is the number of lines parsed. - */ - int (*all_event)(XMLEvent event, const XMLNode* node, SXML_CHAR* text, const int n, SAX_Data* sd); -} SAX_Callbacks; - -/* - Helper function to initialize all 'sax' members to NULL. - Return 'false' is 'sax' is NULL. - */ -int SAX_Callbacks_init(SAX_Callbacks* sax); - -/* - Set of SAX callbacks used by 'XMLDoc_parse_file_DOM'. - These are made available to be able to load an XML document using DOM implementation - with user-defined code at some point (e.g. counting nodes, running search, ...). - In this case, the 'XMLDoc_parse_file_SAX' has to be called instead of the 'XMLDoc_parse_file_DOM', - providing either these callbacks directly, or a functions calling these callbacks. - To do that, you should initialize the 'doc' member of the 'DOM_through_SAX' struct and call the - 'XMLDoc_parse_file_SAX' giving this struct as a the 'user' data pointer. - */ - -typedef struct _DOM_through_SAX { - XMLDoc* doc; /* Document to fill up */ - XMLNode* current; /* For internal use (current father node) */ - ParseError error; /* For internal use (parse status) */ - int line_error; /* For internal use (line number when error occurred) */ - int text_as_nodes; /* For internal use (store text inside nodes as sequential TAG_TEXT nodes) */ -} DOM_through_SAX; - -int DOMXMLDoc_doc_start(SAX_Data* dom); -int DOMXMLDoc_node_start(const XMLNode* node, SAX_Data* dom); -int DOMXMLDoc_node_text(SXML_CHAR* text, SAX_Data* dom); -int DOMXMLDoc_node_end(const XMLNode* node, SAX_Data* dom); -int DOMXMLDoc_parse_error(ParseError error_num, int line_number, SAX_Data* sd); -int DOMXMLDoc_doc_end(SAX_Data* dom); - -/* - Initialize 'sax' with the "official" DOM callbacks. - */ -int SAX_Callbacks_init_DOM(SAX_Callbacks* sax); - -/* --- XMLNode methods --- */ - -/* - Fills 'xmlattr' with 'xmlattr->name' to 'attrName' and 'xmlattr->value' to 'attr Value'. - 'str' is supposed to be like 'attrName[ ]=[ ]["]attr Value["]'. - Return 0 if not enough memory or bad parameters (NULL 'str' or 'xmlattr'). - 2 if last quote is missing in the attribute value. - 1 if 'xmlattr' was filled correctly. - */ -int XML_parse_attribute_to(const SXML_CHAR* str, int to, XMLAttribute* xmlattr); - -#define XML_parse_attribute(str, xmlattr) XML_parse_attribute_to(str, -1, xmlattr) - -/* - Reads a string that is supposed to be an xml tag like '<tag (attribName="attribValue")* [/]>' or '</tag>'. - Fills the 'xmlnode' structure with the tag name and its attributes. - Returns 0 if an error occurred (malformed 'str' or memory). 'TAG_*' when string is recognized. - */ -TagType XML_parse_1string(const SXML_CHAR* str, XMLNode* xmlnode); - -/* - Allocate and initialize XML nodes. - 'n' is the number of contiguous elements to allocate (to create and array). - Return 'NULL' if not enough memory, or the pointer to the elements otherwise. - */ -XMLNode* XMLNode_allocN(int n); - -/* - Shortcut to allocate one node only. - */ -#define XMLNode_alloc() XMLNode_allocN(1) - -/* - Initialize an already-allocated XMLNode. - */ -int XMLNode_init(XMLNode* node); - -/* - Free a node and all its children. - */ -int XMLNode_free(XMLNode* node); - -/* - Free XMLNode 'dst' and copy 'src' to 'dst', along with its children if specified. - If 'src' is NULL, 'dst' is freed and initialized. - */ -int XMLNode_copy(XMLNode* dst, const XMLNode* src, int copy_children); - -/* - Allocate a node and copy 'node' into it. - If 'copy_children' is 'true', all children of 'node' will be copied to the new node. - Return 'NULL' if not enough memory, or a pointer to the new node otherwise. - */ -XMLNode* XMLNode_dup(const XMLNode* node, int copy_children); - -/* - Set the active/inactive state of 'node'. - Set 'active' to 'true' to activate 'node' and all its children, and enable its use - in other functions (e.g. 'XMLDoc_print', 'XMLNode_search_child'). - */ -int XMLNode_set_active(XMLNode* node, int active); - -/* - Set 'node' tag. - Return 'false' for memory error, 'true' otherwise. - */ -int XMLNode_set_tag(XMLNode* node, const SXML_CHAR* tag); - -/* - Set the node type among one of the valid ones (TAG_FATHER, TAG_SELF, TAG_INSTR, - TAG_COMMENT, TAG_CDATA, TAG_DOCTYPE) or any user-registered tag. - Return 'false' when the node or the 'tag_type' is invalid. - */ -int XMLNode_set_type(XMLNode* node, const TagType tag_type); - -/* - Add an attribute to 'node' or update an existing one. - The attribute has a 'name' and a 'value'. - Return the new number of attributes, or -1 for memory problem. - */ -int XMLNode_set_attribute(XMLNode* node, const SXML_CHAR* attr_name, const SXML_CHAR* attr_value); - -/* - Retrieve an attribute value, based on its name, allocating 'attr_value'. - If the attribute name does not exist, set 'attr_value' to the given default value. - Return 'false' when the node is invalid, 'attr_name' is NULL or empty, or 'attr_value' is NULL. - */ -int XMLNode_get_attribute_with_default(XMLNode* node, const SXML_CHAR* attr_name, const SXML_CHAR** attr_value, const SXML_CHAR* default_attr_value); - -/* - Helper macro that retrieve an attribute value, or an empty string if the attribute does - not exist. - */ -#define XMLNode_get_attribute(node, attr_name, attr_value) XMLNode_get_attribute_with_default(node, attr_name, attr_value, C2SX("")) - -/* - Return the number of active attributes of 'node', or '-1' if 'node' is invalid. -*/ -int XMLNode_get_attribute_count(const XMLNode* node); - -/* - Search for the active attribute 'attr_name' in 'node', starting from index 'isearch' - and returns its index, or -1 if not found or error. - */ -int XMLNode_search_attribute(const XMLNode* node, const SXML_CHAR* attr_name, int isearch); - -/* - Remove attribute index 'i_attr'. - Return the new number of attributes or -1 on invalid arguments. - */ -int XMLNode_remove_attribute(XMLNode* node, int i_attr); - -/* - Remove all attributes from 'node'. - */ -int XMLNode_remove_all_attributes(XMLNode* node); - -/* - Set node text. - Return 'true' when successful, 'false' on error. - */ -int XMLNode_set_text(XMLNode* node, const SXML_CHAR* text); - -/* - Helper macro to remove text from 'node'. - */ -#define XMLNode_remove_text(node) XMLNode_set_text(node, NULL); - -/* - Add a child to a node. - Return 'false' for memory problem, 'true' otherwise. - */ -int XMLNode_add_child(XMLNode* node, XMLNode* child); - -/* - Return the number of active children nodes of 'node', or '-1' if 'node' is invalid. - */ -int XMLNode_get_children_count(const XMLNode* node); - -/* - Return a reference to the 'i_child'th active node. - */ -XMLNode* XMLNode_get_child(const XMLNode* node, int i_child); - -/* - Remove the 'i_child'th active child of 'node'. - If 'free_child' is 'true', free the child node itself. This parameter is usually 'true' - but should be 'false' when child nodes are pointers to local or global variables instead of - user-allocated memory. - Return the new number of children or -1 on invalid arguments. - */ -int XMLNode_remove_child(XMLNode* node, int i_child, int free_child); - -/* - Remove all children from 'node'. - */ -int XMLNode_remove_children(XMLNode* node); - -/* - Return 'true' if 'node1' is the same as 'node2' (i.e. same tag, same active attributes). - */ -int XMLNode_equal(const XMLNode* node1, const XMLNode* node2); - -/* - Return the next sibling of node 'node', or NULL if 'node' is invalid or the last child - or if its father could not be determined (i.e. 'node' is a root node). - */ -XMLNode* XMLNode_next_sibling(const XMLNode* node); - -/* - Return the next node in XML order i.e. first child or next sibling, or NULL - if 'node' is invalid or the end of its root node is reached. - */ -XMLNode* XMLNode_next(const XMLNode* node); - - -/* --- XMLDoc methods --- */ - - -/* - Initializes an already-allocated XML document. - */ -int XMLDoc_init(XMLDoc* doc); - -/* - Free an XML document. - Return 'false' if 'doc' was not initialized. - */ -int XMLDoc_free(XMLDoc* doc); - -/* - Set the new 'doc' root node among all existing nodes in 'doc'. - Return 'false' if bad arguments, 'true' otherwise. - */ -int XMLDoc_set_root(XMLDoc* doc, int i_root); - -/* - Add a node to the document, specifying the type. - If its type is TAG_FATHER, it also sets the document root node if previously undefined. - Return the node index, or -1 if bad arguments or memory error. - */ -int XMLDoc_add_node(XMLDoc* doc, XMLNode* node); - -/* - Remove a node from 'doc' root nodes, base on its index. - If 'free_node' is 'true', free the node itself. This parameter is usually 'true' - but should be 'false' when the node is a pointer to local or global variable instead of - user-allocated memory. - Return 'true' if node was removed or 'false' if 'doc' or 'i_node' is invalid. - */ -int XMLDoc_remove_node(XMLDoc* doc, int i_node, int free_node); - -/* - Shortcut macro to retrieve root node from a document. - Equivalent to - doc->nodes[doc->i_root] - */ -#define XMLDoc_root(doc) ((doc)->nodes[(doc)->i_root]) - -/* - Shortcut macro to add a node to 'doc' root node. - Equivalent to - XMLDoc_add_child_root(XMLDoc* doc, XMLNode* child); - */ -#define XMLDoc_add_child_root(doc, child) XMLNode_add_child((doc)->nodes[(doc)->i_root], (child)) - -/* - Default quote to use to print attribute value. - User can redefine it with its own character by adding a #define XML_DEFAULT_QUOTE before including - this file. - */ -#ifndef XML_DEFAULT_QUOTE -#define XML_DEFAULT_QUOTE C2SX('"') -#endif - -/* - Print the node and its children to a file (that can be stdout). - - 'tag_sep' is the string to use to separate nodes from each other (usually "\n"). - - 'child_sep' is the additional string to put for each child level (usually "\t"). - - 'keep_text_spaces' indicates that text should not be printed if it is composed of - spaces, tabs or new lines only (e.g. when XML document spans on several lines due to - pretty-printing). - - 'sz_line' is the maximum number of characters that can be put on a single line. The - node remainder will be output to extra lines. - - 'nb_char_tab' is how many characters should be counted for a tab when counting characters - in the line. It usually is 8 or 4, but at least 1. - - 'depth' is an internal parameter that is used to determine recursively how deep we are in - the tree. It should be initialized to 0 at first call. - Return 'false' on invalid arguments (NULL 'node' or 'f'), 'true' otherwise. - */ -int XMLNode_print_attr_sep(const XMLNode* node, FILE* f, const SXML_CHAR* tag_sep, const SXML_CHAR* child_sep, const SXML_CHAR* attr_sep, int keep_text_spaces, int sz_line, int nb_char_tab); - -/* For backward compatibility */ -#define XMLNode_print(node, f, tag_sep, child_sep, keep_text_spaces, sz_line, nb_char_tab) XMLNode_print_attr_sep(node, f, tag_sep, child_sep, C2SX(" "), keep_text_spaces, sz_line, nb_char_tab) - -/* - Print the node "header": <tagname attribname="attibval" ...[/]>, spanning it on several lines if needed. - Return 'false' on invalid arguments (NULL 'node' or 'f'), 'true' otherwise. - */ -int XMLNode_print_header(const XMLNode* node, FILE* f, int sz_line, int nb_char_tab); - -/* - Prints the XML document using 'XMLNode_print' on all document root nodes. - */ -int XMLDoc_print_attr_sep(const XMLDoc* doc, FILE* f, const SXML_CHAR* tag_sep, const SXML_CHAR* child_sep, const SXML_CHAR* attr_sep, int keep_text_spaces, int sz_line, int nb_char_tab); - -/* For backward compatibility */ -#define XMLDoc_print(doc, f, tag_sep, child_sep, keep_text_spaces, sz_line, nb_char_tab) XMLDoc_print_attr_sep(doc, f, tag_sep, child_sep, C2SX(" "), keep_text_spaces, sz_line, nb_char_tab) - -/* - Create a new XML document from a given 'filename' and load it to 'doc'. - 'text_as_nodes' should be non-zero to put text into separate TAG_TEXT nodes. - Return 'false' in case of error (memory or unavailable filename, malformed document), 'true' otherwise. - */ -int XMLDoc_parse_file_DOM_text_as_nodes(const SXML_CHAR* filename, XMLDoc* doc, int text_as_nodes); - -/* For backward compatibility */ -#define XMLDoc_parse_file_DOM(filename, doc) XMLDoc_parse_file_DOM_text_as_nodes(filename, doc, 0) - -/* - Create a new XML document from a memory buffer 'buffer' that can be given a name 'name', and load - it into 'doc'. - 'text_as_nodes' should be non-zero to put text into separate TAG_TEXT nodes. - Return 'false' in case of error (memory or unavailable filename, malformed document), 'true' otherwise. - */ -int XMLDoc_parse_buffer_DOM_text_as_nodes(const SXML_CHAR* buffer, const SXML_CHAR* name, XMLDoc* doc, int text_as_nodes); - -/* For backward compatibility */ -#define XMLDoc_parse_buffer_DOM(buffer, name, doc) XMLDoc_parse_buffer_DOM_text_as_nodes(buffer, name, doc, 0) - -/* - Parse an XML document from a given 'filename', calling SAX callbacks given in the 'sax' structure. - 'user' is a user-given pointer that will be given back to all callbacks. - Return 'false' in case of error (memory or unavailable filename, malformed document), 'true' otherwise. - */ -int XMLDoc_parse_file_SAX(const SXML_CHAR* filename, const SAX_Callbacks* sax, void* user); - -/* - Parse an XML document from a memory buffer 'buffer' that can be given a name 'name', - calling SAX callbacks given in the 'sax' structure. - 'user' is a user-given pointer that will be given back to all callbacks. - Return 'false' in case of error (memory or unavailable filename, malformed document), 'true' otherwise. - */ -int XMLDoc_parse_buffer_SAX(const SXML_CHAR* buffer, const SXML_CHAR* name, const SAX_Callbacks* sax, void* user); - -/* - Parse an XML file using the DOM implementation. - */ -#define XMLDoc_parse_file XMLDOC_parse_file_DOM - - - -/* --- Utility functions --- */ - -/* - Functions to get next byte from buffer data source and know if the end has been reached. - Return as 'fgetc' and 'feof' would for 'FILE*'. - */ -int _bgetc(DataSourceBuffer* ds); -int _beob(DataSourceBuffer* ds); -/* - Reads a line from data source 'in', eventually (re-)allocating a given buffer 'line'. - Characters read will be stored in 'line' starting at 'i0' (this allows multiple calls to - 'read_line_alloc' on the same 'line' buffer without overwriting it at each call). - 'in_type' specifies the type of data source to be read: 'in' is 'FILE*' if 'in_type' - 'sz_line' is the size of the buffer 'line' if previously allocated. 'line' can point - to NULL, in which case it will be allocated '*sz_line' bytes. After the function returns, - '*sz_line' is the actual buffer size. This allows multiple calls to this function using the - same buffer (without re-allocating/freeing). - If 'sz_line' is non NULL and non 0, it means that '*line' is a VALID pointer to a location - of '*sz_line' SXML_CHAR (not bytes! Multiply by sizeof(SXML_CHAR) to get number of bytes). - Searches for character 'from' until character 'to'. If 'from' is 0, starts from - current position. If 'to' is 0, it is replaced by '\n'. - If 'keep_fromto' is 0, removes characters 'from' and 'to' from the line. - If 'interest_count' is not NULL, will receive the count of 'interest' characters while searching - for 'to' (e.g. use 'interest'='\n' to count lines in file). - Returns the number of characters in the line or 0 if an error occurred. - 'read_line_alloc' uses constant 'MEM_INCR_RLA' to reallocate memory when needed. It is possible - to override this definition to use another value. - */ -int read_line_alloc(void* in, DataSourceType in_type, SXML_CHAR** line, int* sz_line, int i0, SXML_CHAR from, SXML_CHAR to, int keep_fromto, SXML_CHAR interest, int* interest_count); - -/* - Concatenates the string pointed at by 'src1' with 'src2' into '*src1' and - return it ('*src1'). - Return NULL when out of memory. - */ -SXML_CHAR* strcat_alloc(SXML_CHAR** src1, const SXML_CHAR* src2); - -/* - Strip spaces at the beginning and end of 'str', modifying 'str'. - If 'repl_sq' is not '\0', squeezes spaces to an single character ('repl_sq'). - If not '\0', 'protect' is used to protect spaces from being deleted (usually a backslash). - Returns the string or NULL if 'protect' is a space (which would not make sense). - */ -SXML_CHAR* strip_spaces(SXML_CHAR* str, SXML_CHAR repl_sq); - -/* - Remove '\' characters from 'str', modifying it. - Return 'str'. - */ -SXML_CHAR* str_unescape(SXML_CHAR* str); - -/* - Split 'str' into a left and right part around a separator 'sep'. - The left part is located between indexes 'l0' and 'l1' while the right part is - between 'r0' and 'r1' and the separator position is at 'i_sep' (whenever these are - not NULL). - If 'ignore_spaces' is 'true', computed indexes will not take into account potential - spaces around the separator as well as before left part and after right part. - if 'ignore_quotes' is 'true', " or ' will not be taken into account when parsing left - and right members. - Whenever the right member is empty (e.g. "attrib" or "attrib="), '*r0' is initialized - to 'str' size and '*r1' to '*r0-1' (crossed). - If the separator was not found (i.e. left member only), '*i_sep' is '-1'. - Return 'false' when 'str' is malformed, 'true' when splitting was successful. - */ -int split_left_right(SXML_CHAR* str, SXML_CHAR sep, int* l0, int* l1, int* i_sep, int* r0, int* r1, int ignore_spaces, int ignore_quotes); - -typedef enum _BOM_TYPE { - BOM_NONE = 0x00, - BOM_UTF_8 = 0xefbbbf, - BOM_UTF_16BE = 0xfeff, - BOM_UTF_16LE = 0xfffe, - BOM_UTF_32BE = 0x0000feff, - BOM_UTF_32LE = 0xfffe0000 -} BOM_TYPE; -/* - Detect a potential BOM at the current file position and read it into 'bom' (if not NULL, - 'bom' should be at least 5 bytes). It also moves the 'f' beyond the BOM so it's possible to - skip it by calling 'freadBOM(f, NULL, NULL)'. If no BOM is found, it leaves 'f' file pointer - is reset to its original location. - If not null, 'sz_bom' is filled with how many bytes are stored in 'bom'. - Return the BOM type or BOM_NONE if none found (empty 'bom' in this case). - */ -BOM_TYPE freadBOM(FILE* f, unsigned char* bom, int* sz_bom); - -/* - Replace occurrences of special HTML characters escape sequences (e.g. '&') found in 'html' - by its character equivalent (e.g. '&') into 'str'. - If 'html' and 'str' are the same pointer replacement is made in 'str' itself, overwriting it. - If 'str' is NULL, replacement is made into 'html', overwriting it. - Returns 'str' (or 'html' if 'str' was NULL). - */ -SXML_CHAR* html2str(SXML_CHAR* html, SXML_CHAR* str); - -/* - Replace occurrences of special characters (e.g. '&') found in 'str' into their XML escaped - equivalent (e.g. '&') into 'xml'. - 'xml' is supposed allocated to the correct size (e.g. using 'malloc(strlen_html(str)+30)') and - different from 'str' (unlike 'html2str'), as string will expand. If it is NULL, 'str' will be - analyzed and a string will be allocated to the exact size, before being returned. In that case, - it is the responsibility of the caller to free() the result! - Return 'xml' or NULL if 'str' or 'xml' are NULL, or when 'xml' is 'str'. -*/ -SXML_CHAR* str2html(SXML_CHAR* str, SXML_CHAR* xml); - -/* - Return the length of 'str' as if all its special character were replaced by their HTML - equivalent. - Return 0 if 'str' is NULL. - */ -int strlen_html(SXML_CHAR* str); - -/* - Print 'str' to 'f', transforming special characters into their HTML equivalent. - Returns the number of output characters. - */ -int fprintHTML(FILE* f, SXML_CHAR* str); - -/* - Checks whether 'str' corresponds to 'pattern'. - 'pattern' can use wildcads such as '*' (any potentially empty string) or - '?' (any character) and use '\' as an escape character. - Returns 'true' when 'str' matches 'pattern', 'false' otherwise. - */ -int regstrcmp(SXML_CHAR* str, SXML_CHAR* pattern); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/client/sxmlc/sxmlsearch.c b/client/sxmlc/sxmlsearch.c deleted file mode 100755 index c03b12a..0000000 --- a/client/sxmlc/sxmlsearch.c +++ /dev/null @@ -1,639 +0,0 @@ -/* - Copyright (c) 2010, Matthieu Labas - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - OF SUCH DAMAGE. - - The views and conclusions contained in the software and documentation are those of the - authors and should not be interpreted as representing official policies, either expressed - or implied, of the FreeBSD Project. -*/ -#if defined(WIN32) || defined(WIN64) -#pragma warning(disable : 4996) -#endif - -#include <string.h> -#include <stdlib.h> -#include "sxmlc.h" -#include "sxmlsearch.h" - -#define INVALID_XMLNODE_POINTER ((XMLNode*)-1) - -/* The function used to compare a string to a pattern */ -static REGEXPR_COMPARE regstrcmp_search = regstrcmp; - -REGEXPR_COMPARE XMLSearch_set_regexpr_compare(REGEXPR_COMPARE fct) -{ - REGEXPR_COMPARE previous = regstrcmp_search; - - regstrcmp_search = fct; - - return previous; -} - -int XMLSearch_init(XMLSearch* search) -{ - if (search == NULL) - return false; - - if (search->init_value == XML_INIT_DONE) - XMLSearch_free(search, true); - - search->tag = NULL; - search->text = NULL; - search->attributes = NULL; - search->n_attributes = 0; - search->next = NULL; - search->prev = NULL; - search->stop_at = INVALID_XMLNODE_POINTER; /* Because 'NULL' can be a valid value */ - search->init_value = XML_INIT_DONE; - - return true; -} - -int XMLSearch_free(XMLSearch* search, int free_next) -{ - int i; - - if (search == NULL || search->init_value != XML_INIT_DONE) - return false; - - if (search->tag != NULL) { - __free(search->tag); - search->tag = NULL; - } - - if (search->attributes != NULL) { - for (i = 0; i < search->n_attributes; i++) { - if (search->attributes[i].name != NULL) - __free(search->attributes[i].name); - if (search->attributes[i].value != NULL) - __free(search->attributes[i].value); - } - __free(search->attributes); - search->n_attributes = 0; - search->attributes = NULL; - } - - if (free_next && search->next != NULL) { - (void)XMLSearch_free(search->next, true); - __free(search->next); - search->next = NULL; - } - search->init_value = 0; /* Something not XML_INIT_DONE, otherwise we'll go into 'XMLSearch_free' again */ - (void)XMLSearch_init(search); - - return true; -} - -int XMLSearch_search_set_tag(XMLSearch* search, const SXML_CHAR* tag) -{ - if (search == NULL) - return false; - - if (tag == NULL) { - if (search->tag != NULL) { - __free(search->tag); - search->tag = NULL; - } - return true; - } - - search->tag = sx_strdup(tag); - return (search->tag != NULL); -} - -int XMLSearch_search_set_text(XMLSearch* search, const SXML_CHAR* text) -{ - if (search == NULL) - return false; - - if (text == NULL) { - if (search->text != NULL) { - __free(search->text); - search->text = NULL; - } - return true; - } - - search->text = sx_strdup(text); - return (search->text != NULL); -} - -int XMLSearch_search_add_attribute(XMLSearch* search, const SXML_CHAR* attr_name, const SXML_CHAR* attr_value, int value_equal) -{ - int i; - XMLAttribute* pt; - SXML_CHAR* name; - SXML_CHAR* value; - - if (search == NULL) - return -1; - - if (attr_name == NULL || attr_name[0] == NULC) - return -1; - - name = sx_strdup(attr_name); - value = (attr_value == NULL ? NULL : sx_strdup(attr_value)); - if (name == NULL || (attr_value && value == NULL)) { - if (value != NULL) - __free(value); - if (name != NULL) - __free(name); - } - - i = search->n_attributes; - pt = (XMLAttribute*)__realloc(search->attributes, (i + 1) * sizeof(XMLAttribute)); - if (pt == NULL) { - if (value) - __free(value); - __free(name); - return -1; - } - - pt[i].name = name; - pt[i].value = value; - pt[i].active = value_equal; - - search->n_attributes = i+1; - search->attributes = pt; - - return i; -} - -int XMLSearch_search_get_attribute_index(const XMLSearch* search, const SXML_CHAR* attr_name) -{ - int i; - - if (search == NULL || attr_name == NULL || attr_name[0] == NULC) - return -1; - - for (i = 0; i < search->n_attributes; i++) { - if (!sx_strcmp(search->attributes[i].name, attr_name)) - return i; - } - - return -1; -} - -int XMLSearch_search_remove_attribute(XMLSearch* search, int i_attr) -{ - XMLAttribute* pt; - - if (search == NULL || i_attr < 0 || i_attr >= search->n_attributes) - return -1; - - /* Free attribute fields first */ - if (search->n_attributes == 1) - pt = NULL; - else { - pt = (XMLAttribute*)__malloc((search->n_attributes - 1) * sizeof(XMLAttribute)); - if (pt == NULL) - return -1; - } - if (search->attributes[i_attr].name != NULL) - __free(search->attributes[i_attr].name); - if (search->attributes[i_attr].value != NULL) - __free(search->attributes[i_attr].value); - - if (pt != NULL) { - memcpy(pt, search->attributes, i_attr * sizeof(XMLAttribute)); - memcpy(&pt[i_attr], &search->attributes[i_attr + 1], (search->n_attributes - i_attr - 1) * sizeof(XMLAttribute)); - } - if (search->attributes) - __free(search->attributes); - search->attributes = pt; - search->n_attributes--; - - return search->n_attributes; -} - -int XMLSearch_search_set_children_search(XMLSearch* search, XMLSearch* children_search) -{ - if (search == NULL) - return false; - - if (search->next != NULL) - XMLSearch_free(search->next, true); - - search->next = children_search; - children_search->prev = search; - - return true; -} - -SXML_CHAR* XMLSearch_get_XPath_string(const XMLSearch* search, SXML_CHAR** xpath, SXML_CHAR quote) -{ - const XMLSearch* s; - SXML_CHAR squote[] = C2SX("'"); - int i, fill; - - if (xpath == NULL) - return NULL; - - /* NULL 'search' is an empty string */ - if (search == NULL) { - *xpath = sx_strdup(C2SX("")); - if (*xpath == NULL) - return NULL; - - return *xpath; - } - - squote[0] = (quote == NULC ? XML_DEFAULT_QUOTE : quote); - - for (s = search; s != NULL; s = s->next) { - if (s != search && strcat_alloc(xpath, C2SX("/")) == NULL) goto err; /* No "/" prefix for the first criteria */ - if (strcat_alloc(xpath, s->tag == NULL || s->tag[0] == NULC ? C2SX("*"): s->tag) == NULL) goto err; - - if (s->n_attributes > 0 || (s->text != NULL && s->text[0] != NULC)) - if (strcat_alloc(xpath, C2SX("[")) == NULL) goto err; - - fill = false; /* '[' has not been filled with text yet, no ", " separator should be added */ - if (s->text != NULL && s->text[0] != NULC) { - if (strcat_alloc(xpath, C2SX(".=")) == NULL) goto err; - if (strcat_alloc(xpath, squote) == NULL) goto err; - if (strcat_alloc(xpath, s->text) == NULL) goto err; - if (strcat_alloc(xpath, squote) == NULL) goto err; - fill = true; - } - - for (i = 0; i < s->n_attributes; i++) { - if (fill) { - if (strcat_alloc(xpath, C2SX(", ")) == NULL) goto err; - } else - fill = true; /* filling is being performed */ - if (strcat_alloc(xpath, C2SX("@")) == NULL) goto err; - if (strcat_alloc(xpath, s->attributes[i].name) == NULL) goto err; - if (s->attributes[i].value == NULL) continue; - - if (strcat_alloc(xpath, s->attributes[i].active ? C2SX("=") : C2SX("!=")) == NULL) goto err; - if (strcat_alloc(xpath, squote) == NULL) goto err; - if (strcat_alloc(xpath, s->attributes[i].value) == NULL) goto err; - if (strcat_alloc(xpath, squote) == NULL) goto err; - } - if ((s->text != NULL && s->text[0] != NULC) || s->n_attributes > 0) { - if (strcat_alloc(xpath, C2SX("]")) == NULL) goto err; - } - } - - return *xpath; - -err: - __free(*xpath); - *xpath = NULL; - - return NULL; -} - -/* - Extract search information from 'xpath', where 'xpath' represents a single node - (i.e. no '/' inside, except escaped ones), stripped from lead and tail '/'. - tag[.=text, @attrib="value"] with potential spaces around '=' and ','. - Return 'false' if parsing failed, 'true' for success. - This is an internal function so we assume that arguments are valid (non-NULL). - */ -static int _init_search_from_1XPath(SXML_CHAR* xpath, XMLSearch* search) -{ - SXML_CHAR *p, *q; - SXML_CHAR c, c1, cc; - int l0, l1, is, r0, r1; - int ret; - - XMLSearch_init(search); - - /* Look for tag name */ - for (p = xpath; *p != NULC && *p != C2SX('['); p++) ; - c = *p; /* Either '[' or '\0' */ - *p = NULC; - ret = XMLSearch_search_set_tag(search, xpath); - *p = c; - if (!ret) - return false; - - if (*p == NULC) - return true; - - /* Here, '*p' is '[', we have to parse either text or attribute names/values until ']' */ - for (p++; *p && *p != C2SX(']'); p++) { - for (q = p; *q && *q != C2SX(',') && *q != C2SX(']'); q++) ; /* Look for potential ',' separator to null it */ - cc = *q; - if (*q == C2SX(',') || *q == C2SX(']')) - *q = NULC; - ret = true; - switch (*p) { - case C2SX('.'): /* '.[ ]=[ ]["']...["']' to search for text */ - if (!split_left_right(p, C2SX('='), &l0, &l1, &is, &r0, &r1, true, true)) - return false; - c = p[r1+1]; - p[r1+1] = NULC; - ret = XMLSearch_search_set_text(search, &p[r0]); - p[r1+1] = c; - p += r1+1; - break; - - /* Attribute name, possibly '@attrib[[ ]=[ ]"value"]' */ - case C2SX('@'): - if (!split_left_right(++p, '=', &l0, &l1, &is, &r0, &r1, true, true)) - return false; - c = p[l1+1]; - c1 = p[r1+1]; - p[l1+1] = NULC; - p[r1+1] = NULC; - ret = (XMLSearch_search_add_attribute(search, &p[l0], (is < 0 ? NULL : &p[r0]), true) < 0 ? false : true); /* 'is' < 0 when there is no '=' (i.e. check for attribute presence only */ - p[l1+1] = c; - p[r1+1] = c1; - p += r1-1; /* Jump to next value */ - break; - - default: /* Not implemented */ - break; - } - *q = cc; /* Restore ',' separator if any */ - if (!ret) - return false; - } - - return true; -} - -int XMLSearch_init_from_XPath(const SXML_CHAR* xpath, XMLSearch* search) -{ - XMLSearch *search1, *search2; - SXML_CHAR *p, *tag, *tag0; - SXML_CHAR c; - - if (!XMLSearch_init(search)) - return false; - - /* NULL or empty xpath is an empty (initialized only) search */ - if (xpath == NULL || *xpath == NULC) - return true; - - search1 = NULL; /* Search struct to add the xpath portion to */ - search2 = search; /* Search struct to be filled from xpath portion */ - - tag = tag0 = sx_strdup(xpath); /* Create a copy of 'xpath' to be able to patch it (or segfault if 'xpath' is const, cnacu6o Sergey@sourceforge!) */ - while (*tag != NULC) { - if (search2 != search) { /* Allocate a new search when the original one (i.e. 'search') has already been filled */ - search2 = (XMLSearch*)__calloc(1, sizeof(XMLSearch)); - if (search2 == NULL) { - __free(tag0); - (void)XMLSearch_free(search, true); - return false; - } - } - /* Skip all first '/' */ - for (; *tag != NULC && *tag == C2SX('/'); tag++) ; - if (*tag == NULC) { - __free(tag0); - return false; - } - - /* Look for the end of tag name: after '/' (to get another tag) or end of string */ - for (p = &tag[1]; *p != NULC && *p != C2SX('/'); p++) { - if (*p == C2SX('\\') && *++p == NULC) - break; /* Escape character, '\' could be the last character... */ - } - c = *p; /* Backup character before nulling it */ - *p = NULC; - if (!_init_search_from_1XPath(tag, search2)) { - __free(tag0); - (void)XMLSearch_free(search, true); - return false; - } - *p = c; - - /* 'search2' is the newly parsed tag, 'search1' is the previous tag (or NULL if 'search2' is the first tag to parse (i.e. 'search2' == 'search') */ - - if (search1 != NULL) search1->next = search2; - if (search2 != search) search2->prev = search1; - search1 = search2; - search2 = NULL; /* Will force allocation during next loop */ - tag = p; - } - - __free(tag0); - return true; -} - -static int _attribute_matches(XMLAttribute* to_test, XMLAttribute* pattern) -{ - if (to_test == NULL && pattern == NULL) - return true; - - if (to_test == NULL || pattern == NULL) - return false; - - /* No test on name => match */ - if (pattern->name == NULL || pattern->name[0] == NULC) - return true; - - /* Test on name fails => no match */ - if (!regstrcmp_search(to_test->name, pattern->name)) - return false; - - /* No test on value => match */ - if (pattern->value == NULL) - return true; - - /* Test on value according to pattern "equal" attribute */ - return regstrcmp_search(to_test->value, pattern->value) == pattern->active ? true : false; -} - -int XMLSearch_node_matches(const XMLNode* node, const XMLSearch* search) -{ - int i, j; - - if (node == NULL) - return false; - - if (search == NULL) - return true; - - /* No comments, prolog, or such type of nodes are tested */ - if (node->tag_type != TAG_FATHER && node->tag_type != TAG_SELF) - return false; - - /* Check tag */ - if (search->tag != NULL && !regstrcmp_search(node->tag, search->tag)) - return false; - - /* Check text */ - if (search->text != NULL && !regstrcmp_search(node->text, search->text)) - return false; - - /* Check attributes */ - if (search->attributes != NULL) { - for (i = 0; i < search->n_attributes; i++) { - for (j = 0; j < node->n_attributes; j++) { - if (!node->attributes[j].active) - continue; - if (_attribute_matches(&node->attributes[j], &search->attributes[i])) - break; - } - if (j >= node->n_attributes) /* All attributes where scanned without a successful match */ - return false; - } - } - - /* 'node' matches 'search'. If there is a father search, its father must match it */ - if (search->prev != NULL) - return XMLSearch_node_matches(node->father, search->prev); - - /* TODO: Should a node match if search has no more 'prev' search and node father is still below the initial search ? - Depends if XPath started with "//" (=> yes) or "/" (=> no). - if (search->prev == NULL && node->father != search->from) return false; ? */ - - return true; -} - -XMLNode* XMLSearch_next(const XMLNode* from, XMLSearch* search) -{ - XMLNode* node; - - if (search == NULL || from == NULL) - return NULL; - - /* Go down the last child search as fathers will be tested recursively by the 'XMLSearch_node_matches' function */ - for (; search->next != NULL; search = search->next) ; - - /* Initialize the 'stop_at' node on first search, to remember where to stop as there will be multiple calls */ - /* 'stop_at' can be NULL when 'from' is a root node, that is why it should be initialized with something else than NULL */ - if (search->stop_at == INVALID_XMLNODE_POINTER) - search->stop_at = XMLNode_next_sibling(from); - - for (node = XMLNode_next(from); node != search->stop_at; node = XMLNode_next(node)) { /* && node != NULL */ - if (!XMLSearch_node_matches(node, search)) - continue; - - /* 'node' is a matching node */ - - /* No search to perform on 'node' children => 'node' is returned */ - if (search->next == NULL) - return node; - - /* Run the search on 'node' children */ - return XMLSearch_next(node, search->next); - } - - return NULL; -} - -static SXML_CHAR* _get_XPath(const XMLNode* node, SXML_CHAR** xpath) -{ - int i, n, brackets, sz_xpath; - SXML_CHAR* p; - - brackets = 0; - sz_xpath = sx_strlen(node->tag); - if (node->text != NULL) { - sz_xpath += strlen_html(node->text) + 4; /* 4 = '.=""' */ - brackets = 2; /* Text has to be displayed => add '[]' */ - } - for (i = 0; i < node->n_attributes; i++) { - if (!node->attributes[i].active) - continue; - brackets = 2; /* At least one attribute has to be displayed => add '[]' */ - sz_xpath += strlen_html(node->attributes[i].name) + strlen_html(node->attributes[i].value) + 6; /* 6 = ', @=""' */ - } - sz_xpath += brackets + 1; - *xpath = (SXML_CHAR*)__malloc(sz_xpath*sizeof(SXML_CHAR)); - - if (*xpath == NULL) - return NULL; - - sx_strcpy(*xpath, node->tag); - if (node->text != NULL) { - sx_strcat(*xpath, C2SX("[.=\"")); - (void)str2html(node->text, &(*xpath[sx_strlen(*xpath)])); - sx_strcat(*xpath, C2SX("\"")); - n = 1; /* Indicates '[' has been put */ - } else - n = 0; - - for (i = 0; i < node->n_attributes; i++) { - if (!node->attributes[i].active) - continue; - - if (n == 0) { - sx_strcat(*xpath, C2SX("[")); - n = 1; - } else - sx_strcat(*xpath, C2SX(", ")); - p = &(*xpath)[sx_strlen(*xpath)]; - - /* Standard and Unicode versions of 'sprintf' do not have the same signature! :( */ - sx_sprintf(p, -#ifdef SXMLC_UNICODE - sz_xpath, -#endif - C2SX("@%s=%c"), node->attributes[i].name, XML_DEFAULT_QUOTE); - - (void)str2html(node->attributes[i].value, p); - sx_strcat(*xpath, C2SX("\"")); - } - if (n > 0) - sx_strcat(*xpath, C2SX("]")); - - return *xpath; -} - -SXML_CHAR* XMLNode_get_XPath(XMLNode* node, SXML_CHAR** xpath, int incl_parents) -{ - SXML_CHAR* xp = NULL; - SXML_CHAR* xparent; - XMLNode* parent; - - if (node == NULL || node->init_value != XML_INIT_DONE || xpath == NULL) - return NULL; - - if (!incl_parents) { - if (_get_XPath(node, &xp) == NULL) { - *xpath = NULL; - return NULL; - } - return *xpath = xp; - } - - /* Go up to root node */ - parent = node; - do { - xparent = NULL; - if (_get_XPath(parent, &xparent) == NULL) goto xp_err; - if (xp != NULL) { - if (strcat_alloc(&xparent, C2SX("/")) == NULL) goto xp_err; - if (strcat_alloc(&xparent, xp) == NULL) goto xp_err; - } - xp = xparent; - parent = parent->father; - } while (parent != NULL); - if ((*xpath = sx_strdup(C2SX("/"))) == NULL || strcat_alloc(xpath, xp) == NULL) goto xp_err; - - return *xpath; - -xp_err: - if (xp != NULL) __free(xp); - *xpath = NULL; - - return NULL; -} diff --git a/client/sxmlc/sxmlsearch.h b/client/sxmlc/sxmlsearch.h deleted file mode 100755 index f1160aa..0000000 --- a/client/sxmlc/sxmlsearch.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - Copyright (c) 2010, Matthieu Labas - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - OF SUCH DAMAGE. - - The views and conclusions contained in the software and documentation are those of the - authors and should not be interpreted as representing official policies, either expressed - or implied, of the FreeBSD Project. -*/ -#ifndef _SXMLCSEARCH_H_ -#define _SXMLCSEARCH_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "sxmlc.h" - -/* - XML search parameters. Can be initialized from an XPath string. - A pointer to such structure is given to search functions which can modify - its content (the 'from' structure). - */ -typedef struct _XMLSearch { - /* - Search for nodes which tag match this 'tag' field. - If NULL or an empty string, all nodes will be matching. - */ - SXML_CHAR* tag; - - /* - Search for nodes which attributes match all the ones described. - If NULL, all nodes will be matching. - The 'attribute->name' should not be NULL. If corresponding 'attribute->value' - is NULL or an empty-string, search will return the first node with an attribute - 'attribute->name', no matter what is its value. - If 'attribute->value' is not NULL, a matching node should have an attribute - 'attribute->name' with the corresponding value 'attribute->value'. - When 'attribute->value' is not NULL, the 'attribute->active' should be 'true' - to specify that values should be equal, or 'false' to specify that values should - be different. - */ - XMLAttribute* attributes; - int n_attributes; - - /* - Search for nodes which text match this 'text' field. - If NULL or an empty string, all nodes will be matching. - */ - SXML_CHAR* text; - - /* - Next search to perform on children of a node matching current struct. - Used to search for nodes children of specific nodes (used in XPath queries). - */ - struct _XMLSearch* next; - struct _XMLSearch* prev; - - /* - Internal use only. Must be initialized to 'INVALID_XMLNODE_POINTER' prior to first search. - */ - XMLNode* stop_at; - - /* Keep 'init_value' as the last member */ - int init_value; /* Initialized to 'XML_INIT_DONE' to indicate that document has been initialized properly */ -} XMLSearch; - -typedef int (*REGEXPR_COMPARE)(SXML_CHAR* str, SXML_CHAR* pattern); - -/* - Set a new comparison function to evaluate whether a string matches a given pattern. - The default one is the "regstrcmp" which handles limited regular expressions. - 'fct' prototype is 'int fct(SXML_CHAR* str, SXML_CHAR* pattern)' where 'str' is the string to - evaluate the match for and 'pattern' the pattern. It should return 'true' (=1) when - 'str' matches 'pattern' and 'false' (=0) when it does not. - Return the previous function used for matching. - */ -REGEXPR_COMPARE XMLSearch_set_regexpr_compare(REGEXPR_COMPARE fct); - -/* - Initialize 'search' struct to an empty search. - No memory freeing is performed. - Return 'false' when 'search' is NULL. - */ -int XMLSearch_init(XMLSearch* search); - -/* - Free all 'search' members except for the 'search->next' member that should be freed - by its creator, unless 'free_next' is 'true'. - It is recommended that 'free_next' is positioned to 'true' only when the creator did not - handle the whole memory allocation chain, e.g. when using 'XMLSearch_init_from_XPath' - that allocates all search structs. - Return 'false' when 'search' is NULL. - */ -int XMLSearch_free(XMLSearch* search, int free_next); - -/* - Set the search based on tag. - 'tag' should be NULL or empty to search for any node (e.g. search based on attributes - only). In this case, the previous tag is freed. - Return 'true' upon successful completion, 'false' for memory error. - */ -int XMLSearch_search_set_tag(XMLSearch* search, const SXML_CHAR* tag); - -/* - Add an attribute search criteria. - 'attr_name' is mandatory. 'attr_value' should be NULL to test for attribute presence only - (no test on value). An empty string for 'attr_value' is not an equivalent to 'NULL'! - 'value_equal' should be specified to test for attribute value equality (='true') or - difference (='false). - Return the index of the new attribute, or '-1' for memory error. - */ -int XMLSearch_search_add_attribute(XMLSearch* search, const SXML_CHAR* attr_name, const SXML_CHAR* attr_value, int value_equal); - -/* - Search for attribute 'attr_name' in Search attribute list and return its index - or '-1' if not found. - */ -int XMLSearch_search_get_attribute_index(const XMLSearch* search, const SXML_CHAR* attr_name); - -/* - Removes the search attribute given by its index 'i_attr'. - Return the number of attributes left. - */ -int XMLSearch_search_remove_attribute(XMLSearch* search, int i_attr); - -/* - Set the search based on text content. - 'text' should be NULL or empty to search for any node (e.g. search based on attributes - only). In this case, the previous text is freed. - Return 'true' upon successful completion, 'false' for memory error. - */ -int XMLSearch_search_set_text(XMLSearch* search, const SXML_CHAR* text); - -/* - Set an additional search on children nodes of a previously matching node. - Search struct are chained to finally return the node matching the last search struct, - which father node matches the previous search struct, and so on. - This allows describing more complex search queries like XPath - "//FatherTag[@attrib=val]/ChildTag/". - In this case, a first search struct would have 'search->tag = "FatherTag"' and - 'search->attributes[0] = { "attrib", "val" }' and a second search struct with - 'search->tag = "ChildTag"'. - If 'children_search' is NULL, next search is removed. Freeing previous search is to be - performed by its owner. - In any case, if 'search' next search is not NULL, it is freed. - Return 'true' when association has been made, 'false' when an error occurred. - */ -int XMLSearch_search_set_children_search(XMLSearch* search, XMLSearch* children_search); - -/* - Compute an XPath-equivalent string of the 'search' criteria. - 'xpath' is a pointer to a string that will be allocated by the function and should - be freed after use. - 'quote' is the quote character to be used (e.g. '"' or '\''). If '\0', XML_DEFAULT_QUOTE will be used. - A NULL 'search' will return an empty string. - Return 'false' for a memory problem, 'true' otherwise. - */ -SXML_CHAR* XMLSearch_get_XPath_string(const XMLSearch* search, SXML_CHAR** xpath, SXML_CHAR quote); - -/* - Initialize a 'search' struct from an XPath-like query. "XPath-like" means that - it does not fully comply to XPath standard. - 'xpath' should be like "tag[.=text, @attrib="value", @attrib!='value']/tag...". - Warning: the XPath query on node text like 'father[child="text"]' should be - re-written 'father/child[.="text"]' instead (which should be XPath-compliant as well). - Return 'true' when 'search' was correctly initialized, 'false' in case of memory - problem or malformed 'xpath'. - */ -int XMLSearch_init_from_XPath(const SXML_CHAR* xpath, XMLSearch* search); - -/* - Check whether a 'node' matches 'search' criteria. - 'node->tag_type' should be 'TAG_FATHER' or 'TAG_SELF' only. - If 'search->prev' is not nULL (i.e. has a father search), 'node->father' is also - tested, recursively (i.e. grand-father and so on). - Return 'false' when 'node' does not match or for invalid arguments, 'true' - if 'node' is a match. - */ -int XMLSearch_node_matches(const XMLNode* node, const XMLSearch* search); - -/* - Search next matching node, according to search parameters given by 'search'. - Search starts from node 'from' by scanning all its children, and going up to siblings, - uncles and so on. - Searching for the next matching node is performed by running the search again on the last - matching node. So 'search' has to be initialized by 'XMLSearch_init' prior to the first call, - to memorize the initial 'from' node and know where to stop search. - 'from' ITSELF IS NOT CHECKED! Direct call to 'XMLSearch_node_matches(from, search);' should - be made if necessary. - If the document has several root nodes, a complete search in the document should be performed - by manually calling 'XMLSearch_next' on each root node in a for loop. - Note that 'search' should be the initial search struct (i.e. 'search->prev' should be NULL). This - cannot be checked/corrected by the function itself as it is partly recursive. - Return the next matching node according to 'search' criteria, or NULL when no more nodes match - or when an error occurred. - */ -XMLNode* XMLSearch_next(const XMLNode* from, XMLSearch* search); - -/* - Get 'node' XPath-like equivalent: 'tag[.="text", @attribute="value", ...]', potentially - including father nodes XPathes. - The computed XPath is stored in a dynamically-allocated string. - Return the XPath, or NULL if 'node' is invalid or on memory error. - */ -SXML_CHAR* XMLNode_get_XPath(XMLNode* node, SXML_CHAR** xpath, int incl_parents); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/http/CMakeLists.txt b/http/CMakeLists.txt deleted file mode 100644 index 7a3ac86..0000000 --- a/http/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -project (dap_http) - -set(HTTP_SRCS dap_http_client.c dap_http_client_simple.c dap_http_header.c) - -add_library(${PROJECT_NAME} STATIC ${HTTP_SRCS}) -target_link_libraries(${PROJECT_NAME} curl) - -include_directories("${dap_core_INCLUDE_DIRS}") -include_directories("${dap_client_INCLUDE_DIRS}") -include_directories("${dap_http_server_INCLUDE_DIRS}") -add_definitions ("${dap_core_DEFINITIONS}") -add_definitions ("${dap_client_DEFINITIONS}") -add_definitions ("${dap_http_server_DEFINITIONS}") - -set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE) - -set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE) diff --git a/http/dap_http_client.c b/http/dap_http_client.c deleted file mode 100644 index 44eace9..0000000 --- a/http/dap_http_client.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DAP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <libgen.h> -#include "dap_common.h" -#include "dap_client_remote.h" - -#ifdef DAP_SERVER -#include "dap_http.h" -#endif - -#include "dap_http_header.h" -#include "dap_http_client.h" - -#define LOG_TAG "http_client" - -#define BUF_SIZE 2048 - -void dap_http_client_out_header_generate(dap_http_client_t *cl_ht); - -/** - * @brief dap_http_client_init Init HTTP client module - * @return Zero if ok others if not - */ -int dap_http_client_init() -{ - log_it(L_NOTICE,"Initialized HTTP client module"); - return 0; -} - -/** - * @brief dap_http_client_deinit Deinit HTTP client module - */ -void dap_http_client_deinit() -{ - log_it(L_INFO,"HTTP client module deinit"); -} - -/** - * @brief dap_http_client_new Creates HTTP client's internal structure - * @param cl HTTP Client instance - * @param arg Additional argument (usualy not used) - */ -void dap_http_client_new(dap_client_remote_t * cl,void * arg) -{ - (void) arg; - cl->_inheritor = DAP_NEW_Z(dap_http_client_t); - dap_http_client_t * cl_ht=DAP_HTTP_CLIENT(cl); - cl_ht->client=cl; -#ifdef DAP_SERVER - cl_ht->http= DAP_HTTP(cl->server); -#endif - cl_ht->state_read=DAP_HTTP_CLIENT_STATE_START; - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_NONE; - -} - -/** - * @brief dap_http_client_delete - * @param cl HTTP Client instance - * @param arg Additional argument (usualy not used) - */ -void dap_http_client_delete(dap_client_remote_t * cl,void * arg) -{ - dap_http_client_t * cl_ht=DAP_HTTP_CLIENT(cl); - while(cl_ht->in_headers) - dap_http_header_remove(&cl_ht->in_headers,cl_ht->in_headers); - - while(cl_ht->out_headers) - dap_http_header_remove(&cl_ht->out_headers,cl_ht->out_headers); - -#ifdef DAP_SERVER - if(cl_ht->proc) - if(cl_ht->proc->delete_callback) - cl_ht->proc->delete_callback(cl_ht,NULL); -#endif - - if(cl_ht->_inheritor) - free(cl_ht->_inheritor); - (void) arg; -} - - -/** - * @brief detect_end_of_line Detect end of line, return position of its end (with \n symbols) - * @param buf Input buffer - * @param max_size Maximum size of this buffer minus 1 (for terminating zero) - * @return position of the end of line - */ -int detect_end_of_line(const char * buf, size_t max_size) -{ - size_t i; - for(i=0;i<max_size; i++){ - if(buf[i]=='\n'){ - return i; - } - } - return -1; -} - -bool dap_http_request_line_parse(dap_http_client_t * cl_ht, char * buf, size_t buf_length) -{ - size_t pos; - size_t pos_kw_begin=0; - enum parse_state{PS_START=0, PS_ACTION=1, PS_URL=2, PS_TYPE=3, PS_VER_MAJOR=4, PS_VER_MINOR=5} p_st=PS_ACTION; - for(pos=0;pos<buf_length; pos++){ - if(buf[pos]=='\n'){ - break; - }else if(( buf[pos]==' ')||( buf[pos]=='\t')){ - switch(p_st){ - case PS_ACTION:{ - size_t c_size= ((pos-pos_kw_begin+1)>sizeof(cl_ht->action) )? - (sizeof(cl_ht->action)-1) : - (pos-pos_kw_begin) ; - memcpy(cl_ht->action, buf+pos_kw_begin,c_size ); - cl_ht->action[c_size]='\0'; - //log_it(L_DEBUGUG, "Input: action '%s' pos=%lu pos_kw_begin=%lu", cl_ht->action,pos,pos_kw_begin); - p_st=PS_URL; - pos_kw_begin=pos+1; - }break; - case PS_URL:{ - size_t c_size= ((pos-pos_kw_begin+1)>sizeof(cl_ht->action) )? - (sizeof(cl_ht->url_path)-1) : - (pos-pos_kw_begin) ; - memcpy(cl_ht->url_path, buf+pos_kw_begin,c_size ); - cl_ht->url_path[c_size]='\0'; - //log_it(L_DEBUGUG, "Input: url '%s' pos=%lu pos_kw_begin=%lu", cl_ht->url_path,pos,pos_kw_begin); - p_st=PS_TYPE; - pos_kw_begin=pos+1; - }break; - default: - break; - } - }else{ - switch(p_st){ - case PS_START:{ - p_st=PS_ACTION; - pos_kw_begin=pos; - };break; - default:break; - } - } - } - return cl_ht->url_path[0]&&cl_ht->action[0]; -} - -/** - * @brief dap_http_client_read - * @param cl HTTP Client instance - * @param arg Additional argument (usualy not used) - */ -void dap_http_client_read(dap_client_remote_t * cl,void * arg) -{ - - (void) arg; - dap_http_client_t * cl_ht=DAP_HTTP_CLIENT(cl); - char buf_line[4096]; -// log_it(L_DEBUGUG,"HTTP client in state read %d taked bytes in input %lu",cl_ht->state_read,cl->buf_in_size); -cnt:switch(cl_ht->state_read){ - case DAP_HTTP_CLIENT_STATE_START:{ // Beginning of the session. We try to detect - int eol = detect_end_of_line(cl->buf_in,cl->buf_in_size); - if(eol<0){ - return; - }else if((eol+3)<sizeof(buf_line) ){ - memcpy(buf_line,cl->buf_in,eol+1); - dap_client_shrink_buf_in(cl,eol+1); - buf_line[eol+2]='\0'; - if( dap_http_request_line_parse(cl_ht,buf_line,eol+1) ){ - char * query_string; - - if( query_string = strchr(cl_ht->url_path,'?')) - { - size_t len_after=strlen(query_string+1); - if(len_after){ - if(len_after>(sizeof(cl_ht->in_query_string)-1)) - len_after=sizeof(cl_ht->in_query_string)-1; - - if(strstr(query_string, "HTTP/1.1")) - strncpy(cl_ht->in_query_string,query_string+1,len_after - 11); - else - strncpy(cl_ht->in_query_string,query_string+1,len_after); - - if(cl_ht->in_query_string[strlen(cl_ht->in_query_string) - 1] == ' ') - cl_ht->in_query_string[strlen(cl_ht->in_query_string) - 1] = '\0'; - query_string[0]='\0'; - } - } - //log_it(NOTICE, "Input: %s request for %s document (query string '%s')",cl_ht->action,cl_ht->url_path, cl_ht->in_query_string? cl_ht->in_query_string: ""); - char *b_name; - char * url_cpy1, *url_cpy2; - url_cpy1=strdup(cl_ht->url_path); - url_cpy2=strdup(cl_ht->url_path); - - - b_name=basename(url_cpy2); - - strncpy(cl_ht->url_path,b_name,sizeof(cl_ht->url_path)); -#ifdef DAP_SERVER - char * d_name; - d_name=dirname(url_cpy1); - dap_http_url_proc_t * url_proc; - - HASH_FIND_STR(cl_ht->http->url_proc, d_name , url_proc); // Find URL processor - - cl_ht->proc=url_proc; - if(url_proc) { - cl_ht->state_read=DAP_HTTP_CLIENT_STATE_HEADERS; - } - else{ - log_it(L_WARNING, "Input: unprocessed URL request %s is rejected", d_name); - cl_ht->state_read=DAP_HTTP_CLIENT_STATE_NONE; - dap_client_ready_to_read(cl_ht->client,true); - dap_client_ready_to_write(cl_ht->client,true); - cl_ht->reply_status_code=505; - strcpy(cl_ht->reply_reason_phrase,"Error"); - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_START; - cl->buf_in_size=0; - free(url_cpy1); - free(url_cpy2); - break; - } -#else - cl_ht->state_read=DAP_HTTP_CLIENT_STATE_HEADERS; -#endif - //free(d_name); - //free(b_name); - free(url_cpy1); - free(url_cpy2); - }else{ - log_it(L_WARNING, "Input: Wrong request line '%s'",buf_line); - cl->buf_in_size=0; - cl_ht->state_read=DAP_HTTP_CLIENT_STATE_NONE; - dap_client_ready_to_read(cl_ht->client,false); - dap_client_ready_to_write(cl_ht->client,true); - cl_ht->reply_status_code=505; - strcpy(cl_ht->reply_reason_phrase,"Error"); - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_START; - } - }else{ - log_it(L_WARNING,"Too big line in request, more than %llu symbols - thats very strange",sizeof(buf_line)-3); - cl->buf_in_size=0; - cl_ht->state_read=DAP_HTTP_CLIENT_STATE_NONE; - dap_client_ready_to_read(cl_ht->client,false); - dap_client_ready_to_write(cl_ht->client,true); - cl_ht->reply_status_code=505; - strcpy(cl_ht->reply_reason_phrase,"Error"); - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_START; - } - }break; - case DAP_HTTP_CLIENT_STATE_HEADERS:{ // Parse input headers - int eol = detect_end_of_line(cl->buf_in,cl->buf_in_size); - if(eol<0) - return; - else{ - int parse_ret; - memcpy(buf_line,cl->buf_in,eol+1); - buf_line[eol-1]='\0'; - - parse_ret=dap_http_header_parse(cl_ht,buf_line); - // log_it(L_WARNINGNG, "++ ALL HEADERS TO PARSE [%s]", buf_line); - if(parse_ret<0) - log_it(L_WARNING,"Input: not a valid header '%s'",buf_line); - else if(parse_ret==1){ - log_it(L_INFO,"Input: HTTP headers are over"); -#ifdef DAP_SERVER - if(cl_ht->proc->access_callback){ - bool isOk=true; - cl_ht->proc->access_callback(cl_ht,&isOk); - if(!isOk){ - log_it(L_NOTICE,"Access restricted"); - cl_ht->state_read=DAP_HTTP_CLIENT_STATE_NONE; - dap_client_ready_to_read(cl_ht->client,false); - dap_client_ready_to_write(cl_ht->client,true); - cl_ht->reply_status_code=505; - strcpy(cl_ht->reply_reason_phrase,"Error"); - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_START; - } - } - - if(cl_ht->proc->headers_read_callback) - cl_ht->proc->headers_read_callback(cl_ht,NULL); -#endif - // If no headers callback we go to the DATA processing - if(cl_ht->in_content_length ){ - cl_ht->state_read=DAP_HTTP_CLIENT_STATE_DATA; - }else{ - //log_it - //cl_ht->state_read=DAP_HTTP_CLIENT_STATE_NONE; - //cl_ht->client->ready_to_read=t; - //cl_ht->client->signal_close=!cl_ht->keep_alive; - } - - } - dap_client_shrink_buf_in(cl,eol+1); - } - }break; - case DAP_HTTP_CLIENT_STATE_DATA:{//Read the data - // log_it(L_WARNINGNG, "DBG_#002 [%s] [%s]", cl_ht->in_query_string, cl_ht->url_path); - -#ifdef DAP_SERVER - int read_bytes=0; - if(cl_ht->proc->data_read_callback){ - //while(cl_ht->client->buf_in_size){ - cl_ht->proc->data_read_callback(cl_ht,&read_bytes); - dap_client_shrink_buf_in(cl,read_bytes); - //} - }else -#endif - cl->buf_in_size=0; - } break; - case DAP_HTTP_CLIENT_STATE_NONE:{ - cl->buf_in_size=0; - }break; - - } - if(cl->buf_in_size>0){ - //log_it(L_DEBUGUG,"Continue to process to parse input"); - goto cnt; - } -} - -/** - * @brief dap_http_client_write Process write event - * @param cl HTTP Client instance - * @param arg Additional argument (usualy not used) - */ -void dap_http_client_write(dap_client_remote_t * cl,void * arg) -{ - - (void) arg; - dap_http_client_t * cl_ht=DAP_HTTP_CLIENT(cl); - // log_it(L_DEBUGUG,"HTTP client write callback in state %d",cl_ht->state_write); - switch(cl_ht->state_write){ - case DAP_HTTP_CLIENT_STATE_NONE: return; - case DAP_HTTP_CLIENT_STATE_START:{ -#ifdef DAP_SERVER - if(cl_ht->proc) - if(cl_ht->proc->headers_write_callback) - cl_ht->proc->headers_write_callback(cl_ht,NULL); -#endif - log_it(L_DEBUG,"Output: HTTP response with %u status code",cl_ht->reply_status_code); - dap_client_write_f(cl,"HTTP/1.1 %u %s\r\n",cl_ht->reply_status_code, cl_ht->reply_reason_phrase[0]?cl_ht->reply_reason_phrase:"UNDEFINED"); - dap_http_client_out_header_generate(cl_ht); - - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_HEADERS; - }break; - case DAP_HTTP_CLIENT_STATE_HEADERS:{ - dap_http_header_t * hdr=cl_ht->out_headers; - if(hdr==NULL){ - log_it(L_DEBUG, "Output: headers are over (reply status code %u)",cl_ht->reply_status_code); - dap_client_write_f(cl,"\r\n"); - if(cl_ht->out_content_length || cl_ht->out_content_ready){ - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_DATA; - }else{ - log_it(L_DEBUG,"Nothing to output"); - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_NONE; - dap_client_ready_to_write(cl,false); - - cl->signal_close=true; - } - dap_client_ready_to_read(cl,true); - }else{ - //log_it(L_DEBUGUG,"Output: header %s: %s",hdr->name,hdr->value); - dap_client_write_f(cl,"%s: %s\n",hdr->name,hdr->value); - dap_http_header_remove(&cl_ht->out_headers, hdr); - } - }break; - case DAP_HTTP_CLIENT_STATE_DATA:{ -#ifdef DAP_SERVER - if(cl_ht->proc) - if(cl_ht->proc->data_write_callback) - cl_ht->proc->data_write_callback(cl_ht,NULL); -#endif - }break; - } -} - -/** - * @brief dap_http_client_out_header_generate Produce general headers - * @param cl_ht HTTP client instance - */ -void dap_http_client_out_header_generate(dap_http_client_t *cl_ht) -{ - char buf[1024]; - time_t current_time=time(NULL); - time_to_rfc822(buf,sizeof(buf),current_time); - dap_http_header_add(&cl_ht->out_headers,"Date",buf); - if(cl_ht->reply_status_code==200){ - if(cl_ht->out_last_modified){ - time_to_rfc822(buf,sizeof(buf),cl_ht->out_last_modified); - dap_http_header_add(&cl_ht->out_headers,"Last-Modified",buf); - } - if(cl_ht->out_content_type[0]){ - dap_http_header_add(&cl_ht->out_headers,"Content-Type",cl_ht->out_content_type); - log_it(L_DEBUG,"output: Content-Type = '%s'",cl_ht->out_content_type); - } - if(cl_ht->out_content_length){ - snprintf(buf,sizeof(buf),"%llu",(unsigned long long)cl_ht->out_content_length); - dap_http_header_add(&cl_ht->out_headers,"Content-Length",buf); - log_it(L_DEBUG,"output: Content-Length = %llu",cl_ht->out_content_length); - } - } - if(cl_ht->out_connection_close || (!cl_ht->keep_alive) ) - dap_http_header_add(&cl_ht->out_headers,"Connection","Close"); -#ifdef DAP_SERVER - dap_http_header_add(&cl_ht->out_headers,"Server-Name", cl_ht->http->server_name); -#endif - log_it(L_DEBUG,"Output: Headers generated"); -} - -/** - * @brief dap_http_client_error Process errors - * @param cl HTTP Client instance - * @param arg Additional argument (usualy not used) - */ -void dap_http_client_error(struct dap_client_remote * cl,void * arg) -{ - (void) arg; -#ifdef DAP_SERVER - dap_http_client_t * cl_ht=DAP_HTTP_CLIENT(cl); - if(cl_ht->proc) - if(cl_ht->proc->error_callback) - cl_ht->proc->error_callback(cl_ht,arg); -#endif -} diff --git a/http/dap_http_client.h b/http/dap_http_client.h deleted file mode 100644 index 01c48c0..0000000 --- a/http/dap_http_client.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DAP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#ifndef _DAP_HTTP_CLIENT_H_ -#define _DAP_HTTP_CLIENT_H_ - -#include <stdint.h> -#include <time.h> -#include <stdbool.h> -typedef struct dap_client_remote dap_client_remote_t; -struct dap_http_client; -struct dap_http; -struct dap_http_url_proc; - - -typedef enum dap_http_client_state{ - DAP_HTTP_CLIENT_STATE_NONE=0, - DAP_HTTP_CLIENT_STATE_START=1, - DAP_HTTP_CLIENT_STATE_HEADERS=2, - DAP_HTTP_CLIENT_STATE_DATA=3 -} dap_http_client_state_t; - -typedef void (*dap_http_client_callback_t) (struct dap_http_client *,void * arg); // Callback for specific client operations - -typedef struct dap_http_client -{ - char action[128]; // Type of HTTP action (GET, PUT and etc) - char url_path[2048]; // URL path of requested document - uint32_t http_version_major; // Major version of HTTP protocol - uint32_t http_version_minor; // Minor version of HTTP protocol - bool keep_alive; - - dap_http_client_state_t state_read; - dap_http_client_state_t state_write; - - struct dap_http_header * in_headers; - uint64_t in_content_length; - char in_content_type[256]; - char in_query_string[1024]; - char in_cookie[1024]; - - struct dap_http_header * out_headers; - uint64_t out_content_length; - bool out_content_ready; - char out_content_type[256]; - time_t out_last_modified; - bool out_connection_close; - - - dap_client_remote_t * client; - struct dap_http * http; - - uint32_t reply_status_code; - char reply_reason_phrase[256]; - - struct dap_http_url_proc * proc; - - void * _inheritor; - void * _internal; - -} dap_http_client_t; - -#define DAP_HTTP_CLIENT(a) ((dap_http_client_t *) (a)->_inheritor ) - - -#ifdef __cplusplus -extern "C" { -#endif - -int dap_http_client_init(); -void dap_http_client_deinit(); - - -void dap_http_client_new(dap_client_remote_t * cl,void * arg); // Creates HTTP client's internal structure -void dap_http_client_delete(dap_client_remote_t * cl,void * arg); // Free memory for HTTP client's internal structure - -void dap_http_client_read( dap_client_remote_t * cl,void * arg); // Process read event -void dap_http_client_write( dap_client_remote_t * cl,void * arg); // Process write event -void dap_http_client_error( dap_client_remote_t * cl,void * arg); // Process error event - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/http/dap_http_client_simple.c b/http/dap_http_client_simple.c deleted file mode 100644 index 643e818..0000000 --- a/http/dap_http_client_simple.c +++ /dev/null @@ -1,326 +0,0 @@ -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> -#include <pthread.h> -#include <time.h> -#include <curl/curl.h> - -#include "utlist.h" - -#include "dap_common.h" - -#include "dap_http_client.h" -#include "dap_http_client_simple.h" - -typedef struct dap_http_client_internal{ - - dap_http_client_simple_callback_data_t response_callback; - dap_http_client_simple_callback_error_t error_callback; - void * obj; - uint8_t * request; - size_t request_size; - size_t request_sent_size; - struct curl_slist * request_headers; - - uint8_t * response; - size_t response_size; - size_t response_size_max; -} dap_http_client_internal_t; - -CURLM *m_curl_mh; // Multi-thread handle to stack lot of parallel requests -pthread_t curl_pid=0; -pthread_cond_t m_curl_cond = PTHREAD_COND_INITIALIZER; -pthread_mutex_t m_curl_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void *dap_http_client_thread(void * arg); -size_t dap_http_client_curl_request_callback(char * a_ptr, size_t a_size, size_t a_nmemb, void * a_userdata); -size_t dap_http_client_curl_response_callback(char * a_ptr, size_t a_size, size_t a_nmemb, void * a_userdata); -void dap_http_client_internal_delete(dap_http_client_internal_t * a_client); - -#define DAP_HTTP_CLIENT_RESPONSE_SIZE_MAX 40960 - -#define LOG_TAG "dap_http_client" - -/** - * @brief dap_http_client_init - * @return - */ -int dap_http_client_simple_init() -{ - curl_global_init(CURL_GLOBAL_ALL); - m_curl_mh = curl_multi_init(); - pthread_create(&curl_pid,NULL,dap_http_client_thread,NULL ); - return 0; -} - - -/** - * @brief dap_http_client_deinit - */ -void dap_http_client_simple_deinit() -{ - curl_multi_cleanup( m_curl_mh ); -} - -/** - * @brief dap_http_client_internal_delete - * @param a_client - */ -void dap_http_client_internal_delete(dap_http_client_internal_t * a_client_internal) -{ - if( a_client_internal->request_headers) - curl_slist_free_all( a_client_internal->request_headers ); - - if ( a_client_internal->request ) - free(a_client_internal->request); - - if ( a_client_internal->response ) - free(a_client_internal->response); - - free(a_client_internal); -} - -/** - * @brief dap_http_client_simple_request - * @param a_url - * @param a_method - * @param a_request_content_type - * @param a_request - * @param a_request_size - * @param a_response_callback - * @param a_error_callback - * @param a_obj - */ -void dap_http_client_simple_request(const char * a_url, const char * a_method, const char* a_request_content_type, void *a_request, size_t a_request_size, char * a_cookie, dap_http_client_simple_callback_data_t a_response_callback, - dap_http_client_simple_callback_error_t a_error_callback, void *a_obj, void * a_custom) -{ - log_it(L_DEBUG,"Simple HTTP request with static predefined buffer (%lu bytes) on url '%s'", - DAP_HTTP_CLIENT_RESPONSE_SIZE_MAX, a_url); - CURL *l_curl_h = curl_easy_init(); - - dap_http_client_internal_t * l_client_internal = DAP_NEW_Z(dap_http_client_internal_t); - l_client_internal->error_callback = a_error_callback; - l_client_internal->response_callback = a_response_callback; - l_client_internal->obj = a_obj; - - l_client_internal->response_size_max = DAP_HTTP_CLIENT_RESPONSE_SIZE_MAX; - l_client_internal->response = (uint8_t*) calloc(1,DAP_HTTP_CLIENT_RESPONSE_SIZE_MAX); - - l_client_internal->request = malloc(a_request_size); - memcpy(l_client_internal->request, a_request, a_request_size); - l_client_internal->request_size = a_request_size; - - if( ( a_request ) && ( ( - (strcmp( a_method , "POST" ) == 0) || - (strcmp( a_method , "POST_ENC" ) == 0) - ) ) ){ - char l_buf[1024]; - log_it ( L_DEBUG , "POST request with %u bytes of decoded data" , a_request_size ); - - if( a_request_content_type ) - l_client_internal->request_headers = curl_slist_append(l_client_internal->request_headers, a_request_content_type ); - - if( a_custom ) - l_client_internal->request_headers = curl_slist_append(l_client_internal->request_headers,(char*) a_custom ); - - if( a_cookie ) - l_client_internal->request_headers = curl_slist_append(l_client_internal->request_headers,(char*) a_cookie ); - - snprintf(l_buf,sizeof(l_buf),"Content-Length: %lu", a_request_size ); - l_client_internal->request_headers = curl_slist_append(l_client_internal->request_headers, l_buf); - - //curl_easy_setopt( l_curl_h , CURLOPT_READDATA , l_client_internal ); - curl_easy_setopt( l_curl_h , CURLOPT_POST , 1 ); - curl_easy_setopt( l_curl_h , CURLOPT_POSTFIELDSIZE, a_request_size ); - - } - if(l_client_internal->request_headers) - curl_easy_setopt(l_curl_h, CURLOPT_HTTPHEADER, l_client_internal->request_headers); - - curl_easy_setopt( l_curl_h , CURLOPT_PRIVATE, l_client_internal ); - curl_easy_setopt( l_curl_h , CURLOPT_URL, a_url); - - curl_easy_setopt( l_curl_h , CURLOPT_READDATA , l_client_internal ); - curl_easy_setopt( l_curl_h , CURLOPT_READFUNCTION , dap_http_client_curl_request_callback ); - - curl_easy_setopt( l_curl_h , CURLOPT_WRITEDATA , l_client_internal ); - curl_easy_setopt( l_curl_h , CURLOPT_WRITEFUNCTION , dap_http_client_curl_response_callback ); - - curl_multi_add_handle( m_curl_mh, l_curl_h ); - //curl_multi_perform(m_curl_mh, &m_curl_cond); - pthread_cond_signal( &m_curl_cond); - send_select_break(); -} - -/** - * @brief dap_http_client_curl_response_callback - * @param a_ptr - * @param a_size - * @param a_nmemb - * @param a_userdata - * @return - */ -size_t dap_http_client_curl_response_callback(char * a_ptr, size_t a_size, size_t a_nmemb, void * a_userdata) -{ - dap_http_client_internal_t * l_client_internal = (dap_http_client_internal_t *) a_userdata; - log_it(L_DEBUG, "Recieved %lu bytes in HTTP resonse", a_size*a_nmemb); - if( l_client_internal->response_size < l_client_internal->response_size_max){ - size_t l_size = a_size * a_nmemb; - if( l_size > ( l_client_internal->response_size_max - l_client_internal->response_size) ) - l_size = l_client_internal->response_size_max - l_client_internal->response_size; - memcpy(l_client_internal->response + l_client_internal->response_size,a_ptr,l_size); - l_client_internal->response_size += l_size; - }else{ - log_it(L_WARNING,"Too big reply, %lu bytes a lost",a_size*a_nmemb); - } - return a_size*a_nmemb; -} - -/** - * @brief dap_http_client_curl_request_callback - * @param a_ptr - * @param a_size - * @param a_nmemb - * @param a_userdata - * @return - */ -size_t dap_http_client_curl_request_callback(char * a_ptr, size_t a_size, size_t a_nmemb, void * a_userdata) -{ - dap_http_client_internal_t * l_client_internal = (dap_http_client_internal_t *) a_userdata; - size_t l_size = a_size * a_nmemb; - if( ( l_size + l_client_internal->request_sent_size) > l_client_internal->request_size ) - l_size = l_client_internal->request_size - l_client_internal->request_sent_size; - - if( l_size ) { - memcpy( a_ptr, l_client_internal->request + l_client_internal->request_sent_size, l_size ); - l_client_internal->request_sent_size += l_size; - } - return l_size; -} - -/** - * @brief dap_http_client_thread - * @param arg - */ -static void* dap_http_client_thread(void * arg) -{ - (void) arg; - bool l_still_running = true; - do { - struct timeval timeout; - int rc; /* select() return code */ - CURLMcode mc; /* curl_multi_fdset() return code */ - - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - int maxfd = -1; - - long curl_timeo = -1; - - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); - - /* set a suitable timeout to play around with */ - timeout.tv_sec = 10; - timeout.tv_usec = 0; - - curl_multi_timeout( m_curl_mh, &curl_timeo); - if(curl_timeo >= 0) { - timeout.tv_sec = curl_timeo / 1000; - if(timeout.tv_sec > 1) - timeout.tv_sec = 1; - else - timeout.tv_usec = (curl_timeo % 1000) * 1000; - } - - /* get file descriptors from the transfers */ - mc = curl_multi_fdset(m_curl_mh, &fdread, &fdwrite, &fdexcep, &maxfd); - FD_SET(get_select_breaker(),&fdread); - if(get_select_breaker() > maxfd) - maxfd = get_select_breaker(); - - if(mc != CURLM_OK) { - log_it(L_ERROR, "curl_multi_fdset() failed, code %d.\n", mc); - break; - } - - /* On success the value of maxfd is guaranteed to be >= -1. We call - select(maxfd + 1, ...); specially in case of (maxfd == -1) there are - no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- - to sleep 100ms, which is the minimum suggested value in the - curl_multi_fdset() doc. */ - if(maxfd == -1) { - //log_it(L_DEBUG, "Waiting for signal"); - pthread_cond_wait(&m_curl_cond,&m_curl_mutex); - } else { - //log_it(L_DEBUG, "Selecting stuff"); - /* Note that on some platforms 'timeout' may be modified by select(). - If you need access to the original value save a copy beforehand. */ - rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); - } - - switch(rc) { - case -1: { - /* select error */ - } break; - case 0: /* timeout */ - default: { /* action */ - int l_curl_eh_count = 0; - curl_multi_perform( m_curl_mh , &l_curl_eh_count ); - // Check if we have smth complete - struct CURLMsg *m; - do { - int msgq = 0; - m = curl_multi_info_read(m_curl_mh, &msgq); - if(m && (m->msg == CURLMSG_DONE)) { - CURL *e = m->easy_handle; - char * l_private = NULL; - int l_err_code = 0; - curl_easy_getinfo( e, CURLINFO_PRIVATE, &l_private ); - if( l_private ){ - bool l_is_ok = false; - dap_http_client_internal_t * l_client_internal = (dap_http_client_internal_t *) l_private; - switch ( m->data.result){ - case CURLE_OUT_OF_MEMORY: l_err_code = 1 ; log_it(L_CRITICAL, "Out of memory"); break; - case CURLE_COULDNT_CONNECT: l_err_code = 2 ; log_it(L_ERROR, "Couldn't connect to the destination server"); break; - case CURLE_COULDNT_RESOLVE_HOST: l_err_code = 3 ; log_it(L_ERROR, "Couldn't resolve destination address"); break; - case CURLE_OPERATION_TIMEDOUT: l_err_code = 4 ; log_it(L_ERROR, "HTTP request timeout"); break; - case CURLE_URL_MALFORMAT: l_err_code = 5 ; log_it(L_ERROR, "Wrong URL format in the outgoing request"); break; - case CURLE_FTP_WEIRD_SERVER_REPLY: l_err_code = 6 ; log_it(L_WARNING, "Weird server reply"); break; - case CURLE_OK:{ - l_is_ok = true; - log_it(L_DEBUG, "Response size %u",l_client_internal->response_size); - }break; - default: l_err_code = 12345; - } - if( l_is_ok){ - l_client_internal->response_callback(l_client_internal->response, - l_client_internal->response_size, - l_client_internal->obj ); - }else { - log_it(L_WARNING, "HTTP request wasn't processed well with error code %d",m->data.result ); - l_client_internal->error_callback(l_err_code , l_client_internal->obj ); - - } - dap_http_client_internal_delete(l_client_internal); - } else { - log_it(L_CRITICAL, "Can't get private information from libcurl handle to perform the reply to SAP connection"); - } - curl_multi_remove_handle(m_curl_mh, e); - curl_easy_cleanup(e); - } - } while(m); - } break; - } - } while(l_still_running); - - return NULL; -} - - diff --git a/http/dap_http_client_simple.h b/http/dap_http_client_simple.h deleted file mode 100644 index ac5ff11..0000000 --- a/http/dap_http_client_simple.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef DAP_HTTP_CLIENT_H -#define DAP_HTTP_CLIENT_H -#include <stddef.h> -struct dap_http_client_simple; -typedef void (*dap_http_client_simple_callback_error_t) (int,void *); // Callback for specific http client operations -typedef void (*dap_http_client_simple_callback_data_t) (void *,size_t,void *); // Callback for specific http client operations - -typedef struct dap_http_client_simple { - void * _inheritor; -} dap_http_client_simple_t; - -int dap_http_client_simple_init(); -void dap_http_client_simple_deinit(); - -void dap_http_client_simple_request(const char * a_url, const char * a_method, - const char* a_request_content_type , void *a_request, size_t a_request_size, char * a_cookie, - dap_http_client_simple_callback_data_t a_response_callback, - dap_http_client_simple_callback_error_t a_error_callback, void *a_obj, void * a_custom); - -#endif diff --git a/http/dap_http_header.c b/http/dap_http_header.c deleted file mode 100644 index 083f247..0000000 --- a/http/dap_http_header.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DAP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> -#include "dap_common.h" -#include "dap_client.h" -#include "dap_http_client.h" -#include "dap_http_header.h" - -#define LOG_TAG "http_header" - - -/** - * @brief dap_http_header_init Init module - * @return Zero if ok others if not - */ -int dap_http_header_init() -{ - log_it(L_NOTICE, "Initialized HTTP headers module"); - return 0; -} - -/** - * @brief dap_http_header_deinit Deinit module - */ -void dap_http_header_deinit() -{ - log_it(L_INFO, "HTTP headers module deinit"); -} - - -/** - * @brief dap_http_header_parse Parse string with HTTP header - * @param top Top of list with HTTP header structures - * @param str String to parse - * @return Zero if parsed well -1 if it wasn't HTTP header 1 if its "\r\n" string - */ -int dap_http_header_parse(struct dap_http_client * cl_ht, const char * str) -{ - - char name[256], value[1024]; - - size_t str_len=strlen(str); - //sn=sscanf(str,"%255s: %1023s\r\n",name,value); - size_t pos; - if( str_len==0 ) - return 1; - - //log_it(L_DEBUG, "Parse header string '%s'",str); - for(pos=1; pos<str_len;pos++) - if(str[pos]==':'){ - size_t name_len; - name_len=pos; - if(name_len>(sizeof(name)-1) ) - name_len=(sizeof(name)-1); - strncpy(name,str,name_len); - name[name_len]='\0'; - - // log_it(L_DEBUGUG, "Found name '%s'",name); - pos+=2; - size_t value_len=str_len-pos; - if(value_len>(sizeof(value)-1)) - value_len=(sizeof(value)-1); - strncpy(value,str+pos,value_len); - value[value_len]='\0'; - // log_it(L_DEBUGUG, "Found value '%s'",value); - - if(strcmp(name,"Connection")==0){ - if(strcmp(value,"Keep-Alive")==0){ - log_it(L_INFO, "Input: Keep-Alive connection detected"); - cl_ht->keep_alive=true; - } - }else if(strcmp(name,"Content-Type")==0){ - strncpy(cl_ht->in_content_type,value,sizeof(cl_ht->in_content_type)); - }else if(strcmp(name,"Content-Length")==0){ - cl_ht->in_content_length =atoi(value); - }else if(strcmp(name,"Cookie")==0){ - strncpy(cl_ht->in_cookie,value,sizeof(cl_ht->in_cookie)); - } - - - //log_it(L_DEBUG, "Input: Header\t%s '%s'",name,value); - - dap_http_header_add(&cl_ht->in_headers,name,value); - return 0; - } - - - log_it(L_ERROR,"Input: Wasn't found ':' symbol in the header"); - return -1; -} - - - -/** - * @brief http_header_add Add HTTP header to the HTTP server instance - * @param sh HTTP server instance - * @param name Header's name - * @param value Header's value - * @return Pointer to the new HTTP header's structure - */ -dap_http_header_t* dap_http_header_add(dap_http_header_t ** top, const char*name, const char * value) -{ - dap_http_header_t * nh = (dap_http_header_t*) calloc(1,sizeof(dap_http_header_t)); - // log_it(L_DEBUG,"Added header %s",name); - nh->name=strdup(name); - nh->value=strdup(value); - nh->next=*top; - if(*top) - (*top)->prev=nh; - *top=nh; - return nh; -} - - -struct dap_http_header* dap_http_out_header_add(dap_http_client_t * ht, const char*name, const char * value) -{ - return dap_http_header_add(&ht->out_headers,name,value); -} - - -/** - * @brief dap_http_out_header_add_f Add header to the output queue with format-filled string - * @param ht HTTP client instance - * @param name Header name - * @param value Formatted string to header value - * @param ... Arguments for formatted string - * @return - */ -dap_http_header_t * dap_http_out_header_add_f(dap_http_client_t * ht, const char*name, const char * value,...) -{ - va_list ap; - dap_http_header_t * ret; - char buf[1024]; - va_start(ap,value); - vsnprintf(buf,sizeof(buf)-1,value,ap); - ret=dap_http_out_header_add(ht,name,buf); - va_end(ap); - return ret; -} - -/** - * @brief dap_http_header_remove Removes header from the list - * @param dap_hdr HTTP header - */ -void dap_http_header_remove(dap_http_header_t ** top, dap_http_header_t * hdr ) -{ - if(hdr->prev) - hdr->prev=hdr->next; - else - *top=hdr->next; - - if(hdr->next) - hdr->next->prev=hdr->prev; - free(hdr->name); - free(hdr->value); -} - -/** - * @brief dap_http_header_find Looks or the header with specified name - * @param top Top of the list - * @param name Name of the header - * @return NULL if not found or pointer to structure with found item - */ -dap_http_header_t * dap_http_header_find(dap_http_header_t * top, const char*name) -{ - dap_http_header_t * ret; - for(ret=top; ret; ret=ret->next) - if(strcmp(ret->name,name)==0) - return ret; - return ret; -} diff --git a/http/dap_http_header.h b/http/dap_http_header.h deleted file mode 100644 index 23ed7c9..0000000 --- a/http/dap_http_header.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DAP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#ifndef _DAP_HTTP_HEADER_H_ -#define _DAP_HTTP_HEADER_H_ - -//Structure for holding HTTP header in the bidirectional list -typedef struct dap_http_header{ - char * name; - char * value; - struct dap_http_header * next; - struct dap_http_header * prev; -} dap_http_header_t; - -struct dap_http_client; - -extern int dap_http_header_init(); // Init module -extern void dap_http_header_deinit(); // Deinit module - -extern int dap_http_header_parse(struct dap_http_client * cl_ht, const char * str); - -extern dap_http_header_t * dap_http_header_add(dap_http_header_t ** top, const char*name, const char * value); - -extern dap_http_header_t * dap_http_out_header_add(struct dap_http_client * ht, const char*name, const char * value); -extern dap_http_header_t * dap_http_out_header_add_f(struct dap_http_client * ht, const char*name, const char * value,...); - -extern dap_http_header_t * dap_http_header_find(dap_http_header_t * top, const char*name); - -extern void dap_http_header_remove(dap_http_header_t ** top,dap_http_header_t * hdr ); - -#endif diff --git a/http/http.pri b/http/http.pri deleted file mode 100644 index 4c88864..0000000 --- a/http/http.pri +++ /dev/null @@ -1,15 +0,0 @@ -HEADERS += $$PWD/dap_http_client.h \ - $$PWD/dap_http_client_simple.h \ - $$PWD/dap_http_header.h - - -SOURCES += $$PWD/dap_http_client.c \ - $$PWD/dap_http_client_simple.c \ - $$PWD/dap_http_header.c - - -linux-* { - LIBS += -lcurl -} - -INCLUDEPATH += $$PWD diff --git a/libdap.c b/libdap.c deleted file mode 100644 index e69de29..0000000 -- GitLab