code_production/cfg-tools/sdk/include/coding/coding.h

517 lines
23 KiB
C
Raw Normal View History

2022-12-09 07:31:09 +00:00
// gb_base64.h : base64 encoding, allow you use your own BASE64 letter table
//
// Author: Gongbing
//
// Date: 2016-07-02
#pragma once
#ifndef _INCLUDED_REF_
#define _INCLUDED_REF_
#include "../ref/ref.h"
#endif
#define MINI_BUF_LEN 40
// this MACRO should include <algorithm> and <string> header files ...
#define STD_STR_TO_LOWER(str) std::transform((str).begin(), (str).end(), (str).begin(), tolower)
namespace coding_util
{
// all apis return error code, except commenting specially
__declspec(novtable) struct IBase64 : public ref_util::IRef
{
COM_API_DECLARE(bool, init_table(const char* base64_table = 0));
// parameter: result((char*)data, ...)
// return: error code
COM_API_DECLARE(int, encode(const char* data, size_t len, inter_module_data::set_data result, void* param, unsigned int max_line_len = -1, bool need_padding = true));
COM_API_DECLARE(int, decode(const char* data, size_t len, inter_module_data::set_data result, void* param));
};
__declspec(novtable) struct IBitsBuf : public ref_util::IRef
{
COM_API_DECLARE(bool, resize(int len, bool init_val = false));
COM_API_DECLARE(void, reset(bool val = false));
COM_API_DECLARE(void, set(int index, bool val));
COM_API_DECLARE(bool, get(int index));
// following for two-dimension
COM_API_DECLARE(bool, resize(short row, short col, bool init_val = false));
COM_API_DECLARE(void, set(short row, short col, bool val));
COM_API_DECLARE(bool, get(short row, short col));
};
// convert a hex letter to 4-bits integer.
// ch: to receive the result
// return whether the parameter 'hex' is a valid hex-letter
PORT_API(bool) hex_str_2_int(char hex, unsigned char* ch);
/* commonplace code page: refer to https://www.cnblogs.com/answercard/p/10122434.html
GBK: 936
BIG5: 950
UTF-16: 1200
unicode: 1201
GB2312: 20936
hz-gb-2312: 52936
GB18030: 54936
UTF-7: 65000
UTF-8: 65001
*/
// get code page of given charset name, 0 is failure
PORT_API(UINT) code_page_from_name(const char* name);
PORT_API(UINT) code_page_from_name(const wchar_t* name);
// result((wchar_t*)data, ...);
//
// return: error code, 0 is success
PORT_API(int) ansi_2_unicode(const char* data, inter_module_data::set_data result, void* param, int chars = -1, UINT ansi_code_page = CP_ACP);
PORT_API(int) ansi_2_utf8(const char* data, inter_module_data::set_data result, void* param, int chars = -1, UINT ansi_code_page = CP_ACP);
PORT_API(int) unicode_2_ansi(const wchar_t* data, inter_module_data::set_data result, void* param, int chars = -1, UINT ansi_code_page = CP_ACP);
PORT_API(int) unicode_2_utf8(const wchar_t* data, inter_module_data::set_data result, void* param, int chars = -1);
PORT_API(int) utf8_2_ansi(const char* data, inter_module_data::set_data result, void* param, int chars = -1, UINT ansi_code_page = CP_ACP);
PORT_API(int) utf8_2_unicode(const char* data, inter_module_data::set_data result, void* param, int chars = -1);
// case transfer, return changes
PORT_API(int) to_upper(char* str, int len = -1);
PORT_API(int) to_upper(wchar_t* str, int len = -1);
PORT_API(int) to_lower(char* str, int len = -1);
PORT_API(int) to_lower(wchar_t* str, int len = -1);
// Function: transform string between unicode style as 0x1234 and web style such as \u1234, %12%34 ...
// result((wchar_t*)data, ...);
PORT_API(void) from_web_style(const wchar_t* data, inter_module_data::set_data result, void* param);
PORT_API(void) to_web_style(const wchar_t* data, inter_module_data::set_data result, void* param);
namespace bom
{
PORT_API(bool) is_unicode(const char* bom_str, bool* big_ending); // bom_str must be great than 3 bytes, big_ending to receive whether the bom is a Big-Ending unicode
PORT_API(bool) is_utf8(const char* bom_str); // bom_str must be great than 3 bytes
// result((char*)data, ...), maybe DATA_FLAG_ERROR
PORT_API(void) to_ansi(const char* bom_str, size_t bytes, inter_module_data::set_data result, void* param);
PORT_API(void) to_utf8(const char* bom_str, size_t bytes, inter_module_data::set_data result, void* param);
// result((wchar_t*)data, ...), maybe DATA_FLAG_ERROR
PORT_API(void) to_unicode(const char* bom_str, size_t bytes, inter_module_data::set_data result, void* param, bool little_ending = true);
// result((char*)data, ...), maybe DATA_FLAG_ERROR
PORT_API(void) from_ansi(const char* bom_str, size_t bytes, inter_module_data::set_data result, void* param);
PORT_API(void) from_unicode(const wchar_t* bom_str, size_t bytes, inter_module_data::set_data result, void* param, bool little_ending = true);
PORT_API(void) from_utf8(const char* bom_str, size_t bytes, inter_module_data::set_data result, void* param);
}
PORT_API(int) trim_left(char* str, const char* trim_letter = " \t"); // return erased letters count
PORT_API(int) trim_left(wchar_t* str, const wchar_t* trim_letter = L" \t"); // return erased letters count
PORT_API(int) trim_right(char* str, const char* trim_letter = " \t"); // return erased letters count
PORT_API(int) trim_right(wchar_t* str, const wchar_t* trim_letter = L" \t"); // return erased letters count
// return whether replaced, maybe DATA_FLAG_ERROR if 'old' is a sub-string in rep when 'all' is true
// all string should ended with '\0'
PORT_API(bool) replace(const char* str, const char* old, const char* rep, inter_module_data::set_data result, void* param, bool all = true);
PORT_API(bool) replace(const wchar_t* str, const wchar_t* old, const wchar_t* rep, inter_module_data::set_data result, void* param, bool all = true);
// function: to pick the value between 'lead' and 'end' block.
// cont: the origin text
// lead: the leading mark
// end: the ending mark
// result: data - (const wchar_t*) or (const char*) value, without lead and rear mark
// len - data bytes
// total - found count
// flag - DATA_FLAG_FINAL
// param - same as the parameter 'param'
// first: to receive the beginning of the found value
// last: to receive the endding of the found value
// include_tag: picked result whether include the 'lead' and 'end' string
// case_sensitive: whether the lead and end are case sensitive
//
// return: found count, -1 is error
enum mark_layer
{
MARK_LAYER_FLAT = 1, // context formed as lead + val + end + ... + lead + val + end + ...
MARK_LAYER_EMBED, // context formed as lead + (lead + val + end) ... + end + ...
};
PORT_API(int) pick_value(const char* cont, const char* lead, const char* end, inter_module_data::set_data result, void* param, bool include_tag = false, bool case_sensitive = true, mark_layer layer = MARK_LAYER_EMBED);
PORT_API(int) pick_value(const char* cont, const char* lead, const char* end, int* first, int* last, bool include_tag = false, bool case_sensitive = true, mark_layer layer = MARK_LAYER_EMBED);
PORT_API(int) pick_value(const wchar_t* cont, const wchar_t* lead, const wchar_t* end, inter_module_data::set_data result, void* param, bool include_tag = false, bool case_sensitive = true, mark_layer layer = MARK_LAYER_EMBED);
PORT_API(int) pick_value(const wchar_t* cont, const wchar_t* lead, const wchar_t* end, int* first, int* last, bool include_tag = false, bool case_sensitive = true, mark_layer layer = MARK_LAYER_EMBED);
PORT_API(int) pick_first_branch_in_if_else_endif(const wchar_t* cont, const wchar_t* lead, const wchar_t* elif, const wchar_t* end, int* first, int* last, bool include_tag = false, bool case_sensitive = true);
// simple_line: consider followin lines
// line 1\
// -line 2
// true - return "line 1"
// false - return "line 1-line 2"
PORT_API(void) pick_line(const char* str, inter_module_data::set_data result, void* param, int* next_line = NULL, bool simple_line = false);
PORT_API(void) pick_line(const wchar_t* str, inter_module_data::set_data result, void* param, int* next_line = NULL, bool simple_line = false);
PORT_API(void) pick_whole_line(const char* cur, const char* bgn, inter_module_data::set_data result, void* param, int* next_line = NULL, bool simple_line = false);
PORT_API(void) pick_whole_line(const wchar_t* cur, const wchar_t* bgn, inter_module_data::set_data result, void* param, int* next_line = NULL, bool simple_line = false);
enum num_format
{
NUM_FMT_DECIMAL, // float/double
NUM_FMT_INTEGER, // int in decimal
NUM_FMT_BIN,
NUM_FMT_OCT,
NUM_FMT_HEX,
};
// function: to pick a number from string
// num_str: number string
// ret: to receive the ending point of the number
// nf: format of num_str
//
// return: all in double value, if nf is in BIN, OCT or HEX, this contains max 32-bits
// maybe return NON if num_str in DECIMAL or INTEGER
PORT_API(double) pick_number(const char* num_str, const char** ret = NULL, num_format nf = NUM_FMT_DECIMAL);
PORT_API(double) pick_number(const wchar_t* num_str, const wchar_t** ret = NULL, num_format nf = NUM_FMT_DECIMAL);
// function: to pick an integer from a number string
//
// remarks: if all digit is in [0, 9], then consider it as a decimal
// 0xnnn or nnnh: heximal
// nnno: oct
// nnnb: binary
// other: decimal
// return: -1 if failed
PORT_API(unsigned long long) pick_integer(const char* num_str, size_t bytes = 4);
PORT_API(unsigned long long) pick_integer(const wchar_t* num_str, size_t bytes = 4);
// following two apis replace the string in str buffer, and return ERROR_SUCCESS or ERROR_INSUFFICIENT_BUFFER
// all string should ended with '\0'
PORT_API(int) replace(char* str, size_t str_buf_len, const char* old, const char* _new, bool *rep);
PORT_API(int) replace(wchar_t* str, size_t str_buf_len, const wchar_t* old, const wchar_t* _new, bool *rep);
PORT_API(IBase64*) create_base64(void);
PORT_API(IBitsBuf*) create_bits_buffer(void);
// function: calculate md5
// return: md5_val, may be empty if the path_file is not accessible
PORT_API(char*) md5(const char* data, size_t len, char md5_val[MINI_BUF_LEN]);
PORT_API(char*) md5(const wchar_t* path_file, char md5_val[MINI_BUF_LEN]);
enum _aes_type_
{
AES_ECB = 1,
AES_CBC,
AES_OFB,
AES_CFB,
};
PORT_API(int) aes_encoding(const char* plain, size_t len, const char *iv, const char* pwd, inter_module_data::set_data result, void* param, int iv_len = 16, int pwd_len = 16, _aes_type_ type = AES_CBC);
PORT_API(int) aes_decoding(const char* cipher, size_t len, const char *iv, const char* pwd, inter_module_data::set_data result, void* param, int iv_len = 16, int pwd_len = 16, _aes_type_ type = AES_CBC);
// return 0 if success
PORT_API(int) lzw_encoding(const char* plain, size_t len, inter_module_data::set_data result, void* param);
PORT_API(int) lzw_decoding(const char* cipher, size_t len, inter_module_data::set_data result, void* param);
// wildcard matching ...
// str: to be compared string
// pattern: include '*' or '?', e.g. "*.bat"
PORT_API(bool) is_wildcard_match(const char* str, const char* pattern, int str_len = -1, int patt_len = -1);
PORT_API(bool) is_wildcard_match(const wchar_t* str, const wchar_t* pattern, int str_len = -1, int patt_len = -1);
// convert time to string like: "yyyy-mm-dd hh:mm:ss"
// NOTE: parameter 'tmprc' is valid only when 't' is ZERO
enum _time_precision
{
TIME_PRECISION_SECOND = 0,
TIME_PRECISION_MILLISECOND,
TIME_PRECISION_ms = TIME_PRECISION_MILLISECOND,
TIME_PRECISION_MICROSECOND,
TIME_PRECISION_us = TIME_PRECISION_MICROSECOND,
TIME_PRECISION_NANOSECOND,
TIME_PRECISION_ns = TIME_PRECISION_NANOSECOND,
};
enum _week
{
WEEK_DAY_NO = 0,
WEEK_DAY_CN,
WEEK_DAY_EN,
};
PORT_API(bool) local_time_2_string(char tm_str[MINI_BUF_LEN], _time_precision tmprc = TIME_PRECISION_SECOND, _week week = WEEK_DAY_NO, time_t t = 0);
PORT_API(bool) local_time_2_string(wchar_t tm_str[MINI_BUF_LEN], _time_precision tmprc = TIME_PRECISION_SECOND, _week week = WEEK_DAY_NO, time_t t = 0);
PORT_API(const wchar_t*) get_week_string(int day_of_week, bool chinese);
// convert string like "yyyy-mm-dd hh:mm:ss" to local time, return -1 is error
PORT_API(time_t) time_str_2_date_time(const char* tm_str);
PORT_API(time_t) time_str_2_date_time(const wchar_t* tm_str);
// version ...
// function: convert version '1.2.3.4' to 0x01020304
PORT_API(UINT64) version_string_2_int(const char* dot_version);
PORT_API(UINT64) version_string_2_int(const wchar_t* dot_version);
// return ver_buf
PORT_API(char*) version_string_from_int(UINT64 val, char ver_buf[MINI_BUF_LEN]);
PORT_API(wchar_t*) version_string_from_int(UINT64 val, wchar_t ver_buf[MINI_BUF_LEN]);
// return: 0 - equal; 1 - dot_version1 > dot_version2; -1 - dot_version1 < dot_version2
PORT_API(int) compare_version(const char* dot_version1, const char* dot_version2);
PORT_API(int) compare_version(const wchar_t* dot_version1, const wchar_t* dot_version2);
// file time
PORT_API(bool) file_time_2_time(FILETIME ft, time_t* t);
PORT_API(bool) file_time_from_time(time_t t, FILETIME* ft);
// convert the hex-string '12cdef' to [0x12, 0xcd, 0xef]
// return: ending position in hex_str after this
PORT_API(int) hex_string_2_bytes_seq(const char* hex_str, inter_module_data::set_data result, void* param, const char* omit = " \t\r\n");
PORT_API(int) hex_string_2_bytes_seq(const wchar_t* hex_str, inter_module_data::set_data result, void* param, const wchar_t* omit = L" \t\r\n");
// transferred char like '\r', '\n' ... 'ok' to receive whether transfered
PORT_API(char*) to_transfer_text(char trans_char, bool* ok); // return "\n" for '\n'
PORT_API(wchar_t*) to_transfer_text(wchar_t trans_char, bool* ok); // return L"\n" for L'\n
PORT_API(char) from_transfer_text(const char* trans_char, int* used_bytes, bool* ok); // return '\n' for "\n"
PORT_API(wchar_t) from_transfer_text(const wchar_t* trans_char, int* used_bytes, bool* ok); // return L'\n' for L"\n"
// create guid as "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}", return buf
wchar_t* create_guid(wchar_t buf[MINI_BUF_LEN * 2]);
};
namespace cxx_code
{
// function: to check a character is space or not
//
// parameter: ch - the character to be check
//
// return: whether the character 'ch' is a space
//
// NOTE: we assume the following characters spaces:
// ' ', '\r', '\n', '\t'
PORT_API(bool) is_space_char(wchar_t ch);
// function: skip the space character until valid character or ending
//
// parameter: codes - the cxx codes string
//
// pos - [in] starting pos to skip, [out] - the first none-space character position
//
// has_lrn - whether the spaces has '\n'
//
// return: whether any spaces has been skipped, i.e. the out pos is greater than in pos
//
// NOTE: space characters: ' '; '\t'; '\r'; '\n'
PORT_API(bool) skip_space(const wchar_t* codes, int* pos, bool *has_lrn = NULL);
// function: to check the character 'ch' is whether a valid leading character of a variable
PORT_API(bool) is_var_leading_char(wchar_t ch);
// function: to check the character 'ch' is whether a valid character of a variable
PORT_API(bool) is_var_char(wchar_t ch);
// return the line ending char '\n' position or ending position if no, support multi-line joint by '\\'
// str[ret] = L'\n' || str[ret] = 0
PORT_API(long) line_ending(const wchar_t* str, int bgn);
// find the next 'key' position in 'str', omit those in quotes or comments, return -1 when not found
PORT_API(long) next_key(const wchar_t* str, const wchar_t* key, int bgn = 0);
// return comment block beginning position (str[ret] = L'/'), -1 if not a comment block, start from *pos and set ending in pos when return
//
// pos when out will be the line ending (str[*pos] = L'\n') or the last '/' character of "/**/" block (str[*pos] = L'/')
PORT_API(long) comment_block(const wchar_t* str, int* pos);
// function: erase the comments in "/**/" or after "//"
//
// parameter: codes - the cxx codes string
//
// notify - data: (const wchar_t*)the codes string after erasing comments
//
// len: unused
//
// total: unused
//
// flag: always be DATA_FLAG_FINAL
//
// param: same as the parameter 'param' you passed in the function
//
// param - for callback 'notify' using
//
// return: nonsence
//
// NOTE: the last '\n' after the comments will be reserved
PORT_API(void) erase_comments(const wchar_t* codes, INTER_MODULE_CALLBACK_VAR(notify), void* param);
// function: pick a variable or function name
//
// parameter: codes - the cxx codes string
//
// pos - [in] starting pos, [out] - ending position after the last name character, or error position when failed
//
// digit - true to pick a digit, false to pick a variable
//
// return: the beginning of the name, -1 for error
PORT_API(int) pick_variable(const wchar_t* codes, int* pos, bool digit = false);
// function: pick a block between characters 'bgn_ch' and 'end_ch'
//
// parameter: codes - the cxx codes string
//
// pos - [in] starting pos, [out] - ending position after the last name character(codes[*pos] == 'end_ch'), or error position when failed
//
// bgn_ch - the beginning character of the block, e.g. '('
//
// end_ch - the ending character of the block, e.g. ')'
//
// single_line - whether the block will be a single line in commonplace, or else with '\\' at the line ending
//
// other_comment_leading_char - other sinle line comment leading character
//
// return: the beginning of the block (codes[ret] == 'bgn_ch'), -1 for error.
// failed also when single_line was true and meeting line-endig before 'end_ch'
//
// NOTE: this function will ommit the 'bgn_ch' and 'end_ch' which is after '\\' or in quotes "" or ''
PORT_API(int) pick_block(const wchar_t* codes, int* pos, wchar_t bgn_ch, wchar_t end_ch, bool single_line = false, wchar_t other_comment_leading_char = 0);
// function: pick a if-else codes block
//
// parameter: codes - the cxx codes string
//
// pos - [in] starting pos, [out] - ending position after the last name character, or error position when failed
//
// notify - to notify a picked branch
//
// data: (const wchar_t*)condition, "(...)", empty string if the last 'else' branch
//
// len: (const wchar_t*)entity, "{...}"
//
// total: unused, always be ZERO
//
// flag: always be DATA_FLAG_FINAL. no invoking if error occurs
//
// param: same as the parameter 'param' you passed in the function
//
// return: SET_RESULT_CONTINUE to continue, SET_RESULT_STOP to stop this invoking
//
// param - for callback 'notify' using
//
// other_comment_leading_char - other sinle line comment leading character
//
// return: the beginning of the block, -1 for error
//
// NOTE: first word must be "if"
PORT_API(int) pick_if_else_block(const wchar_t* codes, int* pos, INTER_MODULE_CALLBACK_VAR(notify), void* param, wchar_t other_comment_leading_char = 0);
// function: pick a #if-#endif codes block
//
// parameter: codes - the cxx codes string
//
// pos - [in] starting pos, [out] - ending position after the last name character, or error position when failed
//
// notify - to notify a picked branch
//
// data: (const wchar_t*)condition, empty string if the last 'else' branch
//
// len: (const wchar_t*)entity
//
// total: unused, always be ZERO
//
// flag: always be DATA_FLAG_FINAL. no invoking if error occurs
//
// param: same as the parameter 'param' you passed in the function
//
// return: SET_RESULT_CONTINUE to continue, SET_RESULT_STOP to stop this invoking
//
// param - for callback 'notify' using
//
// return: the beginning of the block, -1 for error
//
// NOTE: first word must be "#if"
PORT_API(int) pick_macro_if_else_block(const wchar_t* codes, int* pos, INTER_MODULE_CALLBACK_VAR(notify), void* param);
// function: pick a function block
//
// parameter: codes - the cxx codes string
//
// pos - [in] starting pos, [out] - ending position after the last '}', or error position when return false
//
// notify - data: (const wchar_t*)function name and pre_leading declaration
//
// len: parameters ending with double '\0'
//
// total: (const wchar_t*)function entity, leading with '{' and ending with '}'
//
// flag: always be DATA_FLAG_FINAL. no invoking if error occurs
//
// param: same as the parameter 'param' you passed in the function
//
// param - for callback 'notify' using
//
// other_comment_leading_char - other sinle line comment leading character
//
// return: true when success, and then the function elements is passed back by 'notify'
//
// NOTE: it will be without entity if it was a function invoking
PORT_API(bool) pick_function(const wchar_t* codes, int* pos, INTER_MODULE_CALLBACK_VAR(notify), void* param, wchar_t other_comment_leading_char = 0);
// function: to get the line number from offset 'pos'
//
PORT_API(unsigned) line_from_pos(const wchar_t* cont, unsigned pos);
// Function: to save and calculate a logical action result
//
// e.g.: set 'is_win' is 'true, then check 'is_win' will return true and '!is_win' is false
//
// NOTE: now support '||', '&&' and '!' operator and consider expression like 'i >= 0' as ONE variable
// this means every expression between '&&' and '||' will consider as ONE variable
//
__declspec(novtable) struct ILogicAction : public ref_util::IRef
{
// Function: to set the callback to query value when a variable is unknown
//
// get_variable_val: data - see 'inter_module_data::DATA_FLAG_GET_VAL'
//
// len - see 'inter_module_data::DATA_FLAG_GET_VAL'
//
// total - see 'inter_module_data::DATA_FLAG_GET_VAL'
//
// flag - always be DATA_FLAG_GET_VAL
//
// param - the same as 'param' in this function
//
// NOTE: all unknown variable would be considered as 'false' if you did not set the callback
// variable values has multi-strings format, and end with '\0' per value, double '\0' for all values
COM_API_DECLARE(void, set_callback(inter_module_data::set_data get_variable_val, void* param));
// Function: add or modify known boolean value
//
// var: boolean variable, multi-vars divided by ';'
//
COM_API_DECLARE(void, set_variable_value(const wchar_t* var, const wchar_t* val, int bytes = 0));
COM_API_DECLARE(void, set_variable_value(const wchar_t* var, bool val));
COM_API_DECLARE(void, remove_variable(const wchar_t* var));
COM_API_DECLARE(void, clear(void));
// Function: calculate logical expression such as 'is_win && is_android' ...
//
// logic_exp: logical expression, like 'is_win && is_android', '!is_win' ...
//
// supported: to receive whether the logic_exp is valid/supported now, return value would be nonsence if this was false
//
// return: boolean result. SEE 'supported' !!!
//
COM_API_DECLARE(bool, logic_expression_result(const wchar_t* logic_exp, bool* supported));
// Function: to query an logical expression value without user interacting
//
// Parameter: logic_expression - logical expression, like 'is_win && is_android', '!is_win' ...
//
// val - to receive the expression value if it was existing
//
// Return: whether the 'logic_expression' all are existing already (until calculate the result)
COM_API_DECLARE(bool, query_existing_value(const wchar_t* logic_exp, bool* val));
COM_API_DECLARE(inter_module_data::set_result, last_input_result(void));
// Function: get symbol's value. e.g. return L"1" of symbol_value(L"BUILD_TYPE", ...) if L"BUILD_TYPE=1" was existed
//
// return: value, NULL if not found. you should use it immediately, and need not free it.
COM_API_DECLARE(const wchar_t*, symbol_value(const wchar_t* symbol));
// save the logical-expressions to path_file which it is 'true'
COM_API_DECLARE(int, save(const wchar_t* path_file));
};
// logical action
PORT_API(ILogicAction*) create_logical_action(void);
}