├── .gitignore ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── Makefile ├── README.md ├── src ├── binary_io.cpp ├── binary_io.hpp ├── http_server.cpp ├── http_server.hpp ├── ilogger.cpp ├── ilogger.hpp ├── json.cpp ├── json.hpp ├── main.cpp ├── mongoose.c └── mongoose.h └── workspace ├── base_decode.jpg ├── demo1.jpg ├── demo2.jpg ├── favicon.jpg └── img.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | /objs 35 | /workspace/pro 36 | /workspace/logs -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "defines": [], 9 | "compilerPath": "/usr/bin/gcc", 10 | "cStandard": "gnu11", 11 | "cppStandard": "gnu++14" 12 | } 13 | ], 14 | "version": 4 15 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "g++ - Build and debug active file", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/workspace/pro", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}/workspace", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": true 23 | } 24 | ], 25 | "preLaunchTask": "build", 26 | "miDebuggerPath": "/usr/bin/gdb" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "array": "cpp", 4 | "atomic": "cpp", 5 | "*.tcc": "cpp", 6 | "cctype": "cpp", 7 | "chrono": "cpp", 8 | "clocale": "cpp", 9 | "cmath": "cpp", 10 | "condition_variable": "cpp", 11 | "cstdarg": "cpp", 12 | "cstddef": "cpp", 13 | "cstdint": "cpp", 14 | "cstdio": "cpp", 15 | "cstdlib": "cpp", 16 | "cstring": "cpp", 17 | "ctime": "cpp", 18 | "cwchar": "cpp", 19 | "cwctype": "cpp", 20 | "deque": "cpp", 21 | "unordered_map": "cpp", 22 | "unordered_set": "cpp", 23 | "vector": "cpp", 24 | "exception": "cpp", 25 | "algorithm": "cpp", 26 | "functional": "cpp", 27 | "ratio": "cpp", 28 | "system_error": "cpp", 29 | "tuple": "cpp", 30 | "type_traits": "cpp", 31 | "fstream": "cpp", 32 | "future": "cpp", 33 | "initializer_list": "cpp", 34 | "iomanip": "cpp", 35 | "iosfwd": "cpp", 36 | "istream": "cpp", 37 | "limits": "cpp", 38 | "memory": "cpp", 39 | "mutex": "cpp", 40 | "new": "cpp", 41 | "ostream": "cpp", 42 | "numeric": "cpp", 43 | "sstream": "cpp", 44 | "stdexcept": "cpp", 45 | "streambuf": "cpp", 46 | "thread": "cpp", 47 | "cinttypes": "cpp", 48 | "utility": "cpp", 49 | "typeinfo": "cpp" 50 | } 51 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "shell", 5 | "label": "build", 6 | "command": "make pro -j64" 7 | } 8 | ], 9 | "version": "2.0.0" 10 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 手写AI 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | cpp_srcs := $(shell find src -name "*.cpp") 3 | cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs)) 4 | cpp_objs := $(subst src/,objs/,$(cpp_objs)) 5 | 6 | c_srcs := $(shell find src -name "*.c") 7 | c_objs := $(patsubst %.c,%.o,$(c_srcs)) 8 | c_objs := $(subst src/,objs/,$(c_objs)) 9 | 10 | lean := /data/datav/expstation/lean 11 | include_paths := src 12 | library_paths := 13 | 14 | link_librarys := stdc++ dl 15 | 16 | run_paths := $(foreach item,$(library_paths),-Wl,-rpath=$(item)) 17 | include_paths := $(foreach item,$(include_paths),-I$(item)) 18 | library_paths := $(foreach item,$(library_paths),-L$(item)) 19 | link_librarys := $(foreach item,$(link_librarys),-l$(item)) 20 | 21 | cpp_compile_flags := -std=c++11 -fPIC -m64 -g -fopenmp -w -O0 -DHAS_CUDA_HALF 22 | link_flags := -pthread -fopenmp 23 | 24 | cpp_compile_flags += $(include_paths) 25 | link_flags += $(library_paths) $(link_librarys) $(run_paths) 26 | 27 | pro : workspace/pro 28 | 29 | workspace/pro : $(cpp_objs) $(cu_objs) $(c_objs) 30 | @echo Link $@ 31 | @mkdir -p $(dir $@) 32 | @g++ $^ -o $@ $(link_flags) 33 | 34 | objs/%.o : src/%.cpp 35 | @echo Compile CXX $< 36 | @mkdir -p $(dir $@) 37 | @g++ -c $< -o $@ $(cpp_compile_flags) 38 | 39 | objs/%.o : src/%.c 40 | @echo Compile CXX $< 41 | @mkdir -p $(dir $@) 42 | @g++ -c $< -o $@ $(cpp_compile_flags) 43 | 44 | run : workspace/pro 45 | @cd workspace && ./pro 46 | 47 | debug : 48 | @echo $(includes) 49 | 50 | clean : 51 | @rm -rf objs workspace/pro -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # http_server_cpp 2 | - C++的http服务器,简单好用 3 | 4 | ## 执行方式 5 | ```bash 6 | cd http_server_cpp 7 | make run -j6 8 | ``` 9 | 10 | ## 案例代码 11 | ```C++ 12 | #include "http_server.hpp" 13 | 14 | using namespace std; 15 | 16 | // 定义控制器,处理路由对应的请求,MVC模式里边的C部分, 17 | class LogicalController : public Controller{ 18 | SetupController(LogicalController); 19 | 20 | public: 21 | // 轻易请求的映射,这里的名称就是路由的地址 22 | DefRequestMapping(getReturn); 23 | }; 24 | 25 | // 定义路由的处理函数,类java spring。这里使用返回值作为response。实际上支持多种,请看具体代码 26 | Json::Value LogicalController::getReturn(const Json::Value& param){ 27 | 28 | Json::Value data; 29 | data["alpha"] = 3.15; 30 | data["name"] = "张三"; 31 | return success(data); 32 | } 33 | 34 | int main(int argc, char** argv) { 35 | 36 | // 创建http服务器,具有32个线程 37 | auto server = createHttpServer("0.0.0.0:8090", 32); 38 | if(server == nullptr) return -1; 39 | 40 | // 添加控制器对于路由v1 41 | server->add_controller("/v1", make_shared()); 42 | 43 | // 添加静态文件访问,对于路由/static,绑定到路径./上 44 | server->add_controller("/static", create_file_access_controller("./")); 45 | return while_loop(); 46 | } 47 | ``` 48 | 49 | ## 效果 50 | ![](workspace/demo1.jpg) 51 | ![](workspace/demo2.jpg) 52 | 53 | ## 关于我们 54 | - 我们的博客是:http://www.zifuture.com:8090/ 55 | - 我们的B站地址是:https://space.bilibili.com/1413433465 -------------------------------------------------------------------------------- /src/binary_io.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "binary_io.hpp" 3 | #include "ilogger.hpp" 4 | #include 5 | 6 | using namespace std; 7 | 8 | BinaryIO::~BinaryIO(){ 9 | close(); 10 | } 11 | 12 | bool BinaryIO::opened(){ 13 | if (flag_ == MemoryRead) 14 | return memoryRead_ != nullptr; 15 | else if (flag_ == MemoryWrite) 16 | return true; 17 | return false; 18 | } 19 | 20 | void BinaryIO::close(){ 21 | if (flag_ == MemoryRead) { 22 | memoryRead_ = nullptr; 23 | memoryCursor_ = 0; 24 | memoryLength_ = -1; 25 | } 26 | else if (flag_ == MemoryWrite) { 27 | memoryWrite_.clear(); 28 | memoryCursor_ = 0; 29 | memoryLength_ = -1; 30 | } 31 | } 32 | 33 | string BinaryIO::readData(int numBytes){ 34 | string output; 35 | output.resize(numBytes); 36 | 37 | int readlen = read((void*)output.data(), output.size()); 38 | output.resize(readlen); 39 | return output; 40 | } 41 | 42 | int BinaryIO::read(void* pdata, size_t length){ 43 | 44 | if (flag_ == MemoryRead) { 45 | if (memoryLength_ != -1) { 46 | 47 | if (memoryLength_ < memoryCursor_ + length) { 48 | int remain = memoryLength_ - memoryCursor_; 49 | if (remain > 0) { 50 | memcpy(pdata, memoryRead_ + memoryCursor_, remain); 51 | memoryCursor_ += remain; 52 | return remain; 53 | } 54 | else { 55 | return -1; 56 | } 57 | } 58 | } 59 | memcpy(pdata, memoryRead_ + memoryCursor_, length); 60 | memoryCursor_ += length; 61 | return length; 62 | } 63 | else { 64 | return -1; 65 | } 66 | } 67 | 68 | bool BinaryIO::eof(){ 69 | if (!opened()) return true; 70 | 71 | if (flag_ == MemoryRead){ 72 | return this->memoryCursor_ >= this->memoryLength_; 73 | } 74 | else if (flag_ == MemoryWrite){ 75 | return false; 76 | } 77 | else { 78 | opstate_ = false; 79 | INFO("Unsupport flag: %d", flag_); 80 | return true; 81 | } 82 | } 83 | 84 | int BinaryIO::write(const void* pdata, size_t length){ 85 | 86 | if (flag_ == MemoryWrite) { 87 | memoryWrite_.append((char*)pdata, (char*)pdata + length); 88 | return length; 89 | } 90 | else { 91 | return -1; 92 | } 93 | } 94 | 95 | int BinaryIO::writeData(const string& data){ 96 | return write(data.data(), data.size()); 97 | } 98 | 99 | BinaryIO& BinaryIO::operator >> (string& value){ 100 | //read 101 | int length = 0; 102 | (*this) >> length; 103 | value = readData(length); 104 | return *this; 105 | } 106 | 107 | int BinaryIO::readInt(){ 108 | int value = 0; 109 | (*this) >> value; 110 | return value; 111 | } 112 | 113 | float BinaryIO::readFloat(){ 114 | float value = 0; 115 | (*this) >> value; 116 | return value; 117 | } 118 | 119 | BinaryIO& BinaryIO::operator << (const string& value){ 120 | //write 121 | (*this) << (int)value.size(); 122 | writeData(value); 123 | return *this; 124 | } 125 | 126 | BinaryIO& BinaryIO::operator << (const char* value){ 127 | 128 | int length = strlen(value); 129 | (*this) << (int)length; 130 | write(value, length); 131 | return *this; 132 | } 133 | 134 | BinaryIO& BinaryIO::operator << (const vector& value){ 135 | (*this) << (int)value.size(); 136 | for (int i = 0; i < value.size(); ++i){ 137 | (*this) << value[i]; 138 | } 139 | return *this; 140 | } 141 | 142 | BinaryIO& BinaryIO::operator >> (vector& value){ 143 | int num; 144 | (*this) >> num; 145 | 146 | value.resize(num); 147 | for (int i = 0; i < value.size(); ++i) 148 | (*this) >> value[i]; 149 | return *this; 150 | } 151 | 152 | bool BinaryIO::openMemoryRead(const void* ptr, int memoryLength) { 153 | close(); 154 | 155 | if (!ptr) return false; 156 | memoryRead_ = (const char*)ptr; 157 | memoryCursor_ = 0; 158 | memoryLength_ = memoryLength; 159 | flag_ = MemoryRead; 160 | return true; 161 | } 162 | 163 | void BinaryIO::openMemoryWrite() { 164 | close(); 165 | 166 | memoryWrite_.clear(); 167 | memoryCursor_ = 0; 168 | memoryLength_ = -1; 169 | flag_ = MemoryWrite; 170 | } -------------------------------------------------------------------------------- /src/binary_io.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BINARY_IO_HPP 2 | #define BINARY_IO_HPP 3 | 4 | #include 5 | #include 6 | 7 | class BinaryIO { 8 | public: 9 | enum Head { 10 | MemoryRead = 1, 11 | MemoryWrite = 2 12 | }; 13 | 14 | BinaryIO() { openMemoryWrite(); } 15 | BinaryIO(const void* ptr, int memoryLength = -1) { openMemoryRead(ptr, memoryLength); } 16 | virtual ~BinaryIO(); 17 | bool opened(); 18 | bool openMemoryRead(const void* ptr, int memoryLength = -1); 19 | void openMemoryWrite(); 20 | const std::string& writedMemory() { return memoryWrite_; } 21 | void close(); 22 | int write(const void* pdata, size_t length); 23 | int writeData(const std::string& data); 24 | int read(void* pdata, size_t length); 25 | std::string readData(int numBytes); 26 | int readInt(); 27 | float readFloat(); 28 | bool eof(); 29 | 30 | BinaryIO& operator >> (std::string& value); 31 | BinaryIO& operator << (const std::string& value); 32 | BinaryIO& operator << (const char* value); 33 | BinaryIO& operator << (const std::vector& value); 34 | BinaryIO& operator >> (std::vector& value); 35 | 36 | template 37 | BinaryIO& operator >> (std::vector<_T>& value) { 38 | int length = 0; 39 | (*this) >> length; 40 | 41 | value.resize(length); 42 | read(value.data(), length * sizeof(_T)); 43 | return *this; 44 | } 45 | 46 | template 47 | BinaryIO& operator << (const std::vector<_T>& value) { 48 | (*this) << (int)value.size(); 49 | write(value.data(), sizeof(_T) * value.size()); 50 | return *this; 51 | } 52 | 53 | template 54 | BinaryIO& operator >> (_T& value) { 55 | read(&value, sizeof(_T)); 56 | return *this; 57 | } 58 | 59 | template 60 | BinaryIO& operator << (const _T& value) { 61 | write(&value, sizeof(_T)); 62 | return *this; 63 | } 64 | 65 | bool opstate() const { 66 | return opstate_; 67 | } 68 | 69 | private: 70 | size_t readModeEndSEEK_ = 0; 71 | std::string memoryWrite_; 72 | const char* memoryRead_ = nullptr; 73 | int memoryCursor_ = 0; 74 | int memoryLength_ = -1; 75 | Head flag_ = MemoryWrite; 76 | bool opstate_ = true; 77 | }; 78 | 79 | #endif //BINARY_IO_HPP -------------------------------------------------------------------------------- /src/http_server.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "http_server.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "mongoose.h" 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | static unordered_map CONTENT_TYPE = { 16 | {"", "application/octet-stream"}, 17 | {".", "application/octet-stream"}, 18 | {".*", "application/octet-stream"}, 19 | {".001", "application/x-001"}, 20 | {".301", "application/x-301"}, 21 | {".323", "text/h323"}, 22 | {".906", "application/x-906"}, 23 | {".907", "drawing/907"}, 24 | {".a11", "application/x-a11"}, 25 | {".acp", "audio/x-mei-aac"}, 26 | {".ai", "application/postscript"}, 27 | {".aif", "audio/aiff"}, 28 | {".aifc", "audio/aiff"}, 29 | {".aiff", "audio/aiff"}, 30 | {".anv", "application/x-anv"}, 31 | {".asa", "text/asa"}, 32 | {".asf", "video/x-ms-asf"}, 33 | {".asp", "text/asp"}, 34 | {".asx", "video/x-ms-asf"}, 35 | {".au", "audio/basic"}, 36 | {".avi", "video/avi"}, 37 | {".awf", "application/vnd.adobe.workflow"}, 38 | {".biz", "text/xml"}, 39 | {".bmp", "application/x-bmp"}, 40 | {".bot", "application/x-bot"}, 41 | {".c4t", "application/x-c4t"}, 42 | {".c90", "application/x-c90"}, 43 | {".cal", "application/x-cals"}, 44 | {".cat", "application/s-pki.seccat"}, 45 | {".cdf", "application/x-netcdf"}, 46 | {".cdr", "application/x-cdr"}, 47 | {".cel", "application/x-cel"}, 48 | {".cer", "application/x-x509-ca-cert"}, 49 | {".cg4", "application/x-g4"}, 50 | {".cgm", "application/x-cgm"}, 51 | {".cit", "application/x-cit"}, 52 | {".class", "java/*"}, 53 | {".cml", "text/xml"}, 54 | {".cmp", "application/x-cmp"}, 55 | {".cmx", "application/x-cmx"}, 56 | {".cot", "application/x-cot"}, 57 | {".crl", "application/pkix-crl"}, 58 | {".crt", "application/x-x509-ca-cert"}, 59 | {".csi", "application/x-csi"}, 60 | {".css", "text/css"}, 61 | {".cut", "application/x-cut"}, 62 | {".dbf", "application/x-dbf"}, 63 | {".dbm", "application/x-dbm"}, 64 | {".dbx", "application/x-dbx"}, 65 | {".dcd", "text/xml"}, 66 | {".dcx", "application/x-dcx"}, 67 | {".der", "application/x-x509-ca-cert"}, 68 | {".dgn", "application/x-dgn"}, 69 | {".dib", "application/x-dib"}, 70 | {".dll", "application/x-msdownload"}, 71 | {".doc", "application/msword"}, 72 | {".dot", "application/msword"}, 73 | {".drw", "application/x-drw"}, 74 | {".dtd", "text/xml"}, 75 | {".dwf", "Model/vnd.dwf"}, 76 | {".dwf", "application/x-dwf"}, 77 | {".dwg", "application/x-dwg"}, 78 | {".dxb", "application/x-dxb"}, 79 | {".dxf", "application/x-dxf"}, 80 | {".edn", "application/vnd.adobe.edn"}, 81 | {".emf", "application/x-emf"}, 82 | {".eml", "message/rfc822"}, 83 | {".ent", "text/xml"}, 84 | {".epi", "application/x-epi"}, 85 | {".eps", "application/x-ps"}, 86 | {".eps", "application/postscript"}, 87 | {".etd", "application/x-ebx"}, 88 | {".exe", "application/x-msdownload"}, 89 | {".fax", "image/fax"}, 90 | {".fdf", "application/vnd.fdf"}, 91 | {".fif", "application/fractals"}, 92 | {".fo", "text/xml"}, 93 | {".frm", "application/x-frm"}, 94 | {".g4", "application/x-g4"}, 95 | {".gbr", "application/x-gbr"}, 96 | {".gcd", "application/x-gcd"}, 97 | {".gif", "image/gif"}, 98 | {".gl2", "application/x-gl2"}, 99 | {".gp4", "application/x-gp4"}, 100 | {".hgl", "application/x-hgl"}, 101 | {".hmr", "application/x-hmr"}, 102 | {".hpg", "application/x-hpgl"}, 103 | {".hpl", "application/x-hpl"}, 104 | {".hqx", "application/mac-binhex40"}, 105 | {".hrf", "application/x-hrf"}, 106 | {".hta", "application/hta"}, 107 | {".htc", "text/x-component"}, 108 | {".htm", "text/html"}, 109 | {".html", "text/html"}, 110 | {".htt", "text/webviewhtml"}, 111 | {".htx", "text/html"}, 112 | {".icb", "application/x-icb"}, 113 | {".ico", "image/x-icon"}, 114 | {".ico", "application/x-ico"}, 115 | {".iff", "application/x-iff"}, 116 | {".ig4", "application/x-g4"}, 117 | {".igs", "application/x-igs"}, 118 | {".iii", "application/x-iphone"}, 119 | {".img", "application/x-img"}, 120 | {".ins", "application/x-internet-signup"}, 121 | {".isp", "application/x-internet-signup"}, 122 | {".IVF", "video/x-ivf"}, 123 | {".java", "java/*"}, 124 | {".jfif", "image/jpeg"}, 125 | {".jpe", "image/jpeg"}, 126 | {".jpe", "application/x-jpe"}, 127 | {".jpeg", "image/jpeg"}, 128 | {".jpg", "image/jpeg"}, 129 | {".js", "text/javascript"}, 130 | {".json", "application/json"}, 131 | {".jsp", "text/html"}, 132 | {".la1", "audio/x-liquid-file"}, 133 | {".lar", "application/x-laplayer-reg"}, 134 | {".latex", "application/x-latex"}, 135 | {".lavs", "audio/x-liquid-secure"}, 136 | {".lbm", "application/x-lbm"}, 137 | {".lmsff", "audio/x-la-lms"}, 138 | {".ls", "application/x-javascript"}, 139 | {".ltr", "application/x-ltr"}, 140 | {".m1v", "video/x-mpeg"}, 141 | {".m2v", "video/x-mpeg"}, 142 | {".m3u", "audio/mpegurl"}, 143 | {".m4e", "video/mpeg4"}, 144 | {".mac", "application/x-mac"}, 145 | {".man", "application/x-troff-man"}, 146 | {".math", "text/xml"}, 147 | {".mdb", "application/msaccess"}, 148 | {".mdb", "application/x-mdb"}, 149 | {".mfp", "application/x-shockwave-flash"}, 150 | {".mht", "message/rfc822"}, 151 | {".mhtml", "message/rfc822"}, 152 | {".mi", "application/x-mi"}, 153 | {".mid", "audio/mid"}, 154 | {".midi", "audio/mid"}, 155 | {".mil", "application/x-mil"}, 156 | {".mml", "text/xml"}, 157 | {".mnd", "audio/x-musicnet-download"}, 158 | {".mns", "audio/x-musicnet-stream"}, 159 | {".mocha", "application/x-javascript"}, 160 | {".movie", "video/x-sgi-movie"}, 161 | {".mp1", "audio/mp1"}, 162 | {".mp2", "audio/mp2"}, 163 | {".mp2v", "video/mpeg"}, 164 | {".mp3", "audio/mp3"}, 165 | {".mp4", "video/mp4"}, 166 | {".mpa", "video/x-mpg"}, 167 | {".mpd", "application/-project"}, 168 | {".mpe", "video/x-mpeg"}, 169 | {".mpeg", "video/mpg"}, 170 | {".mpg", "video/mpg"}, 171 | {".mpga", "audio/rn-mpeg"}, 172 | {".mpp", "application/-project"}, 173 | {".mps", "video/x-mpeg"}, 174 | {".mpt", "application/-project"}, 175 | {".mpv", "video/mpg"}, 176 | {".mpv2", "video/mpeg"}, 177 | {".mpw", "application/s-project"}, 178 | {".mpx", "application/-project"}, 179 | {".mtx", "text/xml"}, 180 | {".mxp", "application/x-mmxp"}, 181 | {".net", "image/pnetvue"}, 182 | {".nrf", "application/x-nrf"}, 183 | {".nws", "message/rfc822"}, 184 | {".odc", "text/x-ms-odc"}, 185 | {".out", "application/x-out"}, 186 | {".p10", "application/pkcs10"}, 187 | {".p12", "application/x-pkcs12"}, 188 | {".p7b", "application/x-pkcs7-certificates"}, 189 | {".p7c", "application/pkcs7-mime"}, 190 | {".p7m", "application/pkcs7-mime"}, 191 | {".p7r", "application/x-pkcs7-certreqresp"}, 192 | {".p7s", "application/pkcs7-signature"}, 193 | {".pc5", "application/x-pc5"}, 194 | {".pci", "application/x-pci"}, 195 | {".pcl", "application/x-pcl"}, 196 | {".pcx", "application/x-pcx"}, 197 | {".pdf", "application/pdf"}, 198 | {".pdf", "application/pdf"}, 199 | {".pdx", "application/vnd.adobe.pdx"}, 200 | {".pfx", "application/x-pkcs12"}, 201 | {".pgl", "application/x-pgl"}, 202 | {".pic", "application/x-pic"}, 203 | {".pko", "application-pki.pko"}, 204 | {".pl", "application/x-perl"}, 205 | {".plg", "text/html"}, 206 | {".pls", "audio/scpls"}, 207 | {".plt", "application/x-plt"}, 208 | {".png", "image/png"}, 209 | {".pot", "applications-powerpoint"}, 210 | {".ppa", "application/vs-powerpoint"}, 211 | {".ppm", "application/x-ppm"}, 212 | {".pps", "application-powerpoint"}, 213 | {".ppt", "applications-powerpoint"}, 214 | {".ppt", "application/x-ppt"}, 215 | {".prf", "application/pics-rules"}, 216 | {".prn", "application/x-prn"}, 217 | {".prt", "application/x-prt"}, 218 | {".ps", "application/x-ps"}, 219 | {".ps", "application/postscript"}, 220 | {".ptn", "application/x-ptn"}, 221 | {".pwz", "application/powerpoint"}, 222 | {".r3t", "text/vnd.rn-realtext3d"}, 223 | {".ra", "audio/vnd.rn-realaudio"}, 224 | {".ram", "audio/x-pn-realaudio"}, 225 | {".ras", "application/x-ras"}, 226 | {".rat", "application/rat-file"}, 227 | {".rdf", "text/xml"}, 228 | {".rec", "application/vnd.rn-recording"}, 229 | {".red", "application/x-red"}, 230 | {".rgb", "application/x-rgb"}, 231 | {".rjs", "application/vnd.rn-realsystem-rjs"}, 232 | {".rjt", "application/vnd.rn-realsystem-rjt"}, 233 | {".rlc", "application/x-rlc"}, 234 | {".rle", "application/x-rle"}, 235 | {".rm", "application/vnd.rn-realmedia"}, 236 | {".rmf", "application/vnd.adobe.rmf"}, 237 | {".rmi", "audio/mid"}, 238 | {".rmj", "application/vnd.rn-realsystem-rmj"}, 239 | {".rmm", "audio/x-pn-realaudio"}, 240 | {".rmp", "application/vnd.rn-rn_music_package"}, 241 | {".rms", "application/vnd.rn-realmedia-secure"}, 242 | {".rmvb", "application/vnd.rn-realmedia-vbr"}, 243 | {".rmx", "application/vnd.rn-realsystem-rmx"}, 244 | {".rnx", "application/vnd.rn-realplayer"}, 245 | {".rp", "image/vnd.rn-realpix"}, 246 | {".rpm", "audio/x-pn-realaudio-plugin"}, 247 | {".rsml", "application/vnd.rn-rsml"}, 248 | {".rt", "text/vnd.rn-realtext"}, 249 | {".rtf", "application/msword"}, 250 | {".rtf", "application/x-rtf"}, 251 | {".rv", "video/vnd.rn-realvideo"}, 252 | {".sam", "application/x-sam"}, 253 | {".sat", "application/x-sat"}, 254 | {".sdp", "application/sdp"}, 255 | {".sdw", "application/x-sdw"}, 256 | {".sit", "application/x-stuffit"}, 257 | {".slb", "application/x-slb"}, 258 | {".sld", "application/x-sld"}, 259 | {".slk", "drawing/x-slk"}, 260 | {".smi", "application/smil"}, 261 | {".smil", "application/smil"}, 262 | {".smk", "application/x-smk"}, 263 | {".snd", "audio/basic"}, 264 | {".sol", "text/plain"}, 265 | {".sor", "text/plain"}, 266 | {".spc", "application/x-pkcs7-certificates"}, 267 | {".spl", "application/futuresplash"}, 268 | {".spp", "text/xml"}, 269 | {".ssm", "application/streamingmedia"}, 270 | {".sst", "application-pki.certstore"}, 271 | {".stl", "application/-pki.stl"}, 272 | {".stm", "text/html"}, 273 | {".sty", "application/x-sty"}, 274 | {".svg", "text/xml"}, 275 | {".swf", "application/x-shockwave-flash"}, 276 | {".tdf", "application/x-tdf"}, 277 | {".tg4", "application/x-tg4"}, 278 | {".tga", "application/x-tga"}, 279 | {".tif", "image/tiff"}, 280 | {".tif", "application/x-tif"}, 281 | {".tiff", "image/tiff"}, 282 | {".tld", "text/xml"}, 283 | {".top", "drawing/x-top"}, 284 | {".torrent", "application/x-bittorrent"}, 285 | {".tsd", "text/xml"}, 286 | {".txt", "text/plain"}, 287 | {".uin", "application/x-icq"}, 288 | {".uls", "text/iuls"}, 289 | {".vcf", "text/x-vcard"}, 290 | {".vda", "application/x-vda"}, 291 | {".vdx", "application/vnd.visio"}, 292 | {".vml", "text/xml"}, 293 | {".vpg", "application/x-vpeg005"}, 294 | {".vsd", "application/vnd.visio"}, 295 | {".vsd", "application/x-vsd"}, 296 | {".vss", "application/vnd.visio"}, 297 | {".vst", "application/vnd.visio"}, 298 | {".vst", "application/x-vst"}, 299 | {".vsw", "application/vnd.visio"}, 300 | {".vsx", "application/vnd.visio"}, 301 | {".vtx", "application/vnd.visio"}, 302 | {".vxml", "text/xml"}, 303 | {".wav", "audio/wav"}, 304 | {".wax", "audio/x-ms-wax"}, 305 | {".wb1", "application/x-wb1"}, 306 | {".wb2", "application/x-wb2"}, 307 | {".wb3", "application/x-wb3"}, 308 | {".wbmp", "image/vnd.wap.wbmp"}, 309 | {".wiz", "application/msword"}, 310 | {".wk3", "application/x-wk3"}, 311 | {".wk4", "application/x-wk4"}, 312 | {".wkq", "application/x-wkq"}, 313 | {".wks", "application/x-wks"}, 314 | {".wm", "video/x-ms-wm"}, 315 | {".wma", "audio/x-ms-wma"}, 316 | {".wmd", "application/x-ms-wmd"}, 317 | {".wmf", "application/x-wmf"}, 318 | {".wml", "text/vnd.wap.wml"}, 319 | {".wmv", "video/x-ms-wmv"}, 320 | {".wmx", "video/x-ms-wmx"}, 321 | {".wmz", "application/x-ms-wmz"}, 322 | {".wp6", "application/x-wp6"}, 323 | {".wpd", "application/x-wpd"}, 324 | {".wpg", "application/x-wpg"}, 325 | {".wpl", "application/-wpl"}, 326 | {".wq1", "application/x-wq1"}, 327 | {".wr1", "application/x-wr1"}, 328 | {".wri", "application/x-wri"}, 329 | {".wrk", "application/x-wrk"}, 330 | {".ws", "application/x-ws"}, 331 | {".ws2", "application/x-ws"}, 332 | {".wsc", "text/scriptlet"}, 333 | {".wsdl", "text/xml"}, 334 | {".wvx", "video/x-ms-wvx"}, 335 | {".xdp", "application/vnd.adobe.xdp"}, 336 | {".xdr", "text/xml"}, 337 | {".xfd", "application/vnd.adobe.xfd"}, 338 | {".xfdf", "application/vnd.adobe.xfdf"}, 339 | {".xhtml", "text/html"}, 340 | {".xls", "application/-excel"}, 341 | {".xls", "application/x-xls"}, 342 | {".xlw", "application/x-xlw"}, 343 | {".xml", "text/xml"}, 344 | {".xpl", "audio/scpls"}, 345 | {".xq", "text/xml"}, 346 | {".xql", "text/xml"}, 347 | {".xquery", "text/xml"}, 348 | {".xsd", "text/xml"}, 349 | {".xsl", "text/xml"}, 350 | {".xslt", "text/xml"}, 351 | {".xwd", "application/x-xwd"}, 352 | {".x_b", "application/x-x_b"}, 353 | {".x_t", "application/x-x_t"} 354 | }; 355 | 356 | struct WorkerResult{ 357 | SessionID conn_id; 358 | }; 359 | 360 | Response::Response(){ 361 | set_status_code(200); 362 | set_header("Server", "HTTP Server/1.1"); 363 | //set_header("Transfer-Encoding", "chunked"); 364 | set_header("Content-Type", "application/json"); 365 | } 366 | 367 | bool Request::has_header(const string& name){ 368 | return this->headers.find(name) != this->headers.end(); 369 | } 370 | 371 | string Request::get_header(const string& name){ 372 | auto iter = headers.find(name); 373 | if(iter != headers.end()) 374 | return iter->second; 375 | return ""; 376 | } 377 | 378 | void Response::write_binary(const void* pdata, size_t size){ 379 | output.write(pdata, size); 380 | this->write_mode = ResponseWriteMode_WriteCustom; 381 | } 382 | 383 | void Response::write_plain_text(const string& val){ 384 | set_header("Content-Type", "text/plain"); 385 | output.writeData(val); 386 | this->write_mode = ResponseWriteMode_WriteCustom; 387 | } 388 | 389 | void Response::write_file(const string& file){ 390 | this->file_path = file; 391 | this->remove_header("Content-Type"); 392 | this->write_mode = ResponseWriteMode_WriteFile; 393 | } 394 | 395 | void Response::write_json_styled(const Json::Value& val){ 396 | set_header("Content-Type", "application/json"); 397 | output.writeData(val.toStyledString()); 398 | this->write_mode = ResponseWriteMode_WriteCustom; 399 | } 400 | 401 | void Response::write_json(const Json::Value& val){ 402 | set_header("Content-Type", "application/json"); 403 | output.writeData(Json::FastWriter().write(val)); 404 | this->write_mode = ResponseWriteMode_WriteCustom; 405 | } 406 | 407 | void Response::set_status_code(int code){ 408 | this->status_code = code; 409 | } 410 | 411 | void Response::set_header(const string& key, const string& value){ 412 | this->headers[key] = value; 413 | } 414 | 415 | void Response::remove_header(const string& name){ 416 | this->headers.erase(name); 417 | } 418 | 419 | bool Response::has_header(const string& name){ 420 | return this->headers.find(name) != this->headers.end(); 421 | } 422 | 423 | string Response::get_header(const string& name){ 424 | auto iter = this->headers.find(name); 425 | if(iter != this->headers.end()) 426 | return iter->second; 427 | return ""; 428 | } 429 | 430 | string Response::header_string(){ 431 | string output_string; 432 | for(auto& item : headers){ 433 | output_string += item.first + ": " + item.second + "\r\n"; 434 | } 435 | return output_string; 436 | } 437 | 438 | const string& Response::output_string(){ 439 | return output.writedMemory(); 440 | } 441 | 442 | Session::Session(){ 443 | } 444 | 445 | Session::Session(SessionID id){ 446 | this->conn_id = id; 447 | } 448 | 449 | static void error_process(const shared_ptr& session, int code){ 450 | session->response.set_status_code(code); 451 | session->response.set_header("Content-Type", "application/json"); 452 | 453 | Json::Value response; 454 | response["status"] = "error"; 455 | response["code"] = code; 456 | response["message"] = mg_status_message(code); 457 | response["time"] = iLogger::time_now(); 458 | session->response.write_json_styled(response); 459 | } 460 | 461 | static void parse_uri_vars(const string& uri, unordered_map& save){ 462 | 463 | if(uri.empty()) 464 | return; 465 | 466 | const char *p, *e, *s; 467 | int len; 468 | const char* begin = uri.c_str(); 469 | p = begin; 470 | e = begin + uri.size(); 471 | char buffer[1024]; 472 | 473 | for(;p < e; ++p){ 474 | if(p == begin || p[-1] == '&'){ 475 | s = (const char *) memchr(p, '=', (size_t)(e - p)); 476 | if(s == nullptr) 477 | s = e; 478 | 479 | len = mg_url_decode(p, (size_t)(s - p), buffer, sizeof(buffer), 1); 480 | if (len == -1) 481 | break; 482 | 483 | string name(buffer, buffer + len); 484 | if(s == e){ 485 | save[move(name)]; 486 | break; 487 | } 488 | 489 | p = s + 1; 490 | s = (const char *) memchr(p, '&', (size_t)(e - p)); 491 | if(s == nullptr) 492 | s = e; 493 | 494 | len = mg_url_decode(p, (size_t)(s - p), buffer, sizeof(buffer), 1); 495 | if (len == -1){ 496 | save[move(name)]; 497 | break; 498 | } 499 | 500 | string value(buffer, buffer + len); 501 | save[move(name)] = move(value); 502 | p = s; 503 | } 504 | } 505 | } 506 | 507 | class SessionManager{ 508 | public: 509 | shared_ptr get(SessionID id){ 510 | 511 | unique_lock l(lck_); 512 | auto iter = idmap_.find(id); 513 | if(iter == idmap_.end()) 514 | return nullptr; 515 | 516 | return iter->second; 517 | } 518 | 519 | template 520 | shared_ptr emplace_create(_Args&&... __args){ 521 | unique_lock l(lck_); 522 | shared_ptr newitem(new Session(forward<_Args>(__args)...)); 523 | idmap_[newitem->conn_id] = newitem; 524 | return newitem; 525 | } 526 | 527 | void remove(SessionID id){ 528 | unique_lock l(lck_); 529 | idmap_.erase(id); 530 | } 531 | 532 | private: 533 | mutex lck_; 534 | unordered_map> idmap_; 535 | }; 536 | 537 | enum HandlerType : int{ 538 | HandlerType_None = 0, 539 | HandlerType_Callback = 1, 540 | HandlerType_Controller = 2 541 | }; 542 | 543 | struct Handler{ 544 | HandlerCallback callback; 545 | shared_ptr controller; 546 | HandlerType type = HandlerType_None; 547 | 548 | Handler(){} 549 | 550 | Handler(const HandlerCallback& callback){ 551 | this->callback = callback; 552 | this->type = HandlerType_Callback; 553 | } 554 | 555 | Handler(const shared_ptr& controller){ 556 | this->controller = controller; 557 | this->type = HandlerType_Controller; 558 | } 559 | }; 560 | 561 | 562 | 563 | void Controller::initialize(const string& url, HttpServer* server){ 564 | mapping_url_ = url; 565 | 566 | for(auto& router : router_mapping_.routers){ 567 | for(auto& method : router.second){ 568 | server->add_router( 569 | iLogger::format("%s%s", mapping_url_.c_str(), router.first.c_str()), 570 | bind(&Controller::process_module, this, placeholders::_1, method.second), 571 | method.first 572 | ); 573 | } 574 | } 575 | } 576 | 577 | void Controller::process(const shared_ptr& session){ 578 | error_process(session, 404); 579 | } 580 | 581 | void Controller::process_module(const shared_ptr& session, const ControllerProcess& func){ 582 | auto param = Json::parse_string(session->request.body); 583 | auto tid = this_thread::get_id(); 584 | { 585 | unique_lock l(this->session_lock_); 586 | this->current_session_[tid] = session; 587 | }; 588 | 589 | auto ret = func(param); 590 | if(session->response.write_mode == ResponseWriteMode_WriteReturnJson){ 591 | session->response.output.writeData(ret.toStyledString()); 592 | } 593 | 594 | // 删除id 595 | { 596 | unique_lock l(this->session_lock_); 597 | this->current_session_.erase(tid); 598 | }; 599 | } 600 | 601 | Controller::ControllerProcess Controller::find_match(const string& url, const string& method){ 602 | 603 | if(url.size() < mapping_url_.size()) 604 | return nullptr; 605 | 606 | auto split_url = url.substr(mapping_url_.size()); 607 | auto it = router_mapping_.routers.find(split_url); 608 | if(it != router_mapping_.routers.end()){ 609 | auto subit = it->second.find(method); 610 | if(subit == it->second.end()) 611 | subit = it->second.find("*"); 612 | 613 | if(subit != it->second.end()){ 614 | return subit->second; 615 | } 616 | } 617 | return nullptr; 618 | } 619 | 620 | int Controller::add_router(const string& url, const string& method, const ControllerProcess& process){ 621 | router_mapping_.routers[url][method] = process; 622 | return 0; 623 | } 624 | 625 | bool Controller::is_begin_match(){ 626 | return false; 627 | } 628 | 629 | shared_ptr Controller::get_current_session(){ 630 | unique_lock l(this->session_lock_); 631 | auto it = this->current_session_.find(this_thread::get_id()); 632 | if(it == this->current_session_.end()) 633 | return nullptr; 634 | return it->second; 635 | } 636 | 637 | 638 | class FileAccessController : public Controller{ 639 | public: 640 | FileAccessController(const string& root_directory){ 641 | root_directory_ = root_directory; 642 | 643 | if(root_directory_.empty()){ 644 | root_directory_ = "static"; 645 | return; 646 | } 647 | 648 | if(root_directory_.back() == '/' || root_directory_.back() == '\\') 649 | root_directory_.pop_back(); 650 | } 651 | 652 | bool is_begin_match() override{ 653 | return true; 654 | } 655 | 656 | virtual void process(const shared_ptr& session) override{ 657 | 658 | if(session->request.url.size() < mapping_url_.size()){ 659 | session->response.set_status_code(404); 660 | return; 661 | } 662 | 663 | auto split_url = session->request.url.substr(mapping_url_.size()); 664 | if(!split_url.empty() && split_url.back() == '/') 665 | split_url.pop_back(); 666 | 667 | int lp = split_url.find('?'); 668 | if(lp != -1) 669 | split_url = split_url.substr(0, lp); 670 | 671 | int p = split_url.rfind('.'); 672 | int e = split_url.rfind('/'); 673 | const char* context_type = "application/octet-stream"; 674 | if(p > e){ 675 | auto suffix = split_url.substr(p); 676 | transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower); 677 | auto iter = CONTENT_TYPE.find(suffix); 678 | if(iter != CONTENT_TYPE.end()){ 679 | context_type = iter->second.c_str(); 680 | } 681 | } 682 | 683 | string merge_path = iLogger::format("%s/%s", root_directory_.c_str(), split_url.c_str()); 684 | if(!iLogger::isfile(merge_path)){ 685 | error_process(session, 404); 686 | return; 687 | } 688 | 689 | session->response.set_header("Content-Type", context_type); 690 | time_t file_last_modify = iLogger::last_modify(merge_path); 691 | auto gmt = iLogger::gmtime(file_last_modify); 692 | if(session->request.has_header("If-Modified-Since")){ 693 | auto time = session->request.get_header("If-Modified-Since"); 694 | if(!time.empty()){ 695 | time_t modified_since = iLogger::gmtime2ctime(time); 696 | if(modified_since == file_last_modify){ 697 | const int SC_NOT_MODIFIED = 304; 698 | session->response.set_status_code(SC_NOT_MODIFIED); 699 | session->response.set_header("Cache-Control", "max-age=315360000"); 700 | session->response.set_header("Last-Modified", iLogger::gmtime(file_last_modify)); 701 | return; 702 | } 703 | } 704 | } 705 | //match by ccutil::gmtime 706 | //INFO("Write file: %s", merge_path.c_str()); 707 | session->response.write_file(merge_path); 708 | } 709 | 710 | private: 711 | string root_directory_; 712 | }; 713 | 714 | shared_ptr create_file_access_controller(const string& root_directory){ 715 | return make_shared(root_directory); 716 | } 717 | 718 | class HttpServerImpl : public HttpServer 719 | { 720 | public: 721 | virtual ~HttpServerImpl(){ 722 | this->close(); 723 | } 724 | 725 | virtual void verbose() override{ 726 | verbose_ = true; 727 | } 728 | 729 | size_t size_jobs(){ 730 | return jobs_.size(); 731 | } 732 | 733 | bool start(const string& address, int num_threads = 32); 734 | virtual void add_router(const string& url, const HandlerCallback& callback, const string& method) override; 735 | virtual void add_router_post(const string& url, const HandlerCallback& callback) override; 736 | virtual void add_router_get(const string& url, const HandlerCallback& callback) override; 737 | virtual void add_controller(const string& url, shared_ptr controller) override; 738 | void close(); 739 | void loop(); 740 | int poll(unsigned int timeout); 741 | void worker_thread_proc(); 742 | static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data); 743 | 744 | void commit(shared_ptr user); 745 | 746 | private: 747 | unordered_map> router_map_; //回调函数映射表 748 | vector> begin_match_router_; // etc, static file access 749 | 750 | private: 751 | static void on_http_event(mg_connection *connection, int event_type, void *event_data); 752 | 753 | mg_mgr mgr_; 754 | atomic keeprun_{false}; 755 | string docDirectory_; 756 | string docUrl_; 757 | bool useResourceAccess_ = false; 758 | vector> threads_; 759 | queue> jobs_; 760 | mutex lck_; 761 | condition_variable cv_; 762 | 763 | SessionID s_next_id_ = 0; 764 | SessionManager session_manager_; 765 | shared_ptr loop_thread_; 766 | bool verbose_ = false; 767 | }; 768 | 769 | void HttpServerImpl::on_work_complete(struct mg_connection *nc, int ev, void *ev_data) { 770 | 771 | (void) ev; 772 | struct mg_connection *c=nc; 773 | WorkerResult* res = (WorkerResult*)ev_data; 774 | HttpServerImpl* server = (HttpServerImpl*)nc->mgr->user_data; 775 | 776 | if(c->user_data == NULL) 777 | return; 778 | 779 | if ((SessionID)c->user_data != res->conn_id) 780 | return; 781 | 782 | auto session = server->session_manager_.get(res->conn_id); 783 | if(!session){ 784 | mg_http_send_error(c, 404, "Not Found"); 785 | return; 786 | } 787 | 788 | auto& resp = session->response; 789 | if(resp.write_mode == ResponseWriteMode_WriteFile){ 790 | auto& file = resp.file_path; 791 | string context_type = "application/octet-stream"; 792 | if(!resp.has_header("Content-Type")) 793 | context_type = resp.get_header("Content-Type"); 794 | 795 | mg_http_serve_file3(c, 796 | mg_mk_str(session->request.get_header("Range").c_str()), 797 | mg_mk_str(session->request.get_header("Connection").c_str()), 798 | mg_mk_str(session->request.proto.c_str()), 799 | iLogger::last_modify(file) + 28800, 800 | file.c_str(), mg_mk_str(context_type.c_str()), mg_mk_str("Cache-Control: max-age=315360000")); 801 | server->session_manager_.remove(res->conn_id); 802 | return; 803 | } 804 | 805 | mg_printf(c, "HTTP/1.1 %d %s\r\n", 806 | resp.status_code, 807 | mg_status_message(resp.status_code) 808 | ); 809 | 810 | for(auto& iter : resp.headers) 811 | mg_printf(c, "%s: %s\r\n", iter.first.c_str(), iter.second.c_str()); 812 | 813 | auto& data = resp.output_string(); 814 | mg_printf(c, "Content-Length: %ld\r\n\r\n", data.size()); 815 | if (!data.empty()) 816 | mg_send(c, data.data(), data.size()); 817 | server->session_manager_.remove(res->conn_id); 818 | } 819 | 820 | void HttpServerImpl::worker_thread_proc() { 821 | 822 | while (keeprun_) { 823 | shared_ptr session; 824 | { 825 | unique_lock l(lck_); 826 | cv_.wait(l, [&]{return !jobs_.empty() || !keeprun_;}); 827 | 828 | if(!keeprun_) break; 829 | session = jobs_.front(); 830 | jobs_.pop(); 831 | }; 832 | 833 | bool found_router = false; 834 | auto it = router_map_.find(session->request.url); 835 | if(it == router_map_.end()){ 836 | 837 | // match url* 838 | string& url = session->request.url; 839 | for(auto& item : begin_match_router_){ 840 | if(iLogger::begin_with(url, get<0>(item))){ 841 | found_router = true; 842 | 843 | Handler& handler = get<1>(item); 844 | if(handler.type == HandlerType_Callback){ 845 | handler.callback(session); 846 | }else if(handler.type == HandlerType_Controller){ 847 | handler.controller->process(session); 848 | } 849 | } 850 | } 851 | }else{ 852 | auto subit = it->second.find(session->request.method); 853 | if(subit == it->second.end()) 854 | subit = it->second.find("*"); 855 | 856 | if(subit != it->second.end()){ 857 | found_router = true; 858 | 859 | if(verbose_){ 860 | INFO("Found match: %s [%s] -> %s [%s]", session->request.url.c_str(), session->request.method.c_str(), it->first.c_str(), subit->first.c_str()); 861 | } 862 | 863 | Handler& handler = subit->second; 864 | if(handler.type == HandlerType_Callback){ 865 | handler.callback(session); 866 | }else if(handler.type == HandlerType_Controller){ 867 | handler.controller->process(session); 868 | } 869 | } 870 | } 871 | 872 | WorkerResult result; 873 | result.conn_id = session->conn_id; 874 | 875 | if (!found_router){ 876 | error_process(session, 404); 877 | } 878 | mg_broadcast(&mgr_, on_work_complete, &result, sizeof(result)); 879 | } 880 | } 881 | 882 | bool HttpServerImpl::start(const string& address, int num_threads) 883 | { 884 | this->close(); 885 | 886 | //signal(SIGTERM, SIG_IGN); 887 | //signal(SIGINT, SIG_IGN); 888 | mg_mgr_init(&mgr_, nullptr); 889 | mgr_.user_data = this; 890 | mg_connection *connection = mg_bind(&mgr_, address.c_str(), HttpServerImpl::on_http_event); 891 | if (connection == nullptr){ 892 | INFOE("bind %s fail", address.c_str()); 893 | return false; 894 | } 895 | 896 | mg_set_protocol_http_websocket(connection); 897 | 898 | keeprun_ = true; 899 | loop_thread_.reset(new thread(bind(&HttpServerImpl::loop, this))); 900 | 901 | for (int i = 0; i < num_threads; i++) 902 | threads_.emplace_back(new thread(bind(&HttpServerImpl::worker_thread_proc, this))); 903 | 904 | // 对favicon处理 905 | this->add_router_get("/favicon.ico", [](const std::shared_ptr& session){ 906 | session->response.write_file("favicon.jpg"); 907 | }); 908 | return true; 909 | } 910 | 911 | int HttpServerImpl::poll(unsigned int timeout){ 912 | return mg_mgr_poll(&mgr_, timeout); 913 | } 914 | 915 | void HttpServerImpl::loop(){ 916 | 917 | while (keeprun_) 918 | mg_mgr_poll(&mgr_, 1000); // ms 919 | } 920 | 921 | void HttpServerImpl::commit(shared_ptr user){ 922 | { 923 | unique_lock l(lck_); 924 | jobs_.push(user); 925 | }; 926 | cv_.notify_one(); 927 | } 928 | 929 | void HttpServerImpl::on_http_event(mg_connection *connection, int event_type, void *event_data){ 930 | 931 | HttpServerImpl* server = (HttpServerImpl*)connection->mgr->user_data; 932 | 933 | switch (event_type) { 934 | case MG_EV_ACCEPT:{ 935 | break; 936 | } 937 | 938 | case MG_EV_HTTP_REQUEST: { 939 | http_message *http_req = (http_message *)event_data; 940 | connection->user_data = (void*)++server->s_next_id_; 941 | SessionID id = (SessionID)connection->user_data; 942 | auto user = server->session_manager_.emplace_create(id); 943 | user->request.url = string(http_req->uri.p, http_req->uri.len); 944 | user->request.body = string(http_req->body.p, http_req->body.len); 945 | user->request.query_string = string(http_req->query_string.p, http_req->query_string.len); 946 | user->request.method = string(http_req->method.p, http_req->method.len); 947 | user->request.proto = string(http_req->proto.p, http_req->proto.len); 948 | parse_uri_vars(user->request.query_string, user->request.vars); 949 | 950 | if(!user->request.url.empty() && user->request.url.back() != '/' || user->request.url.empty()) 951 | user->request.url.push_back('/'); 952 | 953 | int i = 0; 954 | while(http_req->header_names[i].len > 0 && i < MG_MAX_HTTP_HEADERS){ 955 | auto& name = http_req->header_names[i]; 956 | auto& value = http_req->header_values[i]; 957 | user->request.headers[string(name.p, name.len)] = string(value.p, value.len); 958 | i++; 959 | } 960 | server->commit(user); 961 | break; 962 | } 963 | 964 | case MG_EV_CLOSE: 965 | if (connection->user_data){ 966 | SessionID id = (SessionID)connection->user_data; 967 | server->session_manager_.remove(id); 968 | } 969 | } 970 | } 971 | 972 | void HttpServerImpl::add_controller(const string& url, shared_ptr controller){ 973 | 974 | string url_remove_back(url); 975 | if(!url_remove_back.empty() && url_remove_back.back() != '/' || url_remove_back.empty()) 976 | url_remove_back.push_back('/'); 977 | 978 | if(controller->is_begin_match()){ 979 | begin_match_router_.emplace_back(url_remove_back, controller); 980 | controller->initialize(url_remove_back, this); 981 | }else{ 982 | router_map_[url_remove_back]["*"] = controller; 983 | controller->initialize(url_remove_back, this); 984 | } 985 | } 986 | 987 | void HttpServerImpl::add_router_post(const string& url, const HandlerCallback& callback){ 988 | this->add_router(url, callback, "POST"); 989 | } 990 | 991 | void HttpServerImpl::add_router_get(const string& url, const HandlerCallback& callback){ 992 | this->add_router(url, callback, "GET"); 993 | } 994 | 995 | void HttpServerImpl::add_router(const string &url, const HandlerCallback& callback, const string& method){ 996 | 997 | string url_remove_back(url); 998 | if(!url_remove_back.empty() && url_remove_back.back() != '/' || url_remove_back.empty()) 999 | url_remove_back.push_back('/'); 1000 | router_map_[url_remove_back][method] = callback; 1001 | } 1002 | 1003 | void HttpServerImpl::close() 1004 | { 1005 | if(keeprun_){ 1006 | INFO("Shutdown http server."); 1007 | keeprun_ = false; 1008 | cv_.notify_all(); 1009 | loop_thread_->join(); 1010 | 1011 | for(auto& t : threads_) 1012 | t->join(); 1013 | 1014 | loop_thread_.reset(); 1015 | threads_.clear(); 1016 | router_map_.clear(); 1017 | mg_mgr_free(&mgr_); 1018 | } 1019 | } 1020 | 1021 | shared_ptr createHttpServer(const string& address, int num_threads){ 1022 | shared_ptr ins(new HttpServerImpl()); 1023 | if(!ins->start(address, num_threads)) 1024 | ins.reset(); 1025 | return ins; 1026 | } 1027 | 1028 | Json::Value success(){ 1029 | Json::Value ret; 1030 | ret["status"] = "success"; 1031 | ret["time"] = iLogger::time_now(); 1032 | return ret; 1033 | } 1034 | 1035 | Json::Value failuref(const char* fmt, ...){ 1036 | 1037 | va_list vl; 1038 | va_start(vl, fmt); 1039 | char buffer[1000]; 1040 | vsnprintf(buffer, sizeof(buffer), fmt, vl); 1041 | 1042 | Json::Value ret; 1043 | ret["status"] = "error"; 1044 | ret["message"] = buffer; 1045 | ret["time"] = iLogger::time_now(); 1046 | return ret; 1047 | } 1048 | -------------------------------------------------------------------------------- /src/http_server.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_SERVER_HPP 2 | #define HTTP_SERVER_HPP 3 | 4 | #pragma once 5 | 6 | #include "ilogger.hpp" 7 | #include "binary_io.hpp" 8 | #include "json.hpp" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | typedef unsigned long SessionID; 19 | 20 | enum ResponseWriteMode : int{ 21 | ResponseWriteMode_WriteReturnJson = 0, 22 | ResponseWriteMode_WriteCustom = 1, 23 | ResponseWriteMode_WriteFile = 2 24 | }; 25 | 26 | struct Response{ 27 | BinaryIO output; 28 | std::unordered_map headers; 29 | int status_code = 0; 30 | ResponseWriteMode write_mode = ResponseWriteMode_WriteReturnJson; 31 | std::string file_path; 32 | 33 | Response(); 34 | void set_status_code(int code); 35 | void set_header(const std::string& key, const std::string& value); 36 | void write_binary(const void* pdata, size_t size); 37 | void write_json_styled(const Json::Value& val); 38 | void write_json(const Json::Value& val); 39 | void write_plain_text(const std::string& val); 40 | void write_file(const std::string& file); 41 | std::string get_header(const std::string& name); 42 | void remove_header(const std::string& name); 43 | bool has_header(const std::string& name); 44 | 45 | std::string header_string(); 46 | const std::string& output_string(); 47 | }; 48 | 49 | struct Request{ 50 | std::string url; 51 | std::string body; 52 | std::string method; 53 | std::string proto; 54 | std::string query_string; 55 | std::unordered_map headers; 56 | std::unordered_map vars; 57 | 58 | bool has_header(const std::string& name); 59 | std::string get_header(const std::string& name); 60 | }; 61 | 62 | struct Session { 63 | SessionID conn_id; 64 | Request request; 65 | Response response; 66 | 67 | Session(); 68 | Session(SessionID id); 69 | }; 70 | 71 | typedef std::function& session)> HandlerCallback; 72 | 73 | #define DefRequestMapping(name) \ 74 | int __##name##_register__{add_router(#name, "*", std::bind(&__Current_Class__::name, this, std::placeholders::_1))}; \ 75 | Json::Value name(const Json::Value& param) 76 | 77 | #define SetupController(classes) using __Current_Class__ = classes; 78 | 79 | class HttpServer; 80 | class Controller{ 81 | protected: 82 | typedef std::function ControllerProcess; 83 | struct RequestMapping{ 84 | std::unordered_map> routers; 85 | }router_mapping_; 86 | 87 | std::string mapping_url_; 88 | std::unordered_map> current_session_; 89 | std::mutex session_lock_; 90 | 91 | public: 92 | void initialize(const std::string& url, HttpServer* server); 93 | virtual void process(const std::shared_ptr& session); 94 | virtual void process_module(const std::shared_ptr& session, const ControllerProcess& func); 95 | virtual ControllerProcess find_match(const std::string& url, const std::string& method); 96 | virtual bool is_begin_match(); 97 | 98 | protected: 99 | int add_router(const std::string& url, const std::string& method, const ControllerProcess& process); 100 | std::shared_ptr get_current_session(); 101 | }; 102 | 103 | std::shared_ptr create_file_access_controller(const std::string& root_directory); 104 | 105 | class HttpServer{ 106 | public: 107 | // method POST GET 108 | virtual void verbose() = 0; 109 | virtual void add_router(const std::string& url, const HandlerCallback& callback, const std::string& method) = 0; 110 | virtual void add_router_post(const std::string& url, const HandlerCallback& callback) = 0; 111 | virtual void add_router_get(const std::string& url, const HandlerCallback& callback) = 0; 112 | virtual void add_controller(const std::string& url, std::shared_ptr controller) = 0; 113 | }; 114 | 115 | std::shared_ptr createHttpServer(const std::string& address, int num_threads = 32); 116 | 117 | template 118 | Json::Value success(const _T& value){ 119 | Json::Value ret; 120 | ret["status"] = "success"; 121 | ret["data"] = value; 122 | ret["time"] = iLogger::time_now(); 123 | return ret; 124 | } 125 | 126 | Json::Value success(); 127 | 128 | template 129 | Json::Value failure(const _T& value){ 130 | Json::Value ret; 131 | ret["status"] = "error"; 132 | ret["message"] = value; 133 | ret["time"] = iLogger::time_now(); 134 | return ret; 135 | } 136 | 137 | Json::Value failuref(const char* fmt, ...); 138 | 139 | #endif //HTTP_SERVER_HPP -------------------------------------------------------------------------------- /src/ilogger.cpp: -------------------------------------------------------------------------------- 1 | 2 | #if defined(_WIN32) 3 | # define U_OS_WINDOWS 4 | #else 5 | # define U_OS_LINUX 6 | #endif 7 | 8 | #include "ilogger.hpp" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #if defined(U_OS_WINDOWS) 23 | # define HAS_UUID 24 | # include 25 | # include 26 | # include 27 | # pragma comment(lib, "shlwapi.lib") 28 | # pragma comment(lib, "ole32.lib") 29 | # pragma comment(lib, "gdi32.lib") 30 | # undef min 31 | # undef max 32 | #endif 33 | 34 | #if defined(U_OS_LINUX) 35 | //# include 36 | # include 37 | # include 38 | # include 39 | # include 40 | # include 41 | # define strtok_s strtok_r 42 | #endif 43 | 44 | 45 | #if defined(U_OS_LINUX) 46 | #define __GetTimeBlock \ 47 | time_t timep; \ 48 | time(&timep); \ 49 | tm& t = *(tm*)localtime(&timep); 50 | #endif 51 | 52 | #if defined(U_OS_WINDOWS) 53 | #define __GetTimeBlock \ 54 | tm t; \ 55 | _getsystime(&t); 56 | #endif 57 | 58 | namespace iLogger{ 59 | 60 | using namespace std; 61 | 62 | const char* level_string(int level){ 63 | switch (level){ 64 | case ILOGGER_VERBOSE: return "verbo"; 65 | case ILOGGER_INFO: return "info"; 66 | case ILOGGER_WARNING: return "warn"; 67 | case ILOGGER_ERROR: return "error"; 68 | case ILOGGER_FATAL: return "fatal"; 69 | default: return "unknow"; 70 | } 71 | } 72 | 73 | std::tuple hsv2rgb(float h, float s, float v){ 74 | const int h_i = static_cast(h * 6); 75 | const float f = h * 6 - h_i; 76 | const float p = v * (1 - s); 77 | const float q = v * (1 - f*s); 78 | const float t = v * (1 - (1 - f) * s); 79 | float r, g, b; 80 | switch (h_i) { 81 | case 0:r = v; g = t; b = p;break; 82 | case 1:r = q; g = v; b = p;break; 83 | case 2:r = p; g = v; b = t;break; 84 | case 3:r = p; g = q; b = v;break; 85 | case 4:r = t; g = p; b = v;break; 86 | case 5:r = v; g = p; b = q;break; 87 | default:r = 1; g = 1; b = 1;break;} 88 | return make_tuple(static_cast(r * 255), static_cast(g * 255), static_cast(b * 255)); 89 | } 90 | 91 | std::tuple random_color(int id){ 92 | float h_plane = ((((unsigned int)id << 2) ^ 0x937151) % 100) / 100.0f;; 93 | float s_plane = ((((unsigned int)id << 3) ^ 0x315793) % 100) / 100.0f; 94 | return hsv2rgb(h_plane, s_plane, 1); 95 | } 96 | 97 | string date_now() { 98 | char time_string[20]; 99 | __GetTimeBlock; 100 | 101 | sprintf(time_string, "%04d-%02d-%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday); 102 | return time_string; 103 | } 104 | 105 | string time_now(){ 106 | char time_string[20]; 107 | __GetTimeBlock; 108 | 109 | sprintf(time_string, "%04d-%02d-%02d %02d:%02d:%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); 110 | return time_string; 111 | } 112 | 113 | size_t file_size(const string& file){ 114 | #if defined(U_OS_LINUX) 115 | struct stat st; 116 | stat(file.c_str(), &st); 117 | return st.st_size; 118 | #elif defined(U_OS_WINDOWS) 119 | WIN32_FIND_DATAA find_data; 120 | HANDLE hFind = FindFirstFileA(file.c_str(), &find_data); 121 | if (hFind == INVALID_HANDLE_VALUE) 122 | return 0; 123 | 124 | FindClose(hFind); 125 | return (uint64_t)find_data.nFileSizeLow | ((uint64_t)find_data.nFileSizeHigh << 32); 126 | #endif 127 | } 128 | 129 | time_t last_modify(const string& file){ 130 | 131 | #if defined(U_OS_LINUX) 132 | struct stat st; 133 | stat(file.c_str(), &st); 134 | return st.st_mtim.tv_sec; 135 | #elif defined(U_OS_WINDOWS) 136 | INFOW("LastModify has not support on windows os"); 137 | return 0; 138 | #endif 139 | } 140 | 141 | void sleep(int ms) { 142 | this_thread::sleep_for(std::chrono::milliseconds(ms)); 143 | } 144 | 145 | int get_month_by_name(char* month){ 146 | if(strcmp(month,"Jan") == 0)return 0; 147 | if(strcmp(month,"Feb") == 0)return 1; 148 | if(strcmp(month,"Mar") == 0)return 2; 149 | if(strcmp(month,"Apr") == 0)return 3; 150 | if(strcmp(month,"May") == 0)return 4; 151 | if(strcmp(month,"Jun") == 0)return 5; 152 | if(strcmp(month,"Jul") == 0)return 6; 153 | if(strcmp(month,"Aug") == 0)return 7; 154 | if(strcmp(month,"Sep") == 0)return 8; 155 | if(strcmp(month,"Oct") == 0)return 9; 156 | if(strcmp(month,"Nov") == 0)return 10; 157 | if(strcmp(month,"Dec") == 0)return 11; 158 | return -1; 159 | } 160 | 161 | int get_week_day_by_name(char* wday){ 162 | if(strcmp(wday,"Sun") == 0)return 0; 163 | if(strcmp(wday,"Mon") == 0)return 1; 164 | if(strcmp(wday,"Tue") == 0)return 2; 165 | if(strcmp(wday,"Wed") == 0)return 3; 166 | if(strcmp(wday,"Thu") == 0)return 4; 167 | if(strcmp(wday,"Fri") == 0)return 5; 168 | if(strcmp(wday,"Sat") == 0)return 6; 169 | return -1; 170 | } 171 | 172 | time_t gmtime2ctime(const string& gmt){ 173 | 174 | char week[4] = {0}; 175 | char month[4] = {0}; 176 | tm date; 177 | sscanf(gmt.c_str(),"%3s, %2d %3s %4d %2d:%2d:%2d GMT",week,&date.tm_mday,month,&date.tm_year,&date.tm_hour,&date.tm_min,&date.tm_sec); 178 | date.tm_mon = get_month_by_name(month); 179 | date.tm_wday = get_week_day_by_name(week); 180 | date.tm_year = date.tm_year - 1900; 181 | return mktime(&date); 182 | } 183 | 184 | string gmtime(time_t t){ 185 | t += 28800; 186 | tm* gmt = ::gmtime(&t); 187 | 188 | // http://en.cppreference.com/w/c/chrono/strftime 189 | // e.g.: Sat, 22 Aug 2015 11:48:50 GMT 190 | // 5+ 3+4+ 5+ 9+ 3 = 29 191 | const char* fmt = "%a, %d %b %Y %H:%M:%S GMT"; 192 | char tstr[30]; 193 | strftime(tstr, sizeof(tstr), fmt, gmt); 194 | return tstr; 195 | } 196 | 197 | string gmtime_now() { 198 | return gmtime(time(nullptr)); 199 | } 200 | 201 | bool mkdir(const string& path){ 202 | #ifdef U_OS_WINDOWS 203 | return CreateDirectoryA(path.c_str(), nullptr); 204 | #else 205 | return ::mkdir(path.c_str(), 0755) == 0; 206 | #endif 207 | } 208 | 209 | bool mkdirs(const string& path){ 210 | 211 | if (path.empty()) return false; 212 | if (exists(path)) return true; 213 | 214 | string _path = path; 215 | char* dir_ptr = (char*)_path.c_str(); 216 | char* iter_ptr = dir_ptr; 217 | 218 | bool keep_going = *iter_ptr != 0; 219 | while (keep_going){ 220 | 221 | if (*iter_ptr == 0) 222 | keep_going = false; 223 | 224 | #ifdef U_OS_WINDOWS 225 | if (*iter_ptr == '/' || *iter_ptr == '\\' || *iter_ptr == 0){ 226 | #else 227 | if ((*iter_ptr == '/' && iter_ptr != dir_ptr) || *iter_ptr == 0){ 228 | #endif 229 | char old = *iter_ptr; 230 | *iter_ptr = 0; 231 | if (!exists(dir_ptr)){ 232 | if (!mkdir(dir_ptr)){ 233 | if(!exists(dir_ptr)){ 234 | INFOE("mkdirs %s return false.", dir_ptr); 235 | return false; 236 | } 237 | } 238 | } 239 | *iter_ptr = old; 240 | } 241 | iter_ptr++; 242 | } 243 | return true; 244 | } 245 | 246 | bool isfile(const string& file){ 247 | 248 | #if defined(U_OS_LINUX) 249 | struct stat st; 250 | stat(file.c_str(), &st); 251 | return S_ISREG(st.st_mode); 252 | #elif defined(U_OS_WINDOWS) 253 | INFOW("is_file has not support on windows os"); 254 | return 0; 255 | #endif 256 | } 257 | 258 | FILE* fopen_mkdirs(const string& path, const string& mode){ 259 | 260 | FILE* f = fopen(path.c_str(), mode.c_str()); 261 | if (f) return f; 262 | 263 | int p = path.rfind('/'); 264 | 265 | #if defined(U_OS_WINDOWS) 266 | int e = path.rfind('\\'); 267 | p = std::max(p, e); 268 | #endif 269 | if (p == -1) 270 | return nullptr; 271 | 272 | string directory = path.substr(0, p); 273 | if (!mkdirs(directory)) 274 | return nullptr; 275 | 276 | return fopen(path.c_str(), mode.c_str()); 277 | } 278 | 279 | bool exists(const string& path){ 280 | 281 | #ifdef U_OS_WINDOWS 282 | return ::PathFileExistsA(path.c_str()); 283 | #elif defined(U_OS_LINUX) 284 | return access(path.c_str(), R_OK) == 0; 285 | #endif 286 | } 287 | 288 | string format(const char* fmt, ...) { 289 | va_list vl; 290 | va_start(vl, fmt); 291 | char buffer[2048]; 292 | vsnprintf(buffer, sizeof(buffer), fmt, vl); 293 | return buffer; 294 | } 295 | 296 | string file_name(const string& path, bool include_suffix){ 297 | 298 | if (path.empty()) return ""; 299 | 300 | int p = path.rfind('/'); 301 | 302 | #ifdef U_OS_WINDOWS 303 | int e = path.rfind('\\'); 304 | p = max(p, e); 305 | #endif 306 | p += 1; 307 | 308 | //include suffix 309 | if (include_suffix) 310 | return path.substr(p); 311 | 312 | int u = path.rfind('.'); 313 | if (u == -1) 314 | return path.substr(p); 315 | 316 | if (u <= p) u = path.size(); 317 | return path.substr(p, u - p); 318 | } 319 | 320 | string directory(const string& path){ 321 | if (path.empty()) 322 | return "."; 323 | 324 | int p = path.rfind('/'); 325 | 326 | #ifdef U_OS_WINDOWS 327 | int e = path.rfind('\\'); 328 | p = max(p, e); 329 | #endif 330 | if(p == -1) 331 | return "."; 332 | 333 | return path.substr(0, p + 1); 334 | } 335 | 336 | bool begin_with(const string& str, const string& with){ 337 | 338 | if (str.length() < with.length()) 339 | return false; 340 | return strncmp(str.c_str(), with.c_str(), with.length()) == 0; 341 | } 342 | 343 | bool end_with(const string& str, const string& with){ 344 | 345 | if (str.length() < with.length()) 346 | return false; 347 | 348 | return strncmp(str.c_str() + str.length() - with.length(), with.c_str(), with.length()) == 0; 349 | } 350 | 351 | long long timestamp_now() { 352 | return chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); 353 | } 354 | 355 | static struct Logger{ 356 | mutex logger_lock_; 357 | string logger_directory; 358 | int logger_level{ILOGGER_INFO}; 359 | vector cache_, local_; 360 | shared_ptr flush_thread_; 361 | atomic keep_run_{false}; 362 | shared_ptr handler; 363 | bool logger_shutdown{false}; 364 | 365 | void write(const string& line) { 366 | 367 | lock_guard l(logger_lock_); 368 | if(logger_shutdown) 369 | return; 370 | 371 | if (!keep_run_) { 372 | 373 | if(flush_thread_) 374 | return; 375 | 376 | cache_.reserve(1000); 377 | keep_run_ = true; 378 | flush_thread_.reset(new thread(std::bind(&Logger::flush_job, this))); 379 | } 380 | cache_.emplace_back(line); 381 | } 382 | 383 | void flush() { 384 | 385 | if (cache_.empty()) 386 | return; 387 | 388 | { 389 | std::lock_guard l(logger_lock_); 390 | std::swap(local_, cache_); 391 | } 392 | 393 | if (!local_.empty() && !logger_directory.empty()) { 394 | 395 | auto now = date_now(); 396 | auto file = format("%s%s.txt", logger_directory.c_str(), now.c_str()); 397 | if (!exists(file)) { 398 | handler.reset(fopen_mkdirs(file, "wb"), fclose); 399 | } 400 | else if (!handler) { 401 | handler.reset(fopen_mkdirs(file, "a+"), fclose); 402 | } 403 | 404 | if (handler) { 405 | for (auto& line : local_) 406 | fprintf(handler.get(), "%s\n", line.c_str()); 407 | fflush(handler.get()); 408 | handler.reset(); 409 | } 410 | } 411 | local_.clear(); 412 | } 413 | 414 | void flush_job() { 415 | 416 | auto tick_begin = timestamp_now(); 417 | std::vector local; 418 | while (keep_run_) { 419 | 420 | if (timestamp_now() - tick_begin < 1000) { 421 | this_thread::sleep_for(std::chrono::milliseconds(100)); 422 | continue; 423 | } 424 | 425 | tick_begin = timestamp_now(); 426 | flush(); 427 | } 428 | flush(); 429 | } 430 | 431 | void set_save_directory(const string& loggerDirectory) { 432 | logger_directory = loggerDirectory; 433 | 434 | if (logger_directory.empty()) 435 | logger_directory = "."; 436 | 437 | #if defined(U_OS_LINUX) 438 | if (logger_directory.back() != '/') { 439 | logger_directory.push_back('/'); 440 | } 441 | #endif 442 | 443 | #if defined(U_OS_WINDOWS) 444 | if (logger_directory.back() != '/' && logger_directory.back() != '\\') { 445 | logger_directory.push_back('/'); 446 | } 447 | #endif 448 | } 449 | 450 | void set_logger_level(int level){ 451 | logger_level = level; 452 | } 453 | 454 | void close(){ 455 | { 456 | lock_guard l(logger_lock_); 457 | if (logger_shutdown) return; 458 | 459 | logger_shutdown = true; 460 | }; 461 | 462 | if (!keep_run_) return; 463 | keep_run_ = false; 464 | flush_thread_->join(); 465 | flush_thread_.reset(); 466 | handler.reset(); 467 | } 468 | 469 | virtual ~Logger(){ 470 | close(); 471 | } 472 | }__g_logger; 473 | 474 | void destroy_logger(){ 475 | __g_logger.close(); 476 | } 477 | 478 | static void remove_color_text(char* buffer){ 479 | 480 | //"\033[31m%s\033[0m" 481 | char* p = buffer; 482 | while(*p){ 483 | 484 | if(*p == 0x1B){ 485 | char np = *(p + 1); 486 | if(np == '['){ 487 | // has token 488 | char* t = p + 2; 489 | while(*t){ 490 | if(*t == 'm'){ 491 | t = t + 1; 492 | char* k = p; 493 | while(*t){ 494 | *k++ = *t++; 495 | } 496 | *k = 0; 497 | break; 498 | } 499 | t++; 500 | } 501 | } 502 | } 503 | p++; 504 | } 505 | } 506 | 507 | void set_logger_save_directory(const string& loggerDirectory){ 508 | __g_logger.set_save_directory(loggerDirectory); 509 | } 510 | 511 | void set_log_level(int level){ 512 | __g_logger.set_logger_level(level); 513 | } 514 | 515 | void __log_func(const char* file, int line, int level, const char* fmt, ...) { 516 | 517 | if(level > __g_logger.logger_level) 518 | return; 519 | 520 | string now = time_now(); 521 | va_list vl; 522 | va_start(vl, fmt); 523 | 524 | char buffer[2048]; 525 | string filename = file_name(file, true); 526 | int n = snprintf(buffer, sizeof(buffer), "[%s]", now.c_str()); 527 | 528 | #if defined(U_OS_WINDOWS) 529 | if (level == ILOGGER_FATAL || level == ILOGGER_ERROR) { 530 | n += snprintf(buffer + n, sizeof(buffer) - n, "[%s]", level_string(level)); 531 | } 532 | else if (level == ILOGGER_WARNING) { 533 | n += snprintf(buffer + n, sizeof(buffer) - n, "[%s]", level_string(level)); 534 | } 535 | else { 536 | n += snprintf(buffer + n, sizeof(buffer) - n, "[%s]", level_string(level)); 537 | } 538 | #elif defined(U_OS_LINUX) 539 | if (level == ILOGGER_FATAL || level == ILOGGER_ERROR) { 540 | n += snprintf(buffer + n, sizeof(buffer) - n, "[\033[31m%s\033[0m]", level_string(level)); 541 | } 542 | else if (level == ILOGGER_WARNING) { 543 | n += snprintf(buffer + n, sizeof(buffer) - n, "[\033[33m%s\033[0m]", level_string(level)); 544 | } 545 | else { 546 | n += snprintf(buffer + n, sizeof(buffer) - n, "[\033[32m%s\033[0m]", level_string(level)); 547 | } 548 | #endif 549 | 550 | n += snprintf(buffer + n, sizeof(buffer) - n, "[%s:%d]:", filename.c_str(), line); 551 | vsnprintf(buffer + n, sizeof(buffer) - n, fmt, vl); 552 | 553 | if (level == ILOGGER_FATAL || level == ILOGGER_ERROR) { 554 | fprintf(stderr, "%s\n", buffer); 555 | } 556 | else if (level == ILOGGER_WARNING) { 557 | fprintf(stdout, "%s\n", buffer); 558 | } 559 | else { 560 | fprintf(stdout, "%s\n", buffer); 561 | } 562 | 563 | if(!__g_logger.logger_directory.empty()){ 564 | #ifdef U_OS_LINUX 565 | // remove save color txt 566 | remove_color_text(buffer); 567 | #endif 568 | __g_logger.write(buffer); 569 | if (level == ILOGGER_FATAL) { 570 | __g_logger.flush(); 571 | fflush(stdout); 572 | abort(); 573 | } 574 | } 575 | } 576 | 577 | string load_text_file(const string& file){ 578 | ifstream in(file, ios::in | ios::binary); 579 | if (!in.is_open()) 580 | return {}; 581 | 582 | in.seekg(0, ios::end); 583 | size_t length = in.tellg(); 584 | 585 | string data; 586 | if (length > 0){ 587 | in.seekg(0, ios::beg); 588 | data.resize(length); 589 | 590 | in.read((char*)&data[0], length); 591 | } 592 | in.close(); 593 | return data; 594 | } 595 | 596 | std::vector load_file(const string& file){ 597 | 598 | ifstream in(file, ios::in | ios::binary); 599 | if (!in.is_open()) 600 | return {}; 601 | 602 | in.seekg(0, ios::end); 603 | size_t length = in.tellg(); 604 | 605 | std::vector data; 606 | if (length > 0){ 607 | in.seekg(0, ios::beg); 608 | data.resize(length); 609 | 610 | in.read((char*)&data[0], length); 611 | } 612 | in.close(); 613 | return data; 614 | } 615 | 616 | bool alphabet_equal(char a, char b, bool ignore_case){ 617 | if (ignore_case){ 618 | a = a > 'a' && a < 'z' ? a - 'a' + 'A' : a; 619 | b = b > 'a' && b < 'z' ? b - 'a' + 'A' : b; 620 | } 621 | return a == b; 622 | } 623 | 624 | static bool pattern_match_body(const char* str, const char* matcher, bool igrnoe_case){ 625 | // abcdefg.pnga *.png > false 626 | // abcdefg.png *.png > true 627 | // abcdefg.png a?cdefg.png > true 628 | 629 | if (!matcher || !*matcher || !str || !*str) return false; 630 | 631 | const char* ptr_matcher = matcher; 632 | while (*str){ 633 | if (*ptr_matcher == '?'){ 634 | ptr_matcher++; 635 | } 636 | else if (*ptr_matcher == '*'){ 637 | if (*(ptr_matcher + 1)){ 638 | if (pattern_match_body(str, ptr_matcher + 1, igrnoe_case)) 639 | return true; 640 | } 641 | else{ 642 | return true; 643 | } 644 | } 645 | else if (!alphabet_equal(*ptr_matcher, *str, igrnoe_case)){ 646 | return false; 647 | } 648 | else{ 649 | if (*ptr_matcher) 650 | ptr_matcher++; 651 | else 652 | return false; 653 | } 654 | str++; 655 | } 656 | 657 | while (*ptr_matcher){ 658 | if (*ptr_matcher != '*') 659 | return false; 660 | ptr_matcher++; 661 | } 662 | return true; 663 | } 664 | 665 | bool pattern_match(const char* str, const char* matcher, bool igrnoe_case){ 666 | // abcdefg.pnga *.png > false 667 | // abcdefg.png *.png > true 668 | // abcdefg.png a?cdefg.png > true 669 | 670 | if (!matcher || !*matcher || !str || !*str) return false; 671 | 672 | char filter[500]; 673 | strcpy(filter, matcher); 674 | 675 | vector arr; 676 | char* ptr_str = filter; 677 | char* ptr_prev_str = ptr_str; 678 | while (*ptr_str){ 679 | if (*ptr_str == ';'){ 680 | *ptr_str = 0; 681 | arr.push_back(ptr_prev_str); 682 | ptr_prev_str = ptr_str + 1; 683 | } 684 | ptr_str++; 685 | } 686 | 687 | if (*ptr_prev_str) 688 | arr.push_back(ptr_prev_str); 689 | 690 | for (int i = 0; i < arr.size(); ++i){ 691 | if (pattern_match_body(str, arr[i], igrnoe_case)) 692 | return true; 693 | } 694 | return false; 695 | } 696 | 697 | #ifdef U_OS_WINDOWS 698 | vector find_files(const string& directory, const string& filter, bool findDirectory, bool includeSubDirectory){ 699 | 700 | string realpath = directory; 701 | if (realpath.empty()) 702 | realpath = "./"; 703 | 704 | char backchar = realpath.back(); 705 | if (backchar != '\\' && backchar != '/') 706 | realpath += "/"; 707 | 708 | vector out; 709 | _WIN32_FIND_DATAA find_data; 710 | stack ps; 711 | ps.push(realpath); 712 | 713 | while (!ps.empty()) 714 | { 715 | string search_path = ps.top(); 716 | ps.pop(); 717 | 718 | HANDLE hFind = FindFirstFileA((search_path + "*").c_str(), &find_data); 719 | if (hFind != INVALID_HANDLE_VALUE){ 720 | do{ 721 | if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0) 722 | continue; 723 | 724 | if (!findDirectory && (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY || 725 | findDirectory && (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY){ 726 | if (PathMatchSpecA(find_data.cFileName, filter.c_str())) 727 | out.push_back(search_path + find_data.cFileName); 728 | } 729 | 730 | if (includeSubDirectory && (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) 731 | ps.push(search_path + find_data.cFileName + "/"); 732 | 733 | } while (FindNextFileA(hFind, &find_data)); 734 | FindClose(hFind); 735 | } 736 | } 737 | return out; 738 | } 739 | #endif 740 | 741 | #ifdef U_OS_LINUX 742 | vector find_files(const string& directory, const string& filter, bool findDirectory, bool includeSubDirectory) 743 | { 744 | string realpath = directory; 745 | if (realpath.empty()) 746 | realpath = "./"; 747 | 748 | char backchar = realpath.back(); 749 | if (backchar != '\\' && backchar != '/') 750 | realpath += "/"; 751 | 752 | struct dirent* fileinfo; 753 | DIR* handle; 754 | stack ps; 755 | vector out; 756 | ps.push(realpath); 757 | 758 | while (!ps.empty()) 759 | { 760 | string search_path = ps.top(); 761 | ps.pop(); 762 | 763 | handle = opendir(search_path.c_str()); 764 | if (handle != 0) 765 | { 766 | while (fileinfo = readdir(handle)) 767 | { 768 | struct stat file_stat; 769 | if (strcmp(fileinfo->d_name, ".") == 0 || strcmp(fileinfo->d_name, "..") == 0) 770 | continue; 771 | 772 | if (lstat((search_path + fileinfo->d_name).c_str(), &file_stat) < 0) 773 | continue; 774 | 775 | if (!findDirectory && !S_ISDIR(file_stat.st_mode) || 776 | findDirectory && S_ISDIR(file_stat.st_mode)) 777 | { 778 | if (pattern_match(fileinfo->d_name, filter.c_str())) 779 | out.push_back(search_path + fileinfo->d_name); 780 | } 781 | 782 | if (includeSubDirectory && S_ISDIR(file_stat.st_mode)) 783 | ps.push(search_path + fileinfo->d_name + "/"); 784 | } 785 | closedir(handle); 786 | } 787 | } 788 | return out; 789 | } 790 | #endif 791 | 792 | string align_blank(const string& input, int align_size, char blank){ 793 | if(input.size() >= align_size) return input; 794 | string output = input; 795 | for(int i = 0; i < align_size - input.size(); ++i) 796 | output.push_back(blank); 797 | return output; 798 | } 799 | 800 | vector split_string(const string& str, const std::string& spstr){ 801 | 802 | vector res; 803 | if (str.empty()) return res; 804 | if (spstr.empty()) return{ str }; 805 | 806 | auto p = str.find(spstr); 807 | if (p == string::npos) return{ str }; 808 | 809 | res.reserve(5); 810 | string::size_type prev = 0; 811 | int lent = spstr.length(); 812 | const char* ptr = str.c_str(); 813 | 814 | while (p != string::npos){ 815 | int len = p - prev; 816 | if (len > 0){ 817 | res.emplace_back(str.substr(prev, len)); 818 | } 819 | prev = p + lent; 820 | p = str.find(spstr, prev); 821 | } 822 | 823 | int len = str.length() - prev; 824 | if (len > 0){ 825 | res.emplace_back(str.substr(prev, len)); 826 | } 827 | return res; 828 | } 829 | 830 | string replace_string(const string& str, const string& token, const string& value){ 831 | 832 | string opstr; 833 | 834 | if (value.length() > token.length()){ 835 | float numToken = str.size() / (float)token.size(); 836 | float newTokenLength = value.size() * numToken; 837 | opstr.resize(newTokenLength); 838 | } 839 | else{ 840 | opstr.resize(str.size()); 841 | } 842 | 843 | char* dest = &opstr[0]; 844 | const char* src = str.c_str(); 845 | string::size_type pos = 0; 846 | string::size_type prev = 0; 847 | size_t token_length = token.length(); 848 | size_t value_length = value.length(); 849 | const char* value_ptr = value.c_str(); 850 | bool keep = true; 851 | 852 | do{ 853 | pos = str.find(token, pos); 854 | if (pos == string::npos){ 855 | keep = false; 856 | pos = str.length(); 857 | } 858 | 859 | size_t copy_length = pos - prev; 860 | memcpy(dest, src + prev, copy_length); 861 | dest += copy_length; 862 | 863 | if (keep){ 864 | pos += token_length; 865 | prev = pos; 866 | memcpy(dest, value_ptr, value_length); 867 | dest += value_length; 868 | } 869 | } while (keep); 870 | 871 | size_t valid_size = dest - &opstr[0]; 872 | opstr.resize(valid_size); 873 | return opstr; 874 | } 875 | 876 | bool save_file(const string& file, const void* data, size_t length, bool mk_dirs){ 877 | 878 | if (mk_dirs){ 879 | int p = (int)file.rfind('/'); 880 | 881 | #ifdef U_OS_WINDOWS 882 | int e = (int)file.rfind('\\'); 883 | p = max(p, e); 884 | #endif 885 | if (p != -1){ 886 | if (!mkdirs(file.substr(0, p))) 887 | return false; 888 | } 889 | } 890 | 891 | FILE* f = fopen(file.c_str(), "wb"); 892 | if (!f) return false; 893 | 894 | if (data && length > 0){ 895 | if (fwrite(data, 1, length, f) != length){ 896 | fclose(f); 897 | return false; 898 | } 899 | } 900 | fclose(f); 901 | return true; 902 | } 903 | 904 | bool save_file(const string& file, const string& data, bool mk_dirs){ 905 | return save_file(file, data.data(), data.size(), mk_dirs); 906 | } 907 | 908 | bool save_file(const string& file, const vector& data, bool mk_dirs){ 909 | return save_file(file, data.data(), data.size(), mk_dirs); 910 | } 911 | 912 | static volatile bool g_has_exit_signal = false; 913 | static int g_signum = 0; 914 | static void signal_callback_handler(int signum){ 915 | INFO("Capture interrupt signal."); 916 | g_has_exit_signal = true; 917 | g_signum = signum; 918 | } 919 | 920 | int while_loop(){ 921 | signal(SIGINT, signal_callback_handler); 922 | signal(SIGQUIT, signal_callback_handler); 923 | while(!g_has_exit_signal){ 924 | this_thread::yield(); 925 | } 926 | INFO("Loop over."); 927 | return g_signum; 928 | } 929 | 930 | 931 | static unsigned char from_b64(unsigned char ch) { 932 | /* Inverse lookup map */ 933 | static const unsigned char tab[128] = { 934 | 255, 255, 255, 255, 935 | 255, 255, 255, 255, /* 0 */ 936 | 255, 255, 255, 255, 937 | 255, 255, 255, 255, /* 8 */ 938 | 255, 255, 255, 255, 939 | 255, 255, 255, 255, /* 16 */ 940 | 255, 255, 255, 255, 941 | 255, 255, 255, 255, /* 24 */ 942 | 255, 255, 255, 255, 943 | 255, 255, 255, 255, /* 32 */ 944 | 255, 255, 255, 62, 945 | 255, 255, 255, 63, /* 40 */ 946 | 52, 53, 54, 55, 947 | 56, 57, 58, 59, /* 48 */ 948 | 60, 61, 255, 255, 949 | 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */ 950 | 255, 0, 1, 2, 951 | 3, 4, 5, 6, /* 64 */ 952 | 7, 8, 9, 10, 953 | 11, 12, 13, 14, /* 72 */ 954 | 15, 16, 17, 18, 955 | 19, 20, 21, 22, /* 80 */ 956 | 23, 24, 25, 255, 957 | 255, 255, 255, 255, /* 88 */ 958 | 255, 26, 27, 28, 959 | 29, 30, 31, 32, /* 96 */ 960 | 33, 34, 35, 36, 961 | 37, 38, 39, 40, /* 104 */ 962 | 41, 42, 43, 44, 963 | 45, 46, 47, 48, /* 112 */ 964 | 49, 50, 51, 255, 965 | 255, 255, 255, 255, /* 120 */ 966 | }; 967 | return tab[ch & 127]; 968 | } 969 | 970 | string base64_decode(const string& base64) { 971 | 972 | if(base64.empty()) 973 | return ""; 974 | 975 | int len = base64.size(); 976 | auto s = (const unsigned char*)base64.data(); 977 | unsigned char a, b, c, d; 978 | int orig_len = len; 979 | int dec_len = 0; 980 | string out_data; 981 | 982 | auto end_s = s + base64.size(); 983 | int count_eq = 0; 984 | while(*--end_s == '='){ 985 | count_eq ++; 986 | } 987 | out_data.resize(len / 4 * 3 - count_eq); 988 | 989 | char *dst = const_cast(out_data.data()); 990 | char *orig_dst = dst; 991 | while (len >= 4 && (a = from_b64(s[0])) != 255 && 992 | (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 && 993 | (d = from_b64(s[3])) != 255) { 994 | s += 4; 995 | len -= 4; 996 | if (a == 200 || b == 200) break; /* '=' can't be there */ 997 | *dst++ = a << 2 | b >> 4; 998 | if (c == 200) break; 999 | *dst++ = b << 4 | c >> 2; 1000 | if (d == 200) break; 1001 | *dst++ = c << 6 | d; 1002 | } 1003 | dec_len = (dst - orig_dst); 1004 | 1005 | // dec_len必定等于out_data.size() 1006 | return out_data; 1007 | } 1008 | 1009 | string base64_encode(const void* data, size_t size) { 1010 | 1011 | string encode_result; 1012 | encode_result.reserve(size / 3 * 4 + (size % 3 != 0 ? 4 : 0)); 1013 | 1014 | const unsigned char * current = static_cast(data); 1015 | static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 1016 | while(size > 2) { 1017 | encode_result += base64_table[current[0] >> 2]; 1018 | encode_result += base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; 1019 | encode_result += base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)]; 1020 | encode_result += base64_table[current[2] & 0x3f]; 1021 | 1022 | current += 3; 1023 | size -= 3; 1024 | } 1025 | 1026 | if(size > 0){ 1027 | encode_result += base64_table[current[0] >> 2]; 1028 | if(size%3 == 1) { 1029 | encode_result += base64_table[(current[0] & 0x03) << 4]; 1030 | encode_result += "=="; 1031 | } else if(size%3 == 2) { 1032 | encode_result += base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; 1033 | encode_result += base64_table[(current[1] & 0x0f) << 2]; 1034 | encode_result += "="; 1035 | } 1036 | } 1037 | return encode_result; 1038 | } 1039 | 1040 | 1041 | }; // namespace Logger -------------------------------------------------------------------------------- /src/ilogger.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ILOGGER_HPP 3 | #define ILOGGER_HPP 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define ILOGGER_VERBOSE 4 12 | #define ILOGGER_INFO 3 13 | #define ILOGGER_WARNING 2 14 | #define ILOGGER_ERROR 1 15 | #define ILOGGER_FATAL 0 16 | #define INFOV(...) iLogger::__log_func(__FILE__, __LINE__, ILOGGER_VERBOSE, __VA_ARGS__) 17 | #define INFO(...) iLogger::__log_func(__FILE__, __LINE__, ILOGGER_INFO, __VA_ARGS__) 18 | #define INFOW(...) iLogger::__log_func(__FILE__, __LINE__, ILOGGER_WARNING, __VA_ARGS__) 19 | #define INFOE(...) iLogger::__log_func(__FILE__, __LINE__, ILOGGER_ERROR, __VA_ARGS__) 20 | #define INFOF(...) iLogger::__log_func(__FILE__, __LINE__, ILOGGER_FATAL, __VA_ARGS__) 21 | 22 | namespace iLogger{ 23 | 24 | using namespace std; 25 | 26 | string date_now(); 27 | string time_now(); 28 | string gmtime_now(); 29 | string gmtime(time_t t); 30 | time_t gmtime2ctime(const string& gmt); 31 | void sleep(int ms); 32 | 33 | bool isfile(const string& file); 34 | bool mkdir(const string& path); 35 | bool mkdirs(const string& path); 36 | bool exists(const string& path); 37 | string format(const char* fmt, ...); 38 | FILE* fopen_mkdirs(const string& path, const string& mode); 39 | string file_name(const string& path, bool include_suffix); 40 | string directory(const string& path); 41 | long long timestamp_now(); 42 | time_t last_modify(const string& file); 43 | vector load_file(const string& file); 44 | string load_text_file(const string& file); 45 | size_t file_size(const string& file); 46 | 47 | bool begin_with(const string& str, const string& with); 48 | bool end_with(const string& str, const string& with); 49 | vector split_string(const string& str, const std::string& spstr); 50 | string replace_string(const string& str, const string& token, const string& value); 51 | 52 | // h[0-1], s[0-1], v[0-1] 53 | // return, 0-255, 0-255, 0-255 54 | tuple hsv2rgb(float h, float s, float v); 55 | tuple random_color(int id); 56 | 57 | // abcdefg.pnga *.png > false 58 | // abcdefg.png *.png > true 59 | // abcdefg.png a?cdefg.png > true 60 | bool pattern_match(const char* str, const char* matcher, bool igrnoe_case = true); 61 | vector find_files( 62 | const string& directory, 63 | const string& filter = "*", bool findDirectory = false, bool includeSubDirectory = false); 64 | 65 | string align_blank(const string& input, int align_size, char blank=' '); 66 | bool save_file(const string& file, const vector& data, bool mk_dirs = true); 67 | bool save_file(const string& file, const string& data, bool mk_dirs = true); 68 | bool save_file(const string& file, const void* data, size_t length, bool mk_dirs = true); 69 | 70 | // 循环等待,并捕获例如ctrl+c等终止信号,收到信号后循环跳出并返回信号类型 71 | // 捕获:SIGINT(2)、SIGQUIT(3) 72 | int while_loop(); 73 | 74 | // 关于logger的api 75 | const char* level_string(int level); 76 | void set_logger_save_directory(const string& loggerDirectory); 77 | 78 | // 当日志的级别低于这个设置时,会打印出来,否则会直接跳过 79 | void set_log_level(int level); 80 | void __log_func(const char* file, int line, int level, const char* fmt, ...); 81 | void destroy_logger(); 82 | 83 | string base64_decode(const string& base64); 84 | string base64_encode(const void* data, size_t size); 85 | }; 86 | 87 | 88 | #endif // ILOGGER_HPP -------------------------------------------------------------------------------- /src/json.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef JSON_HPP_INCLUDED 3 | #define JSON_HPP_INCLUDED 4 | 5 | 6 | //////////////begin of version.h 7 | // DO NOT EDIT. This file (and "version") is generated by CMake. 8 | // Run CMake configure step to update it. 9 | #ifndef JSON_VERSION_H_INCLUDED 10 | # define JSON_VERSION_H_INCLUDED 11 | 12 | # define JSONCPP_VERSION_STRING "1.8.3" 13 | # define JSONCPP_VERSION_MAJOR 1 14 | # define JSONCPP_VERSION_MINOR 8 15 | # define JSONCPP_VERSION_PATCH 3 16 | # define JSONCPP_VERSION_QUALIFIER 17 | # define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) 18 | 19 | #ifdef JSONCPP_USING_SECURE_MEMORY 20 | #undef JSONCPP_USING_SECURE_MEMORY 21 | #endif 22 | #define JSONCPP_USING_SECURE_MEMORY 0 23 | // If non-zero, the library zeroes any memory that it has allocated before 24 | // it frees its memory. 25 | 26 | #endif // JSON_VERSION_H_INCLUDED 27 | 28 | //////////////end of version.h 29 | 30 | 31 | 32 | 33 | 34 | //////////////begin of config.h 35 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 36 | // Distributed under MIT license, or public domain if desired and 37 | // recognized in your jurisdiction. 38 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 39 | 40 | #ifndef JSON_CONFIG_H_INCLUDED 41 | #define JSON_CONFIG_H_INCLUDED 42 | #include 43 | #include //typedef String 44 | #include //typedef int64_t, uint64_t 45 | 46 | /// If defined, indicates that json library is embedded in CppTL library. 47 | //# define JSON_IN_CPPTL 1 48 | 49 | /// If defined, indicates that json may leverage CppTL library 50 | //# define JSON_USE_CPPTL 1 51 | /// If defined, indicates that cpptl vector based map should be used instead of 52 | /// std::map 53 | /// as Value container. 54 | //# define JSON_USE_CPPTL_SMALLMAP 1 55 | 56 | // If non-zero, the library uses exceptions to report bad input instead of C 57 | // assertion macros. The default is to use exceptions. 58 | #ifndef JSON_USE_EXCEPTION 59 | #define JSON_USE_EXCEPTION 1 60 | #endif 61 | 62 | /// If defined, indicates that the source file is amalgated 63 | /// to prevent private header inclusion. 64 | /// Remarks: it is automatically defined in the generated amalgated header. 65 | // #define JSON_IS_AMALGAMATION 66 | 67 | #ifdef JSON_IN_CPPTL 68 | #include 69 | #ifndef JSON_USE_CPPTL 70 | #define JSON_USE_CPPTL 1 71 | #endif 72 | #endif 73 | 74 | #ifdef JSON_IN_CPPTL 75 | #define JSON_API CPPTL_API 76 | #elif defined(JSON_DLL_BUILD) 77 | #if defined(_MSC_VER) || defined(__MINGW32__) 78 | #define JSON_API __declspec(dllexport) 79 | #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING 80 | #endif // if defined(_MSC_VER) 81 | #elif defined(JSON_DLL) 82 | #if defined(_MSC_VER) || defined(__MINGW32__) 83 | #define JSON_API __declspec(dllimport) 84 | #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING 85 | #endif // if defined(_MSC_VER) 86 | #endif // ifdef JSON_IN_CPPTL 87 | #if !defined(JSON_API) 88 | #define JSON_API 89 | #endif 90 | 91 | // If JSON_NO_INT64 is defined, then Json only support C++ "int" type for 92 | // integer 93 | // Storages, and 64 bits integer support is disabled. 94 | // #define JSON_NO_INT64 1 95 | 96 | #if defined(_MSC_VER) // MSVC 97 | # if _MSC_VER <= 1200 // MSVC 6 98 | // Microsoft Visual Studio 6 only support conversion from __int64 to double 99 | // (no conversion from unsigned __int64). 100 | # define JSON_USE_INT64_DOUBLE_CONVERSION 1 101 | // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' 102 | // characters in the debug information) 103 | // All projects I've ever seen with VS6 were using this globally (not bothering 104 | // with pragma push/pop). 105 | # pragma warning(disable : 4786) 106 | # endif // MSVC 6 107 | 108 | # if _MSC_VER >= 1500 // MSVC 2008 109 | /// Indicates that the following function is deprecated. 110 | //# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) 111 | # endif 112 | 113 | #endif // defined(_MSC_VER) 114 | 115 | // In c++11 the override keyword allows you to explicity define that a function 116 | // is intended to override the base-class version. This makes the code more 117 | // managable and fixes a set of common hard-to-find bugs. 118 | #if __cplusplus >= 201103L 119 | # define JSONCPP_OVERRIDE override 120 | # define JSONCPP_NOEXCEPT noexcept 121 | #elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 122 | # define JSONCPP_OVERRIDE override 123 | # define JSONCPP_NOEXCEPT throw() 124 | #elif defined(_MSC_VER) && _MSC_VER >= 1900 125 | # define JSONCPP_OVERRIDE override 126 | # define JSONCPP_NOEXCEPT noexcept 127 | #else 128 | # define JSONCPP_OVERRIDE 129 | # define JSONCPP_NOEXCEPT throw() 130 | #endif 131 | 132 | #ifndef JSON_HAS_RVALUE_REFERENCES 133 | 134 | #if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 135 | #define JSON_HAS_RVALUE_REFERENCES 1 136 | #endif // MSVC >= 2010 137 | 138 | #ifdef __clang__ 139 | #if __has_feature(cxx_rvalue_references) 140 | #define JSON_HAS_RVALUE_REFERENCES 1 141 | #endif // has_feature 142 | 143 | #elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) 144 | #if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) 145 | #define JSON_HAS_RVALUE_REFERENCES 1 146 | #endif // GXX_EXPERIMENTAL 147 | 148 | #endif // __clang__ || __GNUC__ 149 | 150 | #endif // not defined JSON_HAS_RVALUE_REFERENCES 151 | 152 | #ifndef JSON_HAS_RVALUE_REFERENCES 153 | #define JSON_HAS_RVALUE_REFERENCES 0 154 | #endif 155 | 156 | #ifdef __clang__ 157 | # if __has_extension(attribute_deprecated_with_message) 158 | # define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) 159 | # endif 160 | #elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) 161 | # if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) 162 | # define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) 163 | # elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) 164 | # define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) 165 | # endif // GNUC version 166 | #endif // __clang__ || __GNUC__ 167 | 168 | #if !defined(JSONCPP_DEPRECATED) 169 | #define JSONCPP_DEPRECATED(message) 170 | #endif // if !defined(JSONCPP_DEPRECATED) 171 | 172 | #if __GNUC__ >= 6 173 | # define JSON_USE_INT64_DOUBLE_CONVERSION 1 174 | #endif 175 | 176 | #if !defined(JSON_IS_AMALGAMATION) 177 | 178 | //#include "version.h" 179 | 180 | # if JSONCPP_USING_SECURE_MEMORY 181 | # include "allocator.h" //typedef MemoryManager 182 | # endif 183 | 184 | #endif // if !defined(JSON_IS_AMALGAMATION) 185 | 186 | namespace Json { 187 | typedef int Int; 188 | typedef unsigned int UInt; 189 | #if defined(JSON_NO_INT64) 190 | typedef int LargestInt; 191 | typedef unsigned int LargestUInt; 192 | #undef JSON_HAS_INT64 193 | #else // if defined(JSON_NO_INT64) 194 | // For Microsoft Visual use specific types as long long is not supported 195 | #if defined(_MSC_VER) // Microsoft Visual Studio 196 | typedef __int64 Int64; 197 | typedef unsigned __int64 UInt64; 198 | #else // if defined(_MSC_VER) // Other platforms, use long long 199 | typedef int64_t Int64; 200 | typedef uint64_t UInt64; 201 | #endif // if defined(_MSC_VER) 202 | typedef Int64 LargestInt; 203 | typedef UInt64 LargestUInt; 204 | #define JSON_HAS_INT64 205 | #endif // if defined(JSON_NO_INT64) 206 | #if JSONCPP_USING_SECURE_MEMORY 207 | #define JSONCPP_STRING std::basic_string, Json::SecureMemoryManager > 208 | #define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureMemoryManager > 209 | #define JSONCPP_OSTREAM std::basic_ostream> 210 | #define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureMemoryManager > 211 | #define JSONCPP_ISTREAM std::istream 212 | #else 213 | #define JSONCPP_STRING std::string 214 | #define JSONCPP_OSTRINGSTREAM std::ostringstream 215 | #define JSONCPP_OSTREAM std::ostream 216 | #define JSONCPP_ISTRINGSTREAM std::istringstream 217 | #define JSONCPP_ISTREAM std::istream 218 | #endif // if JSONCPP_USING_SECURE_MEMORY 219 | } // end namespace Json 220 | 221 | #endif // JSON_CONFIG_H_INCLUDED 222 | 223 | //////////////end of config.h 224 | 225 | 226 | 227 | 228 | 229 | //////////////begin of assertions.h 230 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 231 | // Distributed under MIT license, or public domain if desired and 232 | // recognized in your jurisdiction. 233 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 234 | 235 | #ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED 236 | #define CPPTL_JSON_ASSERTIONS_H_INCLUDED 237 | 238 | #include 239 | #include 240 | 241 | #if !defined(JSON_IS_AMALGAMATION) 242 | //#include "config.h" 243 | #endif // if !defined(JSON_IS_AMALGAMATION) 244 | 245 | /** It should not be possible for a maliciously designed file to 246 | * cause an abort() or seg-fault, so these macros are used only 247 | * for pre-condition violations and internal logic errors. 248 | */ 249 | #if JSON_USE_EXCEPTION 250 | 251 | // @todo <= add detail about condition in exception 252 | # define JSON_ASSERT(condition) \ 253 | {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} 254 | 255 | # define JSON_FAIL_MESSAGE(message) \ 256 | { \ 257 | JSONCPP_OSTRINGSTREAM oss; oss << message; \ 258 | Json::throwLogicError(oss.str()); \ 259 | abort(); \ 260 | } 261 | 262 | #else // JSON_USE_EXCEPTION 263 | 264 | # define JSON_ASSERT(condition) assert(condition) 265 | 266 | // The call to assert() will show the failure message in debug builds. In 267 | // release builds we abort, for a core-dump or debugger. 268 | # define JSON_FAIL_MESSAGE(message) \ 269 | { \ 270 | JSONCPP_OSTRINGSTREAM oss; oss << message; \ 271 | assert(false && oss.str().c_str()); \ 272 | abort(); \ 273 | } 274 | 275 | 276 | #endif 277 | 278 | #define JSON_ASSERT_MESSAGE(condition, message) \ 279 | if (!(condition)) { \ 280 | JSON_FAIL_MESSAGE(message); \ 281 | } 282 | 283 | #endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED 284 | 285 | //////////////end of assertions.h 286 | 287 | 288 | 289 | 290 | 291 | //////////////begin of allocator.h 292 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 293 | // Distributed under MIT license, or public domain if desired and 294 | // recognized in your jurisdiction. 295 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 296 | 297 | #ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED 298 | #define CPPTL_JSON_ALLOCATOR_H_INCLUDED 299 | 300 | #include 301 | #include 302 | 303 | #pragma pack(push, 8) 304 | 305 | namespace Json { 306 | template 307 | class SecureMemoryManager { 308 | public: 309 | // Type definitions 310 | using value_type = T; 311 | using pointer = T*; 312 | using const_pointer = const T*; 313 | using reference = T&; 314 | using const_reference = const T&; 315 | using size_type = std::size_t; 316 | using difference_type = std::ptrdiff_t; 317 | 318 | /** 319 | * Allocate memory for N items using the standard allocator. 320 | */ 321 | pointer allocate(size_type n) { 322 | // allocate using "global operator new" 323 | return static_cast(::operator new(n * sizeof(T))); 324 | } 325 | 326 | /** 327 | * Release memory which was allocated for N items at pointer P. 328 | * 329 | * The memory block is filled with zeroes before being released. 330 | * The pointer argument is tagged as "volatile" to prevent the 331 | * compiler optimizing out this critical step. 332 | */ 333 | void deallocate(volatile pointer p, size_type n) { 334 | std::memset(p, 0, n * sizeof(T)); 335 | // free using "global operator delete" 336 | ::operator delete(p); 337 | } 338 | 339 | /** 340 | * Construct an item in-place at pointer P. 341 | */ 342 | template 343 | void construct(pointer p, Args&&... args) { 344 | // construct using "placement new" and "perfect forwarding" 345 | ::new (static_cast(p)) T(std::forward(args)...); 346 | } 347 | 348 | size_type max_size() const { 349 | return size_t(-1) / sizeof(T); 350 | } 351 | 352 | pointer address( reference x ) const { 353 | return std::addressof(x); 354 | } 355 | 356 | const_pointer address( const_reference x ) const { 357 | return std::addressof(x); 358 | } 359 | 360 | /** 361 | * Destroy an item in-place at pointer P. 362 | */ 363 | void destroy(pointer p) { 364 | // destroy using "explicit destructor" 365 | p->~T(); 366 | } 367 | 368 | // Boilerplate 369 | SecureMemoryManager() {} 370 | template SecureMemoryManager(const SecureMemoryManager&) {} 371 | template struct rebind { using other = SecureMemoryManager; }; 372 | }; 373 | 374 | 375 | template 376 | bool operator==(const SecureMemoryManager&, const SecureMemoryManager&) { 377 | return true; 378 | } 379 | 380 | template 381 | bool operator!=(const SecureMemoryManager&, const SecureMemoryManager&) { 382 | return false; 383 | } 384 | 385 | } //namespace Json 386 | 387 | #pragma pack(pop) 388 | 389 | #endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED 390 | 391 | //////////////end of allocator.h 392 | 393 | 394 | 395 | 396 | 397 | //////////////begin of autolink.h 398 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 399 | // Distributed under MIT license, or public domain if desired and 400 | // recognized in your jurisdiction. 401 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 402 | 403 | #ifndef JSON_AUTOLINK_H_INCLUDED 404 | #define JSON_AUTOLINK_H_INCLUDED 405 | 406 | //#include "config.h" 407 | 408 | #ifdef JSON_IN_CPPTL 409 | #include 410 | #endif 411 | 412 | #if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \ 413 | !defined(JSON_IN_CPPTL) 414 | #define CPPTL_AUTOLINK_NAME "json" 415 | #undef CPPTL_AUTOLINK_DLL 416 | #ifdef JSON_DLL 417 | #define CPPTL_AUTOLINK_DLL 418 | #endif 419 | //#include "autolink.h" 420 | #endif 421 | 422 | #endif // JSON_AUTOLINK_H_INCLUDED 423 | 424 | //////////////end of autolink.h 425 | 426 | 427 | 428 | 429 | 430 | //////////////begin of forwards.h 431 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 432 | // Distributed under MIT license, or public domain if desired and 433 | // recognized in your jurisdiction. 434 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 435 | 436 | #ifndef JSON_FORWARDS_H_INCLUDED 437 | #define JSON_FORWARDS_H_INCLUDED 438 | 439 | #if !defined(JSON_IS_AMALGAMATION) 440 | //#include "config.h" 441 | #endif // if !defined(JSON_IS_AMALGAMATION) 442 | 443 | namespace Json { 444 | 445 | // writer.h 446 | class FastWriter; 447 | class StyledWriter; 448 | 449 | // reader.h 450 | class Reader; 451 | 452 | // features.h 453 | class Features; 454 | 455 | // value.h 456 | typedef unsigned int ArrayIndex; 457 | class StaticString; 458 | class Path; 459 | class PathArgument; 460 | class Value; 461 | class ValueIteratorBase; 462 | class ValueIterator; 463 | class ValueConstIterator; 464 | 465 | } // namespace Json 466 | 467 | #endif // JSON_FORWARDS_H_INCLUDED 468 | 469 | //////////////end of forwards.h 470 | 471 | 472 | 473 | 474 | 475 | //////////////begin of features.h 476 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 477 | // Distributed under MIT license, or public domain if desired and 478 | // recognized in your jurisdiction. 479 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 480 | 481 | #ifndef CPPTL_JSON_FEATURES_H_INCLUDED 482 | #define CPPTL_JSON_FEATURES_H_INCLUDED 483 | 484 | #if !defined(JSON_IS_AMALGAMATION) 485 | //#include "forwards.h" 486 | #endif // if !defined(JSON_IS_AMALGAMATION) 487 | 488 | #pragma pack(push, 8) 489 | 490 | namespace Json { 491 | 492 | /** \brief Configuration passed to reader and writer. 493 | * This configuration object can be used to force the Reader or Writer 494 | * to behave in a standard conforming way. 495 | */ 496 | class JSON_API Features { 497 | public: 498 | /** \brief A configuration that allows all features and assumes all strings 499 | * are UTF-8. 500 | * - C & C++ comments are allowed 501 | * - Root object can be any JSON value 502 | * - Assumes Value strings are encoded in UTF-8 503 | */ 504 | static Features all(); 505 | 506 | /** \brief A configuration that is strictly compatible with the JSON 507 | * specification. 508 | * - Comments are forbidden. 509 | * - Root object must be either an array or an object value. 510 | * - Assumes Value strings are encoded in UTF-8 511 | */ 512 | static Features strictMode(); 513 | 514 | /** \brief Initialize the configuration like JsonConfig::allFeatures; 515 | */ 516 | Features(); 517 | 518 | /// \c true if comments are allowed. Default: \c true. 519 | bool allowComments_; 520 | 521 | /// \c true if root must be either an array or an object value. Default: \c 522 | /// false. 523 | bool strictRoot_; 524 | 525 | /// \c true if dropped null placeholders are allowed. Default: \c false. 526 | bool allowDroppedNullPlaceholders_; 527 | 528 | /// \c true if numeric object key are allowed. Default: \c false. 529 | bool allowNumericKeys_; 530 | }; 531 | 532 | } // namespace Json 533 | 534 | #pragma pack(pop) 535 | 536 | #endif // CPPTL_JSON_FEATURES_H_INCLUDED 537 | 538 | //////////////end of features.h 539 | 540 | 541 | 542 | 543 | 544 | //////////////begin of value.h 545 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 546 | // Distributed under MIT license, or public domain if desired and 547 | // recognized in your jurisdiction. 548 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 549 | 550 | #ifndef CPPTL_JSON_H_INCLUDED 551 | #define CPPTL_JSON_H_INCLUDED 552 | 553 | #if !defined(JSON_IS_AMALGAMATION) 554 | //#include "forwards.h" 555 | #endif // if !defined(JSON_IS_AMALGAMATION) 556 | #include 557 | #include 558 | #include 559 | 560 | #ifndef JSON_USE_CPPTL_SMALLMAP 561 | #include 562 | #else 563 | #include 564 | #endif 565 | #ifdef JSON_USE_CPPTL 566 | #include 567 | #endif 568 | 569 | //Conditional NORETURN attribute on the throw functions would: 570 | // a) suppress false positives from static code analysis 571 | // b) possibly improve optimization opportunities. 572 | #if !defined(JSONCPP_NORETURN) 573 | # if defined(_MSC_VER) 574 | # define JSONCPP_NORETURN __declspec(noreturn) 575 | # elif defined(__GNUC__) 576 | # define JSONCPP_NORETURN __attribute__ ((__noreturn__)) 577 | # else 578 | # define JSONCPP_NORETURN 579 | # endif 580 | #endif 581 | 582 | // Disable warning C4251: : needs to have dll-interface to 583 | // be used by... 584 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 585 | #pragma warning(push) 586 | #pragma warning(disable : 4251) 587 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 588 | 589 | #pragma pack(push, 8) 590 | 591 | /** \brief JSON (JavaScript Object Notation). 592 | */ 593 | namespace Json { 594 | 595 | /** Base class for all exceptions we throw. 596 | * 597 | * We use nothing but these internally. Of course, STL can throw others. 598 | */ 599 | class JSON_API Exception : public std::exception { 600 | public: 601 | Exception(JSONCPP_STRING const& msg); 602 | ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; 603 | char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; 604 | protected: 605 | JSONCPP_STRING msg_; 606 | }; 607 | 608 | /** Exceptions which the user cannot easily avoid. 609 | * 610 | * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input 611 | * 612 | * \remark derived from Json::Exception 613 | */ 614 | class JSON_API RuntimeError : public Exception { 615 | public: 616 | RuntimeError(JSONCPP_STRING const& msg); 617 | }; 618 | 619 | /** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. 620 | * 621 | * These are precondition-violations (user bugs) and internal errors (our bugs). 622 | * 623 | * \remark derived from Json::Exception 624 | */ 625 | class JSON_API LogicError : public Exception { 626 | public: 627 | LogicError(JSONCPP_STRING const& msg); 628 | }; 629 | 630 | /// used internally 631 | JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); 632 | /// used internally 633 | JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); 634 | 635 | /** \brief Type of the value held by a Value object. 636 | */ 637 | enum ValueType { 638 | nullValue = 0, ///< 'null' value 639 | intValue, ///< signed integer value 640 | uintValue, ///< unsigned integer value 641 | realValue, ///< double value 642 | stringValue, ///< UTF-8 string value 643 | booleanValue, ///< bool value 644 | arrayValue, ///< array value (ordered list) 645 | objectValue ///< object value (collection of name/value pairs). 646 | }; 647 | 648 | enum CommentPlacement { 649 | commentBefore = 0, ///< a comment placed on the line before a value 650 | commentAfterOnSameLine, ///< a comment just after a value on the same line 651 | commentAfter, ///< a comment on the line after a value (only make sense for 652 | /// root value) 653 | numberOfCommentPlacement 654 | }; 655 | 656 | //# ifdef JSON_USE_CPPTL 657 | // typedef CppTL::AnyEnumerator EnumMemberNames; 658 | // typedef CppTL::AnyEnumerator EnumValues; 659 | //# endif 660 | 661 | /** \brief Lightweight wrapper to tag static string. 662 | * 663 | * Value constructor and objectValue member assignement takes advantage of the 664 | * StaticString and avoid the cost of string duplication when storing the 665 | * string or the member name. 666 | * 667 | * Example of usage: 668 | * \code 669 | * Json::Value aValue( StaticString("some text") ); 670 | * Json::Value object; 671 | * static const StaticString code("code"); 672 | * object[code] = 1234; 673 | * \endcode 674 | */ 675 | class JSON_API StaticString { 676 | public: 677 | explicit StaticString(const char* czstring) : c_str_(czstring) {} 678 | 679 | operator const char*() const { return c_str_; } 680 | 681 | const char* c_str() const { return c_str_; } 682 | 683 | private: 684 | const char* c_str_; 685 | }; 686 | 687 | /** \brief Represents a JSON value. 688 | * 689 | * This class is a discriminated union wrapper that can represents a: 690 | * - signed integer [range: Value::minInt - Value::maxInt] 691 | * - unsigned integer (range: 0 - Value::maxUInt) 692 | * - double 693 | * - UTF-8 string 694 | * - boolean 695 | * - 'null' 696 | * - an ordered list of Value 697 | * - collection of name/value pairs (javascript object) 698 | * 699 | * The type of the held value is represented by a #ValueType and 700 | * can be obtained using type(). 701 | * 702 | * Values of an #objectValue or #arrayValue can be accessed using operator[]() 703 | * methods. 704 | * Non-const methods will automatically create the a #nullValue element 705 | * if it does not exist. 706 | * The sequence of an #arrayValue will be automatically resized and initialized 707 | * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. 708 | * 709 | * The get() methods can be used to obtain default value in the case the 710 | * required element does not exist. 711 | * 712 | * It is possible to iterate over the list of a #objectValue values using 713 | * the getMemberNames() method. 714 | * 715 | * \note #Value string-length fit in size_t, but keys must be < 2^30. 716 | * (The reason is an implementation detail.) A #CharReader will raise an 717 | * exception if a bound is exceeded to avoid security holes in your app, 718 | * but the Value API does *not* check bounds. That is the responsibility 719 | * of the caller. 720 | */ 721 | class JSON_API Value { 722 | friend class ValueIteratorBase; 723 | public: 724 | typedef std::vector Members; 725 | typedef ValueIterator iterator; 726 | typedef ValueConstIterator const_iterator; 727 | typedef Json::UInt UInt; 728 | typedef Json::Int Int; 729 | #if defined(JSON_HAS_INT64) 730 | typedef Json::UInt64 UInt64; 731 | typedef Json::Int64 Int64; 732 | #endif // defined(JSON_HAS_INT64) 733 | typedef Json::LargestInt LargestInt; 734 | typedef Json::LargestUInt LargestUInt; 735 | typedef Json::ArrayIndex ArrayIndex; 736 | 737 | static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). 738 | static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null 739 | static Value const& nullSingleton(); ///< Prefer this to null or nullRef. 740 | 741 | /// Minimum signed integer value that can be stored in a Json::Value. 742 | static const LargestInt minLargestInt; 743 | /// Maximum signed integer value that can be stored in a Json::Value. 744 | static const LargestInt maxLargestInt; 745 | /// Maximum unsigned integer value that can be stored in a Json::Value. 746 | static const LargestUInt maxLargestUInt; 747 | 748 | /// Minimum signed int value that can be stored in a Json::Value. 749 | static const Int minInt; 750 | /// Maximum signed int value that can be stored in a Json::Value. 751 | static const Int maxInt; 752 | /// Maximum unsigned int value that can be stored in a Json::Value. 753 | static const UInt maxUInt; 754 | 755 | #if defined(JSON_HAS_INT64) 756 | /// Minimum signed 64 bits int value that can be stored in a Json::Value. 757 | static const Int64 minInt64; 758 | /// Maximum signed 64 bits int value that can be stored in a Json::Value. 759 | static const Int64 maxInt64; 760 | /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. 761 | static const UInt64 maxUInt64; 762 | #endif // defined(JSON_HAS_INT64) 763 | 764 | private: 765 | #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 766 | class CZString { 767 | public: 768 | enum DuplicationPolicy { 769 | noDuplication = 0, 770 | duplicate, 771 | duplicateOnCopy 772 | }; 773 | CZString(ArrayIndex index); 774 | CZString(char const* str, unsigned length, DuplicationPolicy allocate); 775 | CZString(CZString const& other); 776 | #if JSON_HAS_RVALUE_REFERENCES 777 | CZString(CZString&& other); 778 | #endif 779 | ~CZString(); 780 | CZString& operator=(const CZString& other); 781 | 782 | #if JSON_HAS_RVALUE_REFERENCES 783 | CZString& operator=(CZString&& other); 784 | #endif 785 | 786 | bool operator<(CZString const& other) const; 787 | bool operator==(CZString const& other) const; 788 | ArrayIndex index() const; 789 | //const char* c_str() const; ///< \deprecated 790 | char const* data() const; 791 | unsigned length() const; 792 | bool isStaticString() const; 793 | 794 | private: 795 | void swap(CZString& other); 796 | 797 | struct StringStorage { 798 | unsigned policy_: 2; 799 | unsigned length_: 30; // 1GB max 800 | }; 801 | 802 | char const* cstr_; // actually, a prefixed string, unless policy is noDup 803 | union { 804 | ArrayIndex index_; 805 | StringStorage storage_; 806 | }; 807 | }; 808 | 809 | public: 810 | #ifndef JSON_USE_CPPTL_SMALLMAP 811 | typedef std::map ObjectValues; 812 | #else 813 | typedef CppTL::SmallMap ObjectValues; 814 | #endif // ifndef JSON_USE_CPPTL_SMALLMAP 815 | #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 816 | 817 | public: 818 | /** \brief Create a default Value of the given type. 819 | 820 | This is a very useful constructor. 821 | To create an empty array, pass arrayValue. 822 | To create an empty object, pass objectValue. 823 | Another Value can then be set to this one by assignment. 824 | This is useful since clear() and resize() will not alter types. 825 | 826 | Examples: 827 | \code 828 | Json::Value null_value; // null 829 | Json::Value arr_value(Json::arrayValue); // [] 830 | Json::Value obj_value(Json::objectValue); // {} 831 | \endcode 832 | */ 833 | Value(ValueType type = nullValue); 834 | Value(Int value); 835 | Value(UInt value); 836 | #if defined(JSON_HAS_INT64) 837 | Value(Int64 value); 838 | Value(UInt64 value); 839 | #endif // if defined(JSON_HAS_INT64) 840 | Value(double value); 841 | Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) 842 | Value(const char* begin, const char* end); ///< Copy all, incl zeroes. 843 | /** \brief Constructs a value from a static string. 844 | 845 | * Like other value string constructor but do not duplicate the string for 846 | * internal storage. The given string must remain alive after the call to this 847 | * constructor. 848 | * \note This works only for null-terminated strings. (We cannot change the 849 | * size of this class, so we have nowhere to store the length, 850 | * which might be computed later for various operations.) 851 | * 852 | * Example of usage: 853 | * \code 854 | * static StaticString foo("some text"); 855 | * Json::Value aValue(foo); 856 | * \endcode 857 | */ 858 | Value(const StaticString& value); 859 | Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. 860 | #ifdef JSON_USE_CPPTL 861 | Value(const CppTL::ConstString& value); 862 | #endif 863 | Value(bool value); 864 | /// Deep copy. 865 | Value(const Value& other); 866 | #if JSON_HAS_RVALUE_REFERENCES 867 | /// Move constructor 868 | Value(Value&& other); 869 | #endif 870 | ~Value(); 871 | 872 | /// Deep copy, then swap(other). 873 | /// \note Over-write existing comments. To preserve comments, use #swapPayload(). 874 | Value& operator=(Value other); 875 | 876 | /// Swap everything. 877 | void swap(Value& other); 878 | /// Swap values but leave comments and source offsets in place. 879 | void swapPayload(Value& other); 880 | 881 | /// copy everything. 882 | void copy(const Value& other); 883 | /// copy values but leave comments and source offsets in place. 884 | void copyPayload(const Value& other); 885 | 886 | ValueType type() const; 887 | 888 | /// Compare payload only, not comments etc. 889 | bool operator<(const Value& other) const; 890 | bool operator<=(const Value& other) const; 891 | bool operator>=(const Value& other) const; 892 | bool operator>(const Value& other) const; 893 | bool operator==(const Value& other) const; 894 | bool operator!=(const Value& other) const; 895 | int compare(const Value& other) const; 896 | 897 | const char* asCString() const; ///< Embedded zeroes could cause you trouble! 898 | #if JSONCPP_USING_SECURE_MEMORY 899 | unsigned getCStringLength() const; //Allows you to understand the length of the CString 900 | #endif 901 | JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. 902 | /** Get raw char* of string-value. 903 | * \return false if !string. (Seg-fault if str or end are NULL.) 904 | */ 905 | bool getString( 906 | char const** begin, char const** end) const; 907 | #ifdef JSON_USE_CPPTL 908 | CppTL::ConstString asConstString() const; 909 | #endif 910 | Int asInt() const; 911 | UInt asUInt() const; 912 | #if defined(JSON_HAS_INT64) 913 | Int64 asInt64() const; 914 | UInt64 asUInt64() const; 915 | #endif // if defined(JSON_HAS_INT64) 916 | LargestInt asLargestInt() const; 917 | LargestUInt asLargestUInt() const; 918 | float asFloat() const; 919 | double asDouble() const; 920 | bool asBool() const; 921 | 922 | bool isNull() const; 923 | bool isBool() const; 924 | bool isInt() const; 925 | bool isInt64() const; 926 | bool isUInt() const; 927 | bool isUInt64() const; 928 | bool isIntegral() const; 929 | bool isDouble() const; 930 | bool isNumeric() const; 931 | bool isString() const; 932 | bool isArray() const; 933 | bool isObject() const; 934 | 935 | bool isConvertibleTo(ValueType other) const; 936 | 937 | /// Number of values in array or object 938 | ArrayIndex size() const; 939 | 940 | /// \brief Return true if empty array, empty object, or null; 941 | /// otherwise, false. 942 | bool empty() const; 943 | 944 | /// Return isNull() 945 | bool operator!() const; 946 | 947 | /// Remove all object members and array elements. 948 | /// \pre type() is arrayValue, objectValue, or nullValue 949 | /// \post type() is unchanged 950 | void clear(); 951 | 952 | /// Resize the array to size elements. 953 | /// New elements are initialized to null. 954 | /// May only be called on nullValue or arrayValue. 955 | /// \pre type() is arrayValue or nullValue 956 | /// \post type() is arrayValue 957 | void resize(ArrayIndex size); 958 | 959 | /// Access an array element (zero based index ). 960 | /// If the array contains less than index element, then null value are 961 | /// inserted 962 | /// in the array so that its size is index+1. 963 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 964 | /// this from the operator[] which takes a string.) 965 | Value& operator[](ArrayIndex index); 966 | 967 | /// Access an array element (zero based index ). 968 | /// If the array contains less than index element, then null value are 969 | /// inserted 970 | /// in the array so that its size is index+1. 971 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 972 | /// this from the operator[] which takes a string.) 973 | Value& operator[](int index); 974 | 975 | /// Access an array element (zero based index ) 976 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 977 | /// this from the operator[] which takes a string.) 978 | const Value& operator[](ArrayIndex index) const; 979 | 980 | /// Access an array element (zero based index ) 981 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 982 | /// this from the operator[] which takes a string.) 983 | const Value& operator[](int index) const; 984 | 985 | /// If the array contains at least index+1 elements, returns the element 986 | /// value, 987 | /// otherwise returns defaultValue. 988 | Value get(ArrayIndex index, const Value& defaultValue) const; 989 | /// Return true if index < size(). 990 | bool isValidIndex(ArrayIndex index) const; 991 | /// \brief Append value to array at the end. 992 | /// 993 | /// Equivalent to jsonvalue[jsonvalue.size()] = value; 994 | Value& append(const Value& value); 995 | 996 | #if JSON_HAS_RVALUE_REFERENCES 997 | Value& append(Value&& value); 998 | #endif 999 | 1000 | /// Access an object value by name, create a null member if it does not exist. 1001 | /// \note Because of our implementation, keys are limited to 2^30 -1 chars. 1002 | /// Exceeding that will cause an exception. 1003 | Value& operator[](const char* key); 1004 | /// Access an object value by name, returns null if there is no member with 1005 | /// that name. 1006 | const Value& operator[](const char* key) const; 1007 | /// Access an object value by name, create a null member if it does not exist. 1008 | /// \param key may contain embedded nulls. 1009 | Value& operator[](const JSONCPP_STRING& key); 1010 | /// Access an object value by name, returns null if there is no member with 1011 | /// that name. 1012 | /// \param key may contain embedded nulls. 1013 | const Value& operator[](const JSONCPP_STRING& key) const; 1014 | /** \brief Access an object value by name, create a null member if it does not 1015 | exist. 1016 | 1017 | * If the object has no entry for that name, then the member name used to store 1018 | * the new entry is not duplicated. 1019 | * Example of use: 1020 | * \code 1021 | * Json::Value object; 1022 | * static const StaticString code("code"); 1023 | * object[code] = 1234; 1024 | * \endcode 1025 | */ 1026 | Value& operator[](const StaticString& key); 1027 | #ifdef JSON_USE_CPPTL 1028 | /// Access an object value by name, create a null member if it does not exist. 1029 | Value& operator[](const CppTL::ConstString& key); 1030 | /// Access an object value by name, returns null if there is no member with 1031 | /// that name. 1032 | const Value& operator[](const CppTL::ConstString& key) const; 1033 | #endif 1034 | /// Return the member named key if it exist, defaultValue otherwise. 1035 | /// \note deep copy 1036 | Value get(const char* key, const Value& defaultValue) const; 1037 | /// Return the member named key if it exist, defaultValue otherwise. 1038 | /// \note deep copy 1039 | /// \note key may contain embedded nulls. 1040 | Value get(const char* begin, const char* end, const Value& defaultValue) const; 1041 | /// Return the member named key if it exist, defaultValue otherwise. 1042 | /// \note deep copy 1043 | /// \param key may contain embedded nulls. 1044 | Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; 1045 | #ifdef JSON_USE_CPPTL 1046 | /// Return the member named key if it exist, defaultValue otherwise. 1047 | /// \note deep copy 1048 | Value get(const CppTL::ConstString& key, const Value& defaultValue) const; 1049 | #endif 1050 | /// Most general and efficient version of isMember()const, get()const, 1051 | /// and operator[]const 1052 | /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 1053 | Value const* find(char const* begin, char const* end) const; 1054 | /// Most general and efficient version of object-mutators. 1055 | /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 1056 | /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. 1057 | Value const* demand(char const* begin, char const* end); 1058 | /// \brief Remove and return the named member. 1059 | /// 1060 | /// Do nothing if it did not exist. 1061 | /// \return the removed Value, or null. 1062 | /// \pre type() is objectValue or nullValue 1063 | /// \post type() is unchanged 1064 | /// \deprecated 1065 | JSONCPP_DEPRECATED("") 1066 | Value removeMember(const char* key); 1067 | /// Same as removeMember(const char*) 1068 | /// \param key may contain embedded nulls. 1069 | /// \deprecated 1070 | JSONCPP_DEPRECATED("") 1071 | Value removeMember(const JSONCPP_STRING& key); 1072 | /// Same as removeMember(const char* begin, const char* end, Value* removed), 1073 | /// but 'key' is null-terminated. 1074 | bool removeMember(const char* key, Value* removed); 1075 | /** \brief Remove the named map member. 1076 | 1077 | Update 'removed' iff removed. 1078 | \param key may contain embedded nulls. 1079 | \return true iff removed (no exceptions) 1080 | */ 1081 | bool removeMember(JSONCPP_STRING const& key, Value* removed); 1082 | /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) 1083 | bool removeMember(const char* begin, const char* end, Value* removed); 1084 | /** \brief Remove the indexed array element. 1085 | 1086 | O(n) expensive operations. 1087 | Update 'removed' iff removed. 1088 | \return true iff removed (no exceptions) 1089 | */ 1090 | bool removeIndex(ArrayIndex i, Value* removed); 1091 | 1092 | /// Return true if the object has a member named key. 1093 | /// \note 'key' must be null-terminated. 1094 | bool isMember(const char* key) const; 1095 | /// Return true if the object has a member named key. 1096 | /// \param key may contain embedded nulls. 1097 | bool isMember(const JSONCPP_STRING& key) const; 1098 | /// Same as isMember(JSONCPP_STRING const& key)const 1099 | bool isMember(const char* begin, const char* end) const; 1100 | #ifdef JSON_USE_CPPTL 1101 | /// Return true if the object has a member named key. 1102 | bool isMember(const CppTL::ConstString& key) const; 1103 | #endif 1104 | 1105 | /// \brief Return a list of the member names. 1106 | /// 1107 | /// If null, return an empty list. 1108 | /// \pre type() is objectValue or nullValue 1109 | /// \post if type() was nullValue, it remains nullValue 1110 | Members getMemberNames() const; 1111 | 1112 | //# ifdef JSON_USE_CPPTL 1113 | // EnumMemberNames enumMemberNames() const; 1114 | // EnumValues enumValues() const; 1115 | //# endif 1116 | 1117 | /// \deprecated Always pass len. 1118 | JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") 1119 | void setComment(const char* comment, CommentPlacement placement); 1120 | /// Comments must be //... or /* ... */ 1121 | void setComment(const char* comment, size_t len, CommentPlacement placement); 1122 | /// Comments must be //... or /* ... */ 1123 | void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); 1124 | bool hasComment(CommentPlacement placement) const; 1125 | /// Include delimiters and embedded newlines. 1126 | JSONCPP_STRING getComment(CommentPlacement placement) const; 1127 | 1128 | JSONCPP_STRING toStyledString() const; 1129 | 1130 | const_iterator begin() const; 1131 | const_iterator end() const; 1132 | 1133 | iterator begin(); 1134 | iterator end(); 1135 | 1136 | // Accessors for the [start, limit) range of bytes within the JSON text from 1137 | // which this value was parsed, if any. 1138 | void setOffsetStart(ptrdiff_t start); 1139 | void setOffsetLimit(ptrdiff_t limit); 1140 | ptrdiff_t getOffsetStart() const; 1141 | ptrdiff_t getOffsetLimit() const; 1142 | 1143 | private: 1144 | void initBasic(ValueType type, bool allocated = false); 1145 | 1146 | Value& resolveReference(const char* key); 1147 | Value& resolveReference(const char* key, const char* end); 1148 | 1149 | struct CommentInfo { 1150 | CommentInfo(); 1151 | ~CommentInfo(); 1152 | 1153 | void setComment(const char* text, size_t len); 1154 | 1155 | char* comment_; 1156 | }; 1157 | 1158 | // struct MemberNamesTransform 1159 | //{ 1160 | // typedef const char *result_type; 1161 | // const char *operator()( const CZString &name ) const 1162 | // { 1163 | // return name.c_str(); 1164 | // } 1165 | //}; 1166 | 1167 | union ValueHolder { 1168 | LargestInt int_; 1169 | LargestUInt uint_; 1170 | double real_; 1171 | bool bool_; 1172 | char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ 1173 | ObjectValues* map_; 1174 | } value_; 1175 | ValueType type_ : 8; 1176 | unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. 1177 | // If not allocated_, string_ must be null-terminated. 1178 | CommentInfo* comments_; 1179 | 1180 | // [start, limit) byte offsets in the source JSON text from which this Value 1181 | // was extracted. 1182 | ptrdiff_t start_; 1183 | ptrdiff_t limit_; 1184 | }; 1185 | 1186 | /** \brief Experimental and untested: represents an element of the "path" to 1187 | * access a node. 1188 | */ 1189 | class JSON_API PathArgument { 1190 | public: 1191 | friend class Path; 1192 | 1193 | PathArgument(); 1194 | PathArgument(ArrayIndex index); 1195 | PathArgument(const char* key); 1196 | PathArgument(const JSONCPP_STRING& key); 1197 | 1198 | private: 1199 | enum Kind { 1200 | kindNone = 0, 1201 | kindIndex, 1202 | kindKey 1203 | }; 1204 | JSONCPP_STRING key_; 1205 | ArrayIndex index_; 1206 | Kind kind_; 1207 | }; 1208 | 1209 | /** \brief Experimental and untested: represents a "path" to access a node. 1210 | * 1211 | * Syntax: 1212 | * - "." => root node 1213 | * - ".[n]" => elements at index 'n' of root node (an array value) 1214 | * - ".name" => member named 'name' of root node (an object value) 1215 | * - ".name1.name2.name3" 1216 | * - ".[0][1][2].name1[3]" 1217 | * - ".%" => member name is provided as parameter 1218 | * - ".[%]" => index is provied as parameter 1219 | */ 1220 | class JSON_API Path { 1221 | public: 1222 | Path(const JSONCPP_STRING& path, 1223 | const PathArgument& a1 = PathArgument(), 1224 | const PathArgument& a2 = PathArgument(), 1225 | const PathArgument& a3 = PathArgument(), 1226 | const PathArgument& a4 = PathArgument(), 1227 | const PathArgument& a5 = PathArgument()); 1228 | 1229 | const Value& resolve(const Value& root) const; 1230 | Value resolve(const Value& root, const Value& defaultValue) const; 1231 | /// Creates the "path" to access the specified node and returns a reference on 1232 | /// the node. 1233 | Value& make(Value& root) const; 1234 | 1235 | private: 1236 | typedef std::vector InArgs; 1237 | typedef std::vector Args; 1238 | 1239 | void makePath(const JSONCPP_STRING& path, const InArgs& in); 1240 | void addPathInArg(const JSONCPP_STRING& path, 1241 | const InArgs& in, 1242 | InArgs::const_iterator& itInArg, 1243 | PathArgument::Kind kind); 1244 | void invalidPath(const JSONCPP_STRING& path, int location); 1245 | 1246 | Args args_; 1247 | }; 1248 | 1249 | /** \brief base class for Value iterators. 1250 | * 1251 | */ 1252 | class JSON_API ValueIteratorBase { 1253 | public: 1254 | typedef std::bidirectional_iterator_tag iterator_category; 1255 | typedef unsigned int size_t; 1256 | typedef int difference_type; 1257 | typedef ValueIteratorBase SelfType; 1258 | 1259 | bool operator==(const SelfType& other) const { return isEqual(other); } 1260 | 1261 | bool operator!=(const SelfType& other) const { return !isEqual(other); } 1262 | 1263 | difference_type operator-(const SelfType& other) const { 1264 | return other.computeDistance(*this); 1265 | } 1266 | 1267 | /// Return either the index or the member name of the referenced value as a 1268 | /// Value. 1269 | Value key() const; 1270 | 1271 | /// Return the index of the referenced Value, or -1 if it is not an arrayValue. 1272 | UInt index() const; 1273 | 1274 | /// Return the member name of the referenced Value, or "" if it is not an 1275 | /// objectValue. 1276 | /// \note Avoid `c_str()` on result, as embedded zeroes are possible. 1277 | JSONCPP_STRING name() const; 1278 | 1279 | /// Return the member name of the referenced Value. "" if it is not an 1280 | /// objectValue. 1281 | /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. 1282 | JSONCPP_DEPRECATED("Use `key = name();` instead.") 1283 | char const* memberName() const; 1284 | /// Return the member name of the referenced Value, or NULL if it is not an 1285 | /// objectValue. 1286 | /// \note Better version than memberName(). Allows embedded nulls. 1287 | char const* memberName(char const** end) const; 1288 | 1289 | protected: 1290 | Value& deref() const; 1291 | 1292 | void increment(); 1293 | 1294 | void decrement(); 1295 | 1296 | difference_type computeDistance(const SelfType& other) const; 1297 | 1298 | bool isEqual(const SelfType& other) const; 1299 | 1300 | void copy(const SelfType& other); 1301 | 1302 | private: 1303 | Value::ObjectValues::iterator current_; 1304 | // Indicates that iterator is for a null value. 1305 | bool isNull_; 1306 | 1307 | public: 1308 | // For some reason, BORLAND needs these at the end, rather 1309 | // than earlier. No idea why. 1310 | ValueIteratorBase(); 1311 | explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); 1312 | }; 1313 | 1314 | /** \brief const iterator for object and array value. 1315 | * 1316 | */ 1317 | class JSON_API ValueConstIterator : public ValueIteratorBase { 1318 | friend class Value; 1319 | 1320 | public: 1321 | typedef const Value value_type; 1322 | //typedef unsigned int size_t; 1323 | //typedef int difference_type; 1324 | typedef const Value& reference; 1325 | typedef const Value* pointer; 1326 | typedef ValueConstIterator SelfType; 1327 | 1328 | ValueConstIterator(); 1329 | ValueConstIterator(ValueIterator const& other); 1330 | 1331 | private: 1332 | /*! \internal Use by Value to create an iterator. 1333 | */ 1334 | explicit ValueConstIterator(const Value::ObjectValues::iterator& current); 1335 | public: 1336 | SelfType& operator=(const ValueIteratorBase& other); 1337 | 1338 | SelfType operator++(int) { 1339 | SelfType temp(*this); 1340 | ++*this; 1341 | return temp; 1342 | } 1343 | 1344 | SelfType operator--(int) { 1345 | SelfType temp(*this); 1346 | --*this; 1347 | return temp; 1348 | } 1349 | 1350 | SelfType& operator--() { 1351 | decrement(); 1352 | return *this; 1353 | } 1354 | 1355 | SelfType& operator++() { 1356 | increment(); 1357 | return *this; 1358 | } 1359 | 1360 | reference operator*() const { return deref(); } 1361 | 1362 | pointer operator->() const { return &deref(); } 1363 | }; 1364 | 1365 | /** \brief Iterator for object and array value. 1366 | */ 1367 | class JSON_API ValueIterator : public ValueIteratorBase { 1368 | friend class Value; 1369 | 1370 | public: 1371 | typedef Value value_type; 1372 | typedef unsigned int size_t; 1373 | typedef int difference_type; 1374 | typedef Value& reference; 1375 | typedef Value* pointer; 1376 | typedef ValueIterator SelfType; 1377 | 1378 | ValueIterator(); 1379 | explicit ValueIterator(const ValueConstIterator& other); 1380 | ValueIterator(const ValueIterator& other); 1381 | 1382 | private: 1383 | /*! \internal Use by Value to create an iterator. 1384 | */ 1385 | explicit ValueIterator(const Value::ObjectValues::iterator& current); 1386 | public: 1387 | SelfType& operator=(const SelfType& other); 1388 | 1389 | SelfType operator++(int) { 1390 | SelfType temp(*this); 1391 | ++*this; 1392 | return temp; 1393 | } 1394 | 1395 | SelfType operator--(int) { 1396 | SelfType temp(*this); 1397 | --*this; 1398 | return temp; 1399 | } 1400 | 1401 | SelfType& operator--() { 1402 | decrement(); 1403 | return *this; 1404 | } 1405 | 1406 | SelfType& operator++() { 1407 | increment(); 1408 | return *this; 1409 | } 1410 | 1411 | reference operator*() const { return deref(); } 1412 | 1413 | pointer operator->() const { return &deref(); } 1414 | }; 1415 | 1416 | } // namespace Json 1417 | 1418 | 1419 | namespace std { 1420 | /// Specialize std::swap() for Json::Value. 1421 | template<> 1422 | inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } 1423 | } 1424 | 1425 | #pragma pack(pop) 1426 | 1427 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1428 | #pragma warning(pop) 1429 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1430 | 1431 | #endif // CPPTL_JSON_H_INCLUDED 1432 | 1433 | //////////////end of value.h 1434 | 1435 | 1436 | 1437 | 1438 | 1439 | //////////////begin of reader.h 1440 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 1441 | // Distributed under MIT license, or public domain if desired and 1442 | // recognized in your jurisdiction. 1443 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 1444 | 1445 | #ifndef CPPTL_JSON_READER_H_INCLUDED 1446 | #define CPPTL_JSON_READER_H_INCLUDED 1447 | 1448 | #if !defined(JSON_IS_AMALGAMATION) 1449 | //#include "features.h" 1450 | //#include "value.h" 1451 | #endif // if !defined(JSON_IS_AMALGAMATION) 1452 | #include 1453 | #include 1454 | #include 1455 | #include 1456 | #include 1457 | 1458 | // Disable warning C4251: : needs to have dll-interface to 1459 | // be used by... 1460 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1461 | #pragma warning(push) 1462 | #pragma warning(disable : 4251) 1463 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1464 | 1465 | #pragma pack(push, 8) 1466 | 1467 | namespace Json { 1468 | 1469 | /** \brief Unserialize a JSON document into a 1470 | *Value. 1471 | * 1472 | * \deprecated Use CharReader and CharReaderBuilder. 1473 | */ 1474 | class JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") JSON_API Reader { 1475 | public: 1476 | typedef char Char; 1477 | typedef const Char* Location; 1478 | 1479 | /** \brief An error tagged with where in the JSON text it was encountered. 1480 | * 1481 | * The offsets give the [start, limit) range of bytes within the text. Note 1482 | * that this is bytes, not codepoints. 1483 | * 1484 | */ 1485 | struct StructuredError { 1486 | ptrdiff_t offset_start; 1487 | ptrdiff_t offset_limit; 1488 | JSONCPP_STRING message; 1489 | }; 1490 | 1491 | /** \brief Constructs a Reader allowing all features 1492 | * for parsing. 1493 | */ 1494 | Reader(); 1495 | 1496 | /** \brief Constructs a Reader allowing the specified feature set 1497 | * for parsing. 1498 | */ 1499 | Reader(const Features& features); 1500 | 1501 | /** \brief Read a Value from a JSON 1502 | * document. 1503 | * \param document UTF-8 encoded string containing the document to read. 1504 | * \param root [out] Contains the root value of the document if it was 1505 | * successfully parsed. 1506 | * \param collectComments \c true to collect comment and allow writing them 1507 | * back during 1508 | * serialization, \c false to discard comments. 1509 | * This parameter is ignored if 1510 | * Features::allowComments_ 1511 | * is \c false. 1512 | * \return \c true if the document was successfully parsed, \c false if an 1513 | * error occurred. 1514 | */ 1515 | bool 1516 | parse(const std::string& document, Value& root, bool collectComments = true); 1517 | 1518 | /** \brief Read a Value from a JSON 1519 | document. 1520 | * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the 1521 | document to read. 1522 | * \param endDoc Pointer on the end of the UTF-8 encoded string of the 1523 | document to read. 1524 | * Must be >= beginDoc. 1525 | * \param root [out] Contains the root value of the document if it was 1526 | * successfully parsed. 1527 | * \param collectComments \c true to collect comment and allow writing them 1528 | back during 1529 | * serialization, \c false to discard comments. 1530 | * This parameter is ignored if 1531 | Features::allowComments_ 1532 | * is \c false. 1533 | * \return \c true if the document was successfully parsed, \c false if an 1534 | error occurred. 1535 | */ 1536 | bool parse(const char* beginDoc, 1537 | const char* endDoc, 1538 | Value& root, 1539 | bool collectComments = true); 1540 | 1541 | /// \brief Parse from input stream. 1542 | /// \see Json::operator>>(std::istream&, Json::Value&). 1543 | bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); 1544 | 1545 | /** \brief Returns a user friendly string that list errors in the parsed 1546 | * document. 1547 | * \return Formatted error message with the list of errors with their location 1548 | * in 1549 | * the parsed document. An empty string is returned if no error 1550 | * occurred 1551 | * during parsing. 1552 | * \deprecated Use getFormattedErrorMessages() instead (typo fix). 1553 | */ 1554 | JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") 1555 | JSONCPP_STRING getFormatedErrorMessages() const; 1556 | 1557 | /** \brief Returns a user friendly string that list errors in the parsed 1558 | * document. 1559 | * \return Formatted error message with the list of errors with their location 1560 | * in 1561 | * the parsed document. An empty string is returned if no error 1562 | * occurred 1563 | * during parsing. 1564 | */ 1565 | JSONCPP_STRING getFormattedErrorMessages() const; 1566 | 1567 | /** \brief Returns a vector of structured erros encounted while parsing. 1568 | * \return A (possibly empty) vector of StructuredError objects. Currently 1569 | * only one error can be returned, but the caller should tolerate 1570 | * multiple 1571 | * errors. This can occur if the parser recovers from a non-fatal 1572 | * parse error and then encounters additional errors. 1573 | */ 1574 | std::vector getStructuredErrors() const; 1575 | 1576 | /** \brief Add a semantic error message. 1577 | * \param value JSON Value location associated with the error 1578 | * \param message The error message. 1579 | * \return \c true if the error was successfully added, \c false if the 1580 | * Value offset exceeds the document size. 1581 | */ 1582 | bool pushError(const Value& value, const JSONCPP_STRING& message); 1583 | 1584 | /** \brief Add a semantic error message with extra context. 1585 | * \param value JSON Value location associated with the error 1586 | * \param message The error message. 1587 | * \param extra Additional JSON Value location to contextualize the error 1588 | * \return \c true if the error was successfully added, \c false if either 1589 | * Value offset exceeds the document size. 1590 | */ 1591 | bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); 1592 | 1593 | /** \brief Return whether there are any errors. 1594 | * \return \c true if there are no errors to report \c false if 1595 | * errors have occurred. 1596 | */ 1597 | bool good() const; 1598 | 1599 | private: 1600 | enum TokenType { 1601 | tokenEndOfStream = 0, 1602 | tokenObjectBegin, 1603 | tokenObjectEnd, 1604 | tokenArrayBegin, 1605 | tokenArrayEnd, 1606 | tokenString, 1607 | tokenNumber, 1608 | tokenTrue, 1609 | tokenFalse, 1610 | tokenNull, 1611 | tokenArraySeparator, 1612 | tokenMemberSeparator, 1613 | tokenComment, 1614 | tokenError 1615 | }; 1616 | 1617 | class Token { 1618 | public: 1619 | TokenType type_; 1620 | Location start_; 1621 | Location end_; 1622 | }; 1623 | 1624 | class ErrorInfo { 1625 | public: 1626 | Token token_; 1627 | JSONCPP_STRING message_; 1628 | Location extra_; 1629 | }; 1630 | 1631 | typedef std::deque Errors; 1632 | 1633 | bool readToken(Token& token); 1634 | void skipSpaces(); 1635 | bool match(Location pattern, int patternLength); 1636 | bool readComment(); 1637 | bool readCStyleComment(); 1638 | bool readCppStyleComment(); 1639 | bool readString(); 1640 | void readNumber(); 1641 | bool readValue(); 1642 | bool readObject(Token& token); 1643 | bool readArray(Token& token); 1644 | bool decodeNumber(Token& token); 1645 | bool decodeNumber(Token& token, Value& decoded); 1646 | bool decodeString(Token& token); 1647 | bool decodeString(Token& token, JSONCPP_STRING& decoded); 1648 | bool decodeDouble(Token& token); 1649 | bool decodeDouble(Token& token, Value& decoded); 1650 | bool decodeUnicodeCodePoint(Token& token, 1651 | Location& current, 1652 | Location end, 1653 | unsigned int& unicode); 1654 | bool decodeUnicodeEscapeSequence(Token& token, 1655 | Location& current, 1656 | Location end, 1657 | unsigned int& unicode); 1658 | bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); 1659 | bool recoverFromError(TokenType skipUntilToken); 1660 | bool addErrorAndRecover(const JSONCPP_STRING& message, 1661 | Token& token, 1662 | TokenType skipUntilToken); 1663 | void skipUntilSpace(); 1664 | Value& currentValue(); 1665 | Char getNextChar(); 1666 | void 1667 | getLocationLineAndColumn(Location location, int& line, int& column) const; 1668 | JSONCPP_STRING getLocationLineAndColumn(Location location) const; 1669 | void addComment(Location begin, Location end, CommentPlacement placement); 1670 | void skipCommentTokens(Token& token); 1671 | 1672 | static bool containsNewLine(Location begin, Location end); 1673 | static JSONCPP_STRING normalizeEOL(Location begin, Location end); 1674 | 1675 | typedef std::stack Nodes; 1676 | Nodes nodes_; 1677 | Errors errors_; 1678 | JSONCPP_STRING document_; 1679 | Location begin_; 1680 | Location end_; 1681 | Location current_; 1682 | Location lastValueEnd_; 1683 | Value* lastValue_; 1684 | JSONCPP_STRING commentsBefore_; 1685 | Features features_; 1686 | bool collectComments_; 1687 | }; // Reader 1688 | 1689 | /** Interface for reading JSON from a char array. 1690 | */ 1691 | class JSON_API CharReader { 1692 | public: 1693 | virtual ~CharReader() {} 1694 | /** \brief Read a Value from a JSON 1695 | document. 1696 | * The document must be a UTF-8 encoded string containing the document to read. 1697 | * 1698 | * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the 1699 | document to read. 1700 | * \param endDoc Pointer on the end of the UTF-8 encoded string of the 1701 | document to read. 1702 | * Must be >= beginDoc. 1703 | * \param root [out] Contains the root value of the document if it was 1704 | * successfully parsed. 1705 | * \param errs [out] Formatted error messages (if not NULL) 1706 | * a user friendly string that lists errors in the parsed 1707 | * document. 1708 | * \return \c true if the document was successfully parsed, \c false if an 1709 | error occurred. 1710 | */ 1711 | virtual bool parse( 1712 | char const* beginDoc, char const* endDoc, 1713 | Value* root, JSONCPP_STRING* errs) = 0; 1714 | 1715 | class JSON_API Factory { 1716 | public: 1717 | virtual ~Factory() {} 1718 | /** \brief Allocate a CharReader via operator new(). 1719 | * \throw std::exception if something goes wrong (e.g. invalid settings) 1720 | */ 1721 | virtual CharReader* newCharReader() const = 0; 1722 | }; // Factory 1723 | }; // CharReader 1724 | 1725 | /** \brief Build a CharReader implementation. 1726 | 1727 | Usage: 1728 | \code 1729 | using namespace Json; 1730 | CharReaderBuilder builder; 1731 | builder["collectComments"] = false; 1732 | Value value; 1733 | JSONCPP_STRING errs; 1734 | bool ok = parseFromStream(builder, std::cin, &value, &errs); 1735 | \endcode 1736 | */ 1737 | class JSON_API CharReaderBuilder : public CharReader::Factory { 1738 | public: 1739 | // Note: We use a Json::Value so that we can add data-members to this class 1740 | // without a major version bump. 1741 | /** Configuration of this builder. 1742 | These are case-sensitive. 1743 | Available settings (case-sensitive): 1744 | - `"collectComments": false or true` 1745 | - true to collect comment and allow writing them 1746 | back during serialization, false to discard comments. 1747 | This parameter is ignored if allowComments is false. 1748 | - `"allowComments": false or true` 1749 | - true if comments are allowed. 1750 | - `"strictRoot": false or true` 1751 | - true if root must be either an array or an object value 1752 | - `"allowDroppedNullPlaceholders": false or true` 1753 | - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) 1754 | - `"allowNumericKeys": false or true` 1755 | - true if numeric object keys are allowed. 1756 | - `"allowSingleQuotes": false or true` 1757 | - true if '' are allowed for strings (both keys and values) 1758 | - `"stackLimit": integer` 1759 | - Exceeding stackLimit (recursive depth of `readValue()`) will 1760 | cause an exception. 1761 | - This is a security issue (seg-faults caused by deeply nested JSON), 1762 | so the default is low. 1763 | - `"failIfExtra": false or true` 1764 | - If true, `parse()` returns false when extra non-whitespace trails 1765 | the JSON value in the input string. 1766 | - `"rejectDupKeys": false or true` 1767 | - If true, `parse()` returns false when a key is duplicated within an object. 1768 | - `"allowSpecialFloats": false or true` 1769 | - If true, special float values (NaNs and infinities) are allowed 1770 | and their values are lossfree restorable. 1771 | 1772 | You can examine 'settings_` yourself 1773 | to see the defaults. You can also write and read them just like any 1774 | JSON Value. 1775 | \sa setDefaults() 1776 | */ 1777 | Json::Value settings_; 1778 | 1779 | CharReaderBuilder(); 1780 | ~CharReaderBuilder() JSONCPP_OVERRIDE; 1781 | 1782 | CharReader* newCharReader() const JSONCPP_OVERRIDE; 1783 | 1784 | /** \return true if 'settings' are legal and consistent; 1785 | * otherwise, indicate bad settings via 'invalid'. 1786 | */ 1787 | bool validate(Json::Value* invalid) const; 1788 | 1789 | /** A simple way to update a specific setting. 1790 | */ 1791 | Value& operator[](JSONCPP_STRING key); 1792 | 1793 | /** Called by ctor, but you can use this to reset settings_. 1794 | * \pre 'settings' != NULL (but Json::null is fine) 1795 | * \remark Defaults: 1796 | * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults 1797 | */ 1798 | static void setDefaults(Json::Value* settings); 1799 | /** Same as old Features::strictMode(). 1800 | * \pre 'settings' != NULL (but Json::null is fine) 1801 | * \remark Defaults: 1802 | * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode 1803 | */ 1804 | static void strictMode(Json::Value* settings); 1805 | }; 1806 | 1807 | /** Consume entire stream and use its begin/end. 1808 | * Someday we might have a real StreamReader, but for now this 1809 | * is convenient. 1810 | */ 1811 | bool JSON_API parseFromStream( 1812 | CharReader::Factory const&, 1813 | JSONCPP_ISTREAM&, 1814 | Value* root, std::string* errs); 1815 | 1816 | /** \brief Read from 'sin' into 'root'. 1817 | 1818 | Always keep comments from the input JSON. 1819 | 1820 | This can be used to read a file into a particular sub-object. 1821 | For example: 1822 | \code 1823 | Json::Value root; 1824 | cin >> root["dir"]["file"]; 1825 | cout << root; 1826 | \endcode 1827 | Result: 1828 | \verbatim 1829 | { 1830 | "dir": { 1831 | "file": { 1832 | // The input stream JSON would be nested here. 1833 | } 1834 | } 1835 | } 1836 | \endverbatim 1837 | \throw std::exception on parse error. 1838 | \see Json::operator<<() 1839 | */ 1840 | JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); 1841 | 1842 | } // namespace Json 1843 | 1844 | #pragma pack(pop) 1845 | 1846 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1847 | #pragma warning(pop) 1848 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1849 | 1850 | #endif // CPPTL_JSON_READER_H_INCLUDED 1851 | 1852 | //////////////end of reader.h 1853 | 1854 | 1855 | 1856 | 1857 | 1858 | //////////////begin of writer.h 1859 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 1860 | // Distributed under MIT license, or public domain if desired and 1861 | // recognized in your jurisdiction. 1862 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 1863 | 1864 | #ifndef JSON_WRITER_H_INCLUDED 1865 | #define JSON_WRITER_H_INCLUDED 1866 | 1867 | #if !defined(JSON_IS_AMALGAMATION) 1868 | //#include "value.h" 1869 | #endif // if !defined(JSON_IS_AMALGAMATION) 1870 | #include 1871 | #include 1872 | #include 1873 | 1874 | // Disable warning C4251: : needs to have dll-interface to 1875 | // be used by... 1876 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1877 | #pragma warning(push) 1878 | #pragma warning(disable : 4251) 1879 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1880 | 1881 | #pragma pack(push, 8) 1882 | 1883 | namespace Json { 1884 | 1885 | class Value; 1886 | 1887 | /** 1888 | 1889 | Usage: 1890 | \code 1891 | using namespace Json; 1892 | void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { 1893 | std::unique_ptr const writer( 1894 | factory.newStreamWriter()); 1895 | writer->write(value, &std::cout); 1896 | std::cout << std::endl; // add lf and flush 1897 | } 1898 | \endcode 1899 | */ 1900 | class JSON_API StreamWriter { 1901 | protected: 1902 | JSONCPP_OSTREAM* sout_; // not owned; will not delete 1903 | public: 1904 | StreamWriter(); 1905 | virtual ~StreamWriter(); 1906 | /** Write Value into document as configured in sub-class. 1907 | Do not take ownership of sout, but maintain a reference during function. 1908 | \pre sout != NULL 1909 | \return zero on success (For now, we always return zero, so check the stream instead.) 1910 | \throw std::exception possibly, depending on configuration 1911 | */ 1912 | virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; 1913 | 1914 | /** \brief A simple abstract factory. 1915 | */ 1916 | class JSON_API Factory { 1917 | public: 1918 | virtual ~Factory(); 1919 | /** \brief Allocate a CharReader via operator new(). 1920 | * \throw std::exception if something goes wrong (e.g. invalid settings) 1921 | */ 1922 | virtual StreamWriter* newStreamWriter() const = 0; 1923 | }; // Factory 1924 | }; // StreamWriter 1925 | 1926 | /** \brief Write into stringstream, then return string, for convenience. 1927 | * A StreamWriter will be created from the factory, used, and then deleted. 1928 | */ 1929 | JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); 1930 | 1931 | 1932 | /** \brief Build a StreamWriter implementation. 1933 | 1934 | Usage: 1935 | \code 1936 | using namespace Json; 1937 | Value value = ...; 1938 | StreamWriterBuilder builder; 1939 | builder["commentStyle"] = "None"; 1940 | builder["indentation"] = " "; // or whatever you like 1941 | std::unique_ptr writer( 1942 | builder.newStreamWriter()); 1943 | writer->write(value, &std::cout); 1944 | std::cout << std::endl; // add lf and flush 1945 | \endcode 1946 | */ 1947 | class JSON_API StreamWriterBuilder : public StreamWriter::Factory { 1948 | public: 1949 | // Note: We use a Json::Value so that we can add data-members to this class 1950 | // without a major version bump. 1951 | /** Configuration of this builder. 1952 | Available settings (case-sensitive): 1953 | - "commentStyle": "None" or "All" 1954 | - "indentation": "" 1955 | - "enableYAMLCompatibility": false or true 1956 | - slightly change the whitespace around colons 1957 | - "dropNullPlaceholders": false or true 1958 | - Drop the "null" string from the writer's output for nullValues. 1959 | Strictly speaking, this is not valid JSON. But when the output is being 1960 | fed to a browser's Javascript, it makes for smaller output and the 1961 | browser can handle the output just fine. 1962 | - "useSpecialFloats": false or true 1963 | - If true, outputs non-finite floating point values in the following way: 1964 | NaN values as "NaN", positive infinity as "Infinity", and negative infinity 1965 | as "-Infinity". 1966 | 1967 | You can examine 'settings_` yourself 1968 | to see the defaults. You can also write and read them just like any 1969 | JSON Value. 1970 | \sa setDefaults() 1971 | */ 1972 | Json::Value settings_; 1973 | 1974 | StreamWriterBuilder(); 1975 | ~StreamWriterBuilder() JSONCPP_OVERRIDE; 1976 | 1977 | /** 1978 | * \throw std::exception if something goes wrong (e.g. invalid settings) 1979 | */ 1980 | StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; 1981 | 1982 | /** \return true if 'settings' are legal and consistent; 1983 | * otherwise, indicate bad settings via 'invalid'. 1984 | */ 1985 | bool validate(Json::Value* invalid) const; 1986 | /** A simple way to update a specific setting. 1987 | */ 1988 | Value& operator[](JSONCPP_STRING key); 1989 | 1990 | /** Called by ctor, but you can use this to reset settings_. 1991 | * \pre 'settings' != NULL (but Json::null is fine) 1992 | * \remark Defaults: 1993 | * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults 1994 | */ 1995 | static void setDefaults(Json::Value* settings); 1996 | }; 1997 | 1998 | /** \brief Abstract class for writers. 1999 | * \deprecated Use StreamWriter. (And really, this is an implementation detail.) 2000 | */ 2001 | class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { 2002 | public: 2003 | virtual ~Writer(); 2004 | 2005 | virtual JSONCPP_STRING write(const Value& root) = 0; 2006 | }; 2007 | 2008 | /** \brief Outputs a Value in JSON format 2009 | *without formatting (not human friendly). 2010 | * 2011 | * The JSON document is written in a single line. It is not intended for 'human' 2012 | *consumption, 2013 | * but may be usefull to support feature such as RPC where bandwith is limited. 2014 | * \sa Reader, Value 2015 | * \deprecated Use StreamWriterBuilder. 2016 | */ 2017 | class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter : public Writer { 2018 | 2019 | public: 2020 | FastWriter(); 2021 | ~FastWriter() JSONCPP_OVERRIDE {} 2022 | 2023 | void enableYAMLCompatibility(); 2024 | 2025 | /** \brief Drop the "null" string from the writer's output for nullValues. 2026 | * Strictly speaking, this is not valid JSON. But when the output is being 2027 | * fed to a browser's Javascript, it makes for smaller output and the 2028 | * browser can handle the output just fine. 2029 | */ 2030 | void dropNullPlaceholders(); 2031 | 2032 | void omitEndingLineFeed(); 2033 | 2034 | public: // overridden from Writer 2035 | JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; 2036 | 2037 | private: 2038 | void writeValue(const Value& value); 2039 | 2040 | JSONCPP_STRING document_; 2041 | bool yamlCompatiblityEnabled_; 2042 | bool dropNullPlaceholders_; 2043 | bool omitEndingLineFeed_; 2044 | }; 2045 | 2046 | /** \brief Writes a Value in JSON format in a 2047 | *human friendly way. 2048 | * 2049 | * The rules for line break and indent are as follow: 2050 | * - Object value: 2051 | * - if empty then print {} without indent and line break 2052 | * - if not empty the print '{', line break & indent, print one value per 2053 | *line 2054 | * and then unindent and line break and print '}'. 2055 | * - Array value: 2056 | * - if empty then print [] without indent and line break 2057 | * - if the array contains no object value, empty array or some other value 2058 | *types, 2059 | * and all the values fit on one lines, then print the array on a single 2060 | *line. 2061 | * - otherwise, it the values do not fit on one line, or the array contains 2062 | * object or non empty array, then print one value per line. 2063 | * 2064 | * If the Value have comments then they are outputed according to their 2065 | *#CommentPlacement. 2066 | * 2067 | * \sa Reader, Value, Value::setComment() 2068 | * \deprecated Use StreamWriterBuilder. 2069 | */ 2070 | class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledWriter : public Writer { 2071 | public: 2072 | StyledWriter(); 2073 | ~StyledWriter() JSONCPP_OVERRIDE {} 2074 | 2075 | public: // overridden from Writer 2076 | /** \brief Serialize a Value in JSON format. 2077 | * \param root Value to serialize. 2078 | * \return String containing the JSON document that represents the root value. 2079 | */ 2080 | JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; 2081 | 2082 | private: 2083 | void writeValue(const Value& value); 2084 | void writeArrayValue(const Value& value); 2085 | bool isMultineArray(const Value& value); 2086 | void pushValue(const JSONCPP_STRING& value); 2087 | void writeIndent(); 2088 | void writeWithIndent(const JSONCPP_STRING& value); 2089 | void indent(); 2090 | void unindent(); 2091 | void writeCommentBeforeValue(const Value& root); 2092 | void writeCommentAfterValueOnSameLine(const Value& root); 2093 | bool hasCommentForValue(const Value& value); 2094 | static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); 2095 | 2096 | typedef std::vector ChildValues; 2097 | 2098 | ChildValues childValues_; 2099 | JSONCPP_STRING document_; 2100 | JSONCPP_STRING indentString_; 2101 | unsigned int rightMargin_; 2102 | unsigned int indentSize_; 2103 | bool addChildValues_; 2104 | }; 2105 | 2106 | /** \brief Writes a Value in JSON format in a 2107 | human friendly way, 2108 | to a stream rather than to a string. 2109 | * 2110 | * The rules for line break and indent are as follow: 2111 | * - Object value: 2112 | * - if empty then print {} without indent and line break 2113 | * - if not empty the print '{', line break & indent, print one value per 2114 | line 2115 | * and then unindent and line break and print '}'. 2116 | * - Array value: 2117 | * - if empty then print [] without indent and line break 2118 | * - if the array contains no object value, empty array or some other value 2119 | types, 2120 | * and all the values fit on one lines, then print the array on a single 2121 | line. 2122 | * - otherwise, it the values do not fit on one line, or the array contains 2123 | * object or non empty array, then print one value per line. 2124 | * 2125 | * If the Value have comments then they are outputed according to their 2126 | #CommentPlacement. 2127 | * 2128 | * \sa Reader, Value, Value::setComment() 2129 | * \deprecated Use StreamWriterBuilder. 2130 | */ 2131 | class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledStreamWriter { 2132 | public: 2133 | /** 2134 | * \param indentation Each level will be indented by this amount extra. 2135 | */ 2136 | StyledStreamWriter(JSONCPP_STRING indentation = "\t"); 2137 | ~StyledStreamWriter() {} 2138 | 2139 | public: 2140 | /** \brief Serialize a Value in JSON format. 2141 | * \param out Stream to write to. (Can be ostringstream, e.g.) 2142 | * \param root Value to serialize. 2143 | * \note There is no point in deriving from Writer, since write() should not 2144 | * return a value. 2145 | */ 2146 | void write(JSONCPP_OSTREAM& out, const Value& root); 2147 | 2148 | private: 2149 | void writeValue(const Value& value); 2150 | void writeArrayValue(const Value& value); 2151 | bool isMultineArray(const Value& value); 2152 | void pushValue(const JSONCPP_STRING& value); 2153 | void writeIndent(); 2154 | void writeWithIndent(const JSONCPP_STRING& value); 2155 | void indent(); 2156 | void unindent(); 2157 | void writeCommentBeforeValue(const Value& root); 2158 | void writeCommentAfterValueOnSameLine(const Value& root); 2159 | bool hasCommentForValue(const Value& value); 2160 | static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); 2161 | 2162 | typedef std::vector ChildValues; 2163 | 2164 | ChildValues childValues_; 2165 | JSONCPP_OSTREAM* document_; 2166 | JSONCPP_STRING indentString_; 2167 | unsigned int rightMargin_; 2168 | JSONCPP_STRING indentation_; 2169 | bool addChildValues_ : 1; 2170 | bool indented_ : 1; 2171 | }; 2172 | 2173 | #if defined(JSON_HAS_INT64) 2174 | JSONCPP_STRING JSON_API valueToString(Int value); 2175 | JSONCPP_STRING JSON_API valueToString(UInt value); 2176 | #endif // if defined(JSON_HAS_INT64) 2177 | JSONCPP_STRING JSON_API valueToString(LargestInt value); 2178 | JSONCPP_STRING JSON_API valueToString(LargestUInt value); 2179 | JSONCPP_STRING JSON_API valueToString(double value); 2180 | JSONCPP_STRING JSON_API valueToString(bool value); 2181 | JSONCPP_STRING JSON_API valueToQuotedString(const char* value); 2182 | 2183 | /// \brief Output using the StyledStreamWriter. 2184 | /// \see Json::operator>>() 2185 | JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); 2186 | 2187 | Value parse_string(const std::string& jsonstring); 2188 | Value parse_file(const std::string& file); 2189 | 2190 | } // namespace Json 2191 | 2192 | #pragma pack(pop) 2193 | 2194 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 2195 | #pragma warning(pop) 2196 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 2197 | 2198 | #endif // JSON_WRITER_H_INCLUDED 2199 | 2200 | //////////////end of writer.h 2201 | 2202 | 2203 | #endif //JSON_HPP_INCLUDED -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "http_server.hpp" 3 | 4 | using namespace std; 5 | 6 | class LogicalController : public Controller{ 7 | SetupController(LogicalController); 8 | 9 | public: 10 | DefRequestMapping(getCustom); 11 | DefRequestMapping(getReturn); 12 | DefRequestMapping(getBinary); 13 | DefRequestMapping(getFile); 14 | DefRequestMapping(putBase64Image); 15 | }; 16 | 17 | Json::Value LogicalController::putBase64Image(const Json::Value& param){ 18 | 19 | /** 20 | * 注意,这个函数的调用,请用工具(postman)以提交body的方式(raw)提交base64数据 21 | * 才能够在request.body中拿到对应的base64,并正确解码后储存 22 | * 1. 可以在网页上提交一个图片文件,并使用postman进行body-raw提交,例如网址是:https://base64.us/,选择页面下面的“选择文件”按钮 23 | * 2. 去掉生成的base64数据前缀:data:image/png;base64,。保证是纯base64数据输入 24 | * 这是一个图像的base64案例:iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAABLSURBVEhLY2RY9OI/Ax0BE5SmG6DIh/8DJKAswoBxwwswTXcfjlpIdTBqIdXBqIVUB8O/8B61kOpg1EKqg1ELqQ5GLaQ6oLOFDAwA5z0K0dyTzgcAAAAASUVORK5CYII= 25 | * 提交后能看到是个天蓝色的背景加上右上角有黄色的正方形 26 | */ 27 | 28 | auto session = get_current_session(); 29 | auto image_data = iLogger::base64_decode(session->request.body); 30 | iLogger::save_file("base_decode.jpg", image_data); 31 | return success(); 32 | } 33 | 34 | Json::Value LogicalController::getCustom(const Json::Value& param){ 35 | 36 | auto session = get_current_session(); 37 | const char* output = "hello http server"; 38 | session->response.write_binary(output, strlen(output)); 39 | session->response.set_header("Content-Type", "text/plain"); 40 | return success(); 41 | } 42 | 43 | Json::Value LogicalController::getReturn(const Json::Value& param){ 44 | 45 | Json::Value data; 46 | data["alpha"] = 3.15; 47 | data["beta"] = 2.56; 48 | data["name"] = "张三"; 49 | return success(data); 50 | } 51 | 52 | Json::Value LogicalController::getBinary(const Json::Value& param){ 53 | 54 | auto session = get_current_session(); 55 | auto data = iLogger::load_file("img.jpg"); 56 | session->response.write_binary(data.data(), data.size()); 57 | session->response.set_header("Content-Type", "image/jpeg"); 58 | return success(); 59 | } 60 | 61 | Json::Value LogicalController::getFile(const Json::Value& param){ 62 | 63 | auto session = get_current_session(); 64 | session->response.write_file("img.jpg"); 65 | return success(); 66 | } 67 | 68 | int test_http(int port = 8090){ 69 | 70 | INFO("Create controller"); 71 | auto logical_controller = make_shared(); 72 | string address = iLogger::format("0.0.0.0:%d", port); 73 | 74 | INFO("Create http server to: %s", address.c_str()); 75 | auto server = createHttpServer(address, 32); 76 | if(!server) 77 | return -1; 78 | 79 | INFO("Add controller"); 80 | server->add_controller("/v1", logical_controller); 81 | server->add_controller("/static", create_file_access_controller("./")); 82 | INFO("Access url: http://%s/v1", address.c_str()); 83 | 84 | INFO( 85 | "\n" 86 | "访问如下地址即可看到效果:\n" 87 | "1. http://%s/v1/getCustom 使用自定义写出内容作为response\n" 88 | "2. http://%s/v1/getReturn 使用函数返回值中的json作为response\n" 89 | "3. http://%s/v1/getBinary 使用自定义写出二进制数据作为response\n" 90 | "4. http://%s/v1/getFile 使用自定义写出文件路径作为response\n" 91 | "5. http://%s/v1/putBase64Image 通过提交base64图像数据进行解码后储存\n" 92 | "6. http://%s/static/img.jpg 直接访问静态文件处理的controller,具体请看函数说明", 93 | address.c_str(), address.c_str(), address.c_str(), address.c_str(), address.c_str(), address.c_str() 94 | ); 95 | 96 | INFO("按下Ctrl + C结束程序"); 97 | return iLogger::while_loop(); 98 | } 99 | 100 | int main(int argc, char** argv) { 101 | return test_http(); 102 | } -------------------------------------------------------------------------------- /workspace/base_decode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shouxieai/http_server_cpp/508392f6d7ece5eaae7ff4763d50fabe0268638b/workspace/base_decode.jpg -------------------------------------------------------------------------------- /workspace/demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shouxieai/http_server_cpp/508392f6d7ece5eaae7ff4763d50fabe0268638b/workspace/demo1.jpg -------------------------------------------------------------------------------- /workspace/demo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shouxieai/http_server_cpp/508392f6d7ece5eaae7ff4763d50fabe0268638b/workspace/demo2.jpg -------------------------------------------------------------------------------- /workspace/favicon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shouxieai/http_server_cpp/508392f6d7ece5eaae7ff4763d50fabe0268638b/workspace/favicon.jpg -------------------------------------------------------------------------------- /workspace/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shouxieai/http_server_cpp/508392f6d7ece5eaae7ff4763d50fabe0268638b/workspace/img.jpg --------------------------------------------------------------------------------