/* * Tencent is pleased to support the open source community by making * MMKV available. * * Copyright (C) 2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of * the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "MMKVLog.h" #ifdef MMKV_WIN32 #include #endif // MMKV_WIN32 MMKV_NAMESPACE_BEGIN #ifdef MMKV_DEBUG MMKVLogLevel g_currentLogLevel = MMKVLogDebug; #else MMKVLogLevel g_currentLogLevel = MMKVLogInfo; #endif #ifndef __FILE_NAME__ const char *_getFileName(const char *path) { const char *ptr = strrchr(path, '/'); if (!ptr) { ptr = strrchr(path, '\\'); } if (ptr) { return ptr + 1; } else { return path; } } #endif mmkv::MMKVHandler *g_handler = nullptr; MMKV_NAMESPACE_END #ifdef ENABLE_MMKV_LOG # include # include using namespace mmkv; # ifndef MMKV_ANDROID static const char *MMKVLogLevelDesc(MMKVLogLevel level) { switch (level) { case MMKVLogDebug: return "D"; case MMKVLogInfo: return "I"; case MMKVLogWarning: return "W"; case MMKVLogError: return "E"; default: return "N"; } } # ifdef MMKV_APPLE void _MMKVLogWithLevel(MMKVLogLevel level, const char *filename, const char *func, int line, const char *format, ...) { if (level >= g_currentLogLevel) { NSString *nsFormat = [NSString stringWithUTF8String:format]; va_list argList; va_start(argList, format); NSString *message = [[NSString alloc] initWithFormat:nsFormat arguments:argList]; va_end(argList); if (g_handler) { g_handler->mmkvLog(level, filename, line, func, message); } else { NSLog(@"[%s] <%s:%d::%s> %@", MMKVLogLevelDesc(level), filename, line, func, message); } } } # else #if defined(MMKV_WIN32) // Helper to write raw bytes or convert to WideChar based on destination static void WriteUTF8ToStream(const char* utf8_str) { HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD consoleMode; if (GetConsoleMode(hOut, &consoleMode)) { // --- CONSOLE: Convert to UTF-16 and write --- int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, NULL, 0); if (wlen > 0) { wchar_t* wbuf = (wchar_t*)malloc(wlen * sizeof(wchar_t)); if (wbuf) { MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, wbuf, wlen); WriteConsoleW(hOut, wbuf, wlen - 1, NULL, NULL); free(wbuf); } } } else { // --- FILE/PIPE: Write raw UTF-8 bytes --- DWORD bytesWritten; WriteFile(hOut, utf8_str, (DWORD)strlen(utf8_str), &bytesWritten, NULL); } } // Main VarArg Function static void PrintUTF8(const char* format, ...) { va_list args; // 1. Calculate required length // We pass NULL/0 to vsnprintf just to get the required size (excluding null terminator) va_start(args, format); int len = vsnprintf(NULL, 0, format, args); va_end(args); if (len < 0) return; // Encoding error or invalid format // 2. Allocate buffer (len + 1 for null terminator) // Using malloc ensures we don't overflow the stack with huge strings char* buf = (char*)malloc(len + 1); if (!buf) return; // Out of memory // 3. Format the string into the buffer va_start(args, format); vsnprintf(buf, len + 1, format, args); va_end(args); // 4. Send to output helper WriteUTF8ToStream(buf); // 5. Cleanup free(buf); } #endif void _MMKVLogWithLevel(MMKVLogLevel level, const char *filename, const char *func, int line, const char *format, ...) { if (level >= g_currentLogLevel) { std::string message; char buffer[16]; va_list args; va_start(args, format); auto length = std::vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); if (length < 0) { // something wrong message = {}; } else if (length < sizeof(buffer)) { message = std::string(buffer, static_cast(length)); } else { message.resize(static_cast(length), '\0'); va_start(args, format); std::vsnprintf(const_cast(message.data()), static_cast(length) + 1, format, args); va_end(args); } if (g_handler) { g_handler->mmkvLog(level, filename, line, func, message); } else { #if defined(MMKV_WIN32) PrintUTF8("[%s] <%s:%d::%s> %s\n", MMKVLogLevelDesc(level), filename, line, func, message.c_str()); #else printf("[%s] <%s:%d::%s> %s\n", MMKVLogLevelDesc(level), filename, line, func, message.c_str()); #endif //fflush(stdout); } } } # endif // MMKV_APPLE # endif // MMKV_ANDROID #endif // ENABLE_MMKV_LOG