// json.h : simple json parser/maker // // Author: Gongbing // // Date: 2016-07-12, rewrite on 2019-10-27 #pragma once #include #include #ifndef _INCLUDED_REF_ #define _INCLUDED_REF_ #include "../ref/ref.h" #endif namespace known_file_util { struct IJson; struct IJsonW; enum _json_type { JV_UNKNOWN = 0, JV_BOOL, JV_INT, JV_FLOAT, // JV_ARRAY, JV_STRING, JV_OBJECT, JV_UINT64, }; typedef struct _json_member { _json_type type; const char* key; union { void* nothing; // JV_UNKNOWN = 0, bool bool_val; // JV_BOOL, int int_val; // JV_INT, double double_val; // JV_FLOAT, const char* str_val; // JV_STRING, IJson* child; // JV_OBJECT, IJson or IJsonW value unsigned long long uint64_val; // JV_UINT64, }; }JSONMEM, *LPJSONMEM; typedef struct _json_member_w { _json_type type; const wchar_t *key; union { void* nothing; // JV_UNKNOWN = 0, bool bool_val; // JV_BOOL, int int_val; // JV_INT, double double_val; // JV_FLOAT, const wchar_t* str_val; // JV_STRING, IJsonW* child; // JV_OBJECT, IJson or IJsonW value unsigned long long uint64_val; // JV_UINT64, }; }JSONMEMW, *LPJSONMEMW; // NOTE: following interfaces, do NOTHING on transfer chars(no converting from '\n' to 0x0d, ...), user should transfer them yourself !!! __declspec(novtable) struct IJson : public ref_util::IRef { // function: parse a json string // json_str: string that in json format // start: [in] - the start position of json_str, start from 0 if it was NULL; [out] - the ending position when returned // return: true - success COM_API_DECLARE(bool, attach(const char* json_str, int* start = NULL)); COM_API_DECLARE(long, members(void)); // function: convert IJson object to plain text // callback - data: (const char*) // len: bytes of data // total: unused, always be ZERO // flag: always be inter_module_data::DATA_FLAG_FINAL // param: the same as you passed into the API as 'param' COM_API_DECLARE(void, to_string(inter_module_data::set_data result, void* param)); COM_API_DECLARE(const char*, key(void)); // 'val' to receive the key value, use it immediately and need not free // 'key' for get_xxx apis can include path, e.g. get_value("data\\school\\score", score) COM_API_DECLARE(bool, get_value(const char* key, bool& val)); COM_API_DECLARE(bool, get_value(const char* key, int& val)); COM_API_DECLARE(bool, get_value(const char* key, double& val)); COM_API_DECLARE(bool, get_value(const char* key, unsigned long long& val)); COM_API_DECLARE(bool, get_value(const char* key, IJson** val)); // you should call val->release() to free the returned object COM_API_DECLARE(bool, get_value(const char* key, const char** val)); // you should use the 'val' immediately, and need not free it! COM_API_DECLARE(void, clear(void)); COM_API_DECLARE(void, set_key(const char* key_str)); COM_API_DECLARE(bool, set_value(const char* key, bool val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const char* key, int val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const char* key, double val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const char* key, unsigned long long val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const char* key, const char* val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const char* key, IJson* val, bool insert_if_not_exist = true)); // you can call val->release COM_API_DECLARE(bool, set_value(int index, bool val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, int val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, double val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, unsigned long long val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, const char* val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, IJson* val, bool insert = false)); // you can call val->release COM_API_DECLARE(bool, remove_value(const char* key)); COM_API_DECLARE(bool, remove_value(int index)); COM_API_DECLARE(IJson*, first_child(void)); // call 'release()' on returned object after use COM_API_DECLARE(IJson*, next_child(void)); // call 'release()' on returned object after use // enum member, 'JV_UNKNOWN' will enum all members, all values but 'object' need not free // enumerating should stopped if returned JV_UNKNOWN !!! COM_API_DECLARE(JSONMEM, first_member(_json_type type = JV_UNKNOWN)); // call 'release()' on returned object after use COM_API_DECLARE(JSONMEM, next_member(void)); // call 'release()' on returned object after use COM_API_DECLARE(JSONMEM, operator[](int index)); // call 'release()' on returned object after use COM_API_DECLARE(bool, is_array(void)); // whether this object is an array // following apis only effect array COM_API_DECLARE(IJson*&, operator+=(bool val)); // *(IJson*) += true; COM_API_DECLARE(IJson*&, operator+=(int val)); // *(IJson*) += 100; COM_API_DECLARE(IJson*&, operator+=(double val)); // *(IJson*) += 100.0; COM_API_DECLARE(IJson*&, operator+=(unsigned long long val)); // *(IJson*) += (unsigned long long)100; COM_API_DECLARE(IJson*&, operator+=(const char* val)); // *(IJson*) += "array sub string"; COM_API_DECLARE(IJson*&, operator+=(known_file_util::IJson* val)); // *(IJson*) += (IJson*)child; COM_API_DECLARE(IJson*&, operator-=(int index)); // *(IJson*) -= 0; }; // unicode version of IJson, and transfer chars(convert from '\n' to 0x0d, ...) automately __declspec(novtable) struct IJsonW : public ref_util::IRef { // function: parse a json string // json_str: string that in json format // start: [in] - the start position of json_str, start from 0 if it was NULL; [out] - the ending position when returned // return: true - success COM_API_DECLARE(bool, attach(const wchar_t* json_str, int* start = NULL)); COM_API_DECLARE(long, members(void)); // function: convert IJson object to plain text // callback - data: (const wchar_t*) // len: bytes of data // total: unused, always be ZERO // flag: always be inter_module_data::DATA_FLAG_FINAL // param: the same as you passed into the API as 'param' // // tab - set this parameter to get formated text, or else get a compact text (not support now) COM_API_DECLARE(void, to_string(inter_module_data::set_data result, void* param, const wchar_t* tab = NULL)); COM_API_DECLARE(const wchar_t*, key(void)); // 'val' to receive the key value, use it immediately and need not free // 'key' for get_xxx apis can include path, e.g. get_value("data\\school\\score", score) COM_API_DECLARE(bool, get_value(const wchar_t* key, bool& val)); COM_API_DECLARE(bool, get_value(const wchar_t* key, int& val)); COM_API_DECLARE(bool, get_value(const wchar_t* key, double& val)); COM_API_DECLARE(bool, get_value(const wchar_t* key, unsigned long long& val)); COM_API_DECLARE(bool, get_value(const wchar_t* key, IJsonW** val)); // you should call val->release() to free the returned object COM_API_DECLARE(bool, get_value(const wchar_t* key, const wchar_t** val)); // you should use the 'val' immediately, and need not free it! COM_API_DECLARE(void, clear(void)); COM_API_DECLARE(bool, set_as_array(bool arr)); // set as JV_ARRAY, only effect when empty COM_API_DECLARE(void, set_key(const wchar_t* key_str)); COM_API_DECLARE(bool, set_value(const wchar_t* key, bool val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const wchar_t* key, int val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const wchar_t* key, double val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const wchar_t* key, unsigned long long val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const wchar_t* key, const wchar_t* val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, set_value(const wchar_t* key, IJsonW* val, bool insert_if_not_exist = true)); // you can call val->release COM_API_DECLARE(bool, set_value(int index, bool val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, int val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, double val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, unsigned long long val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, const wchar_t* val, bool insert = false)); // for array operation COM_API_DECLARE(bool, set_value(int index, IJsonW* val, bool insert = false)); // you can call val->release COM_API_DECLARE(bool, remove_value(const wchar_t* key)); COM_API_DECLARE(bool, remove_value(int index)); COM_API_DECLARE(IJsonW*, first_child(void)); // call 'release()' on returned object after use COM_API_DECLARE(IJsonW*, next_child(void)); // call 'release()' on returned object after use // enum member, 'JV_UNKNOWN' will enum all members, all values but 'object' need not free // enumerating should stopped if returned JV_UNKNOWN !!! COM_API_DECLARE(JSONMEMW, first_member(_json_type type = JV_UNKNOWN)); // call 'release()' on returned object after use COM_API_DECLARE(JSONMEMW, next_member(void)); // call 'release()' on returned object after use COM_API_DECLARE(JSONMEMW, operator[](int index)); // call 'release()' on returned object after use COM_API_DECLARE(bool, is_array(void)); // whether this object is an array // following apis only effect array COM_API_DECLARE(IJsonW*&, operator+=(bool val)); // *(IJsonW*) += true; COM_API_DECLARE(IJsonW*&, operator+=(int val)); // *(IJsonW*) += 100; COM_API_DECLARE(IJsonW*&, operator+=(double val)); // *(IJsonW*) += 100.0; COM_API_DECLARE(IJsonW*&, operator+=(unsigned long long val)); // *(IJsonW*) += (unsigned long long)100; COM_API_DECLARE(IJsonW*&, operator+=(const wchar_t* val)); // *(IJsonW*) += "array sub string"; COM_API_DECLARE(IJsonW*&, operator+=(known_file_util::IJsonW* val)); // *(IJsonW*) += (IJsonW*)child; COM_API_DECLARE(IJsonW*&, operator-=(int index)); // *(IJsonW*) -= 0; }; // xml parser enum _xml_clear_mask { XML_CLEAR_XML_CHILD = 0x01, XML_CLEAR_TEXT = 0x02, XML_CLEAR_ATTRIBUTES = 0x04, XML_CLEAR_TAG_NAME = 0x08, XML_CLEAR_ALL = -1, }; __declspec(novtable) struct IXmlW : public ref_util::IRef { // function: parse a XML string // xml_str: string that in XML format // start: [in] - the start position of xml_str, start from 0 if it was NULL; [out] - the ending position when returned // return: true - success COM_API_DECLARE(bool, attach(const wchar_t* xml_str, int* start = NULL)); COM_API_DECLARE(void, clear(int clear_mask = XML_CLEAR_ALL)); COM_API_DECLARE(void, set_tag_name(const wchar_t* name)); // for multiple elements with the same 'tag name' can be coexists, all path in following methods // only walk through the first matched element !!! // // e.g. // // // // // // // then call set_attribute(L"html\\meta\\link\\rel", L"icon", false) // or get_child(L"html\\meta\\link") would be failed // COM_API_DECLARE(bool, set_attribute(const wchar_t* attr_path, const wchar_t* attr_val, bool insert_if_not_exist = true)); COM_API_DECLARE(bool, remove_attribute(const wchar_t* attr_path)); // remove the first attribute named path matches 'attr_path' COM_API_DECLARE(bool, add_child(IXmlW* xml, int index = -1)); // function: to replace or add a text text // // parameter: text - the text to be set, clear if it was NULL // // replace - true to replace or clear the text with index 'index'; false to insert a new text at 'index' // // index - the index of the text element, -1 for all text elements when 'replace' was true, or the last element when 'replace' was false // // return: whether done // // NOTE: the index is in only in text children sequence when 'replace' was true, // and in all children sequence when 'replace' was false COM_API_DECLARE(bool, set_text(const wchar_t* text, bool replace = true, int index = -1)); // function: to add a child xml element // // parameter: name - tag name of the element // // attrs - attributes name list, ending with double '\0' // // attr_vals - attributes value list, ending with double '\0', must ONE-to-ONE to attrs // // simple_text - plain text of the element // // index - the inserting position of the element // // return: the new element, you should call 'release' whenever use it // // NOTE: this create a simple xml element: simple_text COM_API_DECLARE(IXmlW*, create_child(const wchar_t* name, const wchar_t* attrs = NULL, const wchar_t* attr_vals = NULL, const wchar_t* simple_text = NULL, int index = -1)); COM_API_DECLARE(bool, remove_child(IXmlW* xml)); COM_API_DECLARE(bool, remove_child(int index)); COM_API_DECLARE(void, set_single_line(bool single_line)); // set single line if has no children when call 'to_string' // whether this object is comment or plain text such as scripts ... COM_API_DECLARE(bool, is_plain_text(void)); COM_API_DECLARE(bool, is_single_line(void)); // whether output single line if has no children when call 'to_string' COM_API_DECLARE(int, child_index(IXmlW* child)); // access ... // function: convert IJson object to plain text // callback - data: (const char*)a BOM string (with BOM head) // len: bytes of data // total: unused, always be ZERO // flag: always be inter_module_data::DATA_FLAG_FINAL // param: the same as you passed into the API as 'param' // with_xml_tag - whether add "" at beginning // tab - to specify the indentation of every child COM_API_DECLARE(void, to_string(inter_module_data::set_data result, void* param, bool with_xml_tag = true, const wchar_t* tab = L" ")); COM_API_DECLARE(void, parse_displaying_text(const wchar_t* xml_text, inter_module_data::set_data result, void* param)); // data: (const wchar_t*) COM_API_DECLARE(const wchar_t*, get_tag_name(void)); COM_API_DECLARE(bool, get_attribute(const wchar_t* attr_path, const wchar_t** val)); COM_API_DECLARE(bool, get_text(const wchar_t** val, int index = 0)); // return 'text' in this formal: text // attributes ... COM_API_DECLARE(long, attributes(void)); COM_API_DECLARE(bool, has_attribute(const wchar_t* name)); COM_API_DECLARE(bool, first_attribute(const wchar_t** name, const wchar_t** val)); COM_API_DECLARE(bool, next_attribute(const wchar_t** name, const wchar_t** val)); // children ... COM_API_DECLARE(long, children(void)); COM_API_DECLARE(IXmlW*, get_child(const wchar_t* child_path)); // call 'release' to free the return value COM_API_DECLARE(IXmlW*, get_child(int index)); // call 'release' to free the return value // function: enumerating children, not finding recursive // // parameter: tag - tag name of the child // // attr - attribute names of the child, ending with double '\0' // // attr_val - attribute values of the child, ONE-to-ONE to 'attr', ending with double '\0' // // return: the child pointer, call 'release' to free it after use // // NOTE: return the first matches the conditions child COM_API_DECLARE(IXmlW*, first_child(const wchar_t* tag = NULL, const wchar_t* attr = NULL, const wchar_t* attr_val = NULL)); COM_API_DECLARE(IXmlW*, next_child(const wchar_t* tag = NULL, const wchar_t* attr = NULL, const wchar_t* attr_val = NULL)); }; // the parameter 'start' can receive the error point if the 'data' was invalid PORT_API(IJson*) create_json(const char* data = NULL, int* start = NULL); PORT_API(IJsonW*) create_jsonW(const wchar_t* data = NULL, int* start = NULL); PORT_API(IXmlW*) create_xmlW(const wchar_t* data = NULL, int* start = NULL); PORT_API(void) trans_from_xml_string(const wchar_t* xml, INTER_MODULE_CALLBACK_VAR(result), void* param); }