├── 3rdparty └── unzip.cpp ├── LICENSE ├── README.md └── include └── FawLib ├── Directory.hpp ├── Encoding.hpp ├── FawLib.hpp ├── File.hpp ├── Process.hpp ├── Register.hpp ├── SetupHelper.hpp ├── String.hpp ├── ThreadPool.hpp └── unzip.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 fawdlstty 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FawLib 2 | 3 | C++公共支持库,目前包括编码转换类、字符串处理类、文件类、目录类、注册表类与安装包类。 4 | 5 | ## 使用说明 6 | 7 | ### 编码处理类 faw::Encoding 8 | 9 | 这个类是一个静态类,无需实例化,只在需要时调用静态方法即可。 10 | 11 | 这个类首先提供了猜测编码功能,可以猜测一串文本是否是ASCII、UTF8、GB18030或UTF16编码。使用方式为: 12 | 13 | ```cpp 14 | std::string_view _data = "xxx"; // 或者从文件中读取等等... 15 | std::string _encoding = faw::Encoding::guess (_data); 16 | if (_encoding == "utf8" || _encoding == "ascii") { 17 | // 能够以utf8方式来解析文本数据 18 | } else if (_encoding == "gb18030" || _encoding == "ascii") { 19 | // 能够以gb18030方式来解析文本数据 20 | } else if (_encoding == "utf16") { 21 | // 能够以utf16方式来解析文本数据 22 | } 23 | ``` 24 | 25 | 另外也能以单独的方式来判断文本数据是否是某个编码: 26 | 27 | ```cpp 28 | std::string_view _data = "xxx"; // 或者从文件中读取等等... 29 | if (faw::Encoding::is_ascii (_data)) { 30 | // 能够以ASCII、utf8或GB18030方式来解析文本数据 31 | } else if (faw::Encoding::is_utf8 (_data)) { 32 | // 能够以utf8方式来解析文本数据 33 | } else if (faw::Encoding::is_gb18030 (_data)) { 34 | // 能够以gb18030方式来解析文本数据 35 | } else if (faw::Encoding::is_utf16 (_data)) { 36 | // 能够以utf16方式来解析文本数据 37 | } 38 | ``` 39 | 40 | 除了能判断文本数据编码以外,还能判断是否是某种转码方式: 41 | 42 | ```cpp 43 | std::string_view _data = "xxx"; // 或者从文件中读取等等... 44 | if (faw::Encoding::is_percent_str (_data)) { 45 | // %23%E5%FA 46 | } else if (faw::Encoding::is_escape_x_str (_data)) { 47 | // \xBB\xD2\x2A 48 | } else if (faw::Encoding::is_escape_u_str (_data)) { 49 | // \u6f73\u23BE 50 | } else if (faw::Encoding::is_base64_str (_data)) { 51 | // Ga7dX83PdQfnua== 52 | } 53 | ``` 54 | 55 | 接下来是编码的转换。提供gb18030、utf8、utf16三种编码的完整的互相转换函数,比如: 56 | 57 | ```cpp 58 | std::wstring _s = faw::Encoding::gb18030_to_utf16 ("test"); 59 | ``` 60 | 61 | 相应的把xx_to_xx里面的xx替换为相应的编码方式即可。除此之外还提供了T编码类型,这种类型根据编译方式为多字节或unicode编译方式动态确定为gb18030或utf16,相应的在编码方式位置写上T即可。 62 | 63 | 然后,此类还提供了常用转码格式的转换函数。 64 | 65 | ```cpp 66 | // %23%E5%FA 67 | // percent/URL 编码转码函数 68 | std::string _encoded = faw::Encoding::percent_str_encode ("测试"); 69 | std::string _decoded = faw::Encoding::percent_str_decode (_encoded); 70 | 71 | // \xBB\xD2\x2A 72 | // escape_x 编码转码函数 73 | _encoded = faw::Encoding::escape_x_str_encode (_decoded); 74 | _decoded = faw::Encoding::escape_x_str_decode (_encoded); 75 | 76 | // \u6f73\u23BE 77 | // escape_u 编码转码函数 78 | _encoded = faw::Encoding::escape_u_str_encode (_decoded); 79 | _decoded = faw::Encoding::escape_u_str_decode (_encoded); 80 | 81 | // Ga7dX83PdQfnua== 82 | // Base64 编码转码函数 83 | _encoded = faw::Encoding::base64_encode (_decoded); 84 | _decoded = faw::Encoding::base64_decode (_encoded); 85 | ``` 86 | 87 | ### 字符串类 faw::String 88 | 89 | 这个类是一个及其简洁的字符串处理类,通过集成编码转码方法,使其可以更加方便的用于几乎所有的场合。不过需要注意的是,它内部是通过std::basic_string类实现,因此它是线程不安全的,使用前请注意。这个类内部会维护一个字符串,维护的字符串以多字节或unicode编译方式动态确定为gb18030或utf16。由于这两种不同编码都能参与字符串类的运算,因此使用当前编码类型的字符串来进行计算能发挥出最大性能。比如_T ("") 90 | 91 | 首先是生成faw::String对象。gb18030字符串和utf16字符串可以直接传入。以下代码中生成的字符串全部完全等价。 92 | 93 | 其中,多字节编译时,s1、s3、s5、s7效率高,因为构造时不用转码;同理,unicode编译时,s2、s4、s6、s8效率高。 94 | 95 | s7、s8只看右边部分。它俩只在C++17上支持,默认在编译时,类型就是faw::String,因此声明类型可以填auto。 96 | 97 | s9、s10均为拷贝字符串,当std::basic_string规则为COW时,拷贝0开销,第一次修改时承受拷贝开销;当std::basic_string规则为SSO时,拷贝承受所有开销,第一次修改时不受其他影响。(这一行不懂没关系,跳过就好) 98 | 99 | ```cpp 100 | faw::String s1 { "abc" }; 101 | faw::String s2 { L"abc" }; 102 | faw::String s3 ( "abc" ); 103 | faw::String s4 ( L"abc" ); 104 | faw::String s5 = "abc"; 105 | faw::String s6 = L"abc"; 106 | faw::String s7 = "abc"_fs; 107 | faw::String s8 = L"abc"_fs; 108 | faw::String s9 (s1); 109 | faw::String s10 (&s1); 110 | ``` 111 | 112 | 然后是“等号=”赋值(+=赋值支持类型与=赋值完全相同,在此不列出代码): 113 | 114 | ```cpp 115 | faw::String s1 = "abc"_fs; 116 | faw::String s2 = L"abc"_fs; 117 | faw::String s3 = s1; 118 | faw::String s4 = &s1; 119 | faw::String s5 = "abc"; 120 | faw::String s6 = L"abc"; 121 | faw::String s7 = std::string ("abc"); 122 | faw::String s8 = std::wstring (L"abc"); 123 | faw::String s9 = std::string_view ("abc"); 124 | faw::String s10 = std::wstring_view (L"abc"); 125 | ``` 126 | 127 | 另外可以这样,完全不考虑编码方式的随意使用: 128 | 129 | ```cpp 130 | faw::String s = "abc"; 131 | s += L"123"; 132 | // 此时s值为 _T ("abc123") 133 | ``` 134 | 135 | 136 | 接下来是+运算符,支持左+、右+,受支持运算类型与=、+=相同,因此不再列出代码。+运算不改变操作数,表达式最终会生成一个新的faw::Sring。 137 | 138 | 字符串类支持*、*=操作,使用方式和python一样,也就是相同的字符串循环多少次: 139 | 140 | ```cpp 141 | String s = "a"; 142 | s *= 10; 143 | // 此时s值为 _T ("aaaaaaaaaa") 144 | ``` 145 | 146 | 然后是字符串比较,gb18030和utf16编码都可以直接比较,受比较字符串的支持类型与+运算符支持类型相同,在此不全部列出。示例如下: 147 | 148 | ```cpp 149 | // 区分大小写的比较 150 | String s = "abc"; 151 | bool b1 = (s == "abc"); // true 152 | bool b2 = (s.is_equal (L"abc")); // true 153 | 154 | // 不区分大小写的比较 155 | bool b3 = s.is_equal_nocase ("Abc"); // true 156 | ``` 157 | 158 | 然后是迭代器,支持如下函数:begin、end、cbegin、cend、rbegin、rend、crbegin、crend,使用方式与std::basic_string相同。示例: 159 | 160 | ```cpp 161 | // 以下代码的输出结果为,a、b、c各占一行 162 | // (只有当类实现了begin和end函数,才支持for-range操作) 163 | faw::String s1 = "abc"; 164 | for (auto c: s1) { 165 | std::cout << (char) c << '\n'; 166 | } 167 | ``` 168 | 169 | 然后是字符串流的处理。这部分比较有意思的地方在于,很容易实现浮点数等的转换。另外规则是,<<、>>指向代表数据流动方向,faw::String对象在数据流运算的左侧、右侧分别代表对字符串最前、最后的操作。其中两个faw::String字符串类型的流运算很容易出现歧义,因此两个这种字符串类型就不能使用流运算符。 170 | 171 | ```cpp 172 | faw::String s1 = "12abc"; 173 | s1 << _T ('d'); // 此时字符串内容为 12abcd 174 | _T ('-') >> s1; // 此时字符串内容为 -12abcd 175 | s1 << "123"; // 此时字符串内容为 -12abcd123 176 | int i = 0; 177 | s1 >> i; // 此时字符串内容为 -12abcd,i内容为123 178 | i << s1; // 此时字符串内容为 abcd,i内容为-12 179 | ``` 180 | 181 | 然后是一些零散的函数,部分源于STL,不过删掉了很多几乎没用的重载函数;其他的用法也很像其他高级语言。杂项函数有: 182 | 183 | 1. 查找函数:find、rfind 184 | 2. 生成新字符串函数:trim_left、trim_right、trim、upper、lower、reverse、replace 185 | 3. 修改自身字符串函数:trim_left_self、trim_right_self、trim_self、upper_self、lower_self、reverse_self、replace_self 186 | 4. 字符串其他基本方法:empty、clear、free、size、operator[]、c_str、str(返回string_t&)、str_view(返回string_view_t)、stra(返回std::string)、strw(返回std::wstring)、match_regex(传入正则就可以返回匹配内容) 187 | 5. split(传入分隔符,返回std::vector<faw::String>) 188 | 6. 静态函数format,用于生成一个新的faw::String字符串。 189 | -------------------------------------------------------------------------------- /include/FawLib/Directory.hpp: -------------------------------------------------------------------------------- 1 | #//////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: Directory 4 | // Description: 文件夹类 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: May 16, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__DIRECTORY_HPP__ 14 | #define FAWLIB__DIRECTORY_HPP__ 15 | 16 | 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #pragma comment (lib, "DbgHelp.lib") 23 | #include 24 | #pragma comment (lib, "shell32.lib") 25 | 26 | #include "String.hpp" 27 | #include "File.hpp" 28 | 29 | 30 | 31 | namespace faw { 32 | class Directory { 33 | Directory () {} 34 | public: 35 | static bool exist (String _path) { 36 | DWORD _attr = ::GetFileAttributes (_path.c_str ()); 37 | return (_attr != INVALID_FILE_ATTRIBUTES && _attr & FILE_ATTRIBUTE_DIRECTORY); 38 | } 39 | static void remove (String _path) { 40 | if (_path.at (-1) == _T ('/') || _path.at (-1) == _T ('\\')) 41 | _path = _path.left (_path.size () - 1); 42 | ::RemoveDirectory (_path.c_str ()); 43 | } 44 | static void remove_nonempty (String _path) { 45 | if (_path.empty ()) 46 | return; 47 | String _path_find = append_folder_or_file (_path, _T ("*")); 48 | WIN32_FIND_DATA wfd { 0 }; 49 | HANDLE hFind = ::FindFirstFile (_path_find.c_str (), &wfd); 50 | if (hFind == INVALID_HANDLE_VALUE) 51 | return; 52 | do { 53 | String _dest { wfd.cFileName }; 54 | if (_dest == _T (".") || _dest == _T ("..")) 55 | continue; 56 | _dest = append_folder_or_file (_path, _dest); 57 | if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 58 | remove_nonempty (_dest); 59 | } else { 60 | File::remove (_dest); 61 | } 62 | } while (::FindNextFile (hFind, &wfd)); 63 | remove (_path); 64 | } 65 | static bool create (String _path, DWORD _attr = 0) { 66 | //bool bRet = (exist (_path) ? true : !!::CreateDirectory (_path.c_str (), NULL)); 67 | //if (bRet) { 68 | // _attr &= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_NORMAL); 69 | // if (_attr) 70 | // ::SetFileAttributes (_path.c_str (), _attr); 71 | //} 72 | //return bRet; 73 | _path.replace_self (_T ('/'), _T ('\\')); 74 | if (_path.at (-1) != _T ('\\')) 75 | _path += _T ('\\'); 76 | bool bRet = !!::MakeSureDirectoryPathExists (_path.stra ().c_str ()); 77 | if (bRet && _attr) { 78 | //DWORD _attr_old = ::GetFileAttributes (_path.c_str ()); 79 | _attr &= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_NORMAL); 80 | ::SetFileAttributes (_path.c_str (), _attr | FILE_ATTRIBUTE_DIRECTORY); 81 | } 82 | return bRet; 83 | } 84 | static String get_subpath (String _path) { 85 | size_t _p = _path.rfind_any ({ _T ('/'), _T ('\\') }); 86 | if (_p == _path.size () - 1) { 87 | _path.left_self (_path.size () - 1); 88 | _p = _path.rfind_any ({ _T ('/'), _T ('\\') }); 89 | } 90 | if (_p == String::_npos) 91 | return _T (""); 92 | return _path.substr (0, _p + 1); 93 | } 94 | static String get_filename (String _path) { 95 | size_t _p = _path.rfind_any ({ _T ('/'), _T ('\\') }); 96 | if (_p == String::_npos) 97 | return _path; 98 | return _path.substr (_p + 1); 99 | } 100 | static String get_last_folder (String _path) { 101 | size_t _p = _path.rfind_any ({ _T ('/'), _T ('\\') }); 102 | if (_p == _path.size () - 1) { 103 | _path.left_self (_path.size () - 1); 104 | _p = _path.rfind_any ({ _T ('/'), _T ('\\') }); 105 | } 106 | if (_p == String::_npos) 107 | return _path; 108 | return _path.substr (_p + 1); 109 | } 110 | static String get_current_file () { 111 | String _s { ::GetCommandLine () }; 112 | TCHAR _end_ch = _T (' '); 113 | if (_s[0] == _T ('"')) 114 | _end_ch << _s; 115 | return _s.left (_s.find (_end_ch)); 116 | } 117 | static String get_current_path () { 118 | String _s = get_current_file (); 119 | size_t _p = _s.rfind_any ({ _T ('/'), _T ('\\') }); 120 | return _s.left (_p + 1); 121 | } 122 | static String get_current_file1 (HMODULE hModule) { 123 | TCHAR buf [MAX_PATH] = { 0 }; 124 | ::GetModuleFileName (hModule, buf, MAX_PATH); 125 | String _s { buf }; 126 | TCHAR _end_ch = _T (' '); 127 | if (_s [0] == _T ('"')) 128 | _end_ch << _s; 129 | return _s.left (_s.find (_end_ch)); 130 | } 131 | static String get_current_path1 (HMODULE hModule) { 132 | String _s = get_current_file1 (hModule); 133 | size_t _p = _s.rfind_any ({ _T ('/'), _T ('\\') }); 134 | return _s.left (_p + 1); 135 | } 136 | static String append_folder_or_file (String _path, String _dest) { 137 | String s { _path }; 138 | if (s.rfind_any ({ _T ('/'), _T ('\\') }) != s.size () - 1) 139 | s += _T ('\\'); 140 | s += _dest; 141 | return s; 142 | } 143 | static String get_temp_file (String _file) { 144 | TCHAR _buf [MAX_PATH], _buf2 [MAX_PATH]; 145 | _buf [0] = _buf2 [0] = _T ('\0'); 146 | if (!::GetTempPath (MAX_PATH, _buf)) 147 | lstrcpy (_buf, _T ("D:\\")); 148 | if (!::GetFullPathName (_buf, MAX_PATH, _buf2, nullptr)) 149 | lstrcpy (_buf2, _T ("D:\\")); 150 | return append_folder_or_file (_buf, _file); 151 | } 152 | static void show_path (String path) { 153 | path.replace_self (_T ('/'), _T ('\\')); 154 | String cmd = String::format (_T ("/select,\"%s\""), path.c_str ()); 155 | ::ShellExecute (NULL, _T ("open"), _T ("explorer.exe"), cmd.c_str (), nullptr, SW_SHOW); 156 | } 157 | 158 | }; 159 | } 160 | 161 | 162 | 163 | #endif //FAWLIB__DIRECTORY_HPP__ 164 | -------------------------------------------------------------------------------- /include/FawLib/Encoding.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: Encoding 4 | // Description: 编码转换类 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: Apr 02, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__ENCODING_HPP__ 14 | #define FAWLIB__ENCODING_HPP__ 15 | 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #ifndef _FAW_STRING_TYPE 23 | #define _FAW_STRING_TYPE 24 | namespace faw { 25 | #ifdef UNICODE 26 | typedef ::std::wstring string_t; 27 | #else 28 | typedef ::std::string string_t; 29 | #endif 30 | } 31 | #if _HAS_CXX17 32 | #include 33 | namespace faw { 34 | #ifdef UNICODE 35 | typedef ::std::wstring_view string_view_t; 36 | #else 37 | typedef ::std::string_view string_view_t; 38 | #endif 39 | } 40 | #else 41 | namespace std { 42 | typedef string string_view; 43 | typedef wstring wstring_view; 44 | } 45 | namespace faw { 46 | typedef string_t string_view_t; 47 | } 48 | #endif 49 | #endif //_USE_STRING_VIEW 50 | 51 | 52 | 53 | namespace faw { 54 | class Encoding { 55 | Encoding () {} 56 | public: 57 | // 编码猜测 58 | static std::string guess (std::string_view data) { 59 | if (is_ascii (data)) { 60 | return "ascii"; 61 | } else if (is_utf8 (data)) { 62 | return "utf8"; 63 | } else if (is_gb18030 (data)) { 64 | return "gb18030"; 65 | } else if (is_utf16 (data)) { 66 | return "utf16"; 67 | } else { 68 | return "iso-8859-1"; 69 | } 70 | } 71 | static bool is_ascii (std::string_view data) { 72 | for (size_t i = 0; i < data.size (); ++i) { 73 | if (data[i] & 0x80) 74 | return false; 75 | } 76 | return true; 77 | } 78 | static bool is_utf8 (std::string_view data) { 79 | auto high_len = [] (unsigned char ch) { 80 | int _len = 0; 81 | while (ch & 0x80) { 82 | ++_len; 83 | ch <<= 1; 84 | } 85 | return _len; 86 | }; 87 | int state = 0; 88 | for (size_t i = 0; i < data.size (); ++i) { 89 | int _len = high_len (data[i]); 90 | if (state > 0) { 91 | if (_len != 1) 92 | return false; 93 | --state; 94 | } else if (_len == 1) { 95 | return false; 96 | } else if (_len > 1) { 97 | state = _len - 1; 98 | } 99 | } 100 | return (state == 0); 101 | } 102 | static bool is_gb18030 (std::string_view data) { 103 | int state = 0; 104 | for (size_t i = 0; i < data.size (); ++i) { 105 | if (data[i] & 0x80) { 106 | state = 1 - state; 107 | } else if (state == 1) { 108 | return false; 109 | } 110 | } 111 | return true; 112 | } 113 | static bool is_utf16 (std::string_view data) { 114 | if (data.size () % 2) 115 | return false; 116 | for (size_t i = 0; i < data.size (); i += 2) { 117 | if ((data[i] & 0x80) != (data[i + 1] & 0x80)) 118 | return false; 119 | } 120 | return true; 121 | } 122 | static bool is_percent_str (std::string_view data) { 123 | bool ret = false; 124 | for (size_t i = 0; i < data.size (); ++i) { 125 | if (data[i] == '%') { 126 | if (i + 1 >= data.size ()) 127 | return false; 128 | if (data[++i] == '%') 129 | continue; 130 | if (i + 1 >= data.size ()) 131 | return false; 132 | if (!_is_hex_char (data[i])) 133 | return false; 134 | if (!_is_hex_char (data[++i])) 135 | return false; 136 | ret = true; 137 | } 138 | } 139 | return ret; 140 | } 141 | static bool is_percent_str (std::wstring_view data) { 142 | return is_percent_str (utf16_to_utf8 (data)); 143 | } 144 | static bool is_escape_x_str (std::string_view data) { 145 | bool ret = false; 146 | for (size_t i = 0; i < data.size (); ++i) { 147 | if (data[i] == '\\') { 148 | if (i + 1 >= data.size ()) 149 | return false; 150 | if (data[++i] == '\\') 151 | continue; 152 | if (data[i] != 'x') 153 | continue; 154 | if (i + 2 >= data.size ()) 155 | return false; 156 | if (!_is_hex_char (data[++i])) 157 | return false; 158 | if (!_is_hex_char (data[++i])) 159 | return false; 160 | ret = true; 161 | } 162 | } 163 | return ret; 164 | } 165 | static bool is_escape_x_str (std::wstring_view data) { 166 | return is_escape_x_str (utf16_to_utf8 (data)); 167 | } 168 | static bool is_escape_u_str (std::string_view data) { 169 | bool ret = false; 170 | for (size_t i = 0; i < data.size (); ++i) { 171 | if (data[i] == '\\') { 172 | if (i + 1 >= data.size ()) 173 | return false; 174 | if (data[++i] == '\\') 175 | continue; 176 | if (data[i] != 'u') 177 | continue; 178 | if (i + 4 >= data.size ()) 179 | return false; 180 | if (!_is_hex_char (data[++i])) 181 | return false; 182 | if (!_is_hex_char (data[++i])) 183 | return false; 184 | if (!_is_hex_char (data[++i])) 185 | return false; 186 | if (!_is_hex_char (data[++i])) 187 | return false; 188 | ret = true; 189 | } 190 | } 191 | return ret; 192 | } 193 | static bool is_escape_u_str (std::wstring_view data) { 194 | return is_escape_u_str (utf16_to_utf8 (data)); 195 | } 196 | static bool is_base64_str (std::string_view data) { 197 | for (size_t i = 0; i < data.size (); ++i) { 198 | if (!_is_base64_char (data[i])) { 199 | if (i < data.size () - 2 || data[i] != '=') 200 | return false; 201 | } 202 | } 203 | return true; 204 | } 205 | static bool is_base64_str (std::wstring_view data) { 206 | return is_base64_str (utf16_to_utf8 (data)); 207 | } 208 | 209 | // 编码转换 210 | static std::wstring gb18030_to_utf16 (std::string_view _old) { return _conv_to_wide (_old, CP_ACP); } 211 | static std::string utf16_to_gb18030 (std::wstring_view _old) { return _conv_to_multi (_old, CP_ACP); } 212 | static std::wstring utf8_to_utf16 (std::string_view _old) { return _conv_to_wide (_old, CP_UTF8); } 213 | static std::string utf16_to_utf8 (std::wstring_view _old) { return _conv_to_multi (_old, CP_UTF8); } 214 | static std::string gb18030_to_utf8 (std::string_view _old) { return utf16_to_utf8 (gb18030_to_utf16 (_old)); } 215 | static std::string utf8_to_gb18030 (std::string_view _old) { return utf16_to_gb18030 (utf8_to_utf16 (_old)); } 216 | #ifdef UNICODE 217 | static std::string T_to_gb18030 (string_view_t _old) { return utf16_to_gb18030 (_old); } 218 | static std::string T_to_utf8 (string_view_t _old) { return utf16_to_utf8 (_old); } 219 | static std::wstring T_to_utf16 (string_view_t _old) { return std::wstring (_old); } 220 | static string_t gb18030_to_T (std::string_view _old) { return gb18030_to_utf16 (_old); } 221 | static string_t utf8_to_T (std::string_view _old) { return utf8_to_utf16 (_old); } 222 | static string_t utf16_to_T (std::wstring_view _old) { return string_t (_old); } 223 | #else 224 | static std::string T_to_gb18030 (string_view_t _old) { return std::string (_old); } 225 | static std::string T_to_utf8 (string_view_t _old) { return gb18030_to_utf8 (_old); } 226 | static std::wstring T_to_utf16 (string_view_t _old) { return gb18030_to_utf16 (_old); } 227 | static string_t gb18030_to_T (std::string_view _old) { return string_t (_old); } 228 | static string_t utf8_to_T (std::string_view _old) { return utf8_to_gb18030 (_old); } 229 | static string_t utf16_to_T (std::wstring_view _old) { return utf16_to_gb18030 (_old); } 230 | #endif 231 | private: 232 | static std::string _conv_to_multi (std::wstring_view _old, UINT ToType) { 233 | int lenOld = lstrlenW (_old.data ()); 234 | int lenNew = ::WideCharToMultiByte (ToType, 0, _old.data (), lenOld, nullptr, 0, nullptr, nullptr); 235 | std::string s; 236 | s.resize (lenNew); 237 | if (!::WideCharToMultiByte (ToType, 0, _old.data (), lenOld, const_cast(s.c_str ()), lenNew, nullptr, nullptr)) 238 | return ""; 239 | return s.c_str (); 240 | } 241 | static std::wstring _conv_to_wide (std::string_view _old, UINT ToType) { 242 | int lenOld = lstrlenA (_old.data ()); 243 | int lenNew = ::MultiByteToWideChar (ToType, 0, _old.data (), lenOld, nullptr, 0); 244 | std::wstring s; 245 | s.resize (lenNew); 246 | if (!::MultiByteToWideChar (ToType, 0, _old.data (), lenOld, const_cast(s.c_str ()), lenNew)) 247 | return L""; 248 | return s.c_str (); 249 | } 250 | static bool _is_hex_char (char ch) { 251 | return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'); 252 | } 253 | static bool _is_base64_char (char ch) { 254 | return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '+' || ch == '/'; 255 | } 256 | static char hex_char_to_dec (char ch) { 257 | if (ch >= '0' && ch <= '9') { 258 | return ch - '0'; 259 | } else if (ch >= 'A' && ch <= 'F') { 260 | return ch - 'A' + 10; 261 | } else if (ch >= 'a' && ch <= 'f') { 262 | return ch - 'a' + 10; 263 | } else { 264 | return 0; 265 | } 266 | } 267 | 268 | public: 269 | // 转码格式转换 270 | static faw::string_t percent_str_encode (faw::string_view_t data) { 271 | std::string _data = T_to_utf8 (data); 272 | static LPCSTR hex_char = "0123456789ABCDEF"; 273 | std::string ret = ""; 274 | for (size_t i = 0; i < _data.size (); ++i) { 275 | char ch = _data [i]; 276 | if (isalnum ((unsigned char) ch) || ch == '-' || ch == '_' || ch == '.' || ch == '~') { 277 | ret += ch; 278 | } else if (ch == ' ') { 279 | ret += "+"; 280 | } else { 281 | ret += '%'; 282 | ret += hex_char[(0xf0 & (uint32_t) ch) >> 4]; 283 | ret += hex_char[0xf & (uint32_t) ch]; 284 | } 285 | } 286 | return utf8_to_T (ret); 287 | } 288 | static faw::string_t percent_str_decode (faw::string_view_t data) { 289 | std::string _data = T_to_utf8 (data); 290 | std::string ret = ""; 291 | for (size_t i = 0; i < _data.size (); ++i) { 292 | char ch = _data [i]; 293 | if (ch == '%') { 294 | ret += (char) ((hex_char_to_dec (_data [i + 1]) << 4) | hex_char_to_dec (_data [i + 2])); 295 | i += 2; 296 | } else { 297 | ret += ch; 298 | } 299 | } 300 | return utf8_to_T (ret); 301 | } 302 | static faw::string_t escape_x_str_encode (faw::string_view_t data) { 303 | std::string _data = T_to_utf8 (data); 304 | static LPCSTR hex_char = "0123456789ABCDEF"; 305 | std::string ret = ""; 306 | for (size_t i = 0; i < _data.size (); ++i) { 307 | TCHAR ch = _data [i]; 308 | if ((ch >= 0x20 && ch <= 0x7e) || ch == '\x09' || ch == '\x0a' || ch == '\x0b' || ch == '\x0d') { 309 | ret += ch; 310 | } else { 311 | ret += "\\x"; 312 | ret += hex_char[(0xf0 & (uint32_t) ch) >> 4]; 313 | ret += hex_char[0xf & (uint32_t) ch]; 314 | } 315 | } 316 | return utf8_to_T (ret); 317 | } 318 | static faw::string_t escape_x_str_decode (faw::string_view_t data) { 319 | std::string _data = T_to_utf8 (data); 320 | std::string ret = ""; 321 | for (size_t i = 0; i < _data.size (); ++i) { 322 | TCHAR ch = _data [i]; 323 | if (ch == '\\') { 324 | ch = _data [++i]; 325 | if (ch == 'x') { 326 | ret += (char) ((hex_char_to_dec (_data [i + 1]) << 4) | hex_char_to_dec (_data [i + 2])); 327 | i += 2; 328 | } else { 329 | ret += '\\'; 330 | ret += ch; 331 | } 332 | } else { 333 | ret += ch; 334 | } 335 | } 336 | return utf8_to_T (ret); 337 | } 338 | static faw::string_t escape_u_str_encode (faw::string_view_t data) { 339 | std::string _data = T_to_utf8 (data); 340 | static LPCSTR hex_char = "0123456789ABCDEF"; 341 | std::string ret = ""; 342 | for (size_t i = 0; i < _data.size (); ++i) { 343 | TCHAR ch = _data [i]; 344 | if (ch & 0x80) { 345 | ret += "\\u"; 346 | ret += hex_char[(0xf0 & (uint32_t) ch) >> 4]; 347 | ret += hex_char[0xf & (uint32_t) ch]; 348 | ch = _data [++i]; 349 | ret += hex_char[(0xf0 & (uint32_t) ch) >> 4]; 350 | ret += hex_char[0xf & (uint32_t) ch]; 351 | } else { 352 | ret += ch; 353 | } 354 | } 355 | return utf8_to_T (ret); 356 | } 357 | static faw::string_t escape_u_str_decode (faw::string_view_t data) { 358 | std::string _data = T_to_utf8 (data); 359 | std::string ret = ""; 360 | for (size_t i = 0; i < _data.size (); ++i) { 361 | TCHAR ch = _data [i]; 362 | if (ch == '\\') { 363 | ch = _data [++i]; 364 | if (ch == 'u') { 365 | ret += (TCHAR) ((hex_char_to_dec (_data [i + 1]) << 4) | hex_char_to_dec (_data [i + 2])); 366 | ret += (TCHAR) ((hex_char_to_dec (_data [i + 3]) << 4) | hex_char_to_dec (_data [i + 4])); 367 | i += 4; 368 | } else { 369 | ret += '\\'; 370 | ret += ch; 371 | } 372 | } else { 373 | ret += ch; 374 | } 375 | } 376 | return utf8_to_T (ret); 377 | } 378 | static faw::string_t base64_encode (faw::string_view_t data) { 379 | std::string _data = T_to_utf8 (data); 380 | static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 381 | std::string ret = ""; 382 | size_t i = 0, j = 0; 383 | TBYTE char_3[3], char_4[4]; 384 | size_t in_len = _data.size (); 385 | PTBYTE bytes_to_encode = (PTBYTE) &_data [0]; 386 | while (in_len--) { 387 | char_3[i++] = *(bytes_to_encode++); 388 | if (i == 3) { 389 | char_4[0] = (char_3[0] & 0xfc) >> 2; 390 | char_4[1] = ((char_3[0] & 0x03) << 4) + ((char_3[1] & 0xf0) >> 4); 391 | char_4[2] = ((char_3[1] & 0x0f) << 2) + ((char_3[2] & 0xc0) >> 6); 392 | char_4[3] = char_3[2] & 0x3f; 393 | 394 | for (i = 0; i < 4; i++) 395 | ret += base64_chars[char_4[i]]; 396 | i = 0; 397 | } 398 | } 399 | if (i) { 400 | for (j = i; j < 3; j++) 401 | char_3[j] = '\0'; 402 | char_4[0] = (char_3[0] & 0xfc) >> 2; 403 | char_4[1] = ((char_3[0] & 0x03) << 4) + ((char_3[1] & 0xf0) >> 4); 404 | char_4[2] = ((char_3[1] & 0x0f) << 2) + ((char_3[2] & 0xc0) >> 6); 405 | for (j = 0; j < i + 1; j++) 406 | ret += base64_chars[char_4[j]]; 407 | while ((i++ < 3)) 408 | ret += '='; 409 | } 410 | return utf8_to_T (ret); 411 | } 412 | static faw::string_t base64_decode (faw::string_view_t data) { 413 | std::string _data = T_to_utf8 (data); 414 | static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 415 | size_t in_len = data.size (), i = 0, j = 0, in_ = 0; 416 | TBYTE char_4[4], char_3[3]; 417 | std::string ret = ""; 418 | auto is_base64 = [] (unsigned char c) { return (isalnum (c) || (c == '+') || (c == '/')); }; 419 | while (in_len-- && (data[in_] != '=') && is_base64 (data[in_])) { 420 | char_4[i++] = data[in_]; in_++; 421 | if (i == 4) { 422 | for (i = 0; i < 4; i++) 423 | char_4[i] = (unsigned char) base64_chars.find (char_4[i]); 424 | char_3[0] = (char_4[0] << 2) + ((char_4[1] & 0x30) >> 4); 425 | char_3[1] = ((char_4[1] & 0xf) << 4) + ((char_4[2] & 0x3c) >> 2); 426 | char_3[2] = ((char_4[2] & 0x3) << 6) + char_4[3]; 427 | 428 | for (i = 0; i < 3; i++) 429 | ret += char_3[i]; 430 | i = 0; 431 | } 432 | } 433 | if (i) { 434 | for (j = 0; j < i; j++) 435 | char_4[j] = (unsigned char) base64_chars.find (char_4[j]); 436 | char_3[0] = (char_4[0] << 2) + ((char_4[1] & 0x30) >> 4); 437 | char_3[1] = ((char_4[1] & 0xf) << 4) + ((char_4[2] & 0x3c) >> 2); 438 | for (j = 0; j < i - 1; j++) ret += char_3[j]; 439 | } 440 | return utf8_to_T (ret); 441 | } 442 | }; 443 | } 444 | 445 | 446 | 447 | #endif //FAWLIB__ENCODING_HPP__ 448 | -------------------------------------------------------------------------------- /include/FawLib/FawLib.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: FawLib 4 | // Description: FawLib统一引入头文件 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: Apr 02, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__FAWLIB_HPP__ 14 | #define FAWLIB__FAWLIB_HPP__ 15 | 16 | 17 | 18 | #define _CRT_SECURE_NO_WARNINGS 19 | 20 | #include "Encoding.hpp" 21 | #include "String.hpp" 22 | #include "SetupHelper.hpp" 23 | #include "Register.hpp" 24 | #include "File.hpp" 25 | #include "Directory.hpp" 26 | #include "Process.hpp" 27 | 28 | 29 | 30 | #endif //FAWLIB__FAWLIB_HPP__ 31 | -------------------------------------------------------------------------------- /include/FawLib/File.hpp: -------------------------------------------------------------------------------- 1 | #//////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: File 4 | // Description: 文件类 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: May 16, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__FILE_HPP__ 14 | #define FAWLIB__FILE_HPP__ 15 | 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include "String.hpp" 25 | #include "Encoding.hpp" 26 | 27 | 28 | 29 | namespace faw { 30 | class File { 31 | File () {} 32 | public: 33 | static bool exist (String _path) { 34 | DWORD _attr = ::GetFileAttributes (_path.c_str ()); 35 | return (_attr != INVALID_FILE_ATTRIBUTES && !(_attr & FILE_ATTRIBUTE_DIRECTORY)); 36 | } 37 | static bool remove (String _path) { return !!::DeleteFile (_path.c_str ()); } 38 | static bool copy (String _src, String _dest) { return !!::CopyFile (_src.c_str (), _dest.c_str (), FALSE); } 39 | static bool move (String _src, String _dest) { return !!::MoveFile (_src.c_str (), _dest.c_str ()); } 40 | static bool write (String _path, String _data, String _encoding = _T ("utf-8"), std::ios::openmode _openmode = std::ios::binary) { 41 | MakeSureDirectoryPathExists (_path.stra ().c_str ()); 42 | _encoding.lower_self (); 43 | if (_encoding == _T ("utf-8") || _encoding == _T ("utf8")) { 44 | std::ofstream ofs (_path.stra (), _openmode); 45 | if (!ofs.is_open ()) 46 | return false; 47 | ofs << Encoding::T_to_utf8 (_data.str ()); 48 | ofs.close (); 49 | } else if (_encoding == _T ("ucs-2") || _encoding == _T ("ucs2") || _encoding == _T ("utf-16") || _encoding == _T ("utf16")) { 50 | std::wofstream ofs (_path.strw (), _openmode); 51 | if (!ofs.is_open ()) 52 | return false; 53 | ofs << Encoding::T_to_utf16 (_data.str ()); 54 | ofs.close (); 55 | } else if (_encoding == _T ("gb18030") || _encoding == _T ("gbk") || _encoding == _T ("gb2312")) { 56 | std::ofstream ofs (_path.stra (), _openmode); 57 | if (!ofs.is_open ()) 58 | return false; 59 | ofs << Encoding::T_to_gb18030 (_data.str ()); 60 | ofs.close (); 61 | } 62 | return true; 63 | } 64 | static String read (String _path, String _encoding = _T ("utf-8")) { 65 | String _ret = _T (""); 66 | if (_encoding == _T ("utf-8") || _encoding == _T ("utf8")) { 67 | std::ifstream ifs (_path.stra (), std::ios::binary); 68 | if (!ifs.is_open ()) 69 | return _ret; 70 | std::string _data ((std::istreambuf_iterator (ifs)), std::istreambuf_iterator ()); 71 | _ret = Encoding::utf8_to_T (_data); 72 | ifs.close (); 73 | } else if (_encoding == _T ("ucs-2") || _encoding == _T ("ucs2") || _encoding == _T ("utf-16") || _encoding == _T ("utf16")) { 74 | std::wifstream ifs (_path.strw (), std::ios::binary); 75 | if (!ifs.is_open ()) 76 | return _ret; 77 | std::string _data ((std::istreambuf_iterator (ifs)), std::istreambuf_iterator ()); 78 | _ret = Encoding::utf8_to_T (_data); 79 | ifs.close (); 80 | } else if (_encoding == _T ("gb18030") || _encoding == _T ("gbk") || _encoding == _T ("gb2312")) { 81 | std::ifstream ifs (_path.stra (), std::ios::binary); 82 | if (!ifs.is_open ()) 83 | return _ret; 84 | std::string _data ((std::istreambuf_iterator (ifs)), std::istreambuf_iterator ()); 85 | _ret = Encoding::gb18030_to_T (_data); 86 | ifs.close (); 87 | } 88 | return _ret; 89 | } 90 | }; 91 | } 92 | 93 | 94 | 95 | #endif //FAWLIB__FILE_HPP__ 96 | -------------------------------------------------------------------------------- /include/FawLib/Process.hpp: -------------------------------------------------------------------------------- 1 | #//////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: Process 4 | // Description: 进程类 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: May 20, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__PROCESS_HPP__ 14 | #define FAWLIB__PROCESS_HPP__ 15 | 16 | 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "String.hpp" 27 | 28 | #pragma comment (lib, "psapi.lib") 29 | 30 | 31 | 32 | namespace faw { 33 | class Process { 34 | Process () {} 35 | public: 36 | static bool create (String _cmd_line, std::function _on_exit = nullptr) { 37 | STARTUPINFO si = { sizeof (STARTUPINFO) }; 38 | PROCESS_INFORMATION pi = { 0 }; 39 | bool bRet = !!::CreateProcess (nullptr, &_cmd_line [0], nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi); 40 | if (!bRet) 41 | return false; 42 | CloseHandle (pi.hThread); 43 | if (_on_exit) { 44 | HANDLE _handle = pi.hProcess; 45 | std::thread ([_on_exit, _handle] () { 46 | DWORD _exit_code = STILL_ACTIVE; 47 | while (_exit_code == STILL_ACTIVE) { 48 | std::this_thread::sleep_for (std::chrono::milliseconds (100)); 49 | if (!::GetExitCodeProcess (_handle, &_exit_code)) 50 | break; 51 | } 52 | CloseHandle (_handle); 53 | _on_exit (); 54 | }).detach (); 55 | } else { 56 | CloseHandle (pi.hProcess); 57 | } 58 | return true; 59 | } 60 | 61 | static void shell (String _url) { 62 | ::ShellExecute (NULL, _T ("open"), _url.c_str (), nullptr, nullptr, SW_SHOW); 63 | } 64 | 65 | // 判断进程是否存在 66 | static bool process_exist (String file) { 67 | HANDLE hSnapShot = ::CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); 68 | PROCESSENTRY32 pe32 { sizeof (PROCESSENTRY32) }; 69 | std::map m; 70 | if (::Process32First (hSnapShot, &pe32)) { 71 | do { 72 | String _path = pe32.szExeFile; 73 | _path.replace_self (_T ('/'), _T ('\\')); 74 | size_t p = _path.rfind (_T ('\\')); 75 | if (_path.substr (p + 1).operator== (file)) { 76 | ::CloseHandle (hSnapShot); 77 | return true; 78 | } 79 | } while (::Process32Next (hSnapShot, &pe32)); 80 | } 81 | ::CloseHandle (hSnapShot); 82 | return false; 83 | } 84 | }; 85 | } 86 | 87 | 88 | 89 | #endif //FAWLIB__PROCESS_HPP__ 90 | -------------------------------------------------------------------------------- /include/FawLib/Register.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: Register 4 | // Description: 注册表操作类 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: May 20, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__REGISTER_HPP__ 14 | #define FAWLIB__REGISTER_HPP__ 15 | 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | 26 | namespace faw { 27 | class Register { 28 | Register () = delete; 29 | 30 | public: 31 | // 创建path 32 | static bool set_path (std::wstring path, BYTE *data, DWORD data_len) { 33 | HKEY main_key = parse_path (path); 34 | return (ERROR_SUCCESS == ::RegSetValueExW (main_key, path.c_str (), 0, REG_BINARY, data, data_len)); 35 | } 36 | static bool set_path (std::wstring path, DWORD data) { 37 | HKEY main_key = parse_path (path); 38 | return (ERROR_SUCCESS == ::RegSetValueExW (main_key, path.c_str (), 0, REG_DWORD, (BYTE*) &data, sizeof (data))); 39 | } 40 | static bool set_path (std::wstring path, std::wstring data, bool expand = false) { 41 | HKEY main_key = parse_path (path); 42 | return (ERROR_SUCCESS == ::RegSetValueW (main_key, path.c_str (), (expand ? REG_EXPAND_SZ : REG_SZ), &data [0], (DWORD) data.size ())); 43 | } 44 | static bool set_path (std::wstring path, std::vector data) { 45 | HKEY main_key = parse_path (path); 46 | std::wstring s = make_multi_sz (data); 47 | return (ERROR_SUCCESS == ::RegSetValueW (main_key, path.c_str (), REG_MULTI_SZ, &s [0], (DWORD) s.size ())); 48 | } 49 | 50 | // 创建/设置key的值 51 | static bool set_key (std::wstring path, std::wstring key_name, BYTE *data, DWORD data_len) { 52 | HKEY hKey = parse_path (path); 53 | if (ERROR_SUCCESS != ::RegOpenKeyExW (hKey, path.c_str (), 0, KEY_WRITE, &hKey)) return false; 54 | bool bRet = (ERROR_SUCCESS == ::RegSetValueExW (hKey, key_name.c_str (), 0, REG_BINARY, data, data_len)); 55 | ::RegCloseKey (hKey); 56 | return bRet; 57 | } 58 | static bool set_key (std::wstring path, std::wstring key_name, DWORD data) { 59 | HKEY hKey = parse_path (path); 60 | if (ERROR_SUCCESS != ::RegOpenKeyExW (hKey, path.c_str (), 0, KEY_WRITE, &hKey)) return false; 61 | bool bRet = (ERROR_SUCCESS == ::RegSetValueExW (hKey, key_name.c_str (), 0, REG_DWORD, (BYTE*) &data, sizeof (data))); 62 | ::RegCloseKey (hKey); 63 | return bRet; 64 | } 65 | static bool set_key (std::wstring path, std::wstring key_name, std::wstring data, bool expand = false) { 66 | HKEY hKey = parse_path (path); 67 | if (ERROR_SUCCESS != ::RegOpenKeyExW (hKey, path.c_str (), 0, KEY_WRITE, &hKey)) return false; 68 | bool bRet = (ERROR_SUCCESS == ::RegSetValueExW (hKey, key_name.c_str (), 0, (expand ? REG_EXPAND_SZ : REG_SZ), (BYTE*) &data [0], (DWORD) data.size () * sizeof (wchar_t))); 69 | ::RegCloseKey (hKey); 70 | return bRet; 71 | } 72 | static bool set_key (std::wstring path, std::wstring key_name, std::vector data) { 73 | HKEY hKey = parse_path (path); 74 | if (ERROR_SUCCESS != ::RegOpenKeyExW (hKey, path.c_str (), 0, KEY_WRITE, &hKey)) return false; 75 | std::wstring s = make_multi_sz (data); 76 | bool bRet = (ERROR_SUCCESS == ::RegSetValueExW (hKey, key_name.c_str (), 0, REG_MULTI_SZ, (BYTE*) &s [0], (DWORD) s.size () * sizeof (wchar_t))); 77 | ::RegCloseKey (hKey); 78 | return bRet; 79 | } 80 | 81 | // 获取path的值 82 | template 83 | static T get_path_value (std::wstring path) { 84 | HKEY main_key = parse_path (path); 85 | DWORD _data_len = 2048, _type = 0; 86 | if constexpr (std::is_same >::value) { 87 | // TODO: make sure 88 | BYTE *_data = new BYTE [2048]; 89 | memset (_data, 0, 2048); 90 | _type = REG_BINARY; 91 | if (ERROR_SUCCESS != ::RegQueryValueExW (main_key, path.c_str (), nullptr, &_type, _data, &_data_len)) { 92 | delete [] _data; 93 | _data = nullptr; 94 | _data_len = 0; 95 | } 96 | return { _data, (size_t) _data_len }; 97 | } else if constexpr (std::is_same ::value) { 98 | // TODO: make sure 99 | DWORD _data = 0; 100 | _data_len = 4; 101 | _type = REG_DWORD; 102 | ::RegQueryValueExW (main_key, path.c_str (), nullptr, &_type, (BYTE*) &_data, &_data_len); 103 | return _data; 104 | } else if constexpr (std::is_same ::value) { 105 | std::wstring _data = L""; 106 | _data.reserve (2048); 107 | ::RegQueryValueW (main_key, path.c_str (), &_data [0], (PLONG) &_data_len); 108 | return std::wstring (_data.c_str (), _data_len / 2); 109 | } else if constexpr (std::is_same >::value) { 110 | // TODO: make sure 111 | std::wstring _data = L""; 112 | _data.reserve (4096); 113 | _type = REG_MULTI_SZ; 114 | ::RegQueryValueExW (main_key, path.c_str (), nullptr, &_type, (BYTE*) &_data [0], &_data_len); 115 | _data.resize (_data_len / 2, L'\0'); 116 | std::vector _v; 117 | wchar_t *p1 = &_data [0]; 118 | while (*p1) { 119 | int len = lstrlenW (p1); 120 | _v.push_back (std::wstring (p1, len)); 121 | p1 += len; 122 | } 123 | return _v; 124 | } else { 125 | return T {}; 126 | } 127 | } 128 | 129 | //// 获取key的值 130 | //template 131 | //static T get_path_value (std::wstring path, std::wstring key_name) { 132 | // HKEY main_key = parse_path (path), sub_key = NULL; 133 | // if (ERROR_SUCCESS != ::RegOpenKeyExW (main_key, path.c_str (), 0, KEY_READ, &sub_key)) return false; 134 | // if constexpr (std::is_same >::value) { 135 | // // 136 | // } else if constexpr (std::is_same ::value) { 137 | // // 138 | // } else if constexpr (std::is_same ::value) { 139 | // // 140 | // } else if constexpr (std::is_same >::value) { 141 | // // 142 | // } else { 143 | // return T {}; 144 | // } 145 | // ::RegCloseKey (sub_key); 146 | // return bRet; 147 | //} 148 | 149 | static bool get_key_value (std::wstring path, std::wstring key_name, BYTE *&data, DWORD &data_len) { 150 | HKEY main_key = parse_path (path), sub_key = NULL; 151 | if (ERROR_SUCCESS != ::RegOpenKeyExW (main_key, path.c_str (), 0, KEY_READ, &sub_key)) return false; 152 | bool bRet = (ERROR_SUCCESS == ::RegQueryValueExW (sub_key, key_name.c_str (), nullptr, nullptr, data, &data_len)); 153 | ::RegCloseKey (sub_key); 154 | return bRet; 155 | } 156 | static bool get_key_value (std::wstring path, std::wstring key_name, DWORD &data) { 157 | HKEY main_key = parse_path (path), sub_key = NULL; 158 | DWORD data_size = sizeof (data); 159 | if (ERROR_SUCCESS != ::RegOpenKeyExW (main_key, path.c_str (), 0, KEY_READ, &sub_key)) return false; 160 | bool bRet = (ERROR_SUCCESS == ::RegQueryValueExW (sub_key, key_name.c_str (), nullptr, nullptr, (BYTE*) &data, &data_size)); 161 | ::RegCloseKey (sub_key); 162 | return bRet; 163 | } 164 | static bool get_key_value (std::wstring path, std::wstring key_name, std::wstring &data) { 165 | HKEY main_key = parse_path (path), sub_key = NULL; 166 | std::wstring _data = L""; 167 | _data.reserve (4096); 168 | DWORD sz = (DWORD) 4096 * sizeof (wchar_t); 169 | if (ERROR_SUCCESS != ::RegOpenKeyExW (main_key, path.c_str (), 0, KEY_READ, &sub_key)) return false; 170 | bool bRet = (ERROR_SUCCESS == ::RegQueryValueExW (sub_key, key_name.c_str (), nullptr, nullptr, (BYTE*) &_data[0], &sz)); 171 | ::RegCloseKey (sub_key); 172 | data = std::wstring (_data.c_str (), sz / 2); 173 | return bRet; 174 | } 175 | static bool get_key_value (std::wstring path, std::wstring key_name, std::vector &data) { 176 | HKEY main_key = parse_path (path), sub_key = NULL; 177 | std::wstring _data = L""; 178 | _data.reserve (4096); 179 | DWORD sz = (DWORD) 4096 * sizeof (wchar_t); 180 | if (ERROR_SUCCESS != ::RegOpenKeyExW (main_key, path.c_str (), 0, KEY_READ, &sub_key)) return false; 181 | bool bRet = (ERROR_SUCCESS == ::RegQueryValueExW (sub_key, key_name.c_str (), nullptr, nullptr, (BYTE*) &_data[0], &sz)); 182 | ::RegCloseKey (sub_key); 183 | data.clear (); 184 | wchar_t *p1 = &_data[0]; 185 | while (*p1) { 186 | int len = lstrlenW (p1); 187 | data.push_back (std::wstring (p1, len)); 188 | p1 += len; 189 | } 190 | return bRet; 191 | } 192 | 193 | // 删除path 194 | static bool delete_path (std::wstring path) { 195 | HKEY main_key = parse_path (path); 196 | return (ERROR_SUCCESS == ::RegDeleteKeyW (main_key, path.c_str ())); 197 | } 198 | 199 | // 删除key 200 | static bool delete_key (std::wstring path, std::wstring key_name) { 201 | HKEY main_key = parse_path (path), sub_key = NULL; 202 | if (ERROR_SUCCESS != ::RegOpenKeyExW (main_key, path.c_str (), 0, KEY_ALL_ACCESS, &sub_key)) return false; 203 | bool bRet = (ERROR_SUCCESS == ::RegDeleteKeyW (sub_key, path.c_str ())); 204 | ::RegCloseKey (sub_key); 205 | return bRet; 206 | } 207 | 208 | // 获知path是否存在 209 | static bool path_exist (std::wstring path) { 210 | HKEY main_key = parse_path (path), sub_key = NULL; 211 | if (ERROR_SUCCESS != ::RegOpenKeyExW (main_key, path.c_str (), 0, KEY_QUERY_VALUE, &sub_key)) return false; 212 | ::RegCloseKey (sub_key); 213 | return TRUE; 214 | } 215 | 216 | private: 217 | static HKEY parse_path (std::wstring &path) { 218 | static std::map mkeys { 219 | { L"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT }, 220 | { L"HKCR", HKEY_CLASSES_ROOT }, 221 | { L"HKEY_CURRENT_USER", HKEY_CURRENT_USER }, 222 | { L"HKCU", HKEY_CURRENT_USER }, 223 | { L"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE }, 224 | { L"HKLM", HKEY_LOCAL_MACHINE }, 225 | { L"HKEY_USERS", HKEY_USERS }, 226 | { L"HKU", HKEY_USERS }, 227 | { L"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG }, 228 | { L"HKCC", HKEY_CURRENT_CONFIG }, 229 | }; 230 | 231 | size_t p = path.find (L'\\'); 232 | if (p == std::string::npos) 233 | p = path.size (); 234 | HKEY mkey = mkeys[path.substr (0, p)]; 235 | path = (path.size () >= p + 1 ? path.substr (p + 1) : L""); 236 | return mkey; 237 | } 238 | static std::wstring make_multi_sz (std::vector &data) { 239 | std::wstring s = L""; 240 | for (auto &_s : data) { 241 | s += _s; 242 | s += L'\0'; 243 | } 244 | s += L'\0'; 245 | return s; 246 | } 247 | }; 248 | } 249 | 250 | 251 | 252 | #endif //FAWLIB__SETUP_HPP__ 253 | -------------------------------------------------------------------------------- /include/FawLib/SetupHelper.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: SetupHelper 4 | // Description: 安装包帮助类 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: May 25, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__SETUP_HELPER_HPP__ 14 | #define FAWLIB__SETUP_HELPER_HPP__ 15 | 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "Encoding.hpp" 25 | #include "String.hpp" 26 | #include "Register.hpp" 27 | #include "Directory.hpp" 28 | #include "File.hpp" 29 | #include "unzip.h" 30 | 31 | 32 | 33 | namespace faw { 34 | class SetupHelper { 35 | public: 36 | // 构造函数 37 | SetupHelper (faw::String _app_name, faw::String _app_path = _T ("")): m_app_name (_app_name) { 38 | if (_app_path.size () > 0) { 39 | m_app_path = _app_path.replace (_T ("/"), _T ("\\")); 40 | if (m_app_path [m_app_path.size () - 1] != _T ('\\')) 41 | m_app_path += _T ('\\'); 42 | } else { 43 | faw::String _reg_path = faw::String::format (_T ("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s"), m_app_name.c_str ()); 44 | std::wstring _data; 45 | if (faw::Register::get_key_value (_reg_path.strw (), L"InstallLocation", _data)) 46 | m_app_path = _data; 47 | } 48 | } 49 | 50 | // 资源压缩包解压缩(zip压缩文件) 51 | std::tuple install_uncompress (HINSTANCE hInstance, LPCTSTR _resType, LPCTSTR _resId, LPCSTR _zipPwd = nullptr, std::function _callback = nullptr) { 52 | size_t _last = 0, _ret = 0; 53 | HRSRC hResource = ::FindResource (hInstance, _resId, _resType); 54 | if (hResource != NULL) { 55 | HGLOBAL hGlobal = ::LoadResource (hInstance, hResource); 56 | if (hGlobal) { 57 | DWORD dwSize = ::SizeofResource (hInstance, hResource); 58 | if (dwSize) { 59 | LPVOID pBuffer = ::LockResource (hGlobal); 60 | HZIP hZip = ::OpenZip (pBuffer, dwSize, _zipPwd); 61 | ZIPENTRY ze = { 0 }; 62 | GetZipItem (hZip, -1, &ze); 63 | int _file_count = ze.index; 64 | faw::Directory::create (m_app_path); 65 | for (int i = 0; i < _file_count; ++i) { 66 | GetZipItem (hZip, i, &ze); 67 | faw::String _tmp = m_app_path + ze.name; 68 | _tmp.replace_self (_T ('/'), _T ('\\')); 69 | if (ze.attr & FILE_ATTRIBUTE_DIRECTORY) { 70 | faw::Directory::create (_tmp, ze.attr); 71 | } else { 72 | if (faw::File::exist (_tmp.c_str ())) { 73 | if (!faw::File::remove (_tmp.c_str ())) { 74 | return { false, _ret }; 75 | } 76 | } 77 | //_ret += (UnzipItem (hZip, i, _tmp.c_str ()) == ZR_OK ? 1 : 0); 78 | if (UnzipItem (hZip, i, _tmp.c_str ()) == ZR_OK) { 79 | _ret += (size_t) (ze.unc_size > 0 ? ze.unc_size : (ze.comp_size >= 0 ? ze.comp_size : 0)); 80 | } else { 81 | return { false, _ret }; 82 | } 83 | ze.attr &= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_NORMAL); 84 | if (ze.attr) 85 | ::SetFileAttributes (_tmp.c_str (), ze.attr); 86 | } 87 | size_t _moment = i * 100 / (size_t) _file_count; 88 | if (_moment != _last && _callback) 89 | _callback (_last = _moment); 90 | } 91 | if (_callback) 92 | _callback (_last = 100); 93 | ::CloseZip (hZip); 94 | } 95 | } 96 | ::FreeResource (hResource); 97 | } 98 | return { true, _ret }; 99 | } 100 | 101 | // 设置注册表 102 | bool install_initRegester (faw::String _exe_path, faw::String _ico_path, faw::String _desp_name, faw::String _publisher, faw::String _version, DWORD _estimated_size) { 103 | // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\filezilla.exe 104 | _exe_path.replace_self (_T ('/'), _T ('\\')); 105 | faw::String _exe_file = faw::Directory::get_filename (_exe_path); 106 | faw::String _reg_path = faw::String::format (_T ("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s"), _exe_file.c_str ()); 107 | faw::String _path_value = faw::String::format (_T ("%s%s"), m_app_path.c_str (), _exe_path.c_str ()); 108 | bool bRet = faw::Register::set_path (_reg_path.strw (), _path_value.strw ()); 109 | _path_value = faw::Directory::get_subpath (_path_value.str ()); 110 | bRet = faw::Register::set_key (_reg_path.strw (), L"Path", _path_value.strw ()) && bRet; 111 | 112 | // 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GitHubDesktop 113 | _reg_path = faw::String::format (_T ("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s"), m_app_name.c_str ()); 114 | std::wstring _reg_path_w = _reg_path.strw (); 115 | bRet = faw::Register::set_path (_reg_path_w, L"") && bRet; 116 | _ico_path = faw::String::format (_T ("%s%s"), _path_value.c_str (), _ico_path.c_str ()); 117 | bRet = faw::Register::set_key (_reg_path_w, L"DisplayIcon", _ico_path.strw ()) && bRet; 118 | bRet = faw::Register::set_key (_reg_path_w, L"DisplayName", _desp_name.strw ()) && bRet; 119 | bRet = faw::Register::set_key (_reg_path_w, L"DisplayVersion", _version.strw ()) && bRet; 120 | bRet = faw::Register::set_key (_reg_path_w, L"EstimatedSize", (DWORD) _estimated_size) && bRet; 121 | char _buf_time [16]; 122 | time_t t = time (NULL); 123 | strftime (_buf_time, 16, "%Y%m%d", localtime (&t)); 124 | faw::String _time_value { _buf_time }; 125 | bRet = faw::Register::set_key (_reg_path_w, L"InstallDate", _time_value.strw ()) && bRet; 126 | bRet = faw::Register::set_key (_reg_path_w, L"NoModify", (DWORD) 1) && bRet; 127 | bRet = faw::Register::set_key (_reg_path_w, L"NoRepair", (DWORD) 1) && bRet; 128 | bRet = faw::Register::set_key (_reg_path_w, L"Publisher", _publisher.strw ()) && bRet; 129 | bRet = faw::Register::set_key (_reg_path_w, L"InstallLocation", _path_value.strw ()) && bRet; 130 | _path_value += _T ("uninstall.exe"); 131 | bRet = faw::Register::set_key (_reg_path_w, L"UninstallString", _path_value.strw ()) && bRet; 132 | //bRet = Register::set_key (_reg_path_w, L"QuietUninstallString", _path_value.strw ()) && bRet; 133 | return true; 134 | } 135 | 136 | // 创建快捷方式 137 | String install_setShortcut (std::map &_desktop, std::map &_startmenu) { 138 | // 创建快捷方式 139 | auto _set_shortcut = [] (faw::String _dest_file, faw::String _work_path, faw::String _save_path) -> bool { 140 | IShellLink *psl = nullptr; 141 | IPersistFile *ppf = nullptr; 142 | HRESULT _result = ::CoCreateInstance (CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &psl); 143 | if (FAILED (_result)) 144 | return false; 145 | _result = psl->QueryInterface (IID_IPersistFile, (void**) &ppf); 146 | if (SUCCEEDED (_result)) { 147 | psl->SetPath (_dest_file.c_str ()); 148 | psl->SetWorkingDirectory (_work_path.c_str ()); 149 | psl->SetShowCmd (SW_SHOW); 150 | ppf->Save (_save_path.strw ().c_str (), TRUE); 151 | } 152 | ppf->Release (); 153 | psl->Release (); 154 | return true; 155 | }; 156 | 157 | faw::String _ret = _T (""); 158 | TCHAR buf [MAX_PATH]; 159 | ::CoInitializeEx (NULL, COINIT_APARTMENTTHREADED); 160 | 161 | // 桌面快捷方式 162 | buf [0] = _T ('\0'); 163 | if (::SHGetSpecialFolderPath (NULL, buf, CSIDL_DESKTOP, TRUE)) { 164 | faw::String _desk_path { buf }; 165 | for (auto &_item : _desktop) { 166 | faw::String _dest_file = faw::Directory::append_folder_or_file (m_app_path, _item.second); 167 | faw::String _save_path = faw::Directory::append_folder_or_file (_desk_path, _item.first); 168 | if (_set_shortcut (_dest_file, m_app_path, _save_path)) { 169 | _ret += _save_path; 170 | _ret += _T ('|'); 171 | } 172 | } 173 | } 174 | 175 | // 开始菜单快捷方式 176 | buf [0] = _T ('\0'); 177 | if (::SHGetSpecialFolderPath (NULL, buf, CSIDL_STARTMENU, TRUE)) { 178 | faw::String _start_path = faw::Directory::append_folder_or_file (buf, _T ("Programs")); 179 | faw::Directory::create (_start_path); 180 | for (auto &_item : _startmenu) { 181 | faw::String _dest_file = faw::Directory::append_folder_or_file (m_app_path, _item.second); 182 | faw::String _save_path = faw::Directory::append_folder_or_file (_start_path, _item.first); 183 | if (_set_shortcut (_dest_file, m_app_path, _save_path)) { 184 | _ret += _save_path; 185 | _ret += _T ('|'); 186 | } 187 | } 188 | _ret += _start_path; 189 | } else { 190 | if (_ret [_ret.size () - 1] == _T ('|')) 191 | _ret.left_self (_ret.size () - 1); 192 | } 193 | 194 | ::CoUninitialize (); 195 | return _ret; 196 | } 197 | 198 | // 卸载软件 199 | void uninstall (faw::String _shortcuts, faw::String _exe_file) { 200 | // 清理快捷方式 201 | std::vector _items = _shortcuts.split (_T ('|')); 202 | for (auto &_item : _items) { 203 | if (faw::File::exist (_item.c_str ())) { 204 | faw::File::remove (_item.c_str ()); 205 | } else if (faw::Directory::exist (_item.c_str ())) { 206 | faw::Directory::remove (_item.c_str ()); 207 | } 208 | } 209 | 210 | // 清理注册表 211 | faw::String _reg_path = faw::String::format (_T ("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s"), _exe_file.c_str ()); 212 | faw::Register::delete_path (_reg_path.strw ()); 213 | _reg_path = faw::String::format (_T ("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s"), m_app_name.c_str ()); 214 | faw::Register::delete_path (_reg_path.strw ()); 215 | 216 | // 清理文件 217 | faw::Directory::remove_nonempty (m_app_path); 218 | } 219 | 220 | // 获取app名称 221 | faw::String get_app_name () const { return m_app_name; } 222 | 223 | // 获取app路径 224 | faw::String get_app_path () const { return m_app_path; } 225 | 226 | // 获取应用程序目录 227 | static faw::String get_program_files (faw::String _folder) { 228 | TCHAR buf [MAX_PATH] = _T ("C:\\Program Files"); 229 | ::SHGetSpecialFolderPath (NULL, buf, CSIDL_PROGRAM_FILES, TRUE); 230 | faw::String s { buf }; 231 | s = faw::Directory::append_folder_or_file (s, _folder); 232 | return s; 233 | } 234 | 235 | // 获取应用程序版本 236 | static String get_software_version (faw::String _app_name) { 237 | faw::String _reg_path = faw::String::format (_T ("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s"), _app_name.c_str ()); 238 | std::wstring _desp_ver = L""; 239 | faw::Register::get_key_value (_reg_path.strw (), L"DisplayVersion", _desp_ver); 240 | return _desp_ver; 241 | } 242 | 243 | // 获取应用程序所在路径 244 | static faw::String get_software_location (faw::String _app_name) { 245 | faw::String _reg_path = faw::String::format (_T ("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s"), _app_name.c_str ()); 246 | std::wstring _desp_ver = L""; 247 | faw::Register::get_key_value (_reg_path.strw (), L"InstallLocation", _desp_ver); 248 | return _desp_ver; 249 | } 250 | 251 | private: 252 | faw::String m_app_name = _T (""); 253 | faw::String m_app_path = _T (""); 254 | }; 255 | } 256 | 257 | 258 | 259 | #endif //FAWLIB__SETUP_HELPER_HPP__ 260 | -------------------------------------------------------------------------------- /include/FawLib/String.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: Encoding 4 | // Description: 编码转换类 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: Jan 24, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__STRING_HPP__ 14 | #define FAWLIB__STRING_HPP__ 15 | 16 | 17 | 18 | #include 19 | #include 20 | //#include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "Encoding.hpp" 32 | 33 | 34 | 35 | namespace faw { 36 | enum class flag { 37 | none = 0x00000000, 38 | decimal_2 = 0x00000000, 39 | decimal_3 = 0x00010000, 40 | decimal_4 = 0x00020000, 41 | decimal_5 = 0x00030000, 42 | decimal_6 = 0x00040000, 43 | decimal_7 = 0x00050000, 44 | decimal_8 = 0x00060000, 45 | decimal_9 = 0x00070000, 46 | whole_10 = 0x00080000, 47 | whole_100 = 0x00090000, 48 | whole_1k = 0x000a0000, 49 | whole_10k = 0x000b0000, 50 | whole_100k = 0x000c0000, 51 | whole_1m = 0x000d0000, 52 | decimal_0 = 0x000e0000, 53 | decimal_1 = 0x000f0000, 54 | _align = 0x00300000, 55 | align_left = 0x00100000, 56 | align_middle = 0x00200000, 57 | align_right = 0x00000000, 58 | }; 59 | // 用于将数据输入管道时,设置左右两侧padding以及浮点数小数位数设置 60 | inline flag set_width (size_t _width, flag _f = flag::none) { return (flag) ((_width & 0xffff) | (size_t) _f); } 61 | 62 | class String { 63 | public: 64 | // 字符串构造函数 65 | String () {} 66 | String (const char _c, size_t _len = 1) { m_str.assign (_len, (TCHAR) _c); } 67 | String (const wchar_t _c, size_t _len = 1) { m_str.assign (_len, (TCHAR) _c); } 68 | String (const char *_s, size_t _len = _npos) { m_str = Encoding::gb18030_to_T (_len == _npos ? std::string_view (_s) : std::string_view (_s, _len)); } 69 | String (const wchar_t *_s, size_t _len = _npos) { m_str = Encoding::utf16_to_T (_len == _npos ? std::wstring_view (_s) : std::wstring_view (_s, _len)); } 70 | String (const std::string &_s): m_str (Encoding::gb18030_to_T (std::string_view (_s))) {} 71 | String (const std::wstring &_s): m_str (Encoding::utf16_to_T (std::wstring_view (_s))) {} 72 | #if _HAS_CXX17 73 | String (const std::string_view _s): m_str (Encoding::gb18030_to_T (_s)) {} 74 | String (const std::wstring_view _s): m_str (Encoding::utf16_to_T (_s)) {} 75 | #endif 76 | String (const String &_s): m_str (_s.m_str) {} 77 | 78 | // 字符串符号重载函数 79 | String &operator= (const char *_s) { m_str = Encoding::gb18030_to_T (std::string_view (_s)); return *this; } 80 | String &operator= (const wchar_t *_s) { m_str = Encoding::utf16_to_T (std::wstring_view (_s)); return *this; } 81 | String &operator= (const std::string &_s) { m_str = Encoding::gb18030_to_T (std::string_view (_s)); return *this; } 82 | String &operator= (const std::wstring &_s) { m_str = Encoding::utf16_to_T (std::wstring_view (_s)); return *this; } 83 | String &operator= (const String &_s) { m_str = _s.m_str; return *this; } 84 | #if _HAS_CXX17 85 | String &operator= (const std::string_view _s) { m_str = Encoding::gb18030_to_T (_s); return *this; } 86 | String &operator= (const std::wstring_view _s) { m_str = Encoding::utf16_to_T (_s); return *this; } 87 | #endif 88 | // 89 | String &operator+= (const char _c) { m_str += (TCHAR) _c; return *this; } 90 | String &operator+= (const wchar_t _c) { m_str += (TCHAR) _c; return *this; } 91 | String &operator+= (const char *_s) { m_str += Encoding::gb18030_to_T (std::string_view (_s)); return *this; } 92 | String &operator+= (const wchar_t *_s) { m_str += Encoding::utf16_to_T (std::wstring_view (_s)); return *this; } 93 | String &operator+= (const std::string &_s) { m_str += Encoding::gb18030_to_T (std::string_view (_s)); return *this; } 94 | String &operator+= (const std::wstring &_s) { m_str += Encoding::utf16_to_T (std::wstring_view (_s)); return *this; } 95 | String &operator+= (const String &_s) { m_str += _s.m_str; return *this; } 96 | #if _HAS_CXX17 97 | String &operator+= (const std::string_view _s) { m_str += Encoding::gb18030_to_T (_s); return *this; } 98 | String &operator+= (const std::wstring_view _s) { m_str += Encoding::utf16_to_T (_s); return *this; } 99 | #endif 100 | // 101 | String operator+ (const char _c) { String _o (*this); _o.m_str += (TCHAR) _c; return _o; } 102 | String operator+ (const wchar_t _c) { String _o (*this); _o.m_str += (TCHAR) _c; return _o; } 103 | String operator+ (const char *_s) { String _o (*this); _o.m_str += Encoding::gb18030_to_T (std::string_view (_s)); return _o; } 104 | String operator+ (const wchar_t *_s) { String _o (*this); _o.m_str += Encoding::utf16_to_T (std::wstring_view (_s)); return _o; } 105 | String operator+ (const std::string &_s) { String _o (*this); _o.m_str += Encoding::gb18030_to_T (std::string_view (_s)); return _o; } 106 | String operator+ (const std::wstring &_s) { String _o (*this); _o.m_str += Encoding::utf16_to_T (std::wstring_view (_s)); return _o; } 107 | String operator+ (const String &_s) { String _o (*this); _o.m_str += _s.m_str; return _o; } 108 | #if _HAS_CXX17 109 | String operator+ (const std::string_view _s) { String _o (*this); _o.m_str += Encoding::gb18030_to_T (_s); return _o; } 110 | String operator+ (const std::wstring_view _s) { String _o (*this); _o.m_str += Encoding::utf16_to_T (_s); return _o; } 111 | #endif 112 | // 113 | friend String operator+ (const char _c, String &_o) { _o.m_str.insert (_o.m_str.begin (), (TCHAR) _c); } 114 | friend String operator+ (const wchar_t _c, String &_o) { _o.m_str.insert (_o.m_str.begin (), (TCHAR) _c); } 115 | friend String operator+ (const char *_s, String &_o) { String _so (_s); _so.m_str += _o.m_str; return _so; } 116 | friend String operator+ (const wchar_t *_s, String &_o) { String _so (_s); _so.m_str += _o.m_str; return _so; } 117 | friend String operator+ (const std::string &_s, String &_o) { String _so (_s); _so.m_str += _o.m_str; return _so; } 118 | friend String operator+ (const std::wstring &_s, String &_o) { String _so (_s); _so.m_str += _o.m_str; return _so; } 119 | #if _HAS_CXX17 120 | friend String operator+ (const std::string_view &_s, String &_o) { String _so (_s); _so.m_str += _o.m_str; return _so; } 121 | friend String operator+ (const std::wstring_view &_s, String &_o) { String _so (_s); _so.m_str += _o.m_str; return _so; } 122 | #endif 123 | 124 | // 比较 125 | bool operator== (const char *_s) const { String _o (_s); return m_str == _o.m_str; } 126 | bool operator== (const wchar_t *_s) const { String _o (_s); return m_str == _o.m_str; } 127 | bool operator== (const std::string &_s) const { String _o (_s); return m_str == _o.m_str; } 128 | bool operator== (const std::wstring &_s) const { String _o (_s); return m_str == _o.m_str; } 129 | bool operator== (const String &_o) const { return m_str == _o.m_str; } 130 | #if _HAS_CXX17 131 | bool operator== (const std::string_view _s) const { String _o (_s); return m_str == _o.m_str; } 132 | bool operator== (const std::wstring_view _s) const { String _o (_s); return m_str == _o.m_str; } 133 | #endif 134 | // 135 | friend bool operator== (const char *_s, String &_o) { return _o == _s; } 136 | friend bool operator== (const wchar_t *_s, String &_o) { return _o == _s; } 137 | friend bool operator== (const std::string &_s, String &_o) { return _o == _s; } 138 | friend bool operator== (const std::wstring &_s, String &_o) { return _o == _s; } 139 | #if _HAS_CXX17 140 | friend bool operator== (const std::string_view _s, String &_o) { return _o == _s; } 141 | friend bool operator== (const std::wstring_view _s, String &_o) { return _o == _s; } 142 | #endif 143 | // 144 | bool operator!= (const char *_s) const { String _o (_s); return m_str != _o.m_str; } 145 | bool operator!= (const wchar_t *_s) const { String _o (_s); return m_str != _o.m_str; } 146 | bool operator!= (const std::string &_s) const { String _o (_s); return m_str != _o.m_str; } 147 | bool operator!= (const std::wstring &_s) const { String _o (_s); return m_str != _o.m_str; } 148 | bool operator!= (const String &_o) const { return m_str != _o.m_str; } 149 | #if _HAS_CXX17 150 | bool operator!= (const std::string_view _s) const { String _o (_s); return m_str != _o.m_str; } 151 | bool operator!= (const std::wstring_view _s) const { String _o (_s); return m_str != _o.m_str; } 152 | #endif 153 | // 154 | friend bool operator!= (const char *_s, String &_o) { return _o != _s; } 155 | friend bool operator!= (const wchar_t *_s, String &_o) { return _o != _s; } 156 | friend bool operator!= (const std::string &_s, String &_o) { return _o != _s; } 157 | friend bool operator!= (const std::wstring &_s, String &_o) { return _o != _s; } 158 | #if _HAS_CXX17 159 | friend bool operator!= (const std::string_view _s, String &_o) { return _o != _s; } 160 | friend bool operator!= (const std::wstring_view _s, String &_o) { return _o != _s; } 161 | #endif 162 | // 163 | bool is_equal (const char *_s) { return operator== (_s); } 164 | bool is_equal (const wchar_t *_s) { return operator== (_s); } 165 | bool is_equal (const std::string &_s) { return operator== (_s); } 166 | bool is_equal (const std::wstring &_s) { return operator== (_s); } 167 | bool is_equal (String &_o) { return operator== (_o); } 168 | #if _HAS_CXX17 169 | bool is_equal (const std::string_view _s) { return operator== (_s); } 170 | bool is_equal (const std::wstring_view _s) { return operator== (_s); } 171 | #endif 172 | // 173 | bool is_equal_nocase (const char *_s) { String _o (_s); return is_equal_nocase (_o); } 174 | bool is_equal_nocase (const wchar_t *_s) { String _o (_s); return is_equal_nocase (_o); } 175 | bool is_equal_nocase (const std::string &_s) { String _o (_s); return is_equal_nocase (_o); } 176 | bool is_equal_nocase (const std::wstring &_s) { String _o (_s); return is_equal_nocase (_o); } 177 | bool is_equal_nocase (String &_o) { size_t size = m_str.size (); 178 | if (size != _o.m_str.size ()) 179 | return false; 180 | for (size_t i = 0; i < size; ++i) { 181 | if (m_str [i] == _o.m_str [i]) { 182 | continue; 183 | } else if (m_str [i] >= _T ('a') && m_str [i] <= _T ('z')) { 184 | if (m_str [i] - _T ('a') + _T ('A') != _o.m_str [i]) 185 | return false; 186 | } else if (m_str [i] >= _T ('A') && m_str [i] <= _T ('Z')) { 187 | if (m_str [i] - _T ('A') + _T ('a') != _o.m_str [i]) 188 | return false; 189 | } else { 190 | return false; 191 | } 192 | } 193 | return true; } 194 | #if _HAS_CXX17 195 | bool is_equal_nocase (const std::string_view _s) { String _o (_s); return is_equal_nocase (_o); } 196 | bool is_equal_nocase (const std::wstring_view _s) { String _o (_s); return is_equal_nocase (_o); } 197 | #endif 198 | 199 | // 其他符号重载函数 200 | String operator* (size_t n) { 201 | String _s; 202 | if (n == 0 || n == _npos) 203 | return _s; 204 | while (n-- > 0) 205 | _s.m_str += m_str; 206 | return _s; 207 | } 208 | friend String operator* (size_t n, String &_o) { return _o.operator* (n); } 209 | String &operator*= (size_t n) { 210 | if (n == 0 || n == _npos) { 211 | m_str.clear (); 212 | } else { 213 | string_t _str = m_str; 214 | while (--n > 0) 215 | m_str += _str; 216 | } 217 | return *this; 218 | } 219 | 220 | // 字符串迭代器处理 221 | string_t::iterator begin () { return m_str.begin (); } 222 | string_t::iterator end () { return m_str.end (); } 223 | string_t::const_iterator cbegin () { return m_str.cbegin (); } 224 | string_t::const_iterator cend () { return m_str.cend (); } 225 | string_t::reverse_iterator rbegin () { return m_str.rbegin (); } 226 | string_t::reverse_iterator rend () { return m_str.rend (); } 227 | string_t::const_reverse_iterator crbegin () { return m_str.crbegin (); } 228 | string_t::const_reverse_iterator crend () { return m_str.crend (); } 229 | 230 | // 字符串流处理 231 | String &operator<< (flag _f) { m_last_flag = _f; return *this; } 232 | friend String &operator>> (flag _f, String &_o) { _o.m_last_flag = _f; return _o; } 233 | String &operator>> (TCHAR &n) { 234 | if (m_str.empty ()) { 235 | n = _T ('\0'); 236 | } else { 237 | n = *m_str.rbegin (); 238 | m_str.pop_back (); 239 | } 240 | return *this; 241 | } 242 | String &operator<< (TCHAR n) { 243 | double _dot = 0; 244 | size_t _width = 0; 245 | flag _align = flag::align_right; 246 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 247 | // 248 | string_t _str (1, n); 249 | _make_flag_space (_width, _align, _str); 250 | m_str += _str; 251 | return *this; 252 | } 253 | friend String &operator>> (TCHAR n, String &_o) { 254 | double _dot = 0; 255 | size_t _width = 0; 256 | flag _align = flag::align_right; 257 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 258 | // 259 | string_t _str (1, n); 260 | _make_flag_space (_width, _align, _str); 261 | _o.m_str.insert (_o.m_str.begin (), _str.begin (), _str.end ()); 262 | return _o; 263 | } 264 | friend String &operator<< (TCHAR &n, String &_o) { 265 | if (_o.m_str.empty ()) { 266 | n = _T ('\0'); 267 | } else { 268 | n = *_o.m_str.begin (); 269 | _o.m_str.erase (_o.m_str.begin ()); 270 | } return _o; 271 | } 272 | String &operator>> (int &n) { 273 | n = 0; 274 | int _level = 1; 275 | for (size_t i = m_str.size () - 1; i != _npos; --i) { 276 | if (m_str[i] >= _T ('0') && m_str[i] <= _T ('9')) { 277 | n += _level * (m_str[i] - _T ('0')); 278 | m_str.erase (m_str.begin () + i); 279 | _level *= 10; 280 | } else if (m_str[i] == _T ('-')) { 281 | n = 0 - n; 282 | m_str.erase (m_str.begin () + i); 283 | break; 284 | } else { 285 | break; 286 | } 287 | } 288 | return *this; 289 | } 290 | String &operator<< (int n) { 291 | double _dot = 0; 292 | size_t _width = 0; 293 | flag _align = flag::align_right; 294 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 295 | // 296 | String _tmp = String::format (_T ("%d"), n); 297 | _make_flag_space (_width, _align, _tmp.m_str); 298 | m_str += _tmp.m_str; 299 | return *this; 300 | } 301 | friend String &operator>> (int n, String &_o) { 302 | double _dot = 0; 303 | size_t _width = 0; 304 | flag _align = flag::align_right; 305 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 306 | // 307 | String _tmp = String::format (_T ("%d"), n); 308 | _make_flag_space (_width, _align, _tmp.m_str); 309 | _o.m_str.insert (_o.m_str.begin (), _tmp.m_str.begin (), _tmp.m_str.end ()); 310 | return _o; 311 | } 312 | friend String &operator<< (int &n, String &_o) { 313 | n = 0; 314 | if (_o.m_str.size () == 0) 315 | return _o; 316 | bool _sign = (_o.m_str[0] == _T ('-')); 317 | size_t i = (_sign ? 1 : 0); 318 | for (; i < _o.m_str.size () && _o.m_str[i] >= _T ('0') && _o.m_str[i] <= _T ('9'); ++i) 319 | n = n * 10 + (_o.m_str[i] - _T ('0')); 320 | if (_sign) 321 | n = 0 - n; 322 | _o.m_str.erase (_o.m_str.begin (), _o.m_str.begin () + i); 323 | return _o; 324 | } 325 | String &operator>> (unsigned int &n) { 326 | n = 0; 327 | unsigned int _level = 1; 328 | for (size_t i = m_str.size () - 1; i != _npos; --i) { 329 | if (m_str[i] >= _T ('0') && m_str[i] <= _T ('9')) { 330 | n += _level * (m_str[i] - _T ('0')); 331 | m_str.erase (m_str.begin () + i); 332 | _level *= 10; 333 | } else { 334 | break; 335 | } 336 | } 337 | return *this; 338 | } 339 | String &operator<< (unsigned int n) { 340 | double _dot = 0; 341 | size_t _width = 0; 342 | flag _align = flag::align_right; 343 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 344 | // 345 | String _tmp = String::format (_T ("%u"), n); 346 | _make_flag_space (_width, _align, _tmp.m_str); 347 | m_str += _tmp.m_str; 348 | return *this; 349 | } 350 | friend String &operator>> (unsigned int n, String &_o) { 351 | double _dot = 0; 352 | size_t _width = 0; 353 | flag _align = flag::align_right; 354 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 355 | // 356 | String _tmp = String::format (_T ("%u"), n); 357 | _make_flag_space (_width, _align, _tmp.m_str); 358 | _o.m_str.insert (_o.m_str.begin (), _tmp.m_str.begin (), _tmp.m_str.end ()); 359 | return _o; 360 | } 361 | friend String &operator<< (unsigned int &n, String &_o) { 362 | n = 0; 363 | if (_o.m_str.size () == 0) 364 | return _o; 365 | size_t i = 0; 366 | for (; i < _o.m_str.size () && _o.m_str[i] >= _T ('0') && _o.m_str[i] <= _T ('9'); ++i) 367 | n = n * 10 + (_o.m_str[i] - _T ('0')); 368 | _o.m_str.erase (_o.m_str.begin (), _o.m_str.begin () + i); 369 | return _o; 370 | } 371 | String &operator>> (float &n) { 372 | n = 0; 373 | float _level = 1; 374 | for (size_t i = m_str.size () - 1; i != _npos; --i) { 375 | if (m_str [i] >= _T ('0') && m_str [i] <= _T ('9')) { 376 | n += _level * (m_str [i] - _T ('0')); 377 | m_str.erase (m_str.begin () + i); 378 | _level *= 10; 379 | } else if (m_str [i] == _T ('-')) { 380 | n = 0 - n; 381 | m_str.erase (m_str.begin () + i); 382 | break; 383 | } else if (m_str [i] == _T ('.')) { 384 | n /= (_level / 10); 385 | _level = 0.1f; 386 | } else { 387 | break; 388 | } 389 | } 390 | return *this; 391 | } 392 | String &operator<< (float n) { 393 | double _dot = 0; 394 | size_t _width = 0; 395 | flag _align = flag::align_right; 396 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 397 | // 398 | String _tmp = String::format (String::format (_T ("%%.%df"), _dot).c_str (), n); 399 | _make_flag_space (_width, _align, _tmp.m_str); 400 | m_str += _tmp.m_str; 401 | return *this; 402 | } 403 | friend String &operator>> (float n, String &_o) { 404 | double _dot = 0; 405 | size_t _width = 0; 406 | flag _align = flag::align_right; 407 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 408 | // 409 | String _tmp = String::format (String::format (_T ("%%.%df"), _dot).c_str (), n); 410 | _make_flag_space (_width, _align, _tmp.m_str); 411 | _o.m_str.insert (_o.m_str.begin (), _tmp.m_str.begin (), _tmp.m_str.end ()); 412 | return _o; 413 | } 414 | friend String &operator<< (float &n, String &_o) { 415 | n = 0; 416 | if (_o.m_str.size () == 0) 417 | return _o; 418 | bool _sign = (_o.m_str [0] == _T ('-')); 419 | float _level = 1.0f; 420 | size_t i = (_sign ? 1 : 0); 421 | for (; i < _o.m_str.size (); ++i) { 422 | if (_o.m_str [i] >= _T ('0') && _o.m_str [i] <= _T ('9')) { 423 | if (_level >= 1.0f) { 424 | n = n * 10 + (_o.m_str [i] - _T ('0')); 425 | } else { 426 | n += _level * (_o.m_str [i] - _T ('0')); 427 | _level /= 10; 428 | } 429 | } else if (_o.m_str [i] == _T ('.')) { 430 | _level = 0.1f; 431 | } 432 | } 433 | if (_sign) 434 | n = 0 - n; 435 | _o.m_str.erase (_o.m_str.begin (), _o.m_str.begin () + i); 436 | return _o; 437 | } 438 | String &operator>> (double &n) { 439 | n = 0; 440 | double _level = 1; 441 | for (size_t i = m_str.size () - 1; i != _npos; --i) { 442 | if (m_str [i] >= _T ('0') && m_str [i] <= _T ('9')) { 443 | n += _level * (m_str [i] - _T ('0')); 444 | m_str.erase (m_str.begin () + i); 445 | _level *= 10; 446 | } else if (m_str [i] == _T ('-')) { 447 | n = 0 - n; 448 | m_str.erase (m_str.begin () + i); 449 | break; 450 | } else if (m_str [i] == _T ('.')) { 451 | n /= (_level / 10); 452 | _level = 0.1; 453 | } else { 454 | break; 455 | } 456 | } 457 | return *this; 458 | } 459 | String &operator<< (double n) { 460 | double _dot = 0; 461 | size_t _width = 0; 462 | flag _align = flag::align_right; 463 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 464 | // 465 | String _tmp = String::format (String::format (_T ("%%.%dlf"), _dot).c_str (), n); 466 | _make_flag_space (_width, _align, _tmp.m_str); 467 | m_str += _tmp.m_str; 468 | return *this; 469 | } 470 | friend String &operator>> (double n, String &_o) { 471 | double _dot = 0; 472 | size_t _width = 0; 473 | flag _align = flag::align_right; 474 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 475 | // 476 | String _tmp = String::format (String::format (_T ("%%.%dlf"), _dot).c_str (), n); 477 | _make_flag_space (_width, _align, _tmp.m_str); 478 | _o.m_str.insert (_o.m_str.begin (), _tmp.m_str.begin (), _tmp.m_str.end ()); 479 | return _o; 480 | } 481 | friend String &operator<< (double &n, String &_o) { 482 | n = 0; 483 | if (_o.m_str.size () == 0) 484 | return _o; 485 | bool _sign = (_o.m_str [0] == _T ('-')); 486 | double _level = 1.0f; 487 | size_t i = (_sign ? 1 : 0); 488 | for (; i < _o.m_str.size (); ++i) { 489 | if (_o.m_str [i] >= _T ('0') && _o.m_str [i] <= _T ('9')) { 490 | if (_level >= 1.0f) { 491 | n = n * 10 + (_o.m_str [i] - _T ('0')); 492 | } else { 493 | n += _level * (_o.m_str [i] - _T ('0')); 494 | _level /= 10; 495 | } 496 | } else if (_o.m_str [i] == _T ('.')) { 497 | _level = 0.1f; 498 | } 499 | } 500 | if (_sign) 501 | n = 0 - n; 502 | _o.m_str.erase (_o.m_str.begin (), _o.m_str.begin () + i); 503 | return _o; 504 | } 505 | friend std::ostream &operator<< (std::ostream &_stm, String &_s) { _stm << _s.stra (); return _stm; } 506 | friend std::wostream &operator<< (std::wostream &_stm, String &_s) { _stm << _s.strw (); return _stm; } 507 | String &operator<< (const char *_s) { 508 | double _dot = 0; 509 | size_t _width = 0; 510 | flag _align = flag::align_right; 511 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 512 | // 513 | String _s2 (_s); 514 | _make_flag_space (_width, _align, _s2.m_str); 515 | m_str += _s2.m_str; 516 | return *this; 517 | } 518 | friend String &operator>> (const char *_s, String &_o) { 519 | double _dot = 0; 520 | size_t _width = 0; 521 | flag _align = flag::align_right; 522 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 523 | // 524 | String _s2 (_s); 525 | _make_flag_space (_width, _align, _s2.m_str); 526 | _o.m_str.insert (_o.m_str.begin (), _s2.m_str.begin (), _s2.m_str.end ()); 527 | return _o; 528 | } 529 | String &operator<< (const wchar_t *_s) { 530 | double _dot = 0; 531 | size_t _width = 0; 532 | flag _align = flag::align_right; 533 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 534 | // 535 | String _s2 (_s); 536 | _make_flag_space (_width, _align, _s2.m_str); 537 | m_str += _s2.m_str; 538 | return *this; 539 | } 540 | friend String &operator>> (const wchar_t *_s, String &_o) { 541 | double _dot = 0; 542 | size_t _width = 0; 543 | flag _align = flag::align_right; 544 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 545 | // 546 | String _s2 (_s); 547 | _make_flag_space (_width, _align, _s2.m_str); 548 | _o.m_str.insert (_o.m_str.begin (), _s2.m_str.begin (), _s2.m_str.end ()); 549 | return _o; 550 | } 551 | String &operator<< (std::string &_s) { 552 | double _dot = 0; 553 | size_t _width = 0; 554 | flag _align = flag::align_right; 555 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 556 | // 557 | String _s2 (_s); 558 | _make_flag_space (_width, _align, _s2.m_str); 559 | m_str += _s2.m_str; 560 | return *this; 561 | } 562 | friend String &operator>> (std::string &_s, String &_o) { 563 | double _dot = 0; 564 | size_t _width = 0; 565 | flag _align = flag::align_right; 566 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 567 | // 568 | String _s2 (_s); 569 | _make_flag_space (_width, _align, _s2.m_str); 570 | _o.m_str.insert (_o.m_str.begin (), _s2.m_str.begin (), _s2.m_str.end ()); 571 | return _o; 572 | } 573 | String &operator<< (std::wstring &_s) { 574 | double _dot = 0; 575 | size_t _width = 0; 576 | flag _align = flag::align_right; 577 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 578 | // 579 | String _s2 (_s); 580 | _make_flag_space (_width, _align, _s2.m_str); 581 | m_str += _s2.m_str; 582 | return *this; 583 | } 584 | friend String &operator>> (std::wstring &_s, String &_o) { 585 | double _dot = 0; 586 | size_t _width = 0; 587 | flag _align = flag::align_right; 588 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 589 | // 590 | String _s2 (_s); 591 | _make_flag_space (_width, _align, _s2.m_str); 592 | _o.m_str.insert (_o.m_str.begin (), _s2.m_str.begin (), _s2.m_str.end ()); 593 | return _o; 594 | } 595 | #if _HAS_CXX17 596 | String &operator<< (std::string_view &_s) { 597 | double _dot = 0; 598 | size_t _width = 0; 599 | flag _align = flag::align_right; 600 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 601 | // 602 | String _s2 (_s); 603 | _make_flag_space (_width, _align, _s2.m_str); 604 | m_str += _s2.m_str; 605 | return *this; 606 | } 607 | friend String &operator>> (std::string_view &_s, String &_o) { 608 | double _dot = 0; 609 | size_t _width = 0; 610 | flag _align = flag::align_right; 611 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 612 | // 613 | String _s2 (_s); 614 | _make_flag_space (_width, _align, _s2.m_str); 615 | _o.m_str.insert (_o.m_str.begin (), _s2.m_str.begin (), _s2.m_str.end ()); 616 | return _o; 617 | } 618 | String &operator<< (std::wstring_view &_s) { 619 | double _dot = 0; 620 | size_t _width = 0; 621 | flag _align = flag::align_right; 622 | std::tie (_dot, _width, _align) = _get_flag_info (m_last_flag); 623 | // 624 | String _s2 (_s); 625 | _make_flag_space (_width, _align, _s2.m_str); 626 | m_str += _s2.m_str; 627 | return *this; 628 | } 629 | friend String &operator>> (std::wstring_view &_s, String &_o) { 630 | double _dot = 0; 631 | size_t _width = 0; 632 | flag _align = flag::align_right; 633 | std::tie (_dot, _width, _align) = _get_flag_info (_o.m_last_flag); 634 | // 635 | String _s2 (_s); 636 | _make_flag_space (_width, _align, _s2.m_str); 637 | _o.m_str.insert (_o.m_str.begin (), _s2.m_str.begin (), _s2.m_str.end ()); 638 | return _o; 639 | } 640 | #endif 641 | 642 | // 字符串查找 643 | size_t find (TCHAR _ch, size_t _off = 0) { return m_str.find (_ch, _off); } 644 | size_t rfind (TCHAR _ch, size_t _off = _npos) { return m_str.rfind (_ch, _off); } 645 | #ifdef _UNICODE 646 | size_t find (std::string &_s, size_t _off = 0) { return m_str.find (Encoding::gb18030_to_utf16 (_s), _off); } 647 | size_t find (std::wstring &_s, size_t _off = 0) { return m_str.find (_s, _off); } 648 | size_t rfind (std::string &_s, size_t _off = 0) { return m_str.rfind (Encoding::gb18030_to_utf16 (_s), _off); } 649 | size_t rfind (std::wstring &_s, size_t _off = 0) { return m_str.rfind (_s, _off); } 650 | # if _HAS_CXX17 651 | size_t find (std::string_view _s, size_t _off = 0) { return m_str.find (Encoding::gb18030_to_utf16 (_s), _off); } 652 | size_t find (std::wstring_view _s, size_t _off = 0) { return m_str.find (_s, _off); } 653 | size_t rfind (std::string_view _s, size_t _off = 0) { return m_str.rfind (Encoding::gb18030_to_utf16 (_s), _off); } 654 | size_t rfind (std::wstring_view _s, size_t _off = 0) { return m_str.rfind (_s, _off); } 655 | # endif 656 | #else 657 | size_t find (std::string &_s, size_t _off = 0) { return m_str.find (_s, _off); } 658 | size_t find (std::wstring &_s, size_t _off = 0) { return m_str.find (Encoding::utf16_to_gb18030 (_s), _off); } 659 | size_t rfind (std::string &_s, size_t _off = 0) { return m_str.rfind (_s, _off); } 660 | size_t rfind (std::wstring &_s, size_t _off = 0) { return m_str.rfind (Encoding::utf16_to_gb18030 (_s), _off); } 661 | # if _HAS_CXX17 662 | size_t find (std::string_view _s, size_t _off = 0) { return m_str.find (_s, _off); } 663 | size_t find (std::wstring_view _s, size_t _off = 0) { return m_str.find (Encoding::utf16_to_gb18030 (_s), _off); } 664 | size_t rfind (std::string_view _s, size_t _off = 0) { return m_str.rfind (_s, _off); } 665 | size_t rfind (std::wstring_view _s, size_t _off = 0) { return m_str.rfind (Encoding::utf16_to_gb18030 (_s), _off); } 666 | # endif 667 | #endif 668 | size_t find_any (std::initializer_list _cs) { 669 | size_t _ret = _npos; 670 | for (auto &_c : _cs) { 671 | size_t _n = find (_c); 672 | _ret = (_ret == _npos || (_n != _npos && _n < _ret) ? _n : _ret); 673 | } 674 | return _ret; 675 | } 676 | size_t find_any (std::initializer_list _ss) { 677 | size_t _ret = _npos; 678 | for (auto &_s : _ss) { 679 | size_t _n = find (std::string_view (_s)); 680 | _ret = (_ret == _npos || (_n != _npos && _n < _ret) ? _n : _ret); 681 | } 682 | return _ret; 683 | } 684 | size_t find_any (std::initializer_list _ss) { 685 | size_t _ret = _npos; 686 | for (auto &_s : _ss) { 687 | size_t _n = find (std::wstring_view (_s)); 688 | _ret = (_ret == _npos || (_n != _npos && _n < _ret) ? _n : _ret); 689 | } 690 | return _ret; 691 | } 692 | size_t rfind_any (std::initializer_list _cs) { 693 | size_t _ret = _npos; 694 | for (auto &_c : _cs) { 695 | size_t _n = rfind (_c); 696 | _ret = (_ret == _npos || (_n != _npos && _n > _ret) ? _n : _ret); 697 | } 698 | return _ret; 699 | } 700 | size_t rfind_any (std::initializer_list _ss) { 701 | size_t _ret = _npos; 702 | for (auto &_s : _ss) { 703 | size_t _n = rfind (std::string_view (_s)); 704 | _ret = (_ret == _npos || (_n != _npos && _n > _ret) ? _n : _ret); 705 | } 706 | return _ret; 707 | } 708 | size_t rfind_any (std::initializer_list _ss) { 709 | size_t _ret = _npos; 710 | for (auto &_s : _ss) { 711 | size_t _n = rfind (std::wstring_view (_s)); 712 | _ret = (_ret == _npos || (_n != _npos && _n > _ret) ? _n : _ret); 713 | } 714 | return _ret; 715 | } 716 | 717 | // 字符串处理(生成新字符串) 718 | String trim_left () const { String _s (*this); _s.m_str.erase (0, _s.m_str.find_first_not_of (_T (' '))); return _s; } 719 | String trim_right () const { String _s (*this); _s.m_str.erase (_s.m_str.find_last_not_of (' ') + 1); return _s; } 720 | String trim () const { return trim_left ().trim_right_self (); } 721 | String upper () const { String _s (*this); std::transform (_s.m_str.begin (), _s.m_str.end (), _s.m_str.begin (), ::toupper); return _s; } 722 | String lower () const { String _s (*this); std::transform (_s.m_str.begin (), _s.m_str.end (), _s.m_str.begin (), ::tolower); return _s; } 723 | String reverse () const { 724 | String _s (*this); 725 | size_t size = _s.m_str.size (); 726 | for (size_t i = 0; i < size / 2; ++i) { 727 | TCHAR ch = _s.m_str [i]; 728 | _s.m_str [i] = _s.m_str [size - i - 1]; 729 | _s.m_str [size - i - 1] = ch; 730 | } 731 | return _s; 732 | } 733 | String replace (std::string_view _src, std::string_view _dest) const { 734 | String _s (*this); 735 | #ifdef _UNICODE 736 | std::wstring _tmp_src = faw::Encoding::gb18030_to_utf16 (_src); 737 | std::wstring _tmp_dest = faw::Encoding::gb18030_to_utf16 (_dest); 738 | return replace (_tmp_src, _tmp_dest); 739 | #else 740 | size_t pos = _s.m_str.find (_src); 741 | while (pos != _npos) { 742 | _s.m_str.replace (pos, _src.size (), _dest); 743 | pos = _src.find (_src, pos + 2); 744 | } 745 | return _s; 746 | #endif 747 | } 748 | String replace (std::wstring_view _src, std::wstring_view _dest) const { 749 | String _s (*this); 750 | #ifdef _UNICODE 751 | size_t pos = _s.m_str.find (_src); 752 | while (pos != _npos) { 753 | _s.m_str.replace (pos, _src.size (), _dest); 754 | pos = _src.find (_src, pos + 2); 755 | } 756 | return _s; 757 | #else 758 | std::string _tmp_src = Encoding::utf16_to_gb18030 (_src); 759 | std::string _tmp_dest = Encoding::utf16_to_gb18030 (_dest); 760 | return replace (_tmp_src, _tmp_dest); 761 | #endif 762 | } 763 | String replace (TCHAR _src, TCHAR _dest) const { 764 | String _s (*this); 765 | size_t pos = _s.m_str.find (_src); 766 | while (pos != _npos) { 767 | _s.m_str [pos] = _dest; 768 | pos = _s.m_str.find (_src, pos + 1); 769 | } 770 | return _s; 771 | } 772 | String left (size_t n) const { return (n >= size () ? str () : str ().substr (0, n)); } 773 | bool left_is (String _str) const { return left (_str.size ()).operator== (_str); } 774 | String right (size_t n) const { return (n >= size () ? str () : str ().substr (size () - n)); } 775 | bool right_is (String _str) const { return right (_str.size ()).operator== (_str); } 776 | String substr (size_t begin, size_t len = String::_npos) const { return (begin >= size () ? _T ("") : (begin + len >= size () ? str ().substr (begin) : str ().substr (begin, len))); } 777 | 778 | // 字符串处理(改变自身) 779 | String &trim_left_self () { m_str.erase (0, m_str.find_first_not_of (_T (' '))); return *this; } 780 | String &trim_right_self () { m_str.erase (m_str.find_last_not_of (' ') + 1); return *this; } 781 | String &trim_self () { return trim_left_self ().trim_right_self (); } 782 | String &upper_self () { std::transform (m_str.begin (), m_str.end (), m_str.begin (), ::toupper); return *this; } 783 | String &lower_self () { std::transform (m_str.begin (), m_str.end (), m_str.begin (), ::tolower); return *this; } 784 | String &reverse_self () { 785 | size_t size = m_str.size (); 786 | for (size_t i = 0; i < size / 2; ++i) { 787 | TCHAR ch = m_str [i]; 788 | m_str [i] = m_str [size - i - 1]; 789 | m_str [size - i - 1] = ch; 790 | } 791 | return *this; 792 | } 793 | String &replace_self (std::string_view _src, std::string_view _dest) { 794 | #ifdef _UNICODE 795 | std::wstring _tmp_src = faw::Encoding::gb18030_to_utf16 (_src); 796 | std::wstring _tmp_dest = faw::Encoding::gb18030_to_utf16 (_dest); 797 | return replace_self (_tmp_src, _tmp_dest); 798 | #else 799 | size_t pos = m_str.find (_src); 800 | while (pos != _npos) { 801 | m_str.replace (pos, _src.size (), _dest); 802 | pos = m_str.find (_src, pos + 2); 803 | } 804 | return *this; 805 | #endif 806 | } 807 | String &replace_self (std::wstring_view _src, std::wstring_view _dest) { 808 | #ifdef _UNICODE 809 | size_t pos = m_str.find (_src); 810 | while (pos != _npos) { 811 | m_str.replace (pos, _src.size (), _dest); 812 | pos = m_str.find (_src, pos + 2); 813 | } 814 | return *this; 815 | #else 816 | std::string _tmp_src = Encoding::utf16_to_gb18030 (_src); 817 | std::string _tmp_dest = Encoding::utf16_to_gb18030 (_dest); 818 | return replace_self (_tmp_src, _tmp_dest); 819 | #endif 820 | } 821 | String &replace_self (TCHAR _src, TCHAR _dest) { 822 | size_t pos = m_str.find (_src); 823 | while (pos != _npos) { 824 | m_str [pos] = _dest; 825 | pos = m_str.find (_src); 826 | } 827 | return *this; 828 | } 829 | String &left_self (size_t n) { m_str = (n >= size () ? str () : str ().substr (0, n)); return *this; } 830 | String &right_self (size_t n) { m_str = (n >= size () ? str () : str ().substr (size () - n)); return *this; } 831 | String &substr_self (size_t begin, size_t len = String::_npos) { m_str = (begin >= size () ? _T ("") : (begin + len >= size () ? str ().substr (begin) : str ().substr (begin, len))); return *this; } 832 | 833 | // 字符串基本方法 834 | bool empty () const { return m_str.empty (); } 835 | void clear () { m_str.clear (); } 836 | void free () { string_t _str = _T (""); _str.swap (m_str); } 837 | size_t size () const { return m_str.size (); } 838 | //TCHAR &operator[] (intptr_t n) { n = (n > 0 ? (n < size () ? n : size () - 1) : (n > -size () ? size () - n : 0)); return m_str [n]; } 839 | TCHAR &operator[] (size_t n) { return m_str [n]; } 840 | TCHAR &at (intptr_t n) { static TCHAR _ch = _T ('\0'); return (size () == 0 ? _ch : m_str [((n % size ()) + size ()) % size ()]); } 841 | const TCHAR *c_str () const { return m_str.c_str (); } 842 | const string_t &str () const { return m_str; } 843 | #if _HAS_CXX17 844 | string_view_t str_view () const { return string_view_t (m_str); } 845 | #endif 846 | std::string stra () const { return Encoding::T_to_gb18030 (m_str); } 847 | std::wstring strw () const { return Encoding::T_to_utf16 (m_str); } 848 | //const TCHAR *operator() () { return m_str.c_str (); } 849 | 850 | // 比较及hash 851 | bool operator< (const String &_str) const { return m_str < _str.m_str; } 852 | bool operator<= (const String &_str) const { return m_str <= _str.m_str; } 853 | bool operator> (const String &_str) const { return m_str > _str.m_str; } 854 | bool operator>= (const String &_str) const { return m_str >= _str.m_str; } 855 | 856 | // 857 | std::vector split (TCHAR _sp = _T (' '), bool no_empty = true) { 858 | size_t start = 0, start_find = 0; 859 | std::vector v; 860 | while (start_find < m_str.size ()) { 861 | size_t p = m_str.find (_sp, start_find); 862 | if (p == _npos) p = m_str.size (); 863 | if (!no_empty || p > start) 864 | v.push_back (m_str.substr (start, p - start)); 865 | start = start_find = p + 1; 866 | } 867 | return v; 868 | } 869 | std::vector split (string_view_t _sp = _T (" "), bool no_empty = true) { 870 | size_t start = 0, start_find = 0; 871 | std::vector v; 872 | while (start_find < m_str.size ()) { 873 | size_t p = m_str.find (_sp, start_find); 874 | if (p == _npos) p = m_str.size (); 875 | if (!no_empty || p > start) 876 | v.push_back (m_str.substr (start, p - start)); 877 | start = start_find = p + _sp.size (); 878 | } 879 | return v; 880 | } 881 | std::vector match_regex (std::string _re) { 882 | std::string _src = stra (); 883 | //std::string err = ""; 884 | std::vector v; 885 | try { 886 | std::regex r (_re); 887 | std::smatch m; 888 | std::string::const_iterator _begin = _src.cbegin (), _end = _src.cend (); 889 | while (std::regex_search (_begin, _end, m, r)) { 890 | v.push_back (m [0].str ()); 891 | _begin = m [0].second; 892 | } 893 | //} catch (std::exception &e) { 894 | // err = e.what (); 895 | } catch (...) { 896 | // err = "未知错误。"; 897 | } 898 | return v; 899 | } 900 | static String format (const char *_fmt, ...) { 901 | std::string str_result = ""; 902 | if (!_fmt || !*_fmt) 903 | return str_result; 904 | try { 905 | va_list ap; 906 | #ifndef __GNUC__ 907 | //来源:http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf 908 | size_t final_n, n = lstrlenA (_fmt) * 2; 909 | std::unique_ptr formatted; 910 | while (true) { 911 | formatted.reset (new char [n]); 912 | va_start (ap, _fmt); 913 | final_n = _vsnprintf_s (&formatted [0], n, _TRUNCATE, _fmt, ap); 914 | va_end (ap); 915 | if (final_n < 0 || final_n >= n) 916 | n += abs ((int) (final_n - n + 1)); 917 | else 918 | break; 919 | } 920 | str_result = formatted.get (); 921 | #else //__GNUC__ 922 | char *buf = nullptr; 923 | va_start (ap, _fmt); 924 | int iresult = vasprintf (&buf, _fmt, ap); 925 | va_end (ap); 926 | if (buf) { 927 | if (iresult >= 0) { 928 | iresult = strlen (buf); 929 | str_result.append (buf, iresult); 930 | } 931 | free (buf); 932 | } 933 | #endif //__GNUC__ 934 | } catch (...) { 935 | } 936 | return str_result; 937 | } 938 | static String format (const wchar_t *_fmt, ...) { 939 | std::wstring str_result = L""; 940 | if (!_fmt || !*_fmt) 941 | return str_result; 942 | try { 943 | va_list ap; 944 | #ifndef __GNUC__ 945 | //来源:http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf 946 | size_t final_n, n = lstrlenW (_fmt) * 2; 947 | std::unique_ptr formatted; 948 | while (true) { 949 | formatted.reset (new wchar_t [n]); 950 | va_start (ap, _fmt); 951 | final_n = _vsnwprintf_s (&formatted [0], n, _TRUNCATE, _fmt, ap); 952 | va_end (ap); 953 | if (final_n < 0 || final_n >= n) 954 | n += abs ((int) (final_n - n + 1)); 955 | else 956 | break; 957 | } 958 | str_result = formatted.get (); 959 | #else //__GNUC__ 960 | wchar_t *buf = nullptr; 961 | va_start (ap, _fmt); 962 | int iresult = vswprintf (&buf, _fmt, ap); 963 | va_end (ap); 964 | if (buf) { 965 | if (iresult >= 0) { 966 | iresult = strlen (buf); 967 | str_result.append (buf, iresult); 968 | } 969 | free (buf); 970 | } 971 | #endif //__GNUC__ 972 | } catch (...) { 973 | } 974 | return str_result; 975 | } 976 | static size_t _npos; 977 | 978 | private: 979 | // flag专用,用于提取flag信息 980 | static std::tuple _get_flag_info (flag &_f) { 981 | static std::map m_dot { { flag::decimal_0, 0 }, { flag::decimal_1, 0.1 }, { flag::decimal_2, 0.01 }, { flag::decimal_3, 0.001 }, { flag::decimal_4, 0.0001 }, { flag::decimal_5, 0.00001 }, { flag::decimal_6, 0.000001 }, { flag::decimal_7, 0.0000001 }, { flag::decimal_8, 0.00000001 }, { flag::decimal_9, 0.000000001 }, { flag::whole_10, 10 }, { flag::whole_100, 100 }, { flag::whole_1k, 1000 }, { flag::whole_10k, 10000 }, { flag::whole_100k, 100000 }, { flag::whole_1m, 1000000 } }; 982 | // 983 | double _dot = 0; 984 | if (m_dot.find ((flag) (((size_t) _f) & 0x000f0000)) != m_dot.end ()) 985 | _dot = m_dot [(flag) (((size_t) _f) & 0x000f0000)]; 986 | size_t _width = ((size_t) _f) & 0x0000ffff; 987 | flag _align = (flag) (((size_t) _f) & ((size_t) flag::_align)); 988 | _align = (_align == flag::_align ? flag::align_right : _align); 989 | _f = flag::none; 990 | return std::make_tuple (_dot, _width, _align); 991 | } 992 | // flag专用,用于获取padding字符串 993 | static void _make_flag_space (size_t _width, flag _align, string_t &_src) { 994 | size_t _left_count = 0, _right_count = 0; 995 | if (_align == flag::align_right && _width > _src.size ()) { 996 | _left_count = _width - _src.size (); 997 | } else if (_align == flag::align_middle && _width > _src.size ()) { 998 | _left_count = (_width - _src.size ()) / 2; 999 | } 1000 | if (_align == flag::align_left && _width > _src.size ()) { 1001 | _right_count = _width - _src.size (); 1002 | } else if (_align == flag::align_middle && _width > _src.size ()) { 1003 | _right_count = _width - _src.size () - _left_count; 1004 | } 1005 | _src.insert (_src.begin (), _left_count, _T (' ')); 1006 | _src.insert (_src.end (), _right_count, _T (' ')); 1007 | } 1008 | 1009 | string_t m_str; 1010 | flag m_last_flag = flag::none; 1011 | }; 1012 | 1013 | __declspec (selectany) size_t String::_npos = string_t::npos; 1014 | } 1015 | 1016 | #if _HAS_CXX17 1017 | inline namespace _faw { 1018 | [[nodiscard]] inline ::faw::String operator "" _fs (const char *_s, size_t _len) noexcept { return ::faw::String (_s, (size_t) _len); } 1019 | [[nodiscard]] inline ::faw::String operator "" _fs (const wchar_t *_s, size_t _len) noexcept { return ::faw::String (_s, (size_t) _len); } 1020 | } 1021 | #endif 1022 | 1023 | 1024 | 1025 | #endif //FAWLIB__STRING_HPP__ 1026 | -------------------------------------------------------------------------------- /include/FawLib/ThreadPool.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Class Name: ThreadPool 4 | // Description: 线程池类 5 | // Class URI: https://github.com/fawdlstty/FawLib 6 | // Author: Fawdlstty 7 | // Author URI: https://www.fawdlstty.com/ 8 | // License: MIT 9 | // Last Update: Apr 02, 2019 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | #ifndef FAWLIB__THREAD_POOL_HPP__ 14 | #define FAWLIB__THREAD_POOL_HPP__ 15 | 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | namespace faw { 28 | class ThreadPool { 29 | public: 30 | ThreadPool (size_t _threads) { 31 | for (size_t i = 0; i < _threads; ++i) { 32 | m_workers.emplace_back ([this] { 33 | while (true) { 34 | std::unique_lock ul (m_mutex); 35 | m_condition.wait (ul, [this] { return !m_run || !m_tasks.empty (); }); 36 | if (!m_run) 37 | return; 38 | std::function _task = std::move (m_tasks.front ()); 39 | m_tasks.pop (); 40 | ul.unlock (); 41 | _task (); 42 | } 43 | }); 44 | } 45 | } 46 | 47 | ~ThreadPool () { 48 | m_run = false; 49 | m_condition.notify_all (); 50 | for (std::thread &_worker : m_workers) 51 | _worker.join (); 52 | } 53 | 54 | template 55 | auto enqueue (F&& f, Args&&... args) ->std::future::type> { 56 | using return_type = typename std::result_of::type; 57 | auto _task = std::make_shared> (std::bind (std::forward (f), std::forward (args)...)); 58 | std::future _res = _task->get_future (); 59 | std::unique_lock ul (m_mutex); 60 | m_tasks.emplace ([_task] () { (*_task)(); }); 61 | ul.unlock (); 62 | m_condition.notify_one (); 63 | return _res; 64 | } 65 | 66 | private: 67 | std::vector m_workers; 68 | std::queue> m_tasks; 69 | std::mutex m_mutex; 70 | std::condition_variable m_condition; 71 | volatile bool m_run = true; 72 | }; 73 | } 74 | 75 | 76 | 77 | #endif //FAWLIB__THREAD_POOL_HPP__ 78 | -------------------------------------------------------------------------------- /include/FawLib/unzip.h: -------------------------------------------------------------------------------- 1 | #ifndef _unzip_H 2 | #define _unzip_H 3 | 4 | // UNZIPPING functions -- for unzipping. 5 | // This file is a repackaged form of extracts from the zlib code available 6 | // at www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original 7 | // copyright notice may be found in unzip.cpp. The repackaging was done 8 | // by Lucian Wischik to simplify and extend its use in Windows/C++. Also 9 | // encryption and unicode filenames have been added. 10 | 11 | 12 | #ifndef _zip_H 13 | DECLARE_HANDLE (HZIP); 14 | #endif 15 | // An HZIP identifies a zip file that has been opened 16 | 17 | typedef DWORD ZRESULT; 18 | // return codes from any of the zip functions. Listed later. 19 | 20 | typedef struct { 21 | int index; // index of this file within the zip 22 | TCHAR name[MAX_PATH]; // filename within the zip 23 | DWORD attr; // attributes, as in GetFileAttributes. 24 | FILETIME atime, ctime, mtime;// access, create, modify filetimes 25 | long comp_size; // sizes of item, compressed and uncompressed. These 26 | long unc_size; // may be -1 if not yet known (e.g. being streamed in) 27 | } ZIPENTRY; 28 | 29 | 30 | HZIP OpenZip (const TCHAR *fn, const char *password = nullptr); 31 | HZIP OpenZip (void *z, unsigned int len, const char *password = nullptr); 32 | HZIP OpenZipHandle (HANDLE h, const char *password); 33 | // OpenZip - opens a zip file and returns a handle with which you can 34 | // subsequently examine its contents. You can open a zip file from: 35 | // from a pipe: OpenZipHandle(hpipe_read,0); 36 | // from a file (by handle): OpenZipHandle(hfile,0); 37 | // from a file (by name): OpenZip("c:\\test.zip","password"); 38 | // from a memory block: OpenZip(bufstart, buflen,0); 39 | // If the file is opened through a pipe, then items may only be 40 | // accessed in increasing order, and an item may only be unzipped once, 41 | // although GetZipItem can be called immediately before and after unzipping 42 | // it. If it's opened in any other way, then full random access is possible. 43 | // Note: pipe input is not yet implemented. 44 | // Note: zip passwords are ascii, not unicode. 45 | // Note: for windows-ce, you cannot close the handle until after CloseZip. 46 | // but for real windows, the zip makes its own copy of your handle, so you 47 | // can close yours anytime. 48 | 49 | ZRESULT GetZipItem (HZIP hz, int index, ZIPENTRY *ze); 50 | // GetZipItem - call this to get information about an item in the zip. 51 | // If index is -1 and the file wasn't opened through a pipe, 52 | // then it returns information about the whole zipfile 53 | // (and in particular ze.index returns the number of index items). 54 | // Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY) 55 | // See below for notes on what happens when you unzip such an item. 56 | // Note: if you are opening the zip through a pipe, then random access 57 | // is not possible and GetZipItem(-1) fails and you can't discover the number 58 | // of items except by calling GetZipItem on each one of them in turn, 59 | // starting at 0, until eventually the call fails. Also, in the event that 60 | // you are opening through a pipe and the zip was itself created into a pipe, 61 | // then then comp_size and sometimes unc_size as well may not be known until 62 | // after the item has been unzipped. 63 | 64 | ZRESULT FindZipItem (HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); 65 | // FindZipItem - finds an item by name. ic means 'insensitive to case'. 66 | // It returns the index of the item, and returns information about it. 67 | // If nothing was found, then index is set to -1 and the function returns 68 | // an error code. 69 | 70 | ZRESULT UnzipItem (HZIP hz, int index, const TCHAR *fn); 71 | ZRESULT UnzipItem (HZIP hz, int index, void *z, unsigned int len); 72 | ZRESULT UnzipItemHandle (HZIP hz, int index, HANDLE h); 73 | // UnzipItem - given an index to an item, unzips it. You can unzip to: 74 | // to a pipe: UnzipItemHandle(hz,i, hpipe_write); 75 | // to a file (by handle): UnzipItemHandle(hz,i, hfile); 76 | // to a file (by name): UnzipItem(hz,i, ze.name); 77 | // to a memory block: UnzipItem(hz,i, buf,buflen); 78 | // In the final case, if the buffer isn't large enough to hold it all, 79 | // then the return code indicates that more is yet to come. If it was 80 | // large enough, and you want to know precisely how big, GetZipItem. 81 | // Note: zip files are normally stored with relative pathnames. If you 82 | // unzip with ZIP_FILENAME a relative pathname then the item gets created 83 | // relative to the current directory - it first ensures that all necessary 84 | // subdirectories have been created. Also, the item may itself be a directory. 85 | // If you unzip a directory with ZIP_FILENAME, then the directory gets created. 86 | // If you unzip it to a handle or a memory block, then nothing gets created 87 | // and it emits 0 bytes. 88 | ZRESULT SetUnzipBaseDir (HZIP hz, const TCHAR *dir); 89 | // if unzipping to a filename, and it's a relative filename, then it will be relative to here. 90 | // (defaults to current-directory). 91 | 92 | 93 | ZRESULT CloseZip (HZIP hz); 94 | // CloseZip - the zip handle must be closed with this function. 95 | 96 | unsigned int FormatZipMessage (ZRESULT code, TCHAR *buf, unsigned int len); 97 | // FormatZipMessage - given an error code, formats it as a string. 98 | // It returns the length of the error message. If buf/len points 99 | // to a real buffer, then it also writes as much as possible into there. 100 | 101 | 102 | // These are the result codes: 103 | #define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, 104 | #define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. 105 | // The following come from general system stuff (e.g. files not openable) 106 | #define ZR_GENMASK 0x0000FF00 107 | #define ZR_NODUPH 0x00000100 // couldn't duplicate the handle 108 | #define ZR_NOFILE 0x00000200 // couldn't create/open the file 109 | #define ZR_NOALLOC 0x00000300 // failed to allocate some resource 110 | #define ZR_WRITE 0x00000400 // a general error writing to the file 111 | #define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip 112 | #define ZR_MORE 0x00000600 // there's still more data to be unzipped 113 | #define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile 114 | #define ZR_READ 0x00000800 // a general error reading the file 115 | #define ZR_PASSWORD 0x00001000 // we didn't get the right password to unzip the file 116 | // The following come from mistakes on the part of the caller 117 | #define ZR_CALLERMASK 0x00FF0000 118 | #define ZR_ARGS 0x00010000 // general mistake with the arguments 119 | #define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't 120 | #define ZR_MEMSIZE 0x00030000 // the memory size is too small 121 | #define ZR_FAILED 0x00040000 // the thing was already failed when you called this function 122 | #define ZR_ENDED 0x00050000 // the zip creation has already been closed 123 | #define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken 124 | #define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped 125 | #define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip 126 | // The following come from bugs within the zip library itself 127 | #define ZR_BUGMASK 0xFF000000 128 | #define ZR_NOTINITED 0x01000000 // initialisation didn't work 129 | #define ZR_SEEK 0x02000000 // trying to seek in an unseekable file 130 | #define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed 131 | #define ZR_FLATE 0x05000000 // an internal error in the de/inflation code 132 | 133 | 134 | 135 | 136 | 137 | // e.g. 138 | // 139 | // SetCurrentDirectory("c:\\docs\\stuff"); 140 | // HZIP hz = OpenZip("c:\\stuff.zip",0); 141 | // ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index; 142 | // for (int i=0; i