// 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 and 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); }