├── .gitattributes ├── .gitignore ├── README.md ├── Wechat Hook 391119.json ├── inc ├── Detours │ ├── detours.h │ └── detver.h ├── base64 │ └── base64.h ├── chat_controller.h ├── chat_room_controller.h ├── client_socket.h ├── config.h ├── contacts_controller.h ├── db_controller.h ├── hook.h ├── hook_controller.h ├── http_client.h ├── http_controller.h ├── http_router.h ├── http_server.h ├── include │ ├── base_config.h │ ├── memory.h │ ├── noncopyable.h │ ├── singleton.h │ ├── thread_pool.h │ ├── utils.h │ └── win_header.h ├── json_utils.h ├── lz4 │ └── lz4.h ├── misc_controller.h ├── mongoose │ └── mongoose.h ├── nlohmann │ ├── adl_serializer.hpp │ ├── byte_container_with_subtype.hpp │ ├── detail │ │ ├── abi_macros.hpp │ │ ├── conversions │ │ │ ├── from_json.hpp │ │ │ ├── to_chars.hpp │ │ │ └── to_json.hpp │ │ ├── exceptions.hpp │ │ ├── hash.hpp │ │ ├── input │ │ │ ├── binary_reader.hpp │ │ │ ├── input_adapters.hpp │ │ │ ├── json_sax.hpp │ │ │ ├── lexer.hpp │ │ │ ├── parser.hpp │ │ │ └── position_t.hpp │ │ ├── iterators │ │ │ ├── internal_iterator.hpp │ │ │ ├── iter_impl.hpp │ │ │ ├── iteration_proxy.hpp │ │ │ ├── iterator_traits.hpp │ │ │ ├── json_reverse_iterator.hpp │ │ │ └── primitive_iterator.hpp │ │ ├── json_custom_base_class.hpp │ │ ├── json_pointer.hpp │ │ ├── json_ref.hpp │ │ ├── macro_scope.hpp │ │ ├── macro_unscope.hpp │ │ ├── meta │ │ │ ├── call_std │ │ │ │ ├── begin.hpp │ │ │ │ └── end.hpp │ │ │ ├── cpp_future.hpp │ │ │ ├── detected.hpp │ │ │ ├── identity_tag.hpp │ │ │ ├── is_sax.hpp │ │ │ ├── std_fs.hpp │ │ │ ├── type_traits.hpp │ │ │ └── void_t.hpp │ │ ├── output │ │ │ ├── binary_writer.hpp │ │ │ ├── output_adapters.hpp │ │ │ └── serializer.hpp │ │ ├── string_concat.hpp │ │ ├── string_escape.hpp │ │ └── value_t.hpp │ ├── json.hpp │ ├── json_fwd.hpp │ ├── ordered_map.hpp │ └── thirdparty │ │ └── hedley │ │ ├── hedley.hpp │ │ └── hedley_undef.hpp ├── offset.h ├── spdlog │ ├── async.h │ ├── async_logger-inl.h │ ├── async_logger.h │ ├── cfg │ │ ├── argv.h │ │ ├── env.h │ │ ├── helpers-inl.h │ │ └── helpers.h │ ├── common-inl.h │ ├── common.h │ ├── details │ │ ├── backtracer-inl.h │ │ ├── backtracer.h │ │ ├── circular_q.h │ │ ├── console_globals.h │ │ ├── file_helper-inl.h │ │ ├── file_helper.h │ │ ├── fmt_helper.h │ │ ├── log_msg-inl.h │ │ ├── log_msg.h │ │ ├── log_msg_buffer-inl.h │ │ ├── log_msg_buffer.h │ │ ├── mpmc_blocking_q.h │ │ ├── null_mutex.h │ │ ├── os-inl.h │ │ ├── os.h │ │ ├── periodic_worker-inl.h │ │ ├── periodic_worker.h │ │ ├── registry-inl.h │ │ ├── registry.h │ │ ├── synchronous_factory.h │ │ ├── tcp_client-windows.h │ │ ├── tcp_client.h │ │ ├── thread_pool-inl.h │ │ ├── thread_pool.h │ │ ├── udp_client-windows.h │ │ ├── udp_client.h │ │ └── windows_include.h │ ├── fmt │ │ ├── bin_to_hex.h │ │ ├── bundled │ │ │ ├── args.h │ │ │ ├── chrono.h │ │ │ ├── color.h │ │ │ ├── compile.h │ │ │ ├── core.h │ │ │ ├── fmt.license.rst │ │ │ ├── format-inl.h │ │ │ ├── format.h │ │ │ ├── locale.h │ │ │ ├── os.h │ │ │ ├── ostream.h │ │ │ ├── printf.h │ │ │ ├── ranges.h │ │ │ ├── std.h │ │ │ └── xchar.h │ │ ├── chrono.h │ │ ├── compile.h │ │ ├── fmt.h │ │ ├── ostr.h │ │ ├── ranges.h │ │ ├── std.h │ │ └── xchar.h │ ├── formatter.h │ ├── fwd.h │ ├── logger-inl.h │ ├── logger.h │ ├── pattern_formatter-inl.h │ ├── pattern_formatter.h │ ├── sinks │ │ ├── android_sink.h │ │ ├── ansicolor_sink-inl.h │ │ ├── ansicolor_sink.h │ │ ├── base_sink-inl.h │ │ ├── base_sink.h │ │ ├── basic_file_sink-inl.h │ │ ├── basic_file_sink.h │ │ ├── callback_sink.h │ │ ├── daily_file_sink.h │ │ ├── dist_sink.h │ │ ├── dup_filter_sink.h │ │ ├── hourly_file_sink.h │ │ ├── kafka_sink.h │ │ ├── mongo_sink.h │ │ ├── msvc_sink.h │ │ ├── null_sink.h │ │ ├── ostream_sink.h │ │ ├── qt_sinks.h │ │ ├── ringbuffer_sink.h │ │ ├── rotating_file_sink-inl.h │ │ ├── rotating_file_sink.h │ │ ├── sink-inl.h │ │ ├── sink.h │ │ ├── stdout_color_sinks-inl.h │ │ ├── stdout_color_sinks.h │ │ ├── stdout_sinks-inl.h │ │ ├── stdout_sinks.h │ │ ├── syslog_sink.h │ │ ├── systemd_sink.h │ │ ├── tcp_sink.h │ │ ├── udp_sink.h │ │ ├── win_eventlog_sink.h │ │ ├── wincolor_sink-inl.h │ │ └── wincolor_sink.h │ ├── spdlog-inl.h │ ├── spdlog.h │ ├── stopwatch.h │ ├── tweakme.h │ └── version.h ├── sqlite_function.h ├── sync_msg_hook.h ├── tinyxml2 │ └── tinyxml2.h ├── wechat_db.h ├── wechat_interface.h ├── wechat_service.h ├── wxhelper.h └── wxutils.h ├── injector.bat ├── injector.exe ├── lib ├── debug │ ├── base64.lib │ ├── detours.lib │ ├── lz4.lib │ ├── mongoose.lib │ ├── spdlogd.lib │ └── tinyxml2.lib └── release │ ├── base64.lib │ ├── detours.lib │ ├── lz4.lib │ ├── mongoose.lib │ ├── spdlog.lib │ └── tinyxml2.lib ├── record.gif ├── resource.h ├── src ├── chat_controller.cc ├── chat_room_controller.cc ├── client_socket.cc ├── config.cc ├── contacts_controller.cc ├── db_controller.cc ├── dllMain.cc ├── hook.cc ├── hook_controller.cc ├── http_client.cc ├── http_router.cc ├── http_server.cc ├── json_utils.cc ├── memory.cc ├── misc_controller.cc ├── sync_msg_hook.cc ├── thread_pool.cc ├── utils.cc ├── wechat_db.cc ├── wechat_service.cc ├── wxhelper.cc └── wxutils.cc ├── version.png ├── wxhelper.rc ├── wxhelper.sln ├── wxhelper.vcxproj └── wxhelper.vcxproj.filters /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /inc/Detours/detver.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Common version parameters. 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #define _USING_V110_SDK71_ 1 11 | #include "winver.h" 12 | #if 0 13 | #include 14 | #include 15 | #else 16 | #ifndef DETOURS_STRINGIFY 17 | #define DETOURS_STRINGIFY_(x) #x 18 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 19 | #endif 20 | 21 | #define VER_FILEFLAGSMASK 0x3fL 22 | #define VER_FILEFLAGS 0x0L 23 | #define VER_FILEOS 0x00040004L 24 | #define VER_FILETYPE 0x00000002L 25 | #define VER_FILESUBTYPE 0x00000000L 26 | #endif 27 | #define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS) 28 | -------------------------------------------------------------------------------- /inc/base64/base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // base64 encoding and decoding with C++. 3 | // Version: 2.rc.09 (release candidate) 4 | // 5 | 6 | #ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A 7 | #define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A 8 | 9 | #include 10 | 11 | #if __cplusplus >= 201703L 12 | #include 13 | #endif // __cplusplus >= 201703L 14 | 15 | std::string base64_encode(std::string const& s, bool url = false); 16 | std::string base64_encode_pem(std::string const& s); 17 | std::string base64_encode_mime(std::string const& s); 18 | 19 | std::string base64_decode(std::string const& s, bool remove_linebreaks = false); 20 | std::string base64_encode(unsigned char const*, size_t len, bool url = false); 21 | 22 | #if __cplusplus >= 201703L 23 | // 24 | // Interface with std::string_view rather than const std::string& 25 | // Requires C++17 26 | // Provided by Yannic Bonenberger (https://github.com/Yannic) 27 | // 28 | std::string base64_encode(std::string_view s, bool url = false); 29 | std::string base64_encode_pem(std::string_view s); 30 | std::string base64_encode_mime(std::string_view s); 31 | 32 | std::string base64_decode(std::string_view s, bool remove_linebreaks = false); 33 | #endif // __cplusplus >= 201703L 34 | 35 | #endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */ -------------------------------------------------------------------------------- /inc/chat_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_CHAT_CONTROLLER_H_ 2 | #define WXHELPER_CHAT_CONTROLLER_H_ 3 | 4 | #include "http_controller.h" 5 | 6 | namespace wxhelper { 7 | class ChatController : public http::HttpController { 8 | public: 9 | PATHS_BEGIN 10 | ADD_PATH("/api/sendTextMsg", SendTextMsg); 11 | ADD_PATH("/api/sendImagesMsg", SendImageMsg); 12 | ADD_PATH("/api/sendFileMsg", SendFileMsg); 13 | 14 | ADD_PATH("/api/sendAtText", SendAtText); 15 | ADD_PATH("/api/sendMultiAtText", SendMultiAtText); 16 | ADD_PATH("/api/sendCustomEmotion", SendCustomEmotion); 17 | ADD_PATH("/api/sendApplet", SendApplet); 18 | ADD_PATH("/api/sendPatMsg", SendPatMsg); 19 | 20 | ADD_PATH("/api/forwardMsg", ForwardMsg); 21 | ADD_PATH("/api/forwardPublicMsgByMsgId", ForwardPublicMsgByMsgId); 22 | ADD_PATH("/api/forwardPublicMsg", ForwardPublicMsg); 23 | PATHS_END 24 | 25 | public: 26 | /// @brief 发送文本 27 | /// @param params json 28 | /// @return json 29 | static std::string SendTextMsg(std::string params); 30 | /// @brief 发送图片 31 | /// @param params json 32 | /// @return json 33 | static std::string SendImageMsg(std::string params); 34 | /// @brief 发送文件 35 | /// @param params json 36 | /// @return json 37 | static std::string SendFileMsg(std::string params); 38 | 39 | /// @brief 发送@文本 40 | /// @param params json 41 | /// @return json 42 | static std::string SendAtText(std::string params); 43 | /// @brief 发送多个@文本 44 | /// @param params json 45 | /// @return json 46 | static std::string SendMultiAtText(std::string params); 47 | /// @brief 发送自定义表情 48 | /// @param params json 49 | /// @return json 50 | static std::string SendCustomEmotion(std::string params); 51 | /// @brief 发送小程序 52 | /// @param params json 53 | /// @return json 54 | static std::string SendApplet(std::string params); 55 | /// @brief 拍一拍 56 | /// @param params json 57 | /// @return json 58 | static std::string SendPatMsg(std::string params); 59 | 60 | 61 | /// @brief 转发消息 62 | /// @param params json 63 | /// @return json 64 | static std::string ForwardMsg(std::string params); 65 | /// @brief 转发公众号消息 66 | /// @param params json 67 | /// @return json 68 | static std::string ForwardPublicMsgByMsgId(std::string params); 69 | /// @brief 发送公众号消息 70 | /// @param params json 71 | /// @return json 72 | static std::string ForwardPublicMsg(std::string params); 73 | /// @brief 获取联系人昵称 74 | /// @param params json 75 | /// @return json 76 | static std::string GetContactOrChatRoomNickname(std::string params); 77 | }; 78 | } // namespace wxhelper 79 | 80 | #endif -------------------------------------------------------------------------------- /inc/chat_room_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_CHAT_ROOM_CONTROLLER_H_ 2 | #define WXHELPER_CHAT_ROOM_CONTROLLER_H_ 3 | 4 | #include "http_controller.h" 5 | 6 | namespace wxhelper { 7 | class ChatRoomController : public http::HttpController { 8 | public: 9 | PATHS_BEGIN 10 | ADD_PATH("/api/getChatRoomDetailInfo", GetChatRoomDetailInfo); 11 | ADD_PATH("/api/getMemberFromChatRoom", GetMemberFromChatRoom); 12 | 13 | ADD_PATH("/api/addMemberToChatRoom", AddMemberToChatRoom); 14 | ADD_PATH("/api/delMemberFromChatRoom", DelMemberFromChatRoom); 15 | 16 | ADD_PATH("/api/createChatRoom", CreateChatRoom); 17 | ADD_PATH("/api/quitChatRoom", QuitChatRoom); 18 | ADD_PATH("/api/inviteMemberToChatRoom", InviteMemberToChatRoom); 19 | 20 | ADD_PATH("/api/topMsg", TopMsg); 21 | ADD_PATH("/api/removeTopMsg", RemoveTopMsg); 22 | 23 | ADD_PATH("/api/getChatRoomMemberNickname", GetChatRoomMemberNickname); 24 | ADD_PATH("/api/modifyChatRoomMemberNickName", ModifyChatRoomMemberNickName); 25 | PATHS_END 26 | 27 | public: 28 | /// @brief 获取群聊详情 29 | /// @param params json 30 | /// @return json 31 | static std::string GetChatRoomDetailInfo(std::string params); 32 | /// @brief 获取群成员 33 | /// @param params json 34 | /// @return json 35 | static std::string GetMemberFromChatRoom(std::string params); 36 | 37 | /// @brief 添加群成员 38 | /// @param params json 39 | /// @return json 40 | static std::string AddMemberToChatRoom(std::string params); 41 | /// @brief 删除群成员 42 | /// @param params json 43 | /// @return json 44 | static std::string DelMemberFromChatRoom(std::string params); 45 | /// @brief 创建群聊 46 | /// @param params json 47 | /// @return json 48 | static std::string CreateChatRoom(std::string params); 49 | /// @brief 退出群聊 50 | /// @param params json 51 | /// @return json 52 | static std::string QuitChatRoom(std::string params); 53 | /// @brief 邀请成员入群 54 | /// @param params json 55 | /// @return json 56 | static std::string InviteMemberToChatRoom(std::string params); 57 | 58 | /// @brief 群聊消息置顶 59 | /// @param params json 60 | /// @return json 61 | static std::string TopMsg(std::string params); 62 | /// @brief 取消群聊消息置顶 63 | /// @param params json 64 | /// @return json 65 | static std::string RemoveTopMsg(std::string params); 66 | 67 | /// @brief 获取群聊成员昵称 68 | /// @param params json 69 | /// @return json 70 | static std::string GetChatRoomMemberNickname(std::string params); 71 | /// @brief 修改群聊成员昵称 72 | /// @param params json 73 | /// @return json 74 | static std::string ModifyChatRoomMemberNickName(std::string params); 75 | }; 76 | } // namespace wxhelper 77 | 78 | #endif -------------------------------------------------------------------------------- /inc/client_socket.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_CLIENT_SOCKET_H_ 2 | #define WXHELPER_CLIENT_SOCKET_H_ 3 | #include 4 | 5 | #include "noncopyable.h" 6 | namespace wxhelper { 7 | class SocketInit : public NonCopyable { 8 | public: 9 | SocketInit(); 10 | 11 | ~SocketInit(); 12 | 13 | bool valid_{false}; 14 | }; 15 | 16 | static SocketInit kSocketInit; 17 | 18 | class TcpClient : public NonCopyable { 19 | public: 20 | TcpClient()=default; 21 | TcpClient(std::string ip, int port); 22 | void SendAndCloseSocket(std::string& content); 23 | 24 | private: 25 | std::string ip_; 26 | int port_; 27 | }; 28 | 29 | } // namespace wxhelper 30 | #endif -------------------------------------------------------------------------------- /inc/config.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_CONFIG_H_ 2 | #define WXHELPER_CONFIG_H_ 3 | #include 4 | 5 | #include "singleton.h" 6 | namespace wxhelper { 7 | 8 | 9 | class Config : public base::Singleton { 10 | public: 11 | void init(); 12 | int GetHideDll(); 13 | std::string GetHttpServerHost(); 14 | int GetHttpServerPort(); 15 | std::string GetRecvMessageMode(); 16 | 17 | std::string GetRecvTcpIp(); 18 | int GetRecvTcpPort(); 19 | 20 | std::string GetRecvHttpUrl(); 21 | int GetRecvHttpTimeout(); 22 | 23 | private: 24 | int hidden_dll_; 25 | std::string http_server_host_; 26 | int http_server_port_; 27 | std::string recv_message_mode_; 28 | std::string recv_tcp_ip_; 29 | int recv_tcp_port_; 30 | std::string recv_http_url_; 31 | int recv_http_timeout_; 32 | }; 33 | } // namespace wxhelper 34 | #endif -------------------------------------------------------------------------------- /inc/contacts_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_CONTACTS_CONTROLLER_H_ 2 | #define WXHELPER_CONTACTS_CONTROLLER_H_ 3 | 4 | #include "http_controller.h" 5 | 6 | namespace wxhelper { 7 | class ContactsController : public http::HttpController { 8 | public: 9 | PATHS_BEGIN 10 | ADD_PATH("/api/getContactList", GetContactList); 11 | ADD_PATH("/api/getContactProfile", GetContactProfile); 12 | ADD_PATH("/api/delContact", DelContact); 13 | ADD_PATH("/api/searchContact", SearchContact); 14 | ADD_PATH("/api/addContact", AddContact); 15 | ADD_PATH("/api/verifyApply", VerifyApply); 16 | PATHS_END 17 | 18 | public: 19 | /// @brief 好友通讯录 20 | /// @param params json 21 | /// @return json 22 | static std::string GetContactList(std::string params); 23 | /// @brief 联系人信息 24 | /// @param params json 25 | /// @return json 26 | static std::string GetContactProfile(std::string params); 27 | /// @brief 删除好友 28 | /// @param params json 29 | /// @return json 30 | static std::string DelContact(std::string params); 31 | /// @brief 搜索联系人 32 | /// @param params json 33 | /// @return json 34 | static std::string SearchContact(std::string params); 35 | /// @brief 加好友 36 | /// @param params json 37 | /// @return json 38 | static std::string AddContact(std::string params); 39 | /// @brief 通过好友验证 40 | /// @param params json 41 | /// @return json 42 | static std::string VerifyApply(std::string params); 43 | }; 44 | } // namespace wxhelper 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /inc/db_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_DB_CONTROLLER_H_ 2 | #define WXHELPER_DB_CONTROLLER_H_ 3 | 4 | #include "http_controller.h" 5 | 6 | namespace wxhelper { 7 | class DbController : public http::HttpController { 8 | public: 9 | PATHS_BEGIN 10 | ADD_PATH("/api/getDBInfo", GetDBInfo); 11 | ADD_PATH("/api/execSql", ExecSql); 12 | PATHS_END 13 | 14 | public: 15 | static std::string GetDBInfo(std::string params); 16 | static std::string ExecSql(std::string params); 17 | }; 18 | } // namespace wxhelper 19 | 20 | #endif -------------------------------------------------------------------------------- /inc/hook.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_HOOK_H_ 2 | #define WXHELPER_HOOK_H_ 3 | #include 4 | #include 5 | 6 | namespace hook { 7 | struct InnerMessageStruct { 8 | char* buffer; 9 | int64_t length; 10 | ~InnerMessageStruct() { 11 | if (this->buffer != NULL) { 12 | delete[] this->buffer; 13 | this->buffer = NULL; 14 | } 15 | } 16 | }; 17 | 18 | void SendHttpMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context, 19 | PTP_WORK Work); 20 | 21 | void SendTcpMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context, 22 | PTP_WORK Work); 23 | class BaseHook { 24 | public: 25 | BaseHook():hook_flag_(false),origin_(nullptr),detour_(nullptr){} 26 | BaseHook(void* origin, void* detour); 27 | int Hook(); 28 | int Unhook(); 29 | virtual ~BaseHook() {} 30 | 31 | protected: 32 | bool hook_flag_; 33 | void* origin_; 34 | void* detour_; 35 | }; 36 | 37 | } // namespace hook 38 | #endif -------------------------------------------------------------------------------- /inc/hook_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_HOOK_CONTROLLER_H_ 2 | #define WXHELPER_HOOK_CONTROLLER_H_ 3 | 4 | #include "http_controller.h" 5 | 6 | namespace wxhelper { 7 | class HookController : public http::HttpController { 8 | public: 9 | PATHS_BEGIN 10 | ADD_PATH("/api/hookSyncMsg", HookSyncMsg); 11 | ADD_PATH("/api/unhookSyncMsg", UnHookSyncMsg); 12 | ADD_PATH("/api/hookLog", HookLog); 13 | ADD_PATH("/api/unhookLog", UnHookLog); 14 | PATHS_END 15 | 16 | public: 17 | /// @brief hook消息 18 | /// @param params json 19 | /// @return json 20 | static std::string HookSyncMsg(std::string params); 21 | /// @brief 取消hook消息 22 | /// @param params json 23 | /// @return json 24 | static std::string UnHookSyncMsg(std::string params); 25 | /// @brief hook日志消息 26 | /// @param params json 27 | /// @return json 28 | static std::string HookLog(std::string params); 29 | /// @brief 取消hook日志消息 30 | /// @param params json 31 | /// @return json 32 | static std::string UnHookLog(std::string params); 33 | }; 34 | } // namespace wxhelper 35 | 36 | #endif -------------------------------------------------------------------------------- /inc/http_client.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_HTTP_CLIENT_H_ 2 | #define WXHELPER_HTTP_CLIENT_H_ 3 | #include 4 | 5 | #include "mongoose.h" 6 | #include "noncopyable.h" 7 | #include "singleton.h" 8 | 9 | namespace http { 10 | 11 | struct Data { 12 | bool done; 13 | int timeout; 14 | std::string url; 15 | std::string post_data; 16 | }; 17 | 18 | class HttpClient : public NonCopyable { 19 | public: 20 | explicit HttpClient(std::string url, int timeout); 21 | void SendRequest(const std::string &content); 22 | private: 23 | static void OnHttpEvent(struct mg_connection *c, int ev, void *ev_data, 24 | void *fn_data); 25 | 26 | private: 27 | std::string url_; 28 | int timeout_; 29 | }; 30 | 31 | } // namespace http 32 | #endif -------------------------------------------------------------------------------- /inc/http_controller.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef WXHELPER_HTTP_CONTROLLER_H_ 3 | #define WXHELPER_HTTP_CONTROLLER_H_ 4 | 5 | #include "http_router.h" 6 | #include "singleton.h" 7 | namespace http { 8 | #define PATHS_BEGIN static void AddPath() { 9 | #define ADD_PATH(path, method) RegisterPath(path, &method) 10 | #define PATHS_END } 11 | 12 | class BaseHttpController { 13 | public: 14 | virtual ~BaseHttpController() {} 15 | }; 16 | 17 | template 18 | class HttpController : public base::Singleton{ 19 | public: 20 | virtual ~HttpController() {} 21 | 22 | protected: 23 | HttpController() {} 24 | 25 | static void RegisterPath(const std::string &path, HttpHandler function) { 26 | HttpRouter::GetInstance().AddPathRouting(path, function); 27 | } 28 | 29 | private: 30 | struct Registrator { 31 | public: 32 | Registrator() { T::AddPath(); } 33 | }; 34 | 35 | static Registrator registrator_; 36 | virtual void *GetRegistrator() { return ®istrator_; } 37 | }; 38 | 39 | template 40 | typename HttpController::Registrator HttpController::registrator_; 41 | } // namespace http 42 | #endif 43 | -------------------------------------------------------------------------------- /inc/http_router.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_HTTP_ROUTER_H_ 2 | #define WXHELPER_HTTP_ROUTER_H_ 3 | #include 4 | #include 5 | #include 6 | 7 | #include "singleton.h" 8 | 9 | namespace http { 10 | typedef std::function HttpHandler; 11 | 12 | class HttpRouter : public base::Singleton { 13 | public: 14 | void HttpRouter::AddPathRouting(const std::string &path, HttpHandler handler); 15 | 16 | std::string HandleHttpRequest(const std::string &path, 17 | const std::string ¶m); 18 | 19 | private: 20 | std::unordered_map route_table_{}; 21 | }; 22 | } // namespace http 23 | #endif -------------------------------------------------------------------------------- /inc/http_server.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_HTTP_SERVER_H_ 2 | #define WXHELPER_HTTP_SERVER_H_ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "mongoose.h" 8 | #include "singleton.h" 9 | namespace http { 10 | 11 | class HttpServer : public base::Singleton { 12 | public: 13 | ~HttpServer(); 14 | void init(std::string &&host, int port); 15 | bool Start(); 16 | bool Stop(); 17 | const mg_mgr *GetMgr() { return &mgr_; } 18 | int GetPort() { return port_; } 19 | bool GetRunning() { return running_; } 20 | std::string GetHost() { return host_; } 21 | 22 | private: 23 | static void LaunchServer(HttpServer *server); 24 | static void EventHandler(struct mg_connection *c, int ev, void *ev_data, 25 | void *fn_data); 26 | static void HandleHttpRequest(struct mg_connection *c, void *ev_data, 27 | void *fn_data); 28 | static void HandleWebsocketRequest(struct mg_connection *c, void *ev_data, 29 | void *fn_data); 30 | 31 | private: 32 | struct mg_mgr mgr_; 33 | std::string host_; 34 | int port_; 35 | std::atomic running_{false}; 36 | HANDLE thread_; 37 | }; 38 | 39 | } // namespace http 40 | 41 | #endif -------------------------------------------------------------------------------- /inc/include/base_config.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_BASE_CONFIG_H_ 2 | #define BASE_BASE_CONFIG_H_ 3 | // Lib/Dll switch 4 | #if !defined(BASE_EXPORTS) && !defined(BASE_IMPORTS) && !defined(BASE_STATIC) 5 | #define BASE_STATIC 6 | #endif 7 | 8 | #if defined(_MSC_VER) 9 | 10 | #ifndef COMPILER_MSVC 11 | #define COMPILER_MSVC 1 12 | #endif 13 | 14 | #if defined(BASE_IMPORTS) 15 | #define BASE_API __declspec(dllimport) 16 | #elif defined(BASE_EXPORTS) 17 | #define BASE_API __declspec(dllexport) 18 | #else 19 | #define BASE_API 20 | #endif 21 | 22 | #elif defined(__GNUC__) 23 | #define COMPILER_GCC 24 | #define BASE_API 25 | #else 26 | #error "Unknown or unsupported compiler" 27 | #endif 28 | 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /inc/include/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_MEMORY_H_ 2 | #define BASE_MEMORY_H_ 3 | #include 4 | #include 5 | namespace base { 6 | namespace memory { 7 | std::vector ScanAndMatchValue(INT64 value, INT64 start,int align); 8 | int Sunday(const byte* total, int tlen, const byte* part, int plen); 9 | } 10 | } // namespace base 11 | #endif -------------------------------------------------------------------------------- /inc/include/noncopyable.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_NONCOPYABLE_H_ 2 | #define BASE_NONCOPYABLE_H_ 3 | class NonCopyable { 4 | protected: 5 | NonCopyable() {} 6 | ~NonCopyable() {} 7 | NonCopyable(const NonCopyable&) = delete; 8 | NonCopyable& operator=(const NonCopyable&) = delete; 9 | }; 10 | 11 | #endif -------------------------------------------------------------------------------- /inc/include/singleton.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_SINGLETON_H_ 2 | #define BASE_SINGLETON_H_ 3 | namespace base { 4 | template 5 | class Singleton { 6 | protected: 7 | Singleton() {} 8 | ~Singleton() {} 9 | 10 | Singleton(const Singleton&) = delete; 11 | Singleton& operator=(const Singleton&) = delete; 12 | 13 | Singleton(Singleton&&) = delete; 14 | Singleton& operator=(Singleton&&) = delete; 15 | 16 | public: 17 | static T& GetInstance() { 18 | static T instance{}; 19 | return instance; 20 | } 21 | }; 22 | } // namespace base 23 | #endif -------------------------------------------------------------------------------- /inc/include/thread_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_THREAD_POOL_H_ 2 | #define BASE_THREAD_POOL_H_ 3 | #include "singleton.h" 4 | #include 5 | 6 | namespace base { 7 | 8 | class ThreadPool :public Singleton{ 9 | public: 10 | ~ThreadPool(); 11 | 12 | bool Create(unsigned long min = 1, unsigned long max = 4); 13 | 14 | bool AddWork(PTP_WORK_CALLBACK callback,PVOID opt); 15 | 16 | private: 17 | PTP_POOL pool_; 18 | PTP_CLEANUP_GROUP cleanup_group_; 19 | TP_CALLBACK_ENVIRON env_; 20 | }; 21 | 22 | } // namespace wxhelper 23 | 24 | #endif -------------------------------------------------------------------------------- /inc/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_UTILS_H_ 2 | #define BASE_UTILS_H_ 3 | #include 4 | 5 | #include 6 | #include 7 | namespace base { 8 | 9 | namespace utils { 10 | 11 | #define STRINGIFY(S) #S 12 | #define DEFER_STRINGIFY(S) STRINGIFY(S) 13 | #define PRAGMA_MESSAGE(MSG) _Pragma(STRINGIFY(message(MSG))) 14 | #define FORMATTED_MESSAGE(MSG) "warning [TODO-" DEFER_STRINGIFY(__COUNTER__) "] " MSG " : " __FILE__ "(" DEFER_STRINGIFY(__LINE__) ")" 15 | #define TODO(MSG) PRAGMA_MESSAGE(FORMATTED_MESSAGE(MSG)) 16 | 17 | std::wstring Utf8ToWstring(const std::string &str); 18 | 19 | std::string WstringToUtf8(const std::wstring &str); 20 | 21 | std::wstring AnsiToWstring(const std::string &input, INT64 locale = CP_ACP); 22 | 23 | std::string WstringToAnsi(const std::wstring &input, INT64 locale = CP_ACP); 24 | 25 | std::string WcharToUtf8(wchar_t *wstr); 26 | 27 | std::string StringToHex(const std::string &str); 28 | 29 | std::string HexToString(const std::string &hex_str); 30 | 31 | std::string BytesToHex(const BYTE *bytes, const int length); 32 | 33 | void HexToBytes(const std::string &hex, BYTE *bytes); 34 | 35 | template 36 | std::vector split(T1 str, T2 letter) { 37 | std::vector arr; 38 | size_t pos; 39 | while ((pos = str.find_first_of(letter)) != T1::npos) { 40 | T1 str1 = str.substr(0, pos); 41 | arr.push_back(str1); 42 | str = str.substr(pos + 1, str.length() - pos - 1); 43 | } 44 | arr.push_back(str); 45 | return arr; 46 | } 47 | 48 | template 49 | T1 replace(T1 source, T2 replaced, T1 replaceto) { 50 | std::vector v_arr = split(source, replaced); 51 | if (v_arr.size() < 2) return source; 52 | T1 temp; 53 | for (unsigned int i = 0; i < v_arr.size() - 1; i++) { 54 | temp += v_arr[i]; 55 | temp += replaceto; 56 | } 57 | temp += v_arr[v_arr.size() - 1]; 58 | return temp; 59 | } 60 | 61 | bool CreateConsole(); 62 | 63 | void CloseConsole(); 64 | 65 | void HideModule(HMODULE module); 66 | 67 | bool IsDigit(const std::string &str); 68 | 69 | std::string Bytes2Hex(const BYTE *bytes, const int length); 70 | 71 | bool IsTextUtf8(const char *str, INT64 length); 72 | 73 | template 74 | static T *WxHeapAlloc(size_t n) { 75 | return (T *)HeapAlloc(GetProcessHeap(), 0, n); 76 | } 77 | 78 | } // namespace utils 79 | } // namespace base 80 | #endif -------------------------------------------------------------------------------- /inc/include/win_header.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_WIN_HEADER_H_ 2 | #define BASE_WIN_HEADER_H_ 3 | #include 4 | 5 | #endif -------------------------------------------------------------------------------- /inc/json_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_JSON_UTILS_H_ 2 | #define WXHELPER_JSON_UTILS_H_ 3 | #include "nlohmann/json.hpp" 4 | namespace wxhelper { 5 | namespace jsonutils { 6 | std::wstring GetWStringParam(nlohmann::json data, std::string key); 7 | std::vector GetArrayParam(nlohmann::json data, std::string key) ; 8 | int GetIntParam(nlohmann::json data, std::string key); 9 | bool GetBoolParam(nlohmann::json data, std::string key); 10 | std::string GetStringParam(nlohmann::json data, std::string key); 11 | int64_t GetInt64Param(nlohmann::json data, std::string key); 12 | } 13 | } 14 | #endif -------------------------------------------------------------------------------- /inc/misc_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_CHAT_CONTROLLER_H_ 2 | #define WXHELPER_CHAT_CONTROLLER_H_ 3 | 4 | #include "http_controller.h" 5 | 6 | namespace wxhelper { 7 | class MiscController : public http::HttpController { 8 | public: 9 | PATHS_BEGIN 10 | ADD_PATH("/api/checkLogin", CheckLogin); 11 | ADD_PATH("/api/userInfo", GetUserInfo); 12 | ADD_PATH("/api/getSNSFirstPage", GetSNSFirstPage); 13 | ADD_PATH("/api/getSNSNextPage", GetSNSNextPage); 14 | ADD_PATH("/api/addFavFromMsg", AddFavFromMsg); 15 | 16 | ADD_PATH("/api/addFavFromImage", AddFavFromImage); 17 | ADD_PATH("/api/decodeImage", DecodeImage); 18 | ADD_PATH("/api/getVoiceByMsgId", GetVoiceByMsgId); 19 | ADD_PATH("/api/ocr", DoOcrTask); 20 | 21 | ADD_PATH("/api/lockWeChat", LockWeChat); 22 | ADD_PATH("/api/unlockWeChat", UnlockWeChat); 23 | ADD_PATH("/api/clickEnterWeChat", ClickEnterWeChat); 24 | ADD_PATH("/api/getLoginUrl", GetLoginUrl); 25 | 26 | ADD_PATH("/api/translateVoice", TranslateVoice); 27 | ADD_PATH("/api/getTranslateVoiceText", GetTranslateVoiceText); 28 | ADD_PATH("/api/openUrlByWeChat", OpenUrlByWeChat); 29 | ADD_PATH("/api/confirmReceipt", ConfirmReceipt); 30 | ADD_PATH("/api/refuseReceipt",RefundReceipt); 31 | ADD_PATH("/api/downloadAttach", DownloadAttach); 32 | ADD_PATH("/api/verifyApply", VerifyApply); 33 | PATHS_END 34 | 35 | public: 36 | /// @brief 检查是否登录 37 | /// @param params json 38 | /// @return json 39 | static std::string CheckLogin(std::string params); 40 | /// @brief 获取登录用户信息 41 | /// @param params json 42 | /// @return json 43 | static std::string GetUserInfo(std::string params); 44 | /// @brief 朋友圈首页 45 | /// @param params json 46 | /// @return json 47 | static std::string GetSNSFirstPage(std::string params); 48 | /// @brief 朋友圈下一页 49 | /// @param params json 50 | /// @return json 51 | static std::string GetSNSNextPage(std::string params); 52 | /// @brief 收藏消息 53 | /// @param params json 54 | /// @return json 55 | static std::string AddFavFromMsg(std::string params); 56 | /// @brief 收藏图片 57 | /// @param params json 58 | /// @return json 59 | static std::string AddFavFromImage(std::string params); 60 | /// @brief 解码图片 61 | /// @param params json 62 | /// @return json 63 | static std::string DecodeImage(std::string params); 64 | /// @brief 获取语音文件 65 | /// @param params json 66 | /// @return json 67 | static std::string GetVoiceByMsgId(std::string params); 68 | /// @brief 图片ocr 69 | /// @param params json 70 | /// @return json 71 | static std::string DoOcrTask(std::string params); 72 | /// @brief 锁定微信 73 | /// @param params json 74 | /// @return json 75 | static std::string LockWeChat(std::string params); 76 | /// @brief 解锁微信 77 | /// @param params json 78 | /// @return json 79 | static std::string UnlockWeChat(std::string params); 80 | /// @brief 进入微信 81 | /// @param params json 82 | /// @return json 83 | static std::string ClickEnterWeChat(std::string params); 84 | /// @brief 获取登录url 85 | /// @param params json 86 | /// @return json 87 | static std::string GetLoginUrl(std::string params); 88 | /// @brief 语音转文本 89 | /// @param params json 90 | /// @return json 91 | static std::string TranslateVoice(std::string params); 92 | /// @brief 获取语音转文本结果 93 | /// @param params json 94 | /// @return json 95 | static std::string GetTranslateVoiceText(std::string params); 96 | /// @brief 通过浏览器打开url 97 | /// @param params json 98 | /// @return json 99 | static std::string OpenUrlByWeChat(std::string params); 100 | /// @brief 确认收款 101 | /// @param params json 102 | /// @return json 103 | static std::string ConfirmReceipt(std::string params); 104 | /// @brief 拒绝收款 105 | /// @param params json 106 | /// @return json 107 | static std::string RefundReceipt(std::string params); 108 | /// @brief 下载附件 109 | /// @param params json 110 | /// @return json 111 | static std::string DownloadAttach(std::string params); 112 | /// @brief 通过好友 113 | /// @param params json 114 | /// @return json 115 | static std::string VerifyApply(std::string params); 116 | }; 117 | } // namespace wxhelper 118 | 119 | #endif -------------------------------------------------------------------------------- /inc/nlohmann/adl_serializer.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | NLOHMANN_JSON_NAMESPACE_BEGIN 19 | 20 | /// @sa https://json.nlohmann.me/api/adl_serializer/ 21 | template 22 | struct adl_serializer 23 | { 24 | /// @brief convert a JSON value to any value type 25 | /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ 26 | template 27 | static auto from_json(BasicJsonType && j, TargetType& val) noexcept( 28 | noexcept(::nlohmann::from_json(std::forward(j), val))) 29 | -> decltype(::nlohmann::from_json(std::forward(j), val), void()) 30 | { 31 | ::nlohmann::from_json(std::forward(j), val); 32 | } 33 | 34 | /// @brief convert a JSON value to any value type 35 | /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ 36 | template 37 | static auto from_json(BasicJsonType && j) noexcept( 38 | noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) 39 | -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) 40 | { 41 | return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); 42 | } 43 | 44 | /// @brief convert any value type to a JSON value 45 | /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ 46 | template 47 | static auto to_json(BasicJsonType& j, TargetType && val) noexcept( 48 | noexcept(::nlohmann::to_json(j, std::forward(val)))) 49 | -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) 50 | { 51 | ::nlohmann::to_json(j, std::forward(val)); 52 | } 53 | }; 54 | 55 | NLOHMANN_JSON_NAMESPACE_END 56 | -------------------------------------------------------------------------------- /inc/nlohmann/byte_container_with_subtype.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include // uint8_t, uint64_t 12 | #include // tie 13 | #include // move 14 | 15 | #include 16 | 17 | NLOHMANN_JSON_NAMESPACE_BEGIN 18 | 19 | /// @brief an internal type for a backed binary type 20 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/ 21 | template 22 | class byte_container_with_subtype : public BinaryType 23 | { 24 | public: 25 | using container_type = BinaryType; 26 | using subtype_type = std::uint64_t; 27 | 28 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 29 | byte_container_with_subtype() noexcept(noexcept(container_type())) 30 | : container_type() 31 | {} 32 | 33 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 34 | byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) 35 | : container_type(b) 36 | {} 37 | 38 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 39 | byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) 40 | : container_type(std::move(b)) 41 | {} 42 | 43 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 44 | byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) 45 | : container_type(b) 46 | , m_subtype(subtype_) 47 | , m_has_subtype(true) 48 | {} 49 | 50 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 51 | byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) 52 | : container_type(std::move(b)) 53 | , m_subtype(subtype_) 54 | , m_has_subtype(true) 55 | {} 56 | 57 | bool operator==(const byte_container_with_subtype& rhs) const 58 | { 59 | return std::tie(static_cast(*this), m_subtype, m_has_subtype) == 60 | std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); 61 | } 62 | 63 | bool operator!=(const byte_container_with_subtype& rhs) const 64 | { 65 | return !(rhs == *this); 66 | } 67 | 68 | /// @brief sets the binary subtype 69 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/ 70 | void set_subtype(subtype_type subtype_) noexcept 71 | { 72 | m_subtype = subtype_; 73 | m_has_subtype = true; 74 | } 75 | 76 | /// @brief return the binary subtype 77 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/ 78 | constexpr subtype_type subtype() const noexcept 79 | { 80 | return m_has_subtype ? m_subtype : static_cast(-1); 81 | } 82 | 83 | /// @brief return whether the value has a subtype 84 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/ 85 | constexpr bool has_subtype() const noexcept 86 | { 87 | return m_has_subtype; 88 | } 89 | 90 | /// @brief clears the binary subtype 91 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/ 92 | void clear_subtype() noexcept 93 | { 94 | m_subtype = 0; 95 | m_has_subtype = false; 96 | } 97 | 98 | private: 99 | subtype_type m_subtype = 0; 100 | bool m_has_subtype = false; 101 | }; 102 | 103 | NLOHMANN_JSON_NAMESPACE_END 104 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/abi_macros.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | // This file contains all macro definitions affecting or depending on the ABI 12 | 13 | #ifndef JSON_SKIP_LIBRARY_VERSION_CHECK 14 | #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) 15 | #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 16 | #warning "Already included a different version of the library!" 17 | #endif 18 | #endif 19 | #endif 20 | 21 | #define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) 22 | #define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) 23 | #define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) 24 | 25 | #ifndef JSON_DIAGNOSTICS 26 | #define JSON_DIAGNOSTICS 0 27 | #endif 28 | 29 | #ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 30 | #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 31 | #endif 32 | 33 | #if JSON_DIAGNOSTICS 34 | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag 35 | #else 36 | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS 37 | #endif 38 | 39 | #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 40 | #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp 41 | #else 42 | #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON 43 | #endif 44 | 45 | #ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION 46 | #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 47 | #endif 48 | 49 | // Construct the namespace ABI tags component 50 | #define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b 51 | #define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ 52 | NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) 53 | 54 | #define NLOHMANN_JSON_ABI_TAGS \ 55 | NLOHMANN_JSON_ABI_TAGS_CONCAT( \ 56 | NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ 57 | NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) 58 | 59 | // Construct the namespace version component 60 | #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ 61 | _v ## major ## _ ## minor ## _ ## patch 62 | #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ 63 | NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) 64 | 65 | #if NLOHMANN_JSON_NAMESPACE_NO_VERSION 66 | #define NLOHMANN_JSON_NAMESPACE_VERSION 67 | #else 68 | #define NLOHMANN_JSON_NAMESPACE_VERSION \ 69 | NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ 70 | NLOHMANN_JSON_VERSION_MINOR, \ 71 | NLOHMANN_JSON_VERSION_PATCH) 72 | #endif 73 | 74 | // Combine namespace components 75 | #define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b 76 | #define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ 77 | NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) 78 | 79 | #ifndef NLOHMANN_JSON_NAMESPACE 80 | #define NLOHMANN_JSON_NAMESPACE \ 81 | nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ 82 | NLOHMANN_JSON_ABI_TAGS, \ 83 | NLOHMANN_JSON_NAMESPACE_VERSION) 84 | #endif 85 | 86 | #ifndef NLOHMANN_JSON_NAMESPACE_BEGIN 87 | #define NLOHMANN_JSON_NAMESPACE_BEGIN \ 88 | namespace nlohmann \ 89 | { \ 90 | inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ 91 | NLOHMANN_JSON_ABI_TAGS, \ 92 | NLOHMANN_JSON_NAMESPACE_VERSION) \ 93 | { 94 | #endif 95 | 96 | #ifndef NLOHMANN_JSON_NAMESPACE_END 97 | #define NLOHMANN_JSON_NAMESPACE_END \ 98 | } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ 99 | } // namespace nlohmann 100 | #endif 101 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/input/position_t.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include // size_t 12 | 13 | #include 14 | 15 | NLOHMANN_JSON_NAMESPACE_BEGIN 16 | namespace detail 17 | { 18 | 19 | /// struct to capture the start position of the current token 20 | struct position_t 21 | { 22 | /// the total number of characters read 23 | std::size_t chars_read_total = 0; 24 | /// the number of characters read in the current line 25 | std::size_t chars_read_current_line = 0; 26 | /// the number of lines read 27 | std::size_t lines_read = 0; 28 | 29 | /// conversion to size_t to preserve SAX interface 30 | constexpr operator size_t() const 31 | { 32 | return chars_read_total; 33 | } 34 | }; 35 | 36 | } // namespace detail 37 | NLOHMANN_JSON_NAMESPACE_END 38 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/iterators/internal_iterator.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | NLOHMANN_JSON_NAMESPACE_BEGIN 15 | namespace detail 16 | { 17 | 18 | /*! 19 | @brief an iterator value 20 | 21 | @note This structure could easily be a union, but MSVC currently does not allow 22 | unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. 23 | */ 24 | template struct internal_iterator 25 | { 26 | /// iterator for JSON objects 27 | typename BasicJsonType::object_t::iterator object_iterator {}; 28 | /// iterator for JSON arrays 29 | typename BasicJsonType::array_t::iterator array_iterator {}; 30 | /// generic iterator for all other types 31 | primitive_iterator_t primitive_iterator {}; 32 | }; 33 | 34 | } // namespace detail 35 | NLOHMANN_JSON_NAMESPACE_END 36 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/iterators/iterator_traits.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include // random_access_iterator_tag 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | NLOHMANN_JSON_NAMESPACE_BEGIN 18 | namespace detail 19 | { 20 | 21 | template 22 | struct iterator_types {}; 23 | 24 | template 25 | struct iterator_types < 26 | It, 27 | void_t> 29 | { 30 | using difference_type = typename It::difference_type; 31 | using value_type = typename It::value_type; 32 | using pointer = typename It::pointer; 33 | using reference = typename It::reference; 34 | using iterator_category = typename It::iterator_category; 35 | }; 36 | 37 | // This is required as some compilers implement std::iterator_traits in a way that 38 | // doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. 39 | template 40 | struct iterator_traits 41 | { 42 | }; 43 | 44 | template 45 | struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> 46 | : iterator_types 47 | { 48 | }; 49 | 50 | template 51 | struct iterator_traits::value>> 52 | { 53 | using iterator_category = std::random_access_iterator_tag; 54 | using value_type = T; 55 | using difference_type = ptrdiff_t; 56 | using pointer = T*; 57 | using reference = T&; 58 | }; 59 | 60 | } // namespace detail 61 | NLOHMANN_JSON_NAMESPACE_END 62 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/iterators/primitive_iterator.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include // ptrdiff_t 12 | #include // numeric_limits 13 | 14 | #include 15 | 16 | NLOHMANN_JSON_NAMESPACE_BEGIN 17 | namespace detail 18 | { 19 | 20 | /* 21 | @brief an iterator for primitive JSON types 22 | 23 | This class models an iterator for primitive JSON types (boolean, number, 24 | string). It's only purpose is to allow the iterator/const_iterator classes 25 | to "iterate" over primitive values. Internally, the iterator is modeled by 26 | a `difference_type` variable. Value begin_value (`0`) models the begin, 27 | end_value (`1`) models past the end. 28 | */ 29 | class primitive_iterator_t 30 | { 31 | private: 32 | using difference_type = std::ptrdiff_t; 33 | static constexpr difference_type begin_value = 0; 34 | static constexpr difference_type end_value = begin_value + 1; 35 | 36 | JSON_PRIVATE_UNLESS_TESTED: 37 | /// iterator as signed integer type 38 | difference_type m_it = (std::numeric_limits::min)(); 39 | 40 | public: 41 | constexpr difference_type get_value() const noexcept 42 | { 43 | return m_it; 44 | } 45 | 46 | /// set iterator to a defined beginning 47 | void set_begin() noexcept 48 | { 49 | m_it = begin_value; 50 | } 51 | 52 | /// set iterator to a defined past the end 53 | void set_end() noexcept 54 | { 55 | m_it = end_value; 56 | } 57 | 58 | /// return whether the iterator can be dereferenced 59 | constexpr bool is_begin() const noexcept 60 | { 61 | return m_it == begin_value; 62 | } 63 | 64 | /// return whether the iterator is at end 65 | constexpr bool is_end() const noexcept 66 | { 67 | return m_it == end_value; 68 | } 69 | 70 | friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 71 | { 72 | return lhs.m_it == rhs.m_it; 73 | } 74 | 75 | friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 76 | { 77 | return lhs.m_it < rhs.m_it; 78 | } 79 | 80 | primitive_iterator_t operator+(difference_type n) noexcept 81 | { 82 | auto result = *this; 83 | result += n; 84 | return result; 85 | } 86 | 87 | friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 88 | { 89 | return lhs.m_it - rhs.m_it; 90 | } 91 | 92 | primitive_iterator_t& operator++() noexcept 93 | { 94 | ++m_it; 95 | return *this; 96 | } 97 | 98 | primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) 99 | { 100 | auto result = *this; 101 | ++m_it; 102 | return result; 103 | } 104 | 105 | primitive_iterator_t& operator--() noexcept 106 | { 107 | --m_it; 108 | return *this; 109 | } 110 | 111 | primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) 112 | { 113 | auto result = *this; 114 | --m_it; 115 | return result; 116 | } 117 | 118 | primitive_iterator_t& operator+=(difference_type n) noexcept 119 | { 120 | m_it += n; 121 | return *this; 122 | } 123 | 124 | primitive_iterator_t& operator-=(difference_type n) noexcept 125 | { 126 | m_it -= n; 127 | return *this; 128 | } 129 | }; 130 | 131 | } // namespace detail 132 | NLOHMANN_JSON_NAMESPACE_END 133 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/json_custom_base_class.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include // conditional, is_same 12 | 13 | #include 14 | 15 | NLOHMANN_JSON_NAMESPACE_BEGIN 16 | namespace detail 17 | { 18 | 19 | /*! 20 | @brief Default base class of the @ref basic_json class. 21 | 22 | So that the correct implementations of the copy / move ctors / assign operators 23 | of @ref basic_json do not require complex case distinctions 24 | (no base class / custom base class used as customization point), 25 | @ref basic_json always has a base class. 26 | By default, this class is used because it is empty and thus has no effect 27 | on the behavior of @ref basic_json. 28 | */ 29 | struct json_default_base {}; 30 | 31 | template 32 | using json_base_class = typename std::conditional < 33 | std::is_same::value, 34 | json_default_base, 35 | T 36 | >::type; 37 | 38 | } // namespace detail 39 | NLOHMANN_JSON_NAMESPACE_END 40 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/json_ref.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | NLOHMANN_JSON_NAMESPACE_BEGIN 18 | namespace detail 19 | { 20 | 21 | template 22 | class json_ref 23 | { 24 | public: 25 | using value_type = BasicJsonType; 26 | 27 | json_ref(value_type&& value) 28 | : owned_value(std::move(value)) 29 | {} 30 | 31 | json_ref(const value_type& value) 32 | : value_ref(&value) 33 | {} 34 | 35 | json_ref(std::initializer_list init) 36 | : owned_value(init) 37 | {} 38 | 39 | template < 40 | class... Args, 41 | enable_if_t::value, int> = 0 > 42 | json_ref(Args && ... args) 43 | : owned_value(std::forward(args)...) 44 | {} 45 | 46 | // class should be movable only 47 | json_ref(json_ref&&) noexcept = default; 48 | json_ref(const json_ref&) = delete; 49 | json_ref& operator=(const json_ref&) = delete; 50 | json_ref& operator=(json_ref&&) = delete; 51 | ~json_ref() = default; 52 | 53 | value_type moved_or_copied() const 54 | { 55 | if (value_ref == nullptr) 56 | { 57 | return std::move(owned_value); 58 | } 59 | return *value_ref; 60 | } 61 | 62 | value_type const& operator*() const 63 | { 64 | return value_ref ? *value_ref : owned_value; 65 | } 66 | 67 | value_type const* operator->() const 68 | { 69 | return &** this; 70 | } 71 | 72 | private: 73 | mutable value_type owned_value = nullptr; 74 | value_type const* value_ref = nullptr; 75 | }; 76 | 77 | } // namespace detail 78 | NLOHMANN_JSON_NAMESPACE_END 79 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/macro_unscope.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | // restore clang diagnostic settings 12 | #if defined(__clang__) 13 | #pragma clang diagnostic pop 14 | #endif 15 | 16 | // clean up 17 | #undef JSON_ASSERT 18 | #undef JSON_INTERNAL_CATCH 19 | #undef JSON_THROW 20 | #undef JSON_PRIVATE_UNLESS_TESTED 21 | #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION 22 | #undef NLOHMANN_BASIC_JSON_TPL 23 | #undef JSON_EXPLICIT 24 | #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL 25 | #undef JSON_INLINE_VARIABLE 26 | #undef JSON_NO_UNIQUE_ADDRESS 27 | #undef JSON_DISABLE_ENUM_SERIALIZATION 28 | #undef JSON_USE_GLOBAL_UDLS 29 | 30 | #ifndef JSON_TEST_KEEP_MACROS 31 | #undef JSON_CATCH 32 | #undef JSON_TRY 33 | #undef JSON_HAS_CPP_11 34 | #undef JSON_HAS_CPP_14 35 | #undef JSON_HAS_CPP_17 36 | #undef JSON_HAS_CPP_20 37 | #undef JSON_HAS_FILESYSTEM 38 | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM 39 | #undef JSON_HAS_THREE_WAY_COMPARISON 40 | #undef JSON_HAS_RANGES 41 | #undef JSON_HAS_STATIC_RTTI 42 | #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 43 | #endif 44 | 45 | #include 46 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/call_std/begin.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | NLOHMANN_JSON_NAMESPACE_BEGIN 14 | 15 | NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); 16 | 17 | NLOHMANN_JSON_NAMESPACE_END 18 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/call_std/end.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | NLOHMANN_JSON_NAMESPACE_BEGIN 14 | 15 | NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); 16 | 17 | NLOHMANN_JSON_NAMESPACE_END 18 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/detected.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | #include 14 | 15 | NLOHMANN_JSON_NAMESPACE_BEGIN 16 | namespace detail 17 | { 18 | 19 | // https://en.cppreference.com/w/cpp/experimental/is_detected 20 | struct nonesuch 21 | { 22 | nonesuch() = delete; 23 | ~nonesuch() = delete; 24 | nonesuch(nonesuch const&) = delete; 25 | nonesuch(nonesuch const&&) = delete; 26 | void operator=(nonesuch const&) = delete; 27 | void operator=(nonesuch&&) = delete; 28 | }; 29 | 30 | template class Op, 33 | class... Args> 34 | struct detector 35 | { 36 | using value_t = std::false_type; 37 | using type = Default; 38 | }; 39 | 40 | template class Op, class... Args> 41 | struct detector>, Op, Args...> 42 | { 43 | using value_t = std::true_type; 44 | using type = Op; 45 | }; 46 | 47 | template class Op, class... Args> 48 | using is_detected = typename detector::value_t; 49 | 50 | template class Op, class... Args> 51 | struct is_detected_lazy : is_detected { }; 52 | 53 | template class Op, class... Args> 54 | using detected_t = typename detector::type; 55 | 56 | template class Op, class... Args> 57 | using detected_or = detector; 58 | 59 | template class Op, class... Args> 60 | using detected_or_t = typename detected_or::type; 61 | 62 | template class Op, class... Args> 63 | using is_detected_exact = std::is_same>; 64 | 65 | template class Op, class... Args> 66 | using is_detected_convertible = 67 | std::is_convertible, To>; 68 | 69 | } // namespace detail 70 | NLOHMANN_JSON_NAMESPACE_END 71 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/identity_tag.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | NLOHMANN_JSON_NAMESPACE_BEGIN 14 | namespace detail 15 | { 16 | 17 | // dispatching helper struct 18 | template struct identity_tag {}; 19 | 20 | } // namespace detail 21 | NLOHMANN_JSON_NAMESPACE_END 22 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/std_fs.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | #if JSON_HAS_EXPERIMENTAL_FILESYSTEM 14 | #include 15 | NLOHMANN_JSON_NAMESPACE_BEGIN 16 | namespace detail 17 | { 18 | namespace std_fs = std::experimental::filesystem; 19 | } // namespace detail 20 | NLOHMANN_JSON_NAMESPACE_END 21 | #elif JSON_HAS_FILESYSTEM 22 | #include 23 | NLOHMANN_JSON_NAMESPACE_BEGIN 24 | namespace detail 25 | { 26 | namespace std_fs = std::filesystem; 27 | } // namespace detail 28 | NLOHMANN_JSON_NAMESPACE_END 29 | #endif 30 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/void_t.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | NLOHMANN_JSON_NAMESPACE_BEGIN 14 | namespace detail 15 | { 16 | 17 | template struct make_void 18 | { 19 | using type = void; 20 | }; 21 | template using void_t = typename make_void::type; 22 | 23 | } // namespace detail 24 | NLOHMANN_JSON_NAMESPACE_END 25 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/string_escape.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | NLOHMANN_JSON_NAMESPACE_BEGIN 14 | namespace detail 15 | { 16 | 17 | /*! 18 | @brief replace all occurrences of a substring by another string 19 | 20 | @param[in,out] s the string to manipulate; changed so that all 21 | occurrences of @a f are replaced with @a t 22 | @param[in] f the substring to replace with @a t 23 | @param[in] t the string to replace @a f 24 | 25 | @pre The search string @a f must not be empty. **This precondition is 26 | enforced with an assertion.** 27 | 28 | @since version 2.0.0 29 | */ 30 | template 31 | inline void replace_substring(StringType& s, const StringType& f, 32 | const StringType& t) 33 | { 34 | JSON_ASSERT(!f.empty()); 35 | for (auto pos = s.find(f); // find first occurrence of f 36 | pos != StringType::npos; // make sure f was found 37 | s.replace(pos, f.size(), t), // replace with t, and 38 | pos = s.find(f, pos + t.size())) // find next occurrence of f 39 | {} 40 | } 41 | 42 | /*! 43 | * @brief string escaping as described in RFC 6901 (Sect. 4) 44 | * @param[in] s string to escape 45 | * @return escaped string 46 | * 47 | * Note the order of escaping "~" to "~0" and "/" to "~1" is important. 48 | */ 49 | template 50 | inline StringType escape(StringType s) 51 | { 52 | replace_substring(s, StringType{"~"}, StringType{"~0"}); 53 | replace_substring(s, StringType{"/"}, StringType{"~1"}); 54 | return s; 55 | } 56 | 57 | /*! 58 | * @brief string unescaping as described in RFC 6901 (Sect. 4) 59 | * @param[in] s string to unescape 60 | * @return unescaped string 61 | * 62 | * Note the order of escaping "~1" to "/" and "~0" to "~" is important. 63 | */ 64 | template 65 | static void unescape(StringType& s) 66 | { 67 | replace_substring(s, StringType{"~1"}, StringType{"/"}); 68 | replace_substring(s, StringType{"~0"}, StringType{"~"}); 69 | } 70 | 71 | } // namespace detail 72 | NLOHMANN_JSON_NAMESPACE_END 73 | -------------------------------------------------------------------------------- /inc/nlohmann/json_fwd.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.11.3 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ 10 | #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ 11 | 12 | #include // int64_t, uint64_t 13 | #include // map 14 | #include // allocator 15 | #include // string 16 | #include // vector 17 | 18 | #include 19 | 20 | /*! 21 | @brief namespace for Niels Lohmann 22 | @see https://github.com/nlohmann 23 | @since version 1.0.0 24 | */ 25 | NLOHMANN_JSON_NAMESPACE_BEGIN 26 | 27 | /*! 28 | @brief default JSONSerializer template argument 29 | 30 | This serializer ignores the template arguments and uses ADL 31 | ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) 32 | for serialization. 33 | */ 34 | template 35 | struct adl_serializer; 36 | 37 | /// a class to store JSON values 38 | /// @sa https://json.nlohmann.me/api/basic_json/ 39 | template class ObjectType = 40 | std::map, 41 | template class ArrayType = std::vector, 42 | class StringType = std::string, class BooleanType = bool, 43 | class NumberIntegerType = std::int64_t, 44 | class NumberUnsignedType = std::uint64_t, 45 | class NumberFloatType = double, 46 | template class AllocatorType = std::allocator, 47 | template class JSONSerializer = 48 | adl_serializer, 49 | class BinaryType = std::vector, // cppcheck-suppress syntaxError 50 | class CustomBaseClass = void> 51 | class basic_json; 52 | 53 | /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document 54 | /// @sa https://json.nlohmann.me/api/json_pointer/ 55 | template 56 | class json_pointer; 57 | 58 | /*! 59 | @brief default specialization 60 | @sa https://json.nlohmann.me/api/json/ 61 | */ 62 | using json = basic_json<>; 63 | 64 | /// @brief a minimal map-like container that preserves insertion order 65 | /// @sa https://json.nlohmann.me/api/ordered_map/ 66 | template 67 | struct ordered_map; 68 | 69 | /// @brief specialization that maintains the insertion order of object keys 70 | /// @sa https://json.nlohmann.me/api/ordered_json/ 71 | using ordered_json = basic_json; 72 | 73 | NLOHMANN_JSON_NAMESPACE_END 74 | 75 | #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ 76 | -------------------------------------------------------------------------------- /inc/spdlog/async.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // 7 | // Async logging using global thread pool 8 | // All loggers created here share same global thread pool. 9 | // Each log message is pushed to a queue along with a shared pointer to the 10 | // logger. 11 | // If a logger deleted while having pending messages in the queue, it's actual 12 | // destruction will defer 13 | // until all its messages are processed by the thread pool. 14 | // This is because each message in the queue holds a shared_ptr to the 15 | // originating logger. 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace spdlog { 26 | 27 | namespace details { 28 | static const size_t default_async_q_size = 8192; 29 | } 30 | 31 | // async logger factory - creates async loggers backed with thread pool. 32 | // if a global thread pool doesn't already exist, create it with default queue 33 | // size of 8192 items and single thread. 34 | template 35 | struct async_factory_impl { 36 | template 37 | static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) { 38 | auto ®istry_inst = details::registry::instance(); 39 | 40 | // create global thread pool if not already exists.. 41 | 42 | auto &mutex = registry_inst.tp_mutex(); 43 | std::lock_guard tp_lock(mutex); 44 | auto tp = registry_inst.get_tp(); 45 | if (tp == nullptr) { 46 | tp = std::make_shared(details::default_async_q_size, 1U); 47 | registry_inst.set_tp(tp); 48 | } 49 | 50 | auto sink = std::make_shared(std::forward(args)...); 51 | auto new_logger = std::make_shared(std::move(logger_name), std::move(sink), 52 | std::move(tp), OverflowPolicy); 53 | registry_inst.initialize_logger(new_logger); 54 | return new_logger; 55 | } 56 | }; 57 | 58 | using async_factory = async_factory_impl; 59 | using async_factory_nonblock = async_factory_impl; 60 | 61 | template 62 | inline std::shared_ptr create_async(std::string logger_name, 63 | SinkArgs &&...sink_args) { 64 | return async_factory::create(std::move(logger_name), 65 | std::forward(sink_args)...); 66 | } 67 | 68 | template 69 | inline std::shared_ptr create_async_nb(std::string logger_name, 70 | SinkArgs &&...sink_args) { 71 | return async_factory_nonblock::create(std::move(logger_name), 72 | std::forward(sink_args)...); 73 | } 74 | 75 | // set global thread pool. 76 | inline void init_thread_pool(size_t q_size, 77 | size_t thread_count, 78 | std::function on_thread_start, 79 | std::function on_thread_stop) { 80 | auto tp = std::make_shared(q_size, thread_count, on_thread_start, 81 | on_thread_stop); 82 | details::registry::instance().set_tp(std::move(tp)); 83 | } 84 | 85 | inline void init_thread_pool(size_t q_size, 86 | size_t thread_count, 87 | std::function on_thread_start) { 88 | init_thread_pool(q_size, thread_count, on_thread_start, [] {}); 89 | } 90 | 91 | inline void init_thread_pool(size_t q_size, size_t thread_count) { 92 | init_thread_pool( 93 | q_size, thread_count, [] {}, [] {}); 94 | } 95 | 96 | // get the global thread pool. 97 | inline std::shared_ptr thread_pool() { 98 | return details::registry::instance().get_tp(); 99 | } 100 | } // namespace spdlog 101 | -------------------------------------------------------------------------------- /inc/spdlog/async_logger-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name, 17 | sinks_init_list sinks_list, 18 | std::weak_ptr tp, 19 | async_overflow_policy overflow_policy) 20 | : async_logger(std::move(logger_name), 21 | sinks_list.begin(), 22 | sinks_list.end(), 23 | std::move(tp), 24 | overflow_policy) {} 25 | 26 | SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name, 27 | sink_ptr single_sink, 28 | std::weak_ptr tp, 29 | async_overflow_policy overflow_policy) 30 | : async_logger( 31 | std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) {} 32 | 33 | // send the log message to the thread pool 34 | SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){ 35 | SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){ 36 | pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); 37 | } 38 | else { 39 | throw_spdlog_ex("async log: thread pool doesn't exist anymore"); 40 | } 41 | } 42 | SPDLOG_LOGGER_CATCH(msg.source) 43 | } 44 | 45 | // send flush request to the thread pool 46 | SPDLOG_INLINE void spdlog::async_logger::flush_(){ 47 | SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){ 48 | pool_ptr->post_flush(shared_from_this(), overflow_policy_); 49 | } 50 | else { 51 | throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); 52 | } 53 | } 54 | SPDLOG_LOGGER_CATCH(source_loc()) 55 | } 56 | 57 | // 58 | // backend functions - called from the thread pool to do the actual job 59 | // 60 | SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) { 61 | for (auto &sink : sinks_) { 62 | if (sink->should_log(msg.level)) { 63 | SPDLOG_TRY { sink->log(msg); } 64 | SPDLOG_LOGGER_CATCH(msg.source) 65 | } 66 | } 67 | 68 | if (should_flush_(msg)) { 69 | backend_flush_(); 70 | } 71 | } 72 | 73 | SPDLOG_INLINE void spdlog::async_logger::backend_flush_() { 74 | for (auto &sink : sinks_) { 75 | SPDLOG_TRY { sink->flush(); } 76 | SPDLOG_LOGGER_CATCH(source_loc()) 77 | } 78 | } 79 | 80 | SPDLOG_INLINE std::shared_ptr spdlog::async_logger::clone(std::string new_name) { 81 | auto cloned = std::make_shared(*this); 82 | cloned->name_ = std::move(new_name); 83 | return cloned; 84 | } 85 | -------------------------------------------------------------------------------- /inc/spdlog/async_logger.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Fast asynchronous logger. 7 | // Uses pre allocated queue. 8 | // Creates a single back thread to pop messages from the queue and log them. 9 | // 10 | // Upon each log write the logger: 11 | // 1. Checks if its log level is enough to log the message 12 | // 2. Push a new copy of the message to a queue (or block the caller until 13 | // space is available in the queue) 14 | // Upon destruction, logs all remaining messages in the queue before 15 | // destructing.. 16 | 17 | #include 18 | 19 | namespace spdlog { 20 | 21 | // Async overflow policy - block by default. 22 | enum class async_overflow_policy { 23 | block, // Block until message can be enqueued 24 | overrun_oldest, // Discard oldest message in the queue if full when trying to 25 | // add new item. 26 | discard_new // Discard new message if the queue is full when trying to add new item. 27 | }; 28 | 29 | namespace details { 30 | class thread_pool; 31 | } 32 | 33 | class SPDLOG_API async_logger final : public std::enable_shared_from_this, 34 | public logger { 35 | friend class details::thread_pool; 36 | 37 | public: 38 | template 39 | async_logger(std::string logger_name, 40 | It begin, 41 | It end, 42 | std::weak_ptr tp, 43 | async_overflow_policy overflow_policy = async_overflow_policy::block) 44 | : logger(std::move(logger_name), begin, end), 45 | thread_pool_(std::move(tp)), 46 | overflow_policy_(overflow_policy) {} 47 | 48 | async_logger(std::string logger_name, 49 | sinks_init_list sinks_list, 50 | std::weak_ptr tp, 51 | async_overflow_policy overflow_policy = async_overflow_policy::block); 52 | 53 | async_logger(std::string logger_name, 54 | sink_ptr single_sink, 55 | std::weak_ptr tp, 56 | async_overflow_policy overflow_policy = async_overflow_policy::block); 57 | 58 | std::shared_ptr clone(std::string new_name) override; 59 | 60 | protected: 61 | void sink_it_(const details::log_msg &msg) override; 62 | void flush_() override; 63 | void backend_sink_it_(const details::log_msg &incoming_log_msg); 64 | void backend_flush_(); 65 | 66 | private: 67 | std::weak_ptr thread_pool_; 68 | async_overflow_policy overflow_policy_; 69 | }; 70 | } // namespace spdlog 71 | 72 | #ifdef SPDLOG_HEADER_ONLY 73 | #include "async_logger-inl.h" 74 | #endif 75 | -------------------------------------------------------------------------------- /inc/spdlog/cfg/argv.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | 8 | // 9 | // Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" 10 | // 11 | // set all loggers to debug level: 12 | // example.exe "SPDLOG_LEVEL=debug" 13 | 14 | // set logger1 to trace level 15 | // example.exe "SPDLOG_LEVEL=logger1=trace" 16 | 17 | // turn off all logging except for logger1 and logger2: 18 | // example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" 19 | 20 | namespace spdlog { 21 | namespace cfg { 22 | 23 | // search for SPDLOG_LEVEL= in the args and use it to init the levels 24 | inline void load_argv_levels(int argc, const char **argv) { 25 | const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; 26 | for (int i = 1; i < argc; i++) { 27 | std::string arg = argv[i]; 28 | if (arg.find(spdlog_level_prefix) == 0) { 29 | auto levels_string = arg.substr(spdlog_level_prefix.size()); 30 | helpers::load_levels(levels_string); 31 | } 32 | } 33 | } 34 | 35 | inline void load_argv_levels(int argc, char **argv) { 36 | load_argv_levels(argc, const_cast(argv)); 37 | } 38 | 39 | } // namespace cfg 40 | } // namespace spdlog 41 | -------------------------------------------------------------------------------- /inc/spdlog/cfg/env.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | // 10 | // Init levels and patterns from env variables SPDLOG_LEVEL 11 | // Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). 12 | // Note - fallback to "info" level on unrecognized levels 13 | // 14 | // Examples: 15 | // 16 | // set global level to debug: 17 | // export SPDLOG_LEVEL=debug 18 | // 19 | // turn off all logging except for logger1: 20 | // export SPDLOG_LEVEL="*=off,logger1=debug" 21 | // 22 | 23 | // turn off all logging except for logger1 and logger2: 24 | // export SPDLOG_LEVEL="off,logger1=debug,logger2=info" 25 | 26 | namespace spdlog { 27 | namespace cfg { 28 | inline void load_env_levels() { 29 | auto env_val = details::os::getenv("SPDLOG_LEVEL"); 30 | if (!env_val.empty()) { 31 | helpers::load_levels(env_val); 32 | } 33 | } 34 | 35 | } // namespace cfg 36 | } // namespace spdlog 37 | -------------------------------------------------------------------------------- /inc/spdlog/cfg/helpers-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace spdlog { 20 | namespace cfg { 21 | namespace helpers { 22 | 23 | // inplace convert to lowercase 24 | inline std::string &to_lower_(std::string &str) { 25 | std::transform(str.begin(), str.end(), str.begin(), [](char ch) { 26 | return static_cast((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); 27 | }); 28 | return str; 29 | } 30 | 31 | // inplace trim spaces 32 | inline std::string &trim_(std::string &str) { 33 | const char *spaces = " \n\r\t"; 34 | str.erase(str.find_last_not_of(spaces) + 1); 35 | str.erase(0, str.find_first_not_of(spaces)); 36 | return str; 37 | } 38 | 39 | // return (name,value) trimmed pair from given "name=value" string. 40 | // return empty string on missing parts 41 | // "key=val" => ("key", "val") 42 | // " key = val " => ("key", "val") 43 | // "key=" => ("key", "") 44 | // "val" => ("", "val") 45 | 46 | inline std::pair extract_kv_(char sep, const std::string &str) { 47 | auto n = str.find(sep); 48 | std::string k, v; 49 | if (n == std::string::npos) { 50 | v = str; 51 | } else { 52 | k = str.substr(0, n); 53 | v = str.substr(n + 1); 54 | } 55 | return std::make_pair(trim_(k), trim_(v)); 56 | } 57 | 58 | // return vector of key/value pairs from sequence of "K1=V1,K2=V2,.." 59 | // "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} 60 | inline std::unordered_map extract_key_vals_(const std::string &str) { 61 | std::string token; 62 | std::istringstream token_stream(str); 63 | std::unordered_map rv{}; 64 | while (std::getline(token_stream, token, ',')) { 65 | if (token.empty()) { 66 | continue; 67 | } 68 | auto kv = extract_kv_('=', token); 69 | rv[kv.first] = kv.second; 70 | } 71 | return rv; 72 | } 73 | 74 | SPDLOG_INLINE void load_levels(const std::string &input) { 75 | if (input.empty() || input.size() > 512) { 76 | return; 77 | } 78 | 79 | auto key_vals = extract_key_vals_(input); 80 | std::unordered_map levels; 81 | level::level_enum global_level = level::info; 82 | bool global_level_found = false; 83 | 84 | for (auto &name_level : key_vals) { 85 | auto &logger_name = name_level.first; 86 | auto level_name = to_lower_(name_level.second); 87 | auto level = level::from_str(level_name); 88 | // ignore unrecognized level names 89 | if (level == level::off && level_name != "off") { 90 | continue; 91 | } 92 | if (logger_name.empty()) // no logger name indicate global level 93 | { 94 | global_level_found = true; 95 | global_level = level; 96 | } else { 97 | levels[logger_name] = level; 98 | } 99 | } 100 | 101 | details::registry::instance().set_levels(std::move(levels), 102 | global_level_found ? &global_level : nullptr); 103 | } 104 | 105 | } // namespace helpers 106 | } // namespace cfg 107 | } // namespace spdlog 108 | -------------------------------------------------------------------------------- /inc/spdlog/cfg/helpers.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace cfg { 11 | namespace helpers { 12 | // 13 | // Init levels from given string 14 | // 15 | // Examples: 16 | // 17 | // set global level to debug: "debug" 18 | // turn off all logging except for logger1: "off,logger1=debug" 19 | // turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" 20 | // 21 | SPDLOG_API void load_levels(const std::string &txt); 22 | } // namespace helpers 23 | 24 | } // namespace cfg 25 | } // namespace spdlog 26 | 27 | #ifdef SPDLOG_HEADER_ONLY 28 | #include "helpers-inl.h" 29 | #endif // SPDLOG_HEADER_ONLY 30 | -------------------------------------------------------------------------------- /inc/spdlog/common-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace level { 15 | 16 | #if __cplusplus >= 201703L 17 | constexpr 18 | #endif 19 | static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; 20 | 21 | static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; 22 | 23 | SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT { 24 | return level_string_views[l]; 25 | } 26 | 27 | SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT { 28 | return short_level_names[l]; 29 | } 30 | 31 | SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT { 32 | auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name); 33 | if (it != std::end(level_string_views)) 34 | return static_cast(std::distance(std::begin(level_string_views), it)); 35 | 36 | // check also for "warn" and "err" before giving up.. 37 | if (name == "warn") { 38 | return level::warn; 39 | } 40 | if (name == "err") { 41 | return level::err; 42 | } 43 | return level::off; 44 | } 45 | } // namespace level 46 | 47 | SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) 48 | : msg_(std::move(msg)) {} 49 | 50 | SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) { 51 | #ifdef SPDLOG_USE_STD_FORMAT 52 | msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); 53 | #else 54 | memory_buf_t outbuf; 55 | fmt::format_system_error(outbuf, last_errno, msg.c_str()); 56 | msg_ = fmt::to_string(outbuf); 57 | #endif 58 | } 59 | 60 | SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT { return msg_.c_str(); } 61 | 62 | SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) { 63 | SPDLOG_THROW(spdlog_ex(msg, last_errno)); 64 | } 65 | 66 | SPDLOG_INLINE void throw_spdlog_ex(std::string msg) { SPDLOG_THROW(spdlog_ex(std::move(msg))); } 67 | 68 | } // namespace spdlog 69 | -------------------------------------------------------------------------------- /inc/spdlog/details/backtracer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | namespace spdlog { 10 | namespace details { 11 | SPDLOG_INLINE backtracer::backtracer(const backtracer &other) { 12 | std::lock_guard lock(other.mutex_); 13 | enabled_ = other.enabled(); 14 | messages_ = other.messages_; 15 | } 16 | 17 | SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT { 18 | std::lock_guard lock(other.mutex_); 19 | enabled_ = other.enabled(); 20 | messages_ = std::move(other.messages_); 21 | } 22 | 23 | SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) { 24 | std::lock_guard lock(mutex_); 25 | enabled_ = other.enabled(); 26 | messages_ = std::move(other.messages_); 27 | return *this; 28 | } 29 | 30 | SPDLOG_INLINE void backtracer::enable(size_t size) { 31 | std::lock_guard lock{mutex_}; 32 | enabled_.store(true, std::memory_order_relaxed); 33 | messages_ = circular_q{size}; 34 | } 35 | 36 | SPDLOG_INLINE void backtracer::disable() { 37 | std::lock_guard lock{mutex_}; 38 | enabled_.store(false, std::memory_order_relaxed); 39 | } 40 | 41 | SPDLOG_INLINE bool backtracer::enabled() const { return enabled_.load(std::memory_order_relaxed); } 42 | 43 | SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) { 44 | std::lock_guard lock{mutex_}; 45 | messages_.push_back(log_msg_buffer{msg}); 46 | } 47 | 48 | SPDLOG_INLINE bool backtracer::empty() const { 49 | std::lock_guard lock{mutex_}; 50 | return messages_.empty(); 51 | } 52 | 53 | // pop all items in the q and apply the given fun on each of them. 54 | SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) { 55 | std::lock_guard lock{mutex_}; 56 | while (!messages_.empty()) { 57 | auto &front_msg = messages_.front(); 58 | fun(front_msg); 59 | messages_.pop_front(); 60 | } 61 | } 62 | } // namespace details 63 | } // namespace spdlog 64 | -------------------------------------------------------------------------------- /inc/spdlog/details/backtracer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // Store log messages in circular buffer. 14 | // Useful for storing debug data in case of error/warning happens. 15 | 16 | namespace spdlog { 17 | namespace details { 18 | class SPDLOG_API backtracer { 19 | mutable std::mutex mutex_; 20 | std::atomic enabled_{false}; 21 | circular_q messages_; 22 | 23 | public: 24 | backtracer() = default; 25 | backtracer(const backtracer &other); 26 | 27 | backtracer(backtracer &&other) SPDLOG_NOEXCEPT; 28 | backtracer &operator=(backtracer other); 29 | 30 | void enable(size_t size); 31 | void disable(); 32 | bool enabled() const; 33 | void push_back(const log_msg &msg); 34 | bool empty() const; 35 | 36 | // pop all items in the q and apply the given fun on each of them. 37 | void foreach_pop(std::function fun); 38 | }; 39 | 40 | } // namespace details 41 | } // namespace spdlog 42 | 43 | #ifdef SPDLOG_HEADER_ONLY 44 | #include "backtracer-inl.h" 45 | #endif 46 | -------------------------------------------------------------------------------- /inc/spdlog/details/circular_q.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | // circular q view of std::vector. 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace spdlog { 11 | namespace details { 12 | template 13 | class circular_q { 14 | size_t max_items_ = 0; 15 | typename std::vector::size_type head_ = 0; 16 | typename std::vector::size_type tail_ = 0; 17 | size_t overrun_counter_ = 0; 18 | std::vector v_; 19 | 20 | public: 21 | using value_type = T; 22 | 23 | // empty ctor - create a disabled queue with no elements allocated at all 24 | circular_q() = default; 25 | 26 | explicit circular_q(size_t max_items) 27 | : max_items_(max_items + 1) // one item is reserved as marker for full q 28 | , 29 | v_(max_items_) {} 30 | 31 | circular_q(const circular_q &) = default; 32 | circular_q &operator=(const circular_q &) = default; 33 | 34 | // move cannot be default, 35 | // since we need to reset head_, tail_, etc to zero in the moved object 36 | circular_q(circular_q &&other) SPDLOG_NOEXCEPT { copy_moveable(std::move(other)); } 37 | 38 | circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT { 39 | copy_moveable(std::move(other)); 40 | return *this; 41 | } 42 | 43 | // push back, overrun (oldest) item if no room left 44 | void push_back(T &&item) { 45 | if (max_items_ > 0) { 46 | v_[tail_] = std::move(item); 47 | tail_ = (tail_ + 1) % max_items_; 48 | 49 | if (tail_ == head_) // overrun last item if full 50 | { 51 | head_ = (head_ + 1) % max_items_; 52 | ++overrun_counter_; 53 | } 54 | } 55 | } 56 | 57 | // Return reference to the front item. 58 | // If there are no elements in the container, the behavior is undefined. 59 | const T &front() const { return v_[head_]; } 60 | 61 | T &front() { return v_[head_]; } 62 | 63 | // Return number of elements actually stored 64 | size_t size() const { 65 | if (tail_ >= head_) { 66 | return tail_ - head_; 67 | } else { 68 | return max_items_ - (head_ - tail_); 69 | } 70 | } 71 | 72 | // Return const reference to item by index. 73 | // If index is out of range 0…size()-1, the behavior is undefined. 74 | const T &at(size_t i) const { 75 | assert(i < size()); 76 | return v_[(head_ + i) % max_items_]; 77 | } 78 | 79 | // Pop item from front. 80 | // If there are no elements in the container, the behavior is undefined. 81 | void pop_front() { head_ = (head_ + 1) % max_items_; } 82 | 83 | bool empty() const { return tail_ == head_; } 84 | 85 | bool full() const { 86 | // head is ahead of the tail by 1 87 | if (max_items_ > 0) { 88 | return ((tail_ + 1) % max_items_) == head_; 89 | } 90 | return false; 91 | } 92 | 93 | size_t overrun_counter() const { return overrun_counter_; } 94 | 95 | void reset_overrun_counter() { overrun_counter_ = 0; } 96 | 97 | private: 98 | // copy from other&& and reset it to disabled state 99 | void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT { 100 | max_items_ = other.max_items_; 101 | head_ = other.head_; 102 | tail_ = other.tail_; 103 | overrun_counter_ = other.overrun_counter_; 104 | v_ = std::move(other.v_); 105 | 106 | // put &&other in disabled, but valid state 107 | other.max_items_ = 0; 108 | other.head_ = other.tail_ = 0; 109 | other.overrun_counter_ = 0; 110 | } 111 | }; 112 | } // namespace details 113 | } // namespace spdlog 114 | -------------------------------------------------------------------------------- /inc/spdlog/details/console_globals.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | struct console_mutex { 13 | using mutex_t = std::mutex; 14 | static mutex_t &mutex() { 15 | static mutex_t s_mutex; 16 | return s_mutex; 17 | } 18 | }; 19 | 20 | struct console_nullmutex { 21 | using mutex_t = null_mutex; 22 | static mutex_t &mutex() { 23 | static mutex_t s_mutex; 24 | return s_mutex; 25 | } 26 | }; 27 | } // namespace details 28 | } // namespace spdlog 29 | -------------------------------------------------------------------------------- /inc/spdlog/details/file_helper.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | // Helper class for file sinks. 13 | // When failing to open a file, retry several times(5) with a delay interval(10 ms). 14 | // Throw spdlog_ex exception on errors. 15 | 16 | class SPDLOG_API file_helper { 17 | public: 18 | file_helper() = default; 19 | explicit file_helper(const file_event_handlers &event_handlers); 20 | 21 | file_helper(const file_helper &) = delete; 22 | file_helper &operator=(const file_helper &) = delete; 23 | ~file_helper(); 24 | 25 | void open(const filename_t &fname, bool truncate = false); 26 | void reopen(bool truncate); 27 | void flush(); 28 | void sync(); 29 | void close(); 30 | void write(const memory_buf_t &buf); 31 | size_t size() const; 32 | const filename_t &filename() const; 33 | 34 | // 35 | // return file path and its extension: 36 | // 37 | // "mylog.txt" => ("mylog", ".txt") 38 | // "mylog" => ("mylog", "") 39 | // "mylog." => ("mylog.", "") 40 | // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") 41 | // 42 | // the starting dot in filenames is ignored (hidden files): 43 | // 44 | // ".mylog" => (".mylog". "") 45 | // "my_folder/.mylog" => ("my_folder/.mylog", "") 46 | // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") 47 | static std::tuple split_by_extension(const filename_t &fname); 48 | 49 | private: 50 | const int open_tries_ = 5; 51 | const unsigned int open_interval_ = 10; 52 | std::FILE *fd_{nullptr}; 53 | filename_t filename_; 54 | file_event_handlers event_handlers_; 55 | }; 56 | } // namespace details 57 | } // namespace spdlog 58 | 59 | #ifdef SPDLOG_HEADER_ONLY 60 | #include "file_helper-inl.h" 61 | #endif 62 | -------------------------------------------------------------------------------- /inc/spdlog/details/log_msg-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace details { 14 | 15 | SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, 16 | spdlog::source_loc loc, 17 | string_view_t a_logger_name, 18 | spdlog::level::level_enum lvl, 19 | spdlog::string_view_t msg) 20 | : logger_name(a_logger_name), 21 | level(lvl), 22 | time(log_time) 23 | #ifndef SPDLOG_NO_THREAD_ID 24 | , 25 | thread_id(os::thread_id()) 26 | #endif 27 | , 28 | source(loc), 29 | payload(msg) { 30 | } 31 | 32 | SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc, 33 | string_view_t a_logger_name, 34 | spdlog::level::level_enum lvl, 35 | spdlog::string_view_t msg) 36 | : log_msg(os::now(), loc, a_logger_name, lvl, msg) {} 37 | 38 | SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, 39 | spdlog::level::level_enum lvl, 40 | spdlog::string_view_t msg) 41 | : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) {} 42 | 43 | } // namespace details 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /inc/spdlog/details/log_msg.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | struct SPDLOG_API log_msg { 12 | log_msg() = default; 13 | log_msg(log_clock::time_point log_time, 14 | source_loc loc, 15 | string_view_t logger_name, 16 | level::level_enum lvl, 17 | string_view_t msg); 18 | log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); 19 | log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); 20 | log_msg(const log_msg &other) = default; 21 | log_msg &operator=(const log_msg &other) = default; 22 | 23 | string_view_t logger_name; 24 | level::level_enum level{level::off}; 25 | log_clock::time_point time; 26 | size_t thread_id{0}; 27 | 28 | // wrapping the formatted text with color (updated by pattern_formatter). 29 | mutable size_t color_range_start{0}; 30 | mutable size_t color_range_end{0}; 31 | 32 | source_loc source; 33 | string_view_t payload; 34 | }; 35 | } // namespace details 36 | } // namespace spdlog 37 | 38 | #ifdef SPDLOG_HEADER_ONLY 39 | #include "log_msg-inl.h" 40 | #endif 41 | -------------------------------------------------------------------------------- /inc/spdlog/details/log_msg_buffer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) 14 | : log_msg{orig_msg} { 15 | buffer.append(logger_name.begin(), logger_name.end()); 16 | buffer.append(payload.begin(), payload.end()); 17 | update_string_views(); 18 | } 19 | 20 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) 21 | : log_msg{other} { 22 | buffer.append(logger_name.begin(), logger_name.end()); 23 | buffer.append(payload.begin(), payload.end()); 24 | update_string_views(); 25 | } 26 | 27 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT 28 | : log_msg{other}, 29 | buffer{std::move(other.buffer)} { 30 | update_string_views(); 31 | } 32 | 33 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) { 34 | log_msg::operator=(other); 35 | buffer.clear(); 36 | buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); 37 | update_string_views(); 38 | return *this; 39 | } 40 | 41 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT { 42 | log_msg::operator=(other); 43 | buffer = std::move(other.buffer); 44 | update_string_views(); 45 | return *this; 46 | } 47 | 48 | SPDLOG_INLINE void log_msg_buffer::update_string_views() { 49 | logger_name = string_view_t{buffer.data(), logger_name.size()}; 50 | payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; 51 | } 52 | 53 | } // namespace details 54 | } // namespace spdlog 55 | -------------------------------------------------------------------------------- /inc/spdlog/details/log_msg_buffer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace spdlog { 9 | namespace details { 10 | 11 | // Extend log_msg with internal buffer to store its payload. 12 | // This is needed since log_msg holds string_views that points to stack data. 13 | 14 | class SPDLOG_API log_msg_buffer : public log_msg { 15 | memory_buf_t buffer; 16 | void update_string_views(); 17 | 18 | public: 19 | log_msg_buffer() = default; 20 | explicit log_msg_buffer(const log_msg &orig_msg); 21 | log_msg_buffer(const log_msg_buffer &other); 22 | log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 23 | log_msg_buffer &operator=(const log_msg_buffer &other); 24 | log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 25 | }; 26 | 27 | } // namespace details 28 | } // namespace spdlog 29 | 30 | #ifdef SPDLOG_HEADER_ONLY 31 | #include "log_msg_buffer-inl.h" 32 | #endif 33 | -------------------------------------------------------------------------------- /inc/spdlog/details/null_mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | // null, no cost dummy "mutex" and dummy "atomic" int 9 | 10 | namespace spdlog { 11 | namespace details { 12 | struct null_mutex { 13 | void lock() const {} 14 | void unlock() const {} 15 | }; 16 | 17 | struct null_atomic_int { 18 | int value; 19 | null_atomic_int() = default; 20 | 21 | explicit null_atomic_int(int new_value) 22 | : value(new_value) {} 23 | 24 | int load(std::memory_order = std::memory_order_relaxed) const { return value; } 25 | 26 | void store(int new_value, std::memory_order = std::memory_order_relaxed) { value = new_value; } 27 | 28 | int exchange(int new_value, std::memory_order = std::memory_order_relaxed) { 29 | std::swap(new_value, value); 30 | return new_value; // return value before the call 31 | } 32 | }; 33 | 34 | } // namespace details 35 | } // namespace spdlog 36 | -------------------------------------------------------------------------------- /inc/spdlog/details/periodic_worker-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | // stop the worker thread and join it 14 | SPDLOG_INLINE periodic_worker::~periodic_worker() { 15 | if (worker_thread_.joinable()) { 16 | { 17 | std::lock_guard lock(mutex_); 18 | active_ = false; 19 | } 20 | cv_.notify_one(); 21 | worker_thread_.join(); 22 | } 23 | } 24 | 25 | } // namespace details 26 | } // namespace spdlog 27 | -------------------------------------------------------------------------------- /inc/spdlog/details/periodic_worker.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // periodic worker thread - periodically executes the given callback function. 7 | // 8 | // RAII over the owned thread: 9 | // creates the thread on construction. 10 | // stops and joins the thread on destruction (if the thread is executing a callback, wait for it 11 | // to finish first). 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | namespace spdlog { 19 | namespace details { 20 | 21 | class SPDLOG_API periodic_worker { 22 | public: 23 | template 24 | periodic_worker(const std::function &callback_fun, 25 | std::chrono::duration interval) { 26 | active_ = (interval > std::chrono::duration::zero()); 27 | if (!active_) { 28 | return; 29 | } 30 | 31 | worker_thread_ = std::thread([this, callback_fun, interval]() { 32 | for (;;) { 33 | std::unique_lock lock(this->mutex_); 34 | if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) { 35 | return; // active_ == false, so exit this thread 36 | } 37 | callback_fun(); 38 | } 39 | }); 40 | } 41 | periodic_worker(const periodic_worker &) = delete; 42 | periodic_worker &operator=(const periodic_worker &) = delete; 43 | // stop the worker thread and join it 44 | ~periodic_worker(); 45 | 46 | private: 47 | bool active_; 48 | std::thread worker_thread_; 49 | std::mutex mutex_; 50 | std::condition_variable cv_; 51 | }; 52 | } // namespace details 53 | } // namespace spdlog 54 | 55 | #ifdef SPDLOG_HEADER_ONLY 56 | #include "periodic_worker-inl.h" 57 | #endif 58 | -------------------------------------------------------------------------------- /inc/spdlog/details/synchronous_factory.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "registry.h" 7 | 8 | namespace spdlog { 9 | 10 | // Default logger factory- creates synchronous loggers 11 | class logger; 12 | 13 | struct synchronous_factory { 14 | template 15 | static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) { 16 | auto sink = std::make_shared(std::forward(args)...); 17 | auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); 18 | details::registry::instance().initialize_logger(new_logger); 19 | return new_logger; 20 | } 21 | }; 22 | } // namespace spdlog 23 | -------------------------------------------------------------------------------- /inc/spdlog/details/tcp_client.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef _WIN32 7 | #error include tcp_client-windows.h instead 8 | #endif 9 | 10 | // tcp client helper 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | namespace spdlog { 24 | namespace details { 25 | class tcp_client { 26 | int socket_ = -1; 27 | 28 | public: 29 | bool is_connected() const { return socket_ != -1; } 30 | 31 | void close() { 32 | if (is_connected()) { 33 | ::close(socket_); 34 | socket_ = -1; 35 | } 36 | } 37 | 38 | int fd() const { return socket_; } 39 | 40 | ~tcp_client() { close(); } 41 | 42 | // try to connect or throw on failure 43 | void connect(const std::string &host, int port) { 44 | close(); 45 | struct addrinfo hints {}; 46 | memset(&hints, 0, sizeof(struct addrinfo)); 47 | hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on 48 | hints.ai_socktype = SOCK_STREAM; // TCP 49 | hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value 50 | hints.ai_protocol = 0; 51 | 52 | auto port_str = std::to_string(port); 53 | struct addrinfo *addrinfo_result; 54 | auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); 55 | if (rv != 0) { 56 | throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv))); 57 | } 58 | 59 | // Try each address until we successfully connect(2). 60 | int last_errno = 0; 61 | for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) { 62 | #if defined(SOCK_CLOEXEC) 63 | const int flags = SOCK_CLOEXEC; 64 | #else 65 | const int flags = 0; 66 | #endif 67 | socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol); 68 | if (socket_ == -1) { 69 | last_errno = errno; 70 | continue; 71 | } 72 | rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); 73 | if (rv == 0) { 74 | break; 75 | } 76 | last_errno = errno; 77 | ::close(socket_); 78 | socket_ = -1; 79 | } 80 | ::freeaddrinfo(addrinfo_result); 81 | if (socket_ == -1) { 82 | throw_spdlog_ex("::connect failed", last_errno); 83 | } 84 | 85 | // set TCP_NODELAY 86 | int enable_flag = 1; 87 | ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), 88 | sizeof(enable_flag)); 89 | 90 | // prevent sigpipe on systems where MSG_NOSIGNAL is not available 91 | #if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) 92 | ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast(&enable_flag), 93 | sizeof(enable_flag)); 94 | #endif 95 | 96 | #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) 97 | #error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available" 98 | #endif 99 | } 100 | 101 | // Send exactly n_bytes of the given data. 102 | // On error close the connection and throw. 103 | void send(const char *data, size_t n_bytes) { 104 | size_t bytes_sent = 0; 105 | while (bytes_sent < n_bytes) { 106 | #if defined(MSG_NOSIGNAL) 107 | const int send_flags = MSG_NOSIGNAL; 108 | #else 109 | const int send_flags = 0; 110 | #endif 111 | auto write_result = 112 | ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags); 113 | if (write_result < 0) { 114 | close(); 115 | throw_spdlog_ex("write(2) failed", errno); 116 | } 117 | 118 | if (write_result == 0) // (probably should not happen but in any case..) 119 | { 120 | break; 121 | } 122 | bytes_sent += static_cast(write_result); 123 | } 124 | } 125 | }; 126 | } // namespace details 127 | } // namespace spdlog 128 | -------------------------------------------------------------------------------- /inc/spdlog/details/thread_pool.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace spdlog { 17 | class async_logger; 18 | 19 | namespace details { 20 | 21 | using async_logger_ptr = std::shared_ptr; 22 | 23 | enum class async_msg_type { log, flush, terminate }; 24 | 25 | // Async msg to move to/from the queue 26 | // Movable only. should never be copied 27 | struct async_msg : log_msg_buffer { 28 | async_msg_type msg_type{async_msg_type::log}; 29 | async_logger_ptr worker_ptr; 30 | 31 | async_msg() = default; 32 | ~async_msg() = default; 33 | 34 | // should only be moved in or out of the queue.. 35 | async_msg(const async_msg &) = delete; 36 | 37 | // support for vs2013 move 38 | #if defined(_MSC_VER) && _MSC_VER <= 1800 39 | async_msg(async_msg &&other) 40 | : log_msg_buffer(std::move(other)), 41 | msg_type(other.msg_type), 42 | worker_ptr(std::move(other.worker_ptr)) {} 43 | 44 | async_msg &operator=(async_msg &&other) { 45 | *static_cast(this) = std::move(other); 46 | msg_type = other.msg_type; 47 | worker_ptr = std::move(other.worker_ptr); 48 | return *this; 49 | } 50 | #else // (_MSC_VER) && _MSC_VER <= 1800 51 | async_msg(async_msg &&) = default; 52 | async_msg &operator=(async_msg &&) = default; 53 | #endif 54 | 55 | // construct from log_msg with given type 56 | async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m) 57 | : log_msg_buffer{m}, 58 | msg_type{the_type}, 59 | worker_ptr{std::move(worker)} {} 60 | 61 | async_msg(async_logger_ptr &&worker, async_msg_type the_type) 62 | : log_msg_buffer{}, 63 | msg_type{the_type}, 64 | worker_ptr{std::move(worker)} {} 65 | 66 | explicit async_msg(async_msg_type the_type) 67 | : async_msg{nullptr, the_type} {} 68 | }; 69 | 70 | class SPDLOG_API thread_pool { 71 | public: 72 | using item_type = async_msg; 73 | using q_type = details::mpmc_blocking_queue; 74 | 75 | thread_pool(size_t q_max_items, 76 | size_t threads_n, 77 | std::function on_thread_start, 78 | std::function on_thread_stop); 79 | thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start); 80 | thread_pool(size_t q_max_items, size_t threads_n); 81 | 82 | // message all threads to terminate gracefully and join them 83 | ~thread_pool(); 84 | 85 | thread_pool(const thread_pool &) = delete; 86 | thread_pool &operator=(thread_pool &&) = delete; 87 | 88 | void post_log(async_logger_ptr &&worker_ptr, 89 | const details::log_msg &msg, 90 | async_overflow_policy overflow_policy); 91 | void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy); 92 | size_t overrun_counter(); 93 | void reset_overrun_counter(); 94 | size_t discard_counter(); 95 | void reset_discard_counter(); 96 | size_t queue_size(); 97 | 98 | private: 99 | q_type q_; 100 | 101 | std::vector threads_; 102 | 103 | void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy); 104 | void worker_loop_(); 105 | 106 | // process next message in the queue 107 | // return true if this thread should still be active (while no terminate msg 108 | // was received) 109 | bool process_next_msg_(); 110 | }; 111 | 112 | } // namespace details 113 | } // namespace spdlog 114 | 115 | #ifdef SPDLOG_HEADER_ONLY 116 | #include "thread_pool-inl.h" 117 | #endif 118 | -------------------------------------------------------------------------------- /inc/spdlog/details/udp_client-windows.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Helper RAII over winsock udp client socket. 7 | // Will throw on construction if socket creation failed. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if defined(_MSC_VER) 19 | #pragma comment(lib, "Ws2_32.lib") 20 | #pragma comment(lib, "Mswsock.lib") 21 | #pragma comment(lib, "AdvApi32.lib") 22 | #endif 23 | 24 | namespace spdlog { 25 | namespace details { 26 | class udp_client { 27 | static constexpr int TX_BUFFER_SIZE = 1024 * 10; 28 | SOCKET socket_ = INVALID_SOCKET; 29 | sockaddr_in addr_ = {}; 30 | 31 | static void init_winsock_() { 32 | WSADATA wsaData; 33 | auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData); 34 | if (rv != 0) { 35 | throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); 36 | } 37 | } 38 | 39 | static void throw_winsock_error_(const std::string &msg, int last_error) { 40 | char buf[512]; 41 | ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, 42 | last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 43 | (sizeof(buf) / sizeof(char)), NULL); 44 | 45 | throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf)); 46 | } 47 | 48 | void cleanup_() { 49 | if (socket_ != INVALID_SOCKET) { 50 | ::closesocket(socket_); 51 | } 52 | socket_ = INVALID_SOCKET; 53 | ::WSACleanup(); 54 | } 55 | 56 | public: 57 | udp_client(const std::string &host, uint16_t port) { 58 | init_winsock_(); 59 | 60 | addr_.sin_family = PF_INET; 61 | addr_.sin_port = htons(port); 62 | addr_.sin_addr.s_addr = INADDR_ANY; 63 | if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) { 64 | int last_error = ::WSAGetLastError(); 65 | ::WSACleanup(); 66 | throw_winsock_error_("error: Invalid address!", last_error); 67 | } 68 | 69 | socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); 70 | if (socket_ == INVALID_SOCKET) { 71 | int last_error = ::WSAGetLastError(); 72 | ::WSACleanup(); 73 | throw_winsock_error_("error: Create Socket failed", last_error); 74 | } 75 | 76 | int option_value = TX_BUFFER_SIZE; 77 | if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, 78 | reinterpret_cast(&option_value), sizeof(option_value)) < 0) { 79 | int last_error = ::WSAGetLastError(); 80 | cleanup_(); 81 | throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error); 82 | } 83 | } 84 | 85 | ~udp_client() { cleanup_(); } 86 | 87 | SOCKET fd() const { return socket_; } 88 | 89 | void send(const char *data, size_t n_bytes) { 90 | socklen_t tolen = sizeof(struct sockaddr); 91 | if (::sendto(socket_, data, static_cast(n_bytes), 0, (struct sockaddr *)&addr_, 92 | tolen) == -1) { 93 | throw_spdlog_ex("sendto(2) failed", errno); 94 | } 95 | } 96 | }; 97 | } // namespace details 98 | } // namespace spdlog 99 | -------------------------------------------------------------------------------- /inc/spdlog/details/udp_client.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Helper RAII over unix udp client socket. 7 | // Will throw on construction if the socket creation failed. 8 | 9 | #ifdef _WIN32 10 | #error "include udp_client-windows.h instead" 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | namespace spdlog { 26 | namespace details { 27 | 28 | class udp_client { 29 | static constexpr int TX_BUFFER_SIZE = 1024 * 10; 30 | int socket_ = -1; 31 | struct sockaddr_in sockAddr_; 32 | 33 | void cleanup_() { 34 | if (socket_ != -1) { 35 | ::close(socket_); 36 | socket_ = -1; 37 | } 38 | } 39 | 40 | public: 41 | udp_client(const std::string &host, uint16_t port) { 42 | socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); 43 | if (socket_ < 0) { 44 | throw_spdlog_ex("error: Create Socket Failed!"); 45 | } 46 | 47 | int option_value = TX_BUFFER_SIZE; 48 | if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, 49 | reinterpret_cast(&option_value), sizeof(option_value)) < 0) { 50 | cleanup_(); 51 | throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!"); 52 | } 53 | 54 | sockAddr_.sin_family = AF_INET; 55 | sockAddr_.sin_port = htons(port); 56 | 57 | if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) { 58 | cleanup_(); 59 | throw_spdlog_ex("error: Invalid address!"); 60 | } 61 | 62 | ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); 63 | } 64 | 65 | ~udp_client() { cleanup_(); } 66 | 67 | int fd() const { return socket_; } 68 | 69 | // Send exactly n_bytes of the given data. 70 | // On error close the connection and throw. 71 | void send(const char *data, size_t n_bytes) { 72 | ssize_t toslen = 0; 73 | socklen_t tolen = sizeof(struct sockaddr); 74 | if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == 75 | -1) { 76 | throw_spdlog_ex("sendto(2) failed", errno); 77 | } 78 | } 79 | }; 80 | } // namespace details 81 | } // namespace spdlog 82 | -------------------------------------------------------------------------------- /inc/spdlog/details/windows_include.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NOMINMAX 4 | #define NOMINMAX // prevent windows redefining min/max 5 | #endif 6 | 7 | #ifndef WIN32_LEAN_AND_MEAN 8 | #define WIN32_LEAN_AND_MEAN 9 | #endif 10 | 11 | #include 12 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/bundled/fmt.license.rst: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - present, Victor Zverovich 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | --- Optional exception to the license --- 23 | 24 | As an exception, if, as a result of your compiling your source code, portions 25 | of this Software are embedded into a machine-executable object form of such 26 | source code, you may redistribute such embedded portions in such object form 27 | without including the above copyright and permission notices. 28 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/bundled/locale.h: -------------------------------------------------------------------------------- 1 | #include "xchar.h" 2 | #warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead 3 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/chrono.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's chrono support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/compile.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's compile-time support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/fmt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016-2018 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | 8 | // 9 | // Include a bundled header-only copy of fmtlib or an external one. 10 | // By default spdlog include its own copy. 11 | // 12 | #include 13 | 14 | #if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format 15 | #include 16 | #elif !defined(SPDLOG_FMT_EXTERNAL) 17 | #if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) 18 | #define FMT_HEADER_ONLY 19 | #endif 20 | #ifndef FMT_USE_WINDOWS_H 21 | #define FMT_USE_WINDOWS_H 0 22 | #endif 23 | // enable the 'n' flag in for backward compatibility with fmt 6.x 24 | #define FMT_DEPRECATED_N_SPECIFIER 25 | // enable ostream formatting for backward compatibility with fmt 8.x 26 | #define FMT_DEPRECATED_OSTREAM 27 | 28 | #include 29 | #include 30 | 31 | #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib 32 | #include 33 | #include 34 | #endif 35 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/ostr.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ostream support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/ranges.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ranges support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/std.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's std support (for formatting e.g. 9 | // std::filesystem::path, std::thread::id, std::monostate, std::variant, ...) 10 | // 11 | #include 12 | 13 | #if !defined(SPDLOG_USE_STD_FORMAT) 14 | #if !defined(SPDLOG_FMT_EXTERNAL) 15 | #ifdef SPDLOG_HEADER_ONLY 16 | #ifndef FMT_HEADER_ONLY 17 | #define FMT_HEADER_ONLY 18 | #endif 19 | #endif 20 | #include 21 | #else 22 | #include 23 | #endif 24 | #endif 25 | -------------------------------------------------------------------------------- /inc/spdlog/fmt/xchar.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's xchar support 9 | // 10 | #include 11 | 12 | #if !defined(SPDLOG_USE_STD_FORMAT) 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #ifdef SPDLOG_HEADER_ONLY 15 | #ifndef FMT_HEADER_ONLY 16 | #define FMT_HEADER_ONLY 17 | #endif 18 | #endif 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /inc/spdlog/formatter.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | class formatter { 12 | public: 13 | virtual ~formatter() = default; 14 | virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; 15 | virtual std::unique_ptr clone() const = 0; 16 | }; 17 | } // namespace spdlog 18 | -------------------------------------------------------------------------------- /inc/spdlog/fwd.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | namespace spdlog { 7 | class logger; 8 | class formatter; 9 | 10 | namespace sinks { 11 | class sink; 12 | } 13 | 14 | namespace level { 15 | enum level_enum : int; 16 | } 17 | 18 | } // namespace spdlog 19 | -------------------------------------------------------------------------------- /inc/spdlog/pattern_formatter.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace spdlog { 20 | namespace details { 21 | 22 | // padding information. 23 | struct padding_info { 24 | enum class pad_side { left, right, center }; 25 | 26 | padding_info() = default; 27 | padding_info(size_t width, padding_info::pad_side side, bool truncate) 28 | : width_(width), 29 | side_(side), 30 | truncate_(truncate), 31 | enabled_(true) {} 32 | 33 | bool enabled() const { return enabled_; } 34 | size_t width_ = 0; 35 | pad_side side_ = pad_side::left; 36 | bool truncate_ = false; 37 | bool enabled_ = false; 38 | }; 39 | 40 | class SPDLOG_API flag_formatter { 41 | public: 42 | explicit flag_formatter(padding_info padinfo) 43 | : padinfo_(padinfo) {} 44 | flag_formatter() = default; 45 | virtual ~flag_formatter() = default; 46 | virtual void format(const details::log_msg &msg, 47 | const std::tm &tm_time, 48 | memory_buf_t &dest) = 0; 49 | 50 | protected: 51 | padding_info padinfo_; 52 | }; 53 | 54 | } // namespace details 55 | 56 | class SPDLOG_API custom_flag_formatter : public details::flag_formatter { 57 | public: 58 | virtual std::unique_ptr clone() const = 0; 59 | 60 | void set_padding_info(const details::padding_info &padding) { 61 | flag_formatter::padinfo_ = padding; 62 | } 63 | }; 64 | 65 | class SPDLOG_API pattern_formatter final : public formatter { 66 | public: 67 | using custom_flags = std::unordered_map>; 68 | 69 | explicit pattern_formatter(std::string pattern, 70 | pattern_time_type time_type = pattern_time_type::local, 71 | std::string eol = spdlog::details::os::default_eol, 72 | custom_flags custom_user_flags = custom_flags()); 73 | 74 | // use default pattern is not given 75 | explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, 76 | std::string eol = spdlog::details::os::default_eol); 77 | 78 | pattern_formatter(const pattern_formatter &other) = delete; 79 | pattern_formatter &operator=(const pattern_formatter &other) = delete; 80 | 81 | std::unique_ptr clone() const override; 82 | void format(const details::log_msg &msg, memory_buf_t &dest) override; 83 | 84 | template 85 | pattern_formatter &add_flag(char flag, Args &&...args) { 86 | custom_handlers_[flag] = details::make_unique(std::forward(args)...); 87 | return *this; 88 | } 89 | void set_pattern(std::string pattern); 90 | void need_localtime(bool need = true); 91 | 92 | private: 93 | std::string pattern_; 94 | std::string eol_; 95 | pattern_time_type pattern_time_type_; 96 | bool need_localtime_; 97 | std::tm cached_tm_; 98 | std::chrono::seconds last_log_secs_; 99 | std::vector> formatters_; 100 | custom_flags custom_handlers_; 101 | 102 | std::tm get_time_(const details::log_msg &msg); 103 | template 104 | void handle_flag_(char flag, details::padding_info padding); 105 | 106 | // Extract given pad spec (e.g. %8X) 107 | // Advance the given it pass the end of the padding spec found (if any) 108 | // Return padding. 109 | static details::padding_info handle_padspec_(std::string::const_iterator &it, 110 | std::string::const_iterator end); 111 | 112 | void compile_pattern_(const std::string &pattern); 113 | }; 114 | } // namespace spdlog 115 | 116 | #ifdef SPDLOG_HEADER_ONLY 117 | #include "pattern_formatter-inl.h" 118 | #endif 119 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/base_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | template 17 | SPDLOG_INLINE spdlog::sinks::base_sink::base_sink() 18 | : formatter_{details::make_unique()} {} 19 | 20 | template 21 | SPDLOG_INLINE spdlog::sinks::base_sink::base_sink( 22 | std::unique_ptr formatter) 23 | : formatter_{std::move(formatter)} {} 24 | 25 | template 26 | void SPDLOG_INLINE spdlog::sinks::base_sink::log(const details::log_msg &msg) { 27 | std::lock_guard lock(mutex_); 28 | sink_it_(msg); 29 | } 30 | 31 | template 32 | void SPDLOG_INLINE spdlog::sinks::base_sink::flush() { 33 | std::lock_guard lock(mutex_); 34 | flush_(); 35 | } 36 | 37 | template 38 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern(const std::string &pattern) { 39 | std::lock_guard lock(mutex_); 40 | set_pattern_(pattern); 41 | } 42 | 43 | template 44 | void SPDLOG_INLINE 45 | spdlog::sinks::base_sink::set_formatter(std::unique_ptr sink_formatter) { 46 | std::lock_guard lock(mutex_); 47 | set_formatter_(std::move(sink_formatter)); 48 | } 49 | 50 | template 51 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern_(const std::string &pattern) { 52 | set_formatter_(details::make_unique(pattern)); 53 | } 54 | 55 | template 56 | void SPDLOG_INLINE 57 | spdlog::sinks::base_sink::set_formatter_(std::unique_ptr sink_formatter) { 58 | formatter_ = std::move(sink_formatter); 59 | } 60 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/base_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | // 6 | // base sink templated over a mutex (either dummy or real) 7 | // concrete implementation should override the sink_it_() and flush_() methods. 8 | // locking is taken care of in this class - no locking needed by the 9 | // implementers.. 10 | // 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace spdlog { 17 | namespace sinks { 18 | template 19 | class SPDLOG_API base_sink : public sink { 20 | public: 21 | base_sink(); 22 | explicit base_sink(std::unique_ptr formatter); 23 | ~base_sink() override = default; 24 | 25 | base_sink(const base_sink &) = delete; 26 | base_sink(base_sink &&) = delete; 27 | 28 | base_sink &operator=(const base_sink &) = delete; 29 | base_sink &operator=(base_sink &&) = delete; 30 | 31 | void log(const details::log_msg &msg) final; 32 | void flush() final; 33 | void set_pattern(const std::string &pattern) final; 34 | void set_formatter(std::unique_ptr sink_formatter) final; 35 | 36 | protected: 37 | // sink formatter 38 | std::unique_ptr formatter_; 39 | Mutex mutex_; 40 | 41 | virtual void sink_it_(const details::log_msg &msg) = 0; 42 | virtual void flush_() = 0; 43 | virtual void set_pattern_(const std::string &pattern); 44 | virtual void set_formatter_(std::unique_ptr sink_formatter); 45 | }; 46 | } // namespace sinks 47 | } // namespace spdlog 48 | 49 | #ifdef SPDLOG_HEADER_ONLY 50 | #include "base_sink-inl.h" 51 | #endif 52 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/basic_file_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace sinks { 15 | 16 | template 17 | SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, 18 | bool truncate, 19 | const file_event_handlers &event_handlers) 20 | : file_helper_{event_handlers} { 21 | file_helper_.open(filename, truncate); 22 | } 23 | 24 | template 25 | SPDLOG_INLINE const filename_t &basic_file_sink::filename() const { 26 | return file_helper_.filename(); 27 | } 28 | 29 | template 30 | SPDLOG_INLINE void basic_file_sink::sink_it_(const details::log_msg &msg) { 31 | memory_buf_t formatted; 32 | base_sink::formatter_->format(msg, formatted); 33 | file_helper_.write(formatted); 34 | } 35 | 36 | template 37 | SPDLOG_INLINE void basic_file_sink::flush_() { 38 | file_helper_.flush(); 39 | } 40 | 41 | } // namespace sinks 42 | } // namespace spdlog 43 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/basic_file_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | /* 17 | * Trivial file sink with single file as target 18 | */ 19 | template 20 | class basic_file_sink final : public base_sink { 21 | public: 22 | explicit basic_file_sink(const filename_t &filename, 23 | bool truncate = false, 24 | const file_event_handlers &event_handlers = {}); 25 | const filename_t &filename() const; 26 | 27 | protected: 28 | void sink_it_(const details::log_msg &msg) override; 29 | void flush_() override; 30 | 31 | private: 32 | details::file_helper file_helper_; 33 | }; 34 | 35 | using basic_file_sink_mt = basic_file_sink; 36 | using basic_file_sink_st = basic_file_sink; 37 | 38 | } // namespace sinks 39 | 40 | // 41 | // factory functions 42 | // 43 | template 44 | inline std::shared_ptr basic_logger_mt(const std::string &logger_name, 45 | const filename_t &filename, 46 | bool truncate = false, 47 | const file_event_handlers &event_handlers = {}) { 48 | return Factory::template create(logger_name, filename, truncate, 49 | event_handlers); 50 | } 51 | 52 | template 53 | inline std::shared_ptr basic_logger_st(const std::string &logger_name, 54 | const filename_t &filename, 55 | bool truncate = false, 56 | const file_event_handlers &event_handlers = {}) { 57 | return Factory::template create(logger_name, filename, truncate, 58 | event_handlers); 59 | } 60 | 61 | } // namespace spdlog 62 | 63 | #ifdef SPDLOG_HEADER_ONLY 64 | #include "basic_file_sink-inl.h" 65 | #endif 66 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/callback_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | // callbacks type 16 | typedef std::function custom_log_callback; 17 | 18 | namespace sinks { 19 | /* 20 | * Trivial callback sink, gets a callback function and calls it on each log 21 | */ 22 | template 23 | class callback_sink final : public base_sink { 24 | public: 25 | explicit callback_sink(const custom_log_callback &callback) 26 | : callback_{callback} {} 27 | 28 | protected: 29 | void sink_it_(const details::log_msg &msg) override { callback_(msg); } 30 | void flush_() override{}; 31 | 32 | private: 33 | custom_log_callback callback_; 34 | }; 35 | 36 | using callback_sink_mt = callback_sink; 37 | using callback_sink_st = callback_sink; 38 | 39 | } // namespace sinks 40 | 41 | // 42 | // factory functions 43 | // 44 | template 45 | inline std::shared_ptr callback_logger_mt(const std::string &logger_name, 46 | const custom_log_callback &callback) { 47 | return Factory::template create(logger_name, callback); 48 | } 49 | 50 | template 51 | inline std::shared_ptr callback_logger_st(const std::string &logger_name, 52 | const custom_log_callback &callback) { 53 | return Factory::template create(logger_name, callback); 54 | } 55 | 56 | } // namespace spdlog 57 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/dist_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "base_sink.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // Distribution sink (mux). Stores a vector of sinks which get called when log 17 | // is called 18 | 19 | namespace spdlog { 20 | namespace sinks { 21 | 22 | template 23 | class dist_sink : public base_sink { 24 | public: 25 | dist_sink() = default; 26 | explicit dist_sink(std::vector> sinks) 27 | : sinks_(sinks) {} 28 | 29 | dist_sink(const dist_sink &) = delete; 30 | dist_sink &operator=(const dist_sink &) = delete; 31 | 32 | void add_sink(std::shared_ptr sub_sink) { 33 | std::lock_guard lock(base_sink::mutex_); 34 | sinks_.push_back(sub_sink); 35 | } 36 | 37 | void remove_sink(std::shared_ptr sub_sink) { 38 | std::lock_guard lock(base_sink::mutex_); 39 | sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sub_sink), sinks_.end()); 40 | } 41 | 42 | void set_sinks(std::vector> sinks) { 43 | std::lock_guard lock(base_sink::mutex_); 44 | sinks_ = std::move(sinks); 45 | } 46 | 47 | std::vector> &sinks() { return sinks_; } 48 | 49 | protected: 50 | void sink_it_(const details::log_msg &msg) override { 51 | for (auto &sub_sink : sinks_) { 52 | if (sub_sink->should_log(msg.level)) { 53 | sub_sink->log(msg); 54 | } 55 | } 56 | } 57 | 58 | void flush_() override { 59 | for (auto &sub_sink : sinks_) { 60 | sub_sink->flush(); 61 | } 62 | } 63 | 64 | void set_pattern_(const std::string &pattern) override { 65 | set_formatter_(details::make_unique(pattern)); 66 | } 67 | 68 | void set_formatter_(std::unique_ptr sink_formatter) override { 69 | base_sink::formatter_ = std::move(sink_formatter); 70 | for (auto &sub_sink : sinks_) { 71 | sub_sink->set_formatter(base_sink::formatter_->clone()); 72 | } 73 | } 74 | std::vector> sinks_; 75 | }; 76 | 77 | using dist_sink_mt = dist_sink; 78 | using dist_sink_st = dist_sink; 79 | 80 | } // namespace sinks 81 | } // namespace spdlog 82 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/dup_filter_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "dist_sink.h" 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // Duplicate message removal sink. 16 | // Skip the message if previous one is identical and less than "max_skip_duration" have passed 17 | // 18 | // Example: 19 | // 20 | // #include 21 | // 22 | // int main() { 23 | // auto dup_filter = std::make_shared(std::chrono::seconds(5), 24 | // level::info); dup_filter->add_sink(std::make_shared()); 25 | // spdlog::logger l("logger", dup_filter); 26 | // l.info("Hello"); 27 | // l.info("Hello"); 28 | // l.info("Hello"); 29 | // l.info("Different Hello"); 30 | // } 31 | // 32 | // Will produce: 33 | // [2019-06-25 17:50:56.511] [logger] [info] Hello 34 | // [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. 35 | // [2019-06-25 17:50:56.512] [logger] [info] Different Hello 36 | 37 | namespace spdlog { 38 | namespace sinks { 39 | template 40 | class dup_filter_sink : public dist_sink { 41 | public: 42 | template 43 | explicit dup_filter_sink(std::chrono::duration max_skip_duration, 44 | level::level_enum notification_level = level::info) 45 | : max_skip_duration_{max_skip_duration}, 46 | log_level_{notification_level} {} 47 | 48 | protected: 49 | std::chrono::microseconds max_skip_duration_; 50 | log_clock::time_point last_msg_time_; 51 | std::string last_msg_payload_; 52 | size_t skip_counter_ = 0; 53 | level::level_enum log_level_; 54 | 55 | void sink_it_(const details::log_msg &msg) override { 56 | bool filtered = filter_(msg); 57 | if (!filtered) { 58 | skip_counter_ += 1; 59 | return; 60 | } 61 | 62 | // log the "skipped.." message 63 | if (skip_counter_ > 0) { 64 | char buf[64]; 65 | auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", 66 | static_cast(skip_counter_)); 67 | if (msg_size > 0 && static_cast(msg_size) < sizeof(buf)) { 68 | details::log_msg skipped_msg{msg.source, msg.logger_name, log_level_, 69 | string_view_t{buf, static_cast(msg_size)}}; 70 | dist_sink::sink_it_(skipped_msg); 71 | } 72 | } 73 | 74 | // log current message 75 | dist_sink::sink_it_(msg); 76 | last_msg_time_ = msg.time; 77 | skip_counter_ = 0; 78 | last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size()); 79 | } 80 | 81 | // return whether the log msg should be displayed (true) or skipped (false) 82 | bool filter_(const details::log_msg &msg) { 83 | auto filter_duration = msg.time - last_msg_time_; 84 | return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_); 85 | } 86 | }; 87 | 88 | using dup_filter_sink_mt = dup_filter_sink; 89 | using dup_filter_sink_st = dup_filter_sink; 90 | 91 | } // namespace sinks 92 | } // namespace spdlog 93 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/msvc_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2016 Alexander Dalshov & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #if defined(_WIN32) 7 | 8 | #include 9 | #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) 10 | #include 11 | #endif 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | // Avoid including windows.h (https://stackoverflow.com/a/30741042) 18 | #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) 19 | extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString); 20 | #else 21 | extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); 22 | #endif 23 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); 24 | 25 | namespace spdlog { 26 | namespace sinks { 27 | /* 28 | * MSVC sink (logging using OutputDebugStringA) 29 | */ 30 | template 31 | class msvc_sink : public base_sink { 32 | public: 33 | msvc_sink() = default; 34 | msvc_sink(bool check_debugger_present) 35 | : check_debugger_present_{check_debugger_present} {}; 36 | 37 | protected: 38 | void sink_it_(const details::log_msg &msg) override { 39 | if (check_debugger_present_ && !IsDebuggerPresent()) { 40 | return; 41 | } 42 | memory_buf_t formatted; 43 | base_sink::formatter_->format(msg, formatted); 44 | formatted.push_back('\0'); // add a null terminator for OutputDebugString 45 | #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) 46 | wmemory_buf_t wformatted; 47 | details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted); 48 | OutputDebugStringW(wformatted.data()); 49 | #else 50 | OutputDebugStringA(formatted.data()); 51 | #endif 52 | } 53 | 54 | void flush_() override {} 55 | 56 | bool check_debugger_present_ = true; 57 | }; 58 | 59 | using msvc_sink_mt = msvc_sink; 60 | using msvc_sink_st = msvc_sink; 61 | 62 | using windebug_sink_mt = msvc_sink_mt; 63 | using windebug_sink_st = msvc_sink_st; 64 | 65 | } // namespace sinks 66 | } // namespace spdlog 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/null_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | 15 | template 16 | class null_sink : public base_sink { 17 | protected: 18 | void sink_it_(const details::log_msg &) override {} 19 | void flush_() override {} 20 | }; 21 | 22 | using null_sink_mt = null_sink; 23 | using null_sink_st = null_sink; 24 | 25 | } // namespace sinks 26 | 27 | template 28 | inline std::shared_ptr null_logger_mt(const std::string &logger_name) { 29 | auto null_logger = Factory::template create(logger_name); 30 | null_logger->set_level(level::off); 31 | return null_logger; 32 | } 33 | 34 | template 35 | inline std::shared_ptr null_logger_st(const std::string &logger_name) { 36 | auto null_logger = Factory::template create(logger_name); 37 | null_logger->set_level(level::off); 38 | return null_logger; 39 | } 40 | 41 | } // namespace spdlog 42 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/ostream_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | template 15 | class ostream_sink final : public base_sink { 16 | public: 17 | explicit ostream_sink(std::ostream &os, bool force_flush = false) 18 | : ostream_(os), 19 | force_flush_(force_flush) {} 20 | ostream_sink(const ostream_sink &) = delete; 21 | ostream_sink &operator=(const ostream_sink &) = delete; 22 | 23 | protected: 24 | void sink_it_(const details::log_msg &msg) override { 25 | memory_buf_t formatted; 26 | base_sink::formatter_->format(msg, formatted); 27 | ostream_.write(formatted.data(), static_cast(formatted.size())); 28 | if (force_flush_) { 29 | ostream_.flush(); 30 | } 31 | } 32 | 33 | void flush_() override { ostream_.flush(); } 34 | 35 | std::ostream &ostream_; 36 | bool force_flush_; 37 | }; 38 | 39 | using ostream_sink_mt = ostream_sink; 40 | using ostream_sink_st = ostream_sink; 41 | 42 | } // namespace sinks 43 | } // namespace spdlog 44 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/ringbuffer_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "spdlog/details/circular_q.h" 7 | #include "spdlog/details/log_msg_buffer.h" 8 | #include "spdlog/details/null_mutex.h" 9 | #include "spdlog/sinks/base_sink.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | /* 18 | * Ring buffer sink 19 | */ 20 | template 21 | class ringbuffer_sink final : public base_sink { 22 | public: 23 | explicit ringbuffer_sink(size_t n_items) 24 | : q_{n_items} {} 25 | 26 | std::vector last_raw(size_t lim = 0) { 27 | std::lock_guard lock(base_sink::mutex_); 28 | auto items_available = q_.size(); 29 | auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; 30 | std::vector ret; 31 | ret.reserve(n_items); 32 | for (size_t i = (items_available - n_items); i < items_available; i++) { 33 | ret.push_back(q_.at(i)); 34 | } 35 | return ret; 36 | } 37 | 38 | std::vector last_formatted(size_t lim = 0) { 39 | std::lock_guard lock(base_sink::mutex_); 40 | auto items_available = q_.size(); 41 | auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; 42 | std::vector ret; 43 | ret.reserve(n_items); 44 | for (size_t i = (items_available - n_items); i < items_available; i++) { 45 | memory_buf_t formatted; 46 | base_sink::formatter_->format(q_.at(i), formatted); 47 | ret.push_back(SPDLOG_BUF_TO_STRING(formatted)); 48 | } 49 | return ret; 50 | } 51 | 52 | protected: 53 | void sink_it_(const details::log_msg &msg) override { 54 | q_.push_back(details::log_msg_buffer{msg}); 55 | } 56 | void flush_() override {} 57 | 58 | private: 59 | details::circular_q q_; 60 | }; 61 | 62 | using ringbuffer_sink_mt = ringbuffer_sink; 63 | using ringbuffer_sink_st = ringbuffer_sink; 64 | 65 | } // namespace sinks 66 | 67 | } // namespace spdlog 68 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/rotating_file_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | 18 | // 19 | // Rotating file sink based on size 20 | // 21 | template 22 | class rotating_file_sink final : public base_sink { 23 | public: 24 | rotating_file_sink(filename_t base_filename, 25 | std::size_t max_size, 26 | std::size_t max_files, 27 | bool rotate_on_open = false, 28 | const file_event_handlers &event_handlers = {}); 29 | static filename_t calc_filename(const filename_t &filename, std::size_t index); 30 | filename_t filename(); 31 | 32 | protected: 33 | void sink_it_(const details::log_msg &msg) override; 34 | void flush_() override; 35 | 36 | private: 37 | // Rotate files: 38 | // log.txt -> log.1.txt 39 | // log.1.txt -> log.2.txt 40 | // log.2.txt -> log.3.txt 41 | // log.3.txt -> delete 42 | void rotate_(); 43 | 44 | // delete the target if exists, and rename the src file to target 45 | // return true on success, false otherwise. 46 | bool rename_file_(const filename_t &src_filename, const filename_t &target_filename); 47 | 48 | filename_t base_filename_; 49 | std::size_t max_size_; 50 | std::size_t max_files_; 51 | std::size_t current_size_; 52 | details::file_helper file_helper_; 53 | }; 54 | 55 | using rotating_file_sink_mt = rotating_file_sink; 56 | using rotating_file_sink_st = rotating_file_sink; 57 | 58 | } // namespace sinks 59 | 60 | // 61 | // factory functions 62 | // 63 | 64 | template 65 | inline std::shared_ptr rotating_logger_mt(const std::string &logger_name, 66 | const filename_t &filename, 67 | size_t max_file_size, 68 | size_t max_files, 69 | bool rotate_on_open = false, 70 | const file_event_handlers &event_handlers = {}) { 71 | return Factory::template create( 72 | logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); 73 | } 74 | 75 | template 76 | inline std::shared_ptr rotating_logger_st(const std::string &logger_name, 77 | const filename_t &filename, 78 | size_t max_file_size, 79 | size_t max_files, 80 | bool rotate_on_open = false, 81 | const file_event_handlers &event_handlers = {}) { 82 | return Factory::template create( 83 | logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); 84 | } 85 | } // namespace spdlog 86 | 87 | #ifdef SPDLOG_HEADER_ONLY 88 | #include "rotating_file_sink-inl.h" 89 | #endif 90 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const { 13 | return msg_level >= level_.load(std::memory_order_relaxed); 14 | } 15 | 16 | SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) { 17 | level_.store(log_level, std::memory_order_relaxed); 18 | } 19 | 20 | SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const { 21 | return static_cast(level_.load(std::memory_order_relaxed)); 22 | } 23 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | namespace sinks { 12 | class SPDLOG_API sink { 13 | public: 14 | virtual ~sink() = default; 15 | virtual void log(const details::log_msg &msg) = 0; 16 | virtual void flush() = 0; 17 | virtual void set_pattern(const std::string &pattern) = 0; 18 | virtual void set_formatter(std::unique_ptr sink_formatter) = 0; 19 | 20 | void set_level(level::level_enum log_level); 21 | level::level_enum level() const; 22 | bool should_log(level::level_enum msg_level) const; 23 | 24 | protected: 25 | // sink log level - default is all 26 | level_t level_{level::trace}; 27 | }; 28 | 29 | } // namespace sinks 30 | } // namespace spdlog 31 | 32 | #ifdef SPDLOG_HEADER_ONLY 33 | #include "sink-inl.h" 34 | #endif 35 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/stdout_color_sinks-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | template 16 | SPDLOG_INLINE std::shared_ptr stdout_color_mt(const std::string &logger_name, 17 | color_mode mode) { 18 | return Factory::template create(logger_name, mode); 19 | } 20 | 21 | template 22 | SPDLOG_INLINE std::shared_ptr stdout_color_st(const std::string &logger_name, 23 | color_mode mode) { 24 | return Factory::template create(logger_name, mode); 25 | } 26 | 27 | template 28 | SPDLOG_INLINE std::shared_ptr stderr_color_mt(const std::string &logger_name, 29 | color_mode mode) { 30 | return Factory::template create(logger_name, mode); 31 | } 32 | 33 | template 34 | SPDLOG_INLINE std::shared_ptr stderr_color_st(const std::string &logger_name, 35 | color_mode mode) { 36 | return Factory::template create(logger_name, mode); 37 | } 38 | } // namespace spdlog 39 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/stdout_color_sinks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef _WIN32 7 | #include 8 | #else 9 | #include 10 | #endif 11 | 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | #ifdef _WIN32 17 | using stdout_color_sink_mt = wincolor_stdout_sink_mt; 18 | using stdout_color_sink_st = wincolor_stdout_sink_st; 19 | using stderr_color_sink_mt = wincolor_stderr_sink_mt; 20 | using stderr_color_sink_st = wincolor_stderr_sink_st; 21 | #else 22 | using stdout_color_sink_mt = ansicolor_stdout_sink_mt; 23 | using stdout_color_sink_st = ansicolor_stdout_sink_st; 24 | using stderr_color_sink_mt = ansicolor_stderr_sink_mt; 25 | using stderr_color_sink_st = ansicolor_stderr_sink_st; 26 | #endif 27 | } // namespace sinks 28 | 29 | template 30 | std::shared_ptr stdout_color_mt(const std::string &logger_name, 31 | color_mode mode = color_mode::automatic); 32 | 33 | template 34 | std::shared_ptr stdout_color_st(const std::string &logger_name, 35 | color_mode mode = color_mode::automatic); 36 | 37 | template 38 | std::shared_ptr stderr_color_mt(const std::string &logger_name, 39 | color_mode mode = color_mode::automatic); 40 | 41 | template 42 | std::shared_ptr stderr_color_st(const std::string &logger_name, 43 | color_mode mode = color_mode::automatic); 44 | 45 | } // namespace spdlog 46 | 47 | #ifdef SPDLOG_HEADER_ONLY 48 | #include "stdout_color_sinks-inl.h" 49 | #endif 50 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/stdout_sinks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef _WIN32 12 | #include 13 | #endif 14 | 15 | namespace spdlog { 16 | 17 | namespace sinks { 18 | 19 | template 20 | class stdout_sink_base : public sink { 21 | public: 22 | using mutex_t = typename ConsoleMutex::mutex_t; 23 | explicit stdout_sink_base(FILE *file); 24 | ~stdout_sink_base() override = default; 25 | 26 | stdout_sink_base(const stdout_sink_base &other) = delete; 27 | stdout_sink_base(stdout_sink_base &&other) = delete; 28 | 29 | stdout_sink_base &operator=(const stdout_sink_base &other) = delete; 30 | stdout_sink_base &operator=(stdout_sink_base &&other) = delete; 31 | 32 | void log(const details::log_msg &msg) override; 33 | void flush() override; 34 | void set_pattern(const std::string &pattern) override; 35 | 36 | void set_formatter(std::unique_ptr sink_formatter) override; 37 | 38 | protected: 39 | mutex_t &mutex_; 40 | FILE *file_; 41 | std::unique_ptr formatter_; 42 | #ifdef _WIN32 43 | HANDLE handle_; 44 | #endif // WIN32 45 | }; 46 | 47 | template 48 | class stdout_sink : public stdout_sink_base { 49 | public: 50 | stdout_sink(); 51 | }; 52 | 53 | template 54 | class stderr_sink : public stdout_sink_base { 55 | public: 56 | stderr_sink(); 57 | }; 58 | 59 | using stdout_sink_mt = stdout_sink; 60 | using stdout_sink_st = stdout_sink; 61 | 62 | using stderr_sink_mt = stderr_sink; 63 | using stderr_sink_st = stderr_sink; 64 | 65 | } // namespace sinks 66 | 67 | // factory methods 68 | template 69 | std::shared_ptr stdout_logger_mt(const std::string &logger_name); 70 | 71 | template 72 | std::shared_ptr stdout_logger_st(const std::string &logger_name); 73 | 74 | template 75 | std::shared_ptr stderr_logger_mt(const std::string &logger_name); 76 | 77 | template 78 | std::shared_ptr stderr_logger_st(const std::string &logger_name); 79 | 80 | } // namespace spdlog 81 | 82 | #ifdef SPDLOG_HEADER_ONLY 83 | #include "stdout_sinks-inl.h" 84 | #endif 85 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/tcp_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #ifdef _WIN32 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #pragma once 21 | 22 | // Simple tcp client sink 23 | // Connects to remote address and send the formatted log. 24 | // Will attempt to reconnect if connection drops. 25 | // If more complicated behaviour is needed (i.e get responses), you can inherit it and override the 26 | // sink_it_ method. 27 | 28 | namespace spdlog { 29 | namespace sinks { 30 | 31 | struct tcp_sink_config { 32 | std::string server_host; 33 | int server_port; 34 | bool lazy_connect = false; // if true connect on first log call instead of on construction 35 | 36 | tcp_sink_config(std::string host, int port) 37 | : server_host{std::move(host)}, 38 | server_port{port} {} 39 | }; 40 | 41 | template 42 | class tcp_sink : public spdlog::sinks::base_sink { 43 | public: 44 | // connect to tcp host/port or throw if failed 45 | // host can be hostname or ip address 46 | 47 | explicit tcp_sink(tcp_sink_config sink_config) 48 | : config_{std::move(sink_config)} { 49 | if (!config_.lazy_connect) { 50 | this->client_.connect(config_.server_host, config_.server_port); 51 | } 52 | } 53 | 54 | ~tcp_sink() override = default; 55 | 56 | protected: 57 | void sink_it_(const spdlog::details::log_msg &msg) override { 58 | spdlog::memory_buf_t formatted; 59 | spdlog::sinks::base_sink::formatter_->format(msg, formatted); 60 | if (!client_.is_connected()) { 61 | client_.connect(config_.server_host, config_.server_port); 62 | } 63 | client_.send(formatted.data(), formatted.size()); 64 | } 65 | 66 | void flush_() override {} 67 | tcp_sink_config config_; 68 | details::tcp_client client_; 69 | }; 70 | 71 | using tcp_sink_mt = tcp_sink; 72 | using tcp_sink_st = tcp_sink; 73 | 74 | } // namespace sinks 75 | } // namespace spdlog 76 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/udp_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #ifdef _WIN32 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // Simple udp client sink 21 | // Sends formatted log via udp 22 | 23 | namespace spdlog { 24 | namespace sinks { 25 | 26 | struct udp_sink_config { 27 | std::string server_host; 28 | uint16_t server_port; 29 | 30 | udp_sink_config(std::string host, uint16_t port) 31 | : server_host{std::move(host)}, 32 | server_port{port} {} 33 | }; 34 | 35 | template 36 | class udp_sink : public spdlog::sinks::base_sink { 37 | public: 38 | // host can be hostname or ip address 39 | explicit udp_sink(udp_sink_config sink_config) 40 | : client_{sink_config.server_host, sink_config.server_port} {} 41 | 42 | ~udp_sink() override = default; 43 | 44 | protected: 45 | void sink_it_(const spdlog::details::log_msg &msg) override { 46 | spdlog::memory_buf_t formatted; 47 | spdlog::sinks::base_sink::formatter_->format(msg, formatted); 48 | client_.send(formatted.data(), formatted.size()); 49 | } 50 | 51 | void flush_() override {} 52 | details::udp_client client_; 53 | }; 54 | 55 | using udp_sink_mt = udp_sink; 56 | using udp_sink_st = udp_sink; 57 | 58 | } // namespace sinks 59 | 60 | // 61 | // factory functions 62 | // 63 | template 64 | inline std::shared_ptr udp_logger_mt(const std::string &logger_name, 65 | sinks::udp_sink_config skin_config) { 66 | return Factory::template create(logger_name, skin_config); 67 | } 68 | 69 | } // namespace spdlog 70 | -------------------------------------------------------------------------------- /inc/spdlog/sinks/wincolor_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace spdlog { 18 | namespace sinks { 19 | /* 20 | * Windows color console sink. Uses WriteConsoleA to write to the console with 21 | * colors 22 | */ 23 | template 24 | class wincolor_sink : public sink { 25 | public: 26 | wincolor_sink(void *out_handle, color_mode mode); 27 | ~wincolor_sink() override; 28 | 29 | wincolor_sink(const wincolor_sink &other) = delete; 30 | wincolor_sink &operator=(const wincolor_sink &other) = delete; 31 | 32 | // change the color for the given level 33 | void set_color(level::level_enum level, std::uint16_t color); 34 | void log(const details::log_msg &msg) final override; 35 | void flush() final override; 36 | void set_pattern(const std::string &pattern) override final; 37 | void set_formatter(std::unique_ptr sink_formatter) override final; 38 | void set_color_mode(color_mode mode); 39 | 40 | protected: 41 | using mutex_t = typename ConsoleMutex::mutex_t; 42 | void *out_handle_; 43 | mutex_t &mutex_; 44 | bool should_do_colors_; 45 | std::unique_ptr formatter_; 46 | std::array colors_; 47 | 48 | // set foreground color and return the orig console attributes (for resetting later) 49 | std::uint16_t set_foreground_color_(std::uint16_t attribs); 50 | 51 | // print a range of formatted message to console 52 | void print_range_(const memory_buf_t &formatted, size_t start, size_t end); 53 | 54 | // in case we are redirected to file (not in console mode) 55 | void write_to_file_(const memory_buf_t &formatted); 56 | 57 | void set_color_mode_impl(color_mode mode); 58 | }; 59 | 60 | template 61 | class wincolor_stdout_sink : public wincolor_sink { 62 | public: 63 | explicit wincolor_stdout_sink(color_mode mode = color_mode::automatic); 64 | }; 65 | 66 | template 67 | class wincolor_stderr_sink : public wincolor_sink { 68 | public: 69 | explicit wincolor_stderr_sink(color_mode mode = color_mode::automatic); 70 | }; 71 | 72 | using wincolor_stdout_sink_mt = wincolor_stdout_sink; 73 | using wincolor_stdout_sink_st = wincolor_stdout_sink; 74 | 75 | using wincolor_stderr_sink_mt = wincolor_stderr_sink; 76 | using wincolor_stderr_sink_st = wincolor_stderr_sink; 77 | } // namespace sinks 78 | } // namespace spdlog 79 | 80 | #ifdef SPDLOG_HEADER_ONLY 81 | #include "wincolor_sink-inl.h" 82 | #endif 83 | -------------------------------------------------------------------------------- /inc/spdlog/spdlog-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | SPDLOG_INLINE void initialize_logger(std::shared_ptr logger) { 16 | details::registry::instance().initialize_logger(std::move(logger)); 17 | } 18 | 19 | SPDLOG_INLINE std::shared_ptr get(const std::string &name) { 20 | return details::registry::instance().get(name); 21 | } 22 | 23 | SPDLOG_INLINE void set_formatter(std::unique_ptr formatter) { 24 | details::registry::instance().set_formatter(std::move(formatter)); 25 | } 26 | 27 | SPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type) { 28 | set_formatter( 29 | std::unique_ptr(new pattern_formatter(std::move(pattern), time_type))); 30 | } 31 | 32 | SPDLOG_INLINE void enable_backtrace(size_t n_messages) { 33 | details::registry::instance().enable_backtrace(n_messages); 34 | } 35 | 36 | SPDLOG_INLINE void disable_backtrace() { details::registry::instance().disable_backtrace(); } 37 | 38 | SPDLOG_INLINE void dump_backtrace() { default_logger_raw()->dump_backtrace(); } 39 | 40 | SPDLOG_INLINE level::level_enum get_level() { return default_logger_raw()->level(); } 41 | 42 | SPDLOG_INLINE bool should_log(level::level_enum log_level) { 43 | return default_logger_raw()->should_log(log_level); 44 | } 45 | 46 | SPDLOG_INLINE void set_level(level::level_enum log_level) { 47 | details::registry::instance().set_level(log_level); 48 | } 49 | 50 | SPDLOG_INLINE void flush_on(level::level_enum log_level) { 51 | details::registry::instance().flush_on(log_level); 52 | } 53 | 54 | SPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg)) { 55 | details::registry::instance().set_error_handler(handler); 56 | } 57 | 58 | SPDLOG_INLINE void register_logger(std::shared_ptr logger) { 59 | details::registry::instance().register_logger(std::move(logger)); 60 | } 61 | 62 | SPDLOG_INLINE void apply_all(const std::function)> &fun) { 63 | details::registry::instance().apply_all(fun); 64 | } 65 | 66 | SPDLOG_INLINE void drop(const std::string &name) { details::registry::instance().drop(name); } 67 | 68 | SPDLOG_INLINE void drop_all() { details::registry::instance().drop_all(); } 69 | 70 | SPDLOG_INLINE void shutdown() { details::registry::instance().shutdown(); } 71 | 72 | SPDLOG_INLINE void set_automatic_registration(bool automatic_registration) { 73 | details::registry::instance().set_automatic_registration(automatic_registration); 74 | } 75 | 76 | SPDLOG_INLINE std::shared_ptr default_logger() { 77 | return details::registry::instance().default_logger(); 78 | } 79 | 80 | SPDLOG_INLINE spdlog::logger *default_logger_raw() { 81 | return details::registry::instance().get_default_raw(); 82 | } 83 | 84 | SPDLOG_INLINE void set_default_logger(std::shared_ptr default_logger) { 85 | details::registry::instance().set_default_logger(std::move(default_logger)); 86 | } 87 | 88 | SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr logger) { 89 | details::registry::instance().apply_logger_env_levels(std::move(logger)); 90 | } 91 | 92 | } // namespace spdlog 93 | -------------------------------------------------------------------------------- /inc/spdlog/stopwatch.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | // Stopwatch support for spdlog (using std::chrono::steady_clock). 10 | // Displays elapsed seconds since construction as double. 11 | // 12 | // Usage: 13 | // 14 | // spdlog::stopwatch sw; 15 | // ... 16 | // spdlog::debug("Elapsed: {} seconds", sw); => "Elapsed 0.005116733 seconds" 17 | // spdlog::info("Elapsed: {:.6} seconds", sw); => "Elapsed 0.005163 seconds" 18 | // 19 | // 20 | // If other units are needed (e.g. millis instead of double), include "fmt/chrono.h" and use 21 | // "duration_cast<..>(sw.elapsed())": 22 | // 23 | // #include 24 | //.. 25 | // using std::chrono::duration_cast; 26 | // using std::chrono::milliseconds; 27 | // spdlog::info("Elapsed {}", duration_cast(sw.elapsed())); => "Elapsed 5ms" 28 | 29 | namespace spdlog { 30 | class stopwatch { 31 | using clock = std::chrono::steady_clock; 32 | std::chrono::time_point start_tp_; 33 | 34 | public: 35 | stopwatch() 36 | : start_tp_{clock::now()} {} 37 | 38 | std::chrono::duration elapsed() const { 39 | return std::chrono::duration(clock::now() - start_tp_); 40 | } 41 | 42 | void reset() { start_tp_ = clock::now(); } 43 | }; 44 | } // namespace spdlog 45 | 46 | // Support for fmt formatting (e.g. "{:012.9}" or just "{}") 47 | namespace 48 | #ifdef SPDLOG_USE_STD_FORMAT 49 | std 50 | #else 51 | fmt 52 | #endif 53 | { 54 | 55 | template <> 56 | struct formatter : formatter { 57 | template 58 | auto format(const spdlog::stopwatch &sw, FormatContext &ctx) const -> decltype(ctx.out()) { 59 | return formatter::format(sw.elapsed().count(), ctx); 60 | } 61 | }; 62 | } // namespace std 63 | -------------------------------------------------------------------------------- /inc/spdlog/version.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #define SPDLOG_VER_MAJOR 1 7 | #define SPDLOG_VER_MINOR 12 8 | #define SPDLOG_VER_PATCH 0 9 | 10 | #define SPDLOG_TO_VERSION(major, minor, patch) (major * 10000 + minor * 100 + patch) 11 | #define SPDLOG_VERSION SPDLOG_TO_VERSION(SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH) 12 | -------------------------------------------------------------------------------- /inc/sync_msg_hook.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_SYNC_MSG_HOOK_H_ 2 | #define WXHELPER_SYNC_MSG_HOOK_H_ 3 | #include "hook.h" 4 | #include "singleton.h" 5 | #include "wechat_interface.h" 6 | namespace wxhelper{ 7 | static wechat::function::__DoAddMsg kDoAddMsg= nullptr; 8 | class SyncMsgHook : public hook::BaseHook,public base::Singleton { 9 | public: 10 | void Init(); 11 | private: 12 | static void HandleSyncMsg(int64_t param1, int64_t param2, int64_t param3); 13 | }; 14 | 15 | } 16 | 17 | #endif -------------------------------------------------------------------------------- /inc/wechat_db.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_WECHAT_DB_H_ 2 | #define WXHELPER_WECHAT_DB_H_ 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "singleton.h" 9 | #include "sqlite_function.h" 10 | #include "wechat_interface.h" 11 | 12 | namespace wechat { 13 | 14 | class WeChatDb : public base::Singleton { 15 | public: 16 | void Init(); 17 | std::vector GetWeChatDbHandles(); 18 | int Select(uint64_t db_hanle, const std::string &sql, 19 | std::vector> &query_result); 20 | 21 | int64_t GetLocalIdByMsgId(uint64_t msgid, int64_t &dbIndex); 22 | std::vector GetChatMsgByMsgId(uint64_t msgid); 23 | 24 | std::string GetVoiceBuffByMsgId(uint64_t msgid); 25 | 26 | std::string GetPublicMsgCompressContentByMsgId(uint64_t msgid); 27 | 28 | std::string GetChatMsgStrContentByMsgId(uint64_t msgid); 29 | 30 | int64_t GetDbHandleByDbName(wchar_t *dbname); 31 | 32 | private: 33 | void AddDatebaseInfo(uint64_t storage); 34 | int ExecSelect(uint64_t db, const std::string &sql, 35 | std::vector> &data); 36 | int ExecuteSQL(uint64_t db, const char *sql, 37 | sqlite3::sqlite3_callback callback, void *data); 38 | 39 | private: 40 | std::unordered_map dbmap_; 41 | std::vector dbs_; 42 | sqlite3::SqliteFunction func_; 43 | uint64_t base_addr_; 44 | mutable std::recursive_mutex m; 45 | }; 46 | 47 | } // namespace wechat 48 | #endif 49 | -------------------------------------------------------------------------------- /inc/wxhelper.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef WXHELPER_WXHELPER_H_ 3 | #define WXHELPER_WXHELPER_H_ 4 | #include 5 | #include "singleton.h" 6 | namespace wxhelper { 7 | class WxHelper : public base::Singleton{ 8 | 9 | public: 10 | void init(HMODULE module); 11 | void finally(); 12 | }; 13 | } 14 | #endif -------------------------------------------------------------------------------- /inc/wxutils.h: -------------------------------------------------------------------------------- 1 | #ifndef WXHELPER_WXUTILS_H_ 2 | #define WXHELPER_WXUTILS_H_ 3 | #include 4 | 5 | #include 6 | namespace wxhelper { 7 | namespace wxutils { 8 | 9 | 10 | 11 | 12 | 13 | #ifdef _WIN64 14 | int64_t GetWeChatWinBase(); 15 | #else 16 | int32_t GetWeChatWinBase(); 17 | #endif 18 | std::string ReadSKBuiltinString(INT64 addr); 19 | std::string ReadSKBuiltinBuffer(INT64 addr); 20 | std::string ReadWeChatStr(INT64 addr); 21 | 22 | std::string ImageXor(std::string buf); 23 | std::wstring ReadWstring(INT64 addr); 24 | std::string ReadWstringThenConvert(INT64 addr); 25 | int DecodeImage(const wchar_t* file_path, const wchar_t* save_dir); 26 | bool FindOrCreateDirectory(const std::wstring &path); 27 | } // namespace wxutils 28 | 29 | } // namespace wxhelper 30 | #endif -------------------------------------------------------------------------------- /injector.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | chcp 65001 >nul 3 | 4 | :: 检查是否以管理员权限运行 5 | openfiles >nul 2>&1 6 | if '%errorlevel%' NEQ 0 ( 7 | :: 检查是否已经在管理员模式下 8 | if not "%1"=="elevated" ( 9 | echo 需要管理员权限来运行此脚本。正在以管理员权限重新启动... 10 | powershell -Command "Start-Process cmd.exe -ArgumentList '/c %~f0 elevated' -Verb RunAs" 11 | exit /b 12 | ) 13 | echo 脚本已以管理员权限运行。 14 | ) 15 | 16 | :: 获取wechat.exe的PID 17 | echo 正在获取wechat.exe进程的PID... 18 | for /f "tokens=2 delims=," %%i in ('wmic process where "name='wechat.exe'" get processid /format:csv') do ( 19 | set pid=%%i 20 | ) 21 | 22 | :: 去掉PID前后的空白字符 23 | set pid=%pid: =% 24 | 25 | :: 打印PID到控制台 26 | echo 进程ID: %pid% 27 | 28 | :: 检查是否成功获取到PID 29 | if "%pid%"=="" ( 30 | echo 未找到wechat.exe进程 31 | pause 32 | exit /b 1 33 | ) 34 | 35 | :: 获取当前脚本所在的目录 36 | set scriptdir=%~dp0 37 | 38 | :: 设置DLL的路径和injector.exe的路径 39 | set dllpath=%scriptdir%debug\wxhelper.dll 40 | set injectorpath=%scriptdir%injector.exe 41 | 42 | :: 打印DLL路径和injector.exe路径 43 | echo DLL路径: %dllpath% 44 | echo injector.exe路径: %injectorpath% 45 | 46 | :: 检查injector.exe是否存在 47 | if not exist "%injectorpath%" ( 48 | echo injector.exe 文件未找到: %injectorpath% 49 | pause 50 | exit /b 1 51 | ) 52 | 53 | :: 执行injector.exe 54 | echo 正在执行 "%injectorpath%" -p %pid% -i %dllpath% 55 | "%injectorpath%" -p %pid% -i %dllpath% 56 | 57 | pause 58 | -------------------------------------------------------------------------------- /injector.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/injector.exe -------------------------------------------------------------------------------- /lib/debug/base64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/debug/base64.lib -------------------------------------------------------------------------------- /lib/debug/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/debug/detours.lib -------------------------------------------------------------------------------- /lib/debug/lz4.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/debug/lz4.lib -------------------------------------------------------------------------------- /lib/debug/mongoose.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/debug/mongoose.lib -------------------------------------------------------------------------------- /lib/debug/spdlogd.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/debug/spdlogd.lib -------------------------------------------------------------------------------- /lib/debug/tinyxml2.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/debug/tinyxml2.lib -------------------------------------------------------------------------------- /lib/release/base64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/release/base64.lib -------------------------------------------------------------------------------- /lib/release/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/release/detours.lib -------------------------------------------------------------------------------- /lib/release/lz4.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/release/lz4.lib -------------------------------------------------------------------------------- /lib/release/mongoose.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/release/mongoose.lib -------------------------------------------------------------------------------- /lib/release/spdlog.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/release/spdlog.lib -------------------------------------------------------------------------------- /lib/release/tinyxml2.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/lib/release/tinyxml2.lib -------------------------------------------------------------------------------- /record.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/record.gif -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/resource.h -------------------------------------------------------------------------------- /src/client_socket.cc: -------------------------------------------------------------------------------- 1 | #include "client_socket.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "spdlog/spdlog.h" 7 | namespace wxhelper { 8 | 9 | SocketInit::SocketInit() { 10 | WSADATA was_data = {0}; 11 | if (WSAStartup(MAKEWORD(2, 2), &was_data)) { 12 | valid_ = true; 13 | } 14 | } 15 | 16 | SocketInit::~SocketInit() { 17 | if (valid_) { 18 | WSACleanup(); 19 | } 20 | } 21 | 22 | TcpClient::TcpClient(std::string ip, int port) : ip_(ip), port_(port) {} 23 | 24 | void TcpClient::SendAndCloseSocket(std::string& content) { 25 | SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 26 | if (client_socket < 0) { 27 | SPDLOG_ERROR("socket init fail"); 28 | return; 29 | } 30 | BOOL status = false; 31 | sockaddr_in client_addr; 32 | memset(&client_addr, 0, sizeof(client_addr)); 33 | client_addr.sin_family = AF_INET; 34 | client_addr.sin_port = htons((u_short)port_); 35 | InetPtonA(AF_INET, ip_.c_str(), &client_addr.sin_addr.s_addr); 36 | if (connect(client_socket, reinterpret_cast(&client_addr), 37 | sizeof(sockaddr)) < 0) { 38 | SPDLOG_ERROR("socket connect fail. host:{} , port:{},", ip_, port_); 39 | closesocket(client_socket); 40 | return; 41 | } 42 | char recv_buf[1024] = {0}; 43 | int ret = 44 | send(client_socket, content.c_str(), static_cast(content.size()), 0); 45 | if (ret < 0) { 46 | SPDLOG_ERROR("socket send fail ,ret:{}", ret); 47 | closesocket(client_socket); 48 | return; 49 | } 50 | ret = shutdown(client_socket, SD_SEND); 51 | if (ret == SOCKET_ERROR) { 52 | SPDLOG_ERROR("shutdown failed with erro:{}", ret); 53 | closesocket(client_socket); 54 | return; 55 | } 56 | do { 57 | ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0); 58 | if (ret > 0) { 59 | } else if (ret == 0) { 60 | SPDLOG_INFO("Connection closed"); 61 | closesocket(client_socket); 62 | return; 63 | } else { 64 | SPDLOG_ERROR("recv failed with error:{}", WSAGetLastError()); 65 | closesocket(client_socket); 66 | return; 67 | } 68 | } while (ret > 0); 69 | } 70 | } // namespace wxhelper -------------------------------------------------------------------------------- /src/config.cc: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | 5 | #include "spdlog/sinks/daily_file_sink.h" 6 | #include "spdlog/sinks/rotating_file_sink.h" 7 | #include "spdlog/sinks/stdout_color_sinks.h" 8 | #include "spdlog/spdlog.h" 9 | 10 | #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO 11 | namespace wxhelper { 12 | 13 | void Config::init() { 14 | auto logger = 15 | spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 23, 59); 16 | logger->flush_on(spdlog::level::err); 17 | spdlog::set_default_logger(logger); 18 | spdlog::flush_every(std::chrono::seconds(3)); 19 | spdlog::set_level(spdlog::level::info); 20 | spdlog::set_pattern("%Y-%m-%d %H:%M:%S [%l] [%t] - <%s>|<%#>|<%!>,%v"); 21 | http_server_port_ = 22 | GetPrivateProfileInt("config", "HttpServerPort", 19088, "./config.ini"); 23 | hidden_dll_ = GetPrivateProfileInt("config", "HiddenDll", 0, "./config.ini"); 24 | TCHAR host[MAX_PATH]; 25 | GetPrivateProfileStringA("config", "HttpServerHost", "http://0.0.0.0", host, 26 | sizeof(host), "./config.ini"); 27 | http_server_host_ = host; 28 | TCHAR mode[MAX_PATH]; 29 | GetPrivateProfileString("config", "RecvMessageMode", "tcp", mode, 30 | sizeof(mode), "./config.ini"); 31 | recv_message_mode_ = mode; 32 | 33 | TCHAR tcp_ip[MAX_PATH]; 34 | GetPrivateProfileString("config", "RecvTcpIp", "127.0.0.1", tcp_ip, 35 | sizeof(tcp_ip), "./config.ini"); 36 | recv_tcp_ip_ = tcp_ip; 37 | recv_tcp_port_ = 38 | GetPrivateProfileInt("config", "RecvTcpPort", 19099, "./config.ini"); 39 | TCHAR url[MAX_PATH]; 40 | GetPrivateProfileString("config", "RecvHttpUrl", "127.0.0.1", url, 41 | sizeof(url), "./config.ini"); 42 | recv_http_url_ = url; 43 | recv_http_timeout_ = 44 | GetPrivateProfileInt("config", "RecvHttpTimeout", 3000, "./config.ini"); 45 | SPDLOG_INFO( 46 | "wxhelper config:" 47 | "HttpServerPort={},HttpServerHost={},RecvMessageMode={},RecvTcpIp=" 48 | "{},RecvTcpPort={},RecvHttpUrl={},RecvHttpTimeout={}", 49 | http_server_port_, http_server_host_, recv_message_mode_, recv_tcp_ip_, 50 | recv_tcp_port_, recv_http_url_, recv_http_timeout_); 51 | } 52 | 53 | int Config::GetHideDll() { return hidden_dll_; } 54 | std::string Config::GetHttpServerHost() { return http_server_host_; } 55 | int Config::GetHttpServerPort() { return http_server_port_; } 56 | std::string Config::GetRecvMessageMode() { return recv_message_mode_; } 57 | 58 | std::string Config::GetRecvTcpIp() { return recv_tcp_ip_; } 59 | int Config::GetRecvTcpPort() { return recv_tcp_port_; } 60 | 61 | std::string Config::GetRecvHttpUrl() { return recv_http_url_; } 62 | int Config::GetRecvHttpTimeout() { return recv_http_timeout_; } 63 | 64 | } // namespace wxhelper 65 | -------------------------------------------------------------------------------- /src/db_controller.cc: -------------------------------------------------------------------------------- 1 | #include "db_controller.h" 2 | 3 | #include "nlohmann/json.hpp" 4 | #include "utils.h" 5 | #include "wechat_db.h" 6 | #include "json_utils.h" 7 | 8 | namespace wxhelper { 9 | 10 | std::string DbController::GetDBInfo(std::string params) { 11 | std::vector v = wechat::WeChatDb::GetInstance().GetWeChatDbHandles(); 12 | nlohmann::json ret_data = {{"data", nlohmann::json::array()}}; 13 | for (unsigned int i = 0; i < v.size(); ++i) { 14 | nlohmann::json db_info; 15 | db_info["tables"] = nlohmann::json::array(); 16 | wechat::DatabaseInfo* db = reinterpret_cast(v[i]); 17 | db_info["handle"] = db->handle; 18 | std::wstring dbname(db->db_name); 19 | db_info["databaseName"] = base::utils::WstringToUtf8(dbname); 20 | for (auto table : db->tables) { 21 | nlohmann::json table_info = {{"name", table.name}, 22 | {"tableName", table.table_name}, 23 | {"sql", table.sql}, 24 | {"rootpage", table.rootpage}}; 25 | db_info["tables"].push_back(table_info); 26 | } 27 | ret_data["data"].push_back(db_info); 28 | } 29 | ret_data["code"] = 1; 30 | ret_data["msg"] = "success"; 31 | return ret_data.dump(); 32 | } 33 | 34 | std::string DbController::ExecSql(std::string params) { 35 | nlohmann::json jp = nlohmann::json::parse(params); 36 | int64_t db_handle = jsonutils::GetInt64Param(jp, "dbHandle"); 37 | std::string sql = jsonutils::GetStringParam(jp, "sql"); 38 | std::vector> items; 39 | int success = wechat::WeChatDb::GetInstance().Select(db_handle, sql.c_str(), items); 40 | nlohmann::json ret_data = { 41 | {"data", nlohmann::json::array()}, {"code", success}, {"msg", "success"}}; 42 | if (success == 0) { 43 | ret_data["msg"] = "no data"; 44 | return ret_data.dump(); 45 | } 46 | for (auto it : items) { 47 | nlohmann::json temp_arr = nlohmann::json::array(); 48 | for (size_t i = 0; i < it.size(); i++) { 49 | temp_arr.push_back(it[i]); 50 | } 51 | ret_data["data"].push_back(temp_arr); 52 | } 53 | return ret_data.dump(); 54 | } 55 | 56 | } // namespace wxhelper 57 | -------------------------------------------------------------------------------- /src/dllMain.cc: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "wxhelper.h" 4 | BOOL APIENTRY DllMain(HMODULE module, DWORD ul_reason_for_call, 5 | LPVOID reserved) { 6 | switch (ul_reason_for_call) { 7 | case DLL_PROCESS_ATTACH: { 8 | OutputDebugString("start\n"); 9 | DisableThreadLibraryCalls(module); 10 | wxhelper::WxHelper::GetInstance().init(module); 11 | break; 12 | } 13 | case DLL_THREAD_ATTACH: { 14 | break; 15 | } 16 | case DLL_THREAD_DETACH: { 17 | break; 18 | } 19 | case DLL_PROCESS_DETACH: { 20 | OutputDebugString("end\n"); 21 | wxhelper::WxHelper::GetInstance().finally(); 22 | break; 23 | } 24 | } 25 | return TRUE; 26 | } -------------------------------------------------------------------------------- /src/hook.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hook.h" 3 | 4 | 5 | #include "client_socket.h" 6 | #include "config.h" 7 | #include "detours.h" 8 | #include "http_client.h" 9 | #include "nlohmann/json.hpp" 10 | #include "spdlog/spdlog.h" 11 | // #include "thread_pool.h" 12 | #include "utils.h" 13 | #include "wxutils.h" 14 | namespace hook { 15 | void SendHttpMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context, 16 | PTP_WORK Work) { 17 | InnerMessageStruct *msg = (InnerMessageStruct *)context; 18 | if (msg == NULL) { 19 | SPDLOG_INFO("http msg is null"); 20 | return; 21 | } 22 | std::unique_ptr sms(msg); 23 | nlohmann::json j_msg = nlohmann::json::parse( 24 | msg->buffer, msg->buffer + msg->length, nullptr, false); 25 | if (j_msg.is_discarded()) { 26 | return; 27 | } 28 | std::string jstr = j_msg.dump() + "\n"; 29 | std::string url = wxhelper::Config::GetInstance().GetRecvHttpUrl(); 30 | int timeout = wxhelper::Config::GetInstance().GetRecvHttpTimeout(); 31 | http::HttpClient client{url, timeout}; 32 | client.SendRequest(jstr); 33 | } 34 | 35 | 36 | void SendTcpMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context, 37 | PTP_WORK Work) { 38 | InnerMessageStruct *msg = (InnerMessageStruct *)context; 39 | if (msg == NULL) { 40 | SPDLOG_INFO("add work:msg is null"); 41 | return; 42 | } 43 | std::unique_ptr sms(msg); 44 | nlohmann::json j_msg = nlohmann::json::parse( 45 | msg->buffer, msg->buffer + msg->length, nullptr, false); 46 | if (j_msg.is_discarded()) { 47 | return; 48 | } 49 | std::string jstr = j_msg.dump() + "\n"; 50 | std::string ip = wxhelper::Config::GetInstance().GetRecvTcpIp(); 51 | int port = wxhelper::Config::GetInstance().GetRecvTcpPort(); 52 | wxhelper::TcpClient client{ip, port}; 53 | client.SendAndCloseSocket(jstr); 54 | } 55 | 56 | 57 | 58 | BaseHook::BaseHook(void *origin, void *detour) 59 | : origin_(origin), detour_(detour) {} 60 | 61 | int BaseHook::Hook() { 62 | if (hook_flag_) { 63 | SPDLOG_INFO("hook already called"); 64 | return 2; 65 | } 66 | DetourTransactionBegin(); 67 | DetourUpdateThread(GetCurrentThread()); 68 | DetourAttach((PVOID *)origin_, detour_); 69 | LONG ret = DetourTransactionCommit(); 70 | if (ret == NO_ERROR) { 71 | hook_flag_ = true; 72 | } 73 | return ret; 74 | } 75 | 76 | int BaseHook::Unhook() { 77 | if (!hook_flag_) { 78 | SPDLOG_INFO("hook already called"); 79 | return NO_ERROR; 80 | } 81 | UINT64 base = wxhelper::wxutils::GetWeChatWinBase(); 82 | DetourTransactionBegin(); 83 | DetourUpdateThread(GetCurrentThread()); 84 | DetourDetach((PVOID *)origin_, detour_); 85 | LONG ret = DetourTransactionCommit(); 86 | if (ret == NO_ERROR) { 87 | hook_flag_ = false; 88 | } 89 | return ret; 90 | } 91 | 92 | } // namespace hook -------------------------------------------------------------------------------- /src/hook_controller.cc: -------------------------------------------------------------------------------- 1 | #include "hook_controller.h" 2 | 3 | #include "json_utils.h" 4 | #include "nlohmann/json.hpp" 5 | #include "sync_msg_hook.h" 6 | 7 | namespace jsonutils = wxhelper::jsonutils; 8 | namespace wxhelper { 9 | std::string HookController::HookSyncMsg(std::string params) { 10 | int success = SyncMsgHook::GetInstance().Hook(); 11 | nlohmann::json ret_data = { 12 | {"code", success}, {"data", {}}, {"msg", "success"}}; 13 | return ret_data.dump(); 14 | } 15 | std::string HookController::UnHookSyncMsg(std::string params) { 16 | int success = SyncMsgHook::GetInstance().Unhook(); 17 | nlohmann::json ret_data = { 18 | {"code", success}, {"data", {}}, {"msg", "success"}}; 19 | return ret_data.dump(); 20 | } 21 | std::string HookController::HookLog(std::string params) { 22 | nlohmann::json ret = { 23 | {"code", 200}, {"data", {}}, {"msg", "Not Implemented"}}; 24 | return ret.dump(); 25 | } 26 | std::string HookController::UnHookLog(std::string params) { 27 | nlohmann::json ret = { 28 | {"code", 200}, {"data", {}}, {"msg", "Not Implemented"}}; 29 | return ret.dump(); 30 | } 31 | } // namespace wxhelper -------------------------------------------------------------------------------- /src/http_client.cc: -------------------------------------------------------------------------------- 1 | #include "http_client.h" 2 | 3 | namespace http { 4 | 5 | HttpClient::HttpClient(std::string url, int timeout) 6 | : url_(url), timeout_(timeout) {} 7 | 8 | void HttpClient::SendRequest(const std::string &content) { 9 | struct mg_mgr mgr; 10 | Data data; 11 | data.done = false; 12 | data.post_data = content; 13 | data.url = url_; 14 | data.timeout = timeout_; 15 | mg_mgr_init(&mgr); 16 | mg_http_connect(&mgr, url_.c_str(), &HttpClient::OnHttpEvent, &data); 17 | while (!data.done) { 18 | mg_mgr_poll(&mgr, 500); 19 | } 20 | mg_mgr_free(&mgr); 21 | data.done = false; 22 | } 23 | 24 | void HttpClient::OnHttpEvent(struct mg_connection *c, int ev, void *ev_data, 25 | void *fn_data) { 26 | 27 | Data *data = (Data *)fn_data; 28 | const char *s_url = data->url.c_str(); 29 | int timeout = data->timeout; 30 | if (ev == MG_EV_OPEN) { 31 | // Connection created. Store connect expiration time in c->data 32 | *(uint64_t *)c->data = mg_millis() + timeout; 33 | } else if (ev == MG_EV_POLL) { 34 | if (mg_millis() > *(uint64_t *)c->data && 35 | (c->is_connecting || c->is_resolving)) { 36 | mg_error(c, "Connect timeout"); 37 | } 38 | } else if (ev == MG_EV_CONNECT) { 39 | struct mg_str host = mg_url_host(s_url); 40 | if (mg_url_is_ssl(s_url)) { 41 | // no implement 42 | } 43 | // Send request 44 | size_t content_length = data->post_data.size(); 45 | mg_printf(c, 46 | "POST %s HTTP/1.0\r\n" 47 | "Host: %.*s\r\n" 48 | "Content-Type: application/json\r\n" 49 | "Content-Length: %d\r\n" 50 | "\r\n", 51 | mg_url_uri(s_url), (int)host.len, host.ptr, content_length); 52 | mg_send(c, data->post_data.c_str(), content_length); 53 | } else if (ev == MG_EV_HTTP_MSG) { 54 | // Response is received. Print it 55 | #ifdef _DEBUG 56 | struct mg_http_message *hm = (struct mg_http_message *)ev_data; 57 | printf("%.*s", (int)hm->message.len, hm->message.ptr); 58 | #endif 59 | // c->is_closing = 1; // Tell mongoose to close this connection 60 | c->is_draining = 1; 61 | data->done = true; // Tell event loop to stops 62 | } else if (ev == MG_EV_ERROR) { 63 | data->done = true; // Error, tell event loop to stop 64 | } else if (ev == MG_EV_CLOSE) { 65 | if (!data->done) { 66 | data->done = true; 67 | } 68 | } else if (ev == MG_EV_HTTP_CHUNK) { 69 | mg_error(c, "http chunk no implement"); 70 | c->is_closing = 1; 71 | data->done = true; 72 | } 73 | } 74 | 75 | } // namespace http -------------------------------------------------------------------------------- /src/http_router.cc: -------------------------------------------------------------------------------- 1 | #include "http_router.h" 2 | 3 | #include 4 | 5 | #include "nlohmann/json.hpp" 6 | #include "spdlog/spdlog.h" 7 | namespace http { 8 | void HttpRouter::AddPathRouting(const std::string &path, HttpHandler handler) { 9 | route_table_[path] = handler; 10 | SPDLOG_INFO("route table size={}", route_table_.size()); 11 | } 12 | std::string HttpRouter::HandleHttpRequest(const std::string &path, 13 | const std::string ¶m) { 14 | SPDLOG_INFO("route table size={}", route_table_.size()); 15 | auto it = route_table_.find(path); 16 | if (it != route_table_.end()) { 17 | return it->second(param); 18 | } else { 19 | nlohmann::json ret_data = { 20 | {"code", 200}, {"data", {}}, {"msg", "the url is not supported"}}; 21 | return ret_data.dump(); 22 | } 23 | } 24 | } // namespace http -------------------------------------------------------------------------------- /src/json_utils.cc: -------------------------------------------------------------------------------- 1 | #include "json_utils.h" 2 | #include "utils.h" 3 | #define STR2ULL(str) (base::utils::IsDigit(str) ? stoull(str) : 0) 4 | #define STR2LL(str) (base::utils::IsDigit(str) ? stoll(str) : 0) 5 | #define STR2I(str) (base::utils::IsDigit(str) ? stoi(str) : 0) 6 | namespace wxhelper { 7 | namespace jsonutils { 8 | std::wstring GetWStringParam(nlohmann::json data, std::string key) { 9 | return base::utils::Utf8ToWstring(data[key].get()); 10 | } 11 | 12 | std::vector GetArrayParam(nlohmann::json data, std::string key) { 13 | std::vector result; 14 | std::wstring param = GetWStringParam(data, key); 15 | result = base::utils::split(param, L','); 16 | return result; 17 | } 18 | 19 | int GetIntParam(nlohmann::json data, std::string key) { 20 | int result; 21 | try { 22 | result = data[key].get(); 23 | } catch (nlohmann::json::exception) { 24 | result = STR2I(data[key].get()); 25 | } 26 | return result; 27 | } 28 | 29 | bool GetBoolParam(nlohmann::json data, std::string key) { 30 | return data[key].get(); 31 | } 32 | 33 | std::string GetStringParam(nlohmann::json data, std::string key) { 34 | return data[key].get(); 35 | } 36 | 37 | int64_t GetInt64Param(nlohmann::json data, std::string key) { 38 | int64_t result; 39 | try { 40 | result = data[key].get(); 41 | } catch (nlohmann::json::exception) { 42 | result = STR2LL(data[key].get()); 43 | } 44 | return result; 45 | } 46 | } // namespace jsonutils 47 | } // namespace wxhelper 48 | -------------------------------------------------------------------------------- /src/memory.cc: -------------------------------------------------------------------------------- 1 | #include "include/memory.h" 2 | 3 | namespace base { 4 | namespace memory { 5 | std::vector ScanAndMatchValue(INT64 value, INT64 start, int align) { 6 | SYSTEM_INFO sys_info; 7 | GetSystemInfo(&sys_info); 8 | std::vector result; 9 | INT64 min_addr = 10 | reinterpret_cast(sys_info.lpMinimumApplicationAddress); 11 | INT64 max_addr = 12 | reinterpret_cast(sys_info.lpMaximumApplicationAddress); 13 | const INT64 page_size = sys_info.dwPageSize; 14 | min_addr = min_addr > start ? min_addr : start; 15 | 16 | auto current_addr = min_addr; 17 | MEMORY_BASIC_INFORMATION mem_info = {}; 18 | HANDLE handle = GetCurrentProcess(); 19 | while (current_addr < max_addr) { 20 | VirtualQueryEx(handle, reinterpret_cast(current_addr), &mem_info, 21 | sizeof(MEMORY_BASIC_INFORMATION)); 22 | 23 | if ((INT64)mem_info.RegionSize <= 0) { 24 | break; 25 | } 26 | INT64 region_size = mem_info.RegionSize; 27 | if ((mem_info.State & MEM_COMMIT) == MEM_COMMIT && 28 | (mem_info.Protect & PAGE_GUARD) != PAGE_GUARD && 29 | (mem_info.Protect & PAGE_NOACCESS) != PAGE_NOACCESS) { 30 | for (INT64 i = 0; i < region_size; i += align) { 31 | if (value == *(INT64 *)current_addr) { 32 | result.push_back(current_addr); 33 | } 34 | current_addr += align; 35 | } 36 | } else { 37 | current_addr += region_size; 38 | } 39 | } 40 | return result; 41 | } 42 | 43 | int Sunday(const byte* total, int tlen, const byte* part, int plen) { 44 | byte move[128] = {0}; 45 | for (int i = 0; i < plen; i++) { 46 | move[part[i]] = plen - i; 47 | } 48 | int s = 0; 49 | int j; 50 | while (s <= tlen - plen) { 51 | j = 0; 52 | while (total[s + j] == part[j]) { 53 | j++; 54 | if (j == plen) { 55 | return s; 56 | } 57 | } 58 | s += move[total[s + plen]]; 59 | } 60 | return -1; 61 | } 62 | 63 | } // namespace memory 64 | } // namespace base -------------------------------------------------------------------------------- /src/sync_msg_hook.cc: -------------------------------------------------------------------------------- 1 | #include "sync_msg_hook.h" 2 | 3 | #include "base64.h" 4 | #include "config.h" 5 | #include "nlohmann/json.hpp" 6 | #include "offset.h" 7 | #include "spdlog/spdlog.h" 8 | #include "thread_pool.h" 9 | #include "utils.h" 10 | 11 | #include "wxutils.h" 12 | 13 | namespace wxhelper { 14 | 15 | void SyncMsgHook::Init() { 16 | int64_t addr = wxutils::GetWeChatWinBase() + wechat::offset::kDoAddMsg; 17 | kDoAddMsg = (wechat::function::__DoAddMsg)addr; 18 | origin_ = &kDoAddMsg; 19 | detour_ = &HandleSyncMsg; 20 | hook_flag_ = false; 21 | } 22 | 23 | void SyncMsgHook::HandleSyncMsg(int64_t param1, int64_t param2, int64_t param3) { 24 | nlohmann::json msg; 25 | 26 | msg["pid"] = GetCurrentProcessId(); 27 | msg["fromUser"] = wxutils::ReadSKBuiltinString(*(int64_t *)(param2 + 0x18)); 28 | msg["toUser"] = wxutils::ReadSKBuiltinString(*(int64_t *)(param2 + 0x28)); 29 | msg["content"] = wxutils::ReadSKBuiltinString(*(int64_t *)(param2 + 0x30)); 30 | msg["signature"] = wxutils::ReadWeChatStr(*(int64_t *)(param2 + 0x48)); 31 | msg["msgId"] = *(int64_t *)(param2 + 0x60); 32 | msg["msgSequence"] = *(DWORD *)(param2 + 0x5C); 33 | msg["createTime"] = *(DWORD *)(param2 + 0x58); 34 | msg["displayFullContent"] = wxutils::ReadWeChatStr(*(int64_t *)(param2 + 0x50)); 35 | DWORD type = *(DWORD *)(param2 + 0x24); 36 | msg["type"] = type; 37 | if (type == 3) { 38 | std::string img = wxutils::ReadSKBuiltinBuffer(*(int64_t *)(param2 + 0x40)); 39 | SPDLOG_INFO("encode size:{}", img.size()); 40 | msg["base64Img"] = base64_encode(img); 41 | } 42 | std::string jstr = msg.dump() + '\n'; 43 | hook::InnerMessageStruct *inner_msg = new hook::InnerMessageStruct; 44 | inner_msg->buffer = new char[jstr.size() + 1]; 45 | memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1); 46 | inner_msg->length = jstr.size(); 47 | std::string mode = Config::GetInstance().GetRecvMessageMode(); 48 | if (mode == "http") { 49 | bool add = base::ThreadPool::GetInstance().AddWork( 50 | hook::SendHttpMsgCallback, inner_msg); 51 | SPDLOG_INFO("add http msg work:{}", add); 52 | } else if (mode == "tcp") { 53 | bool add = base::ThreadPool::GetInstance().AddWork(hook::SendTcpMsgCallback, 54 | inner_msg); 55 | SPDLOG_INFO("add tcp msg work:{}", add); 56 | } 57 | if (kDoAddMsg == nullptr){ 58 | int64_t addr = wxutils::GetWeChatWinBase() + wechat::offset::kDoAddMsg; 59 | kDoAddMsg = (wechat::function::__DoAddMsg)addr; 60 | } 61 | kDoAddMsg(param1, param2, param3); 62 | } 63 | } // namespace wxhelper -------------------------------------------------------------------------------- /src/thread_pool.cc: -------------------------------------------------------------------------------- 1 | #include "include/thread_pool.h" 2 | 3 | namespace base { 4 | ThreadPool::~ThreadPool() { 5 | if (cleanup_group_) { 6 | CloseThreadpoolCleanupGroupMembers(cleanup_group_, true, NULL); 7 | CloseThreadpoolCleanupGroup(cleanup_group_); 8 | } 9 | DestroyThreadpoolEnvironment(&env_); 10 | if (pool_) { 11 | CloseThreadpool(pool_); 12 | } 13 | } 14 | 15 | bool ThreadPool::Create(unsigned long min, unsigned long max) { 16 | InitializeThreadpoolEnvironment(&env_); 17 | pool_ = CreateThreadpool(NULL); 18 | if (NULL == pool_) { 19 | return false; 20 | } 21 | SetThreadpoolThreadMaximum(pool_, max); 22 | BOOL ret = SetThreadpoolThreadMinimum(pool_, min); 23 | if (FALSE == ret) { 24 | return false; 25 | } 26 | cleanup_group_ = CreateThreadpoolCleanupGroup(); 27 | if (NULL == cleanup_group_) { 28 | return false; 29 | } 30 | SetThreadpoolCallbackPool(&env_, pool_); 31 | SetThreadpoolCallbackCleanupGroup(&env_, cleanup_group_, NULL); 32 | return true; 33 | } 34 | 35 | bool ThreadPool::AddWork(PTP_WORK_CALLBACK callback, PVOID opt) { 36 | PTP_WORK work = CreateThreadpoolWork(callback, opt, &env_); 37 | if (NULL == work) { 38 | return false; 39 | } 40 | SubmitThreadpoolWork(work); 41 | return true; 42 | } 43 | 44 | } // namespace base -------------------------------------------------------------------------------- /src/wxhelper.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "wxhelper.h" 3 | 4 | #include "config.h" 5 | #include "http_server.h" 6 | #include "thread_pool.h" 7 | #include "utils.h" 8 | #include "wxutils.h" 9 | #include "wechat_db.h" 10 | #include "sync_msg_hook.h" 11 | #include "wechat_service.h" 12 | namespace wxhelper { 13 | 14 | void WxHelper::init(HMODULE module) { 15 | Config::GetInstance().init(); 16 | if (Config::GetInstance().GetHideDll()) { 17 | base::utils::HideModule(module); 18 | } 19 | wechat::WeChatDb::GetInstance().Init(); 20 | wechat::WeChatService::GetInstance().Init(); 21 | SyncMsgHook::GetInstance().Init(); 22 | http::HttpServer::GetInstance().init( 23 | Config::GetInstance().GetHttpServerHost(), 24 | Config::GetInstance().GetHttpServerPort()); 25 | http::HttpServer::GetInstance().Start(); 26 | base::ThreadPool::GetInstance().Create(2, 8); 27 | } 28 | void WxHelper::finally() { http::HttpServer::GetInstance().Stop(); } 29 | } // namespace wxhelper -------------------------------------------------------------------------------- /src/wxutils.cc: -------------------------------------------------------------------------------- 1 | #include "wxutils.h" 2 | 3 | #include "utils.h" 4 | #define BUFSIZE 1024 5 | #define JPEG0 0xFF 6 | #define JPEG1 0xD8 7 | #define JPEG2 0xFF 8 | #define PNG0 0x89 9 | #define PNG1 0x50 10 | #define PNG2 0x4E 11 | #define BMP0 0x42 12 | #define BMP1 0x4D 13 | #define GIF0 0x47 14 | #define GIF1 0x49 15 | #define GIF2 0x46 16 | namespace wxhelper { 17 | namespace wxutils { 18 | #ifdef _WIN64 19 | int64_t GetWeChatWinBase() { 20 | return (int64_t)GetModuleHandleA("WeChatWin.dll"); 21 | } 22 | #else 23 | int32_t GetWeChatWinBase() { 24 | return (int32_t)GetModuleHandleA("WeChatWin.dll"); 25 | } 26 | #endif 27 | 28 | std::string ReadSKBuiltinString(INT64 addr) { 29 | INT64 inner_string = *(INT64 *)(addr + 0x8); 30 | if (inner_string == 0) { 31 | return std::string(); 32 | } 33 | return ReadWeChatStr(inner_string); 34 | } 35 | 36 | std::string ReadSKBuiltinBuffer(INT64 addr) { 37 | INT64 len = *(INT64 *)(addr + 0x10); 38 | if (len == 0) { 39 | return std::string(); 40 | } 41 | INT64 inner_string = *(INT64 *)(addr + 0x8); 42 | if (inner_string == 0) { 43 | return std::string(); 44 | } 45 | return ReadWeChatStr(inner_string); 46 | } 47 | 48 | std::string ReadWeChatStr(INT64 addr) { 49 | INT64 len = *(INT64 *)(addr + 0x10); 50 | if (len == 0) { 51 | return std::string(); 52 | } 53 | INT64 max_len = *(INT64 *)(addr + 0x18); 54 | if ((max_len | 0xF) == 0xF) { 55 | return std::string((char *)addr, len); 56 | } 57 | char *char_from_user = *(char **)(addr); 58 | return std::string(char_from_user, len); 59 | } 60 | 61 | std::string ImageXor(std::string buf) { 62 | const char *origin = buf.c_str(); 63 | short key = 0; 64 | if ((*origin ^ JPEG0) == (*(origin + 1) ^ JPEG1)) { 65 | key = *origin ^ JPEG0; 66 | } else if ((*origin ^ PNG1) == (*(origin + 1) ^ PNG2)) { 67 | key = *origin ^ PNG1; 68 | } else if ((*origin ^ GIF0) == (*(origin + 1) ^ GIF1)) { 69 | key = *origin ^ GIF0; 70 | } else if ((*origin ^ BMP0) == (*(origin + 1) ^ BMP1)) { 71 | key = *origin ^ BMP0; 72 | } else { 73 | key = -1; 74 | } 75 | if (key > 0) { 76 | char *img_buf = new char[buf.size()]; 77 | for (unsigned int i = 0; i < buf.size(); i++) { 78 | img_buf[i] = *(origin + i) ^ key; 79 | } 80 | std::string str(img_buf); 81 | delete[] img_buf; 82 | img_buf = NULL; 83 | return str; 84 | } 85 | return std::string(); 86 | } 87 | 88 | std::wstring ReadWstring(INT64 addr) { 89 | DWORD len = *(DWORD *)(addr + 0x8); 90 | if (len == 0) { 91 | return std::wstring(); 92 | } 93 | wchar_t *str = *(wchar_t **)(addr); 94 | if (str == NULL) { 95 | return std::wstring(); 96 | } 97 | return std::wstring(str, len); 98 | } 99 | std::string ReadWstringThenConvert(INT64 addr) { 100 | std::wstring wstr = ReadWstring(addr); 101 | return base::utils::WstringToUtf8(wstr); 102 | } 103 | 104 | int DecodeImage(const wchar_t *file_path, const wchar_t *save_dir) { 105 | return -1; 106 | } 107 | 108 | bool FindOrCreateDirectory(const std::wstring &path) { 109 | WIN32_FIND_DATAW fd; 110 | HANDLE found = ::FindFirstFileW(path.c_str(), &fd); 111 | if (found != INVALID_HANDLE_VALUE && 112 | (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { 113 | FindClose(found); 114 | return true; 115 | } 116 | 117 | if (!::CreateDirectoryW(path.c_str(), NULL)) { 118 | return false; 119 | } 120 | return true; 121 | } 122 | 123 | } // namespace wxutils 124 | } // namespace wxhelper 125 | -------------------------------------------------------------------------------- /version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/version.png -------------------------------------------------------------------------------- /wxhelper.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomms/wxhelper/a8bd504a982acd0b1f240255d4f2d1dc1a19e5c8/wxhelper.rc -------------------------------------------------------------------------------- /wxhelper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34723.18 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxhelper", "wxhelper.vcxproj", "{40818871-0BD0-4363-B5C3-198F3CEF6CC0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {40818871-0BD0-4363-B5C3-198F3CEF6CC0}.Debug|x64.ActiveCfg = Debug|x64 15 | {40818871-0BD0-4363-B5C3-198F3CEF6CC0}.Debug|x64.Build.0 = Debug|x64 16 | {40818871-0BD0-4363-B5C3-198F3CEF6CC0}.Release|x64.ActiveCfg = Release|x64 17 | {40818871-0BD0-4363-B5C3-198F3CEF6CC0}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {6E2841B9-FB48-4FB4-80D0-6970D17FB19C} 24 | EndGlobalSection 25 | EndGlobal 26 | --------------------------------------------------------------------------------