#include #include #include #include #include #include #if defined(WIN32) || defined(_WIN64) #include #include #include #include #include #define MKDIR(a, b) mkdir(a) #pragma comment(lib, "imagehlp.lib") #pragma comment(lib, "Psapi.lib") #pragma comment(lib, "shlwapi.lib") #else #define MKDIR(a, b) mkdir(a, b) #include #include #include #include #include #include #endif #include #include "../wrapper/hg_log.h" #include #include #include "ini_file.h" #define VMRSS_LINE 21 //实际物理内存使用? #define MAX_LOG_FILE_SIZE 10 * 1024 * 1024 #ifdef _INTSIZEOF #undef _INTSIZEOF #define _INTSIZEOF(n) ((sizeof(n) + sizeof(long) - 1) & ~(sizeof(long) - 1)) #endif extern std::string g_scanner_path; // Ending with '\\' static std::string log_divider("=========================================================================\n"); class log_cls { typedef void(*log_to)(const char*, void*, void*); std::string path_file_; FILE* file_; log_to log_; int level_; log_callback lcb_; std::mutex lock_; static log_cls* inst_; static FILE* create_log_file(const char* path_file, bool truncate) { FILE* file_ = fopen(path_file, "a+b"); if (file_) { fseek(file_, 0, SEEK_END); if (ftell(file_) == 0) { unsigned char bom[] = { 0x0ef, 0x0bb, 0x0bf }; fwrite(bom, sizeof(bom), 1, file_); } std::string now(g_time_tag + hg_log::current_time() + g_time_tag); now += truncate ? " trcated.\n" : " started.\n"; now.insert(0, log_divider); fwrite(now.c_str(), 1, now.length(), file_); } return file_; } static void log_none(const char* info, void* param, void* param2) {} static void log_consonle(const char* info, void* param, void* param2) { printf(info); } static void log_file(const char* info, void* param, void* param2) { FILE** file = (FILE**)param; if(*file == nullptr) *file = create_log_file(((std::string*)param2)->c_str(), false); if (*file) { fwrite(info, 1, strlen(info), *file); fflush(*file); if (ftell(*file) >= MAX_LOG_FILE_SIZE) { fclose(*file); remove(((std::string*)param2)->c_str()); *file = create_log_file(((std::string*)param2)->c_str(), true); } } } protected: log_cls() : path_file_(""), file_(0), log_(&log_cls::log_consonle), level_(LOG_LEVEL_ALL), lcb_(NULL) {} ~log_cls() { if (file_) { fclose(file_); file_ = 0; } } public: static std::string g_time_tag; static log_cls* instance(void) { if (!log_cls::inst_) log_cls::inst_ = new log_cls(); return log_cls::inst_; } static void clear(void) { if (log_cls::inst_) { delete log_cls::inst_; log_cls::inst_ = nullptr; } } int set_log_type(int type, void* param) { int ret = 0; if (file_) { fclose(file_); file_ = 0; } lcb_ = NULL; log_ = NULL; if (type == LOG_TYPE_NONE) log_ = &log_cls::log_none; else if(type == LOG_TYPE_CONSOLE) log_ = &log_cls::log_consonle; else if (type == LOG_TYPE_FILE) { log_ = &log_cls::log_file; ret = -1; if (param) { path_file_ = (char*)param; file_ = create_log_file(path_file_.c_str(), false); if (file_) ret = 0; } } else if (type == LOG_TYPE_CALLBACK) { lcb_ = (log_callback)param; } if(ret != 0) log_ = &log_cls::log_none; return ret; } void set_log_level(int level) { level_ = level; } bool is_log_level_enabled(int level) { return level >= level_; } void log(const char* info) { std::lock_guard lock(lock_); log_(info, &file_, &path_file_); } std::string get_log_file_path(bool copy) { std::string file(""); if (log_ == &log_cls::log_file && file_) { file = path_file_; if (copy) { file += ".txt"; FILE* dst = fopen(file.c_str(), "wb"); if (!dst) file = ""; else { std::lock_guard lock(lock_); char buf[1024] = { 0 }; size_t l = 0; fseek(file_, 0, SEEK_SET); while ((l = fread(buf, 1, sizeof(buf), file_))) fwrite(buf, 1, l, dst); fclose(dst); } } } return file; } void clear_log(void) { if (log_ == &log_cls::log_file && file_) { std::lock_guard lock(lock_); fclose(file_); remove(path_file_.c_str()); file_ = create_log_file(path_file_.c_str(), true); } } }; log_cls* log_cls::inst_ = NULL; std::string log_cls::g_time_tag = "====="; #ifdef EXPORT_AS_C extern "C" { #endif namespace hg_log { static simple_ini ini_; static log_callback lcb_ = NULL; typedef struct _find_file { std::string pattern; std::string found; }FINDFILE, * LPFF; static bool on_found(const char* file, void* param) { LPFF lpff = (LPFF)param; char pth = PATH_SEPARATOR[0]; const char* name = strrchr(file, pth); if (name++ == nullptr) name = file; std::string lc(name); str_tolower(lc); if (lc.find(lpff->pattern) != std::string::npos) { lpff->found = file; return false; } return true; } #if defined(WIN32) || defined(_WIN64) static std::string u2a(const wchar_t* u, UINT cp = CP_ACP) { std::string a(""); if (u) { char stack[256] = { 0 }, * ansi = NULL; int len = 0; len = WideCharToMultiByte(cp, 0, u, lstrlenW(u), NULL, 0, NULL, NULL); ansi = new char[len + 2]; len = WideCharToMultiByte(cp, 0, u, lstrlenW(u), ansi, len, NULL, NULL); ansi[len--] = 0; a = ansi; delete[] ansi; } return a; } static int enum_files(const char* dir, bool recursive, bool(*found_file)(const char* path_file, void* param), void* param) { int ret = 0; HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); MODULEENTRY32W pei = { 0 }; if (h == INVALID_HANDLE_VALUE) ret = GetLastError(); else { pei.dwSize = sizeof(pei); if (Module32FirstW(h, &pei)) { do { std::string ansi(u2a(pei.szExePath)); if (!found_file(ansi.c_str(), param)) break; pei.dwSize = sizeof(pei); } while (Module32NextW(h, &pei)); } CloseHandle(h); } return ret; } #else static std::string link_file(const char* lnk) { char path[256] = { 0 }; int len = readlink(lnk, path, sizeof(path) - 1); return len > 0 ? path : lnk; } static int enum_files(const char* dir, bool recursive, bool(*found_file)(const char* path_file, void* param), void* param) { int ret = 0; DIR* pdir = nullptr; struct dirent* ent = nullptr; pdir = opendir(dir); if (!pdir) return errno; while ((ent = readdir(pdir))) { if (ent->d_type & DT_DIR) { if (recursive) { if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) { std::string sub(dir); sub += "/"; sub += ent->d_name; ret = enum_files(sub.c_str(), recursive, found_file, param); if (ret == 0x5e17) break; } } } else { std::string file(dir); file += "/"; file += ent->d_name; if (!found_file(link_file(file.c_str()).c_str(), param)) { ret = 0x5e17; break; } } } return ret; } #endif std::string get_scanimage_ver() { #if defined(WIN32) || defined(_WIN64) return ""; #else FILE* fp = NULL; char buf[128] = { 0 }; fp = popen("scanimage -V", "r"); if (!fp) return ""; int ret = fread(buf, 1, sizeof(buf) - 1, fp); if(ret<1) return ""; pclose(fp); std::string str = buf; return str.substr(str.size()-7); #endif } void clear_log(void) { log_cls::instance()->clear_log(); } //static std::string get_scanimage_ver() //{ // FILE* fp = popen("scanimage -V","r"); // if (!fp) // { // return ""; // } // long len = 0; // fseek(fp, 0, SEEK_END); // len = ftell(fp); // fseek(fp, 0, SEEK_SET); // char* buf = new char[len]; // if (!buf) // { // return ""; // } // int ret = fread(buf, 1, sizeof(buf) - 1, fp); // pclose(); //} std::string format_ptr(void* ptr) { char buf[40]; if (sizeof(ptr) == sizeof(int)) { sprintf(buf, "0x%08x", ptr); } else { unsigned int* n = (unsigned int*)&ptr; sprintf(buf, "0x%x%08x", n[1], n[0]); } return buf; } std::string format_current_thread_id(void) { #if defined(WIN32) || defined(_WIN64) return format_ptr((void*)GetCurrentThreadId()); #else return format_ptr((void*)pthread_self()); #endif } std::string current_time(void) { char buf[40] = { 0 }; hg_get_current_time(buf); return buf; } std::string format_size(unsigned long size) { char buf[40]; if (size > 1024 * 1024 * 1024) { double d = size; d /= 1024 * 1024 * 1024; sprintf(buf, "%.2fGB", d); } else if (size > 1024 * 1024) { double d = size; d /= 1024 * 1024; sprintf(buf, "%.2fMB", d); } else if (size > 1024) { double d = size; d /= 1024; sprintf(buf, "%.1fKB", d); } else { sprintf(buf, "%u bytes", (unsigned int)size); } return buf; } std::string u2utf8(const wchar_t* u) { std::string utf8(""); #if defined(WIN32) || defined(_WIN64) utf8 = u2a(u, CP_UTF8); #else #endif return utf8; } std::string pe_path(std::string* name) { #if defined(WIN32) || defined(_WIN64) wchar_t path[MAX_PATH] = { 0 }, * last = NULL; GetModuleFileNameW(NULL, path, _countof(path) - 1); last = wcsrchr(path, L'\\'); if (last) { if (name) *name = u2utf8(last + 1); *last = 0; } return u2utf8(path); #else char path[256] = { 0 }; int len = readlink("/proc/self/exe", path, sizeof(path) - 1); if (len > 0 && len < sizeof(path)) { for (--len; len > 0; --len) { if (path[len] == '/') { path[len] = 0; if (name) *name = path + len + 1; break; } } } return path; #endif } unsigned long long available_memory(void) { #if defined(WIN32) || defined(_WIN64) MEMORYSTATUSEX ms; if (GlobalMemoryStatusEx(&ms)) return ms.ullAvailPhys; else return -1; #else struct sysinfo si; if (sysinfo(&si) == 0) return si.freeram * si.mem_unit; #endif } void str_tolower(std::string& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); } bool create_folder(const char* fodler) { return MKDIR(fodler, S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST; } std::string ini_get(const char* app, const char* key) { return ini_.get(app, key); } void ini_set(const char* app, const char* key, const char* val) { ini_.set(app, key, val); } std::string get_module_full_path(const char* module_part_name) { char path[128] = { 0 }; FINDFILE ff; ff.pattern = module_part_name; str_tolower(ff.pattern); #if defined(WIN32) || defined(_WIN64) #else sprintf(path, "/proc/%u/map_files/", getpid()); #endif enum_files(path, false, on_found, &ff); return ff.found; } std::string get_scanner_path(void) { return g_scanner_path; } unsigned int get_page_size(unsigned int* map_unit) { unsigned int ps = 1024; #if defined(WIN32) || defined(_WIN64) SYSTEM_INFO si = { 0 }; GetSystemInfo(&si); ps = si.dwPageSize; if (map_unit) *map_unit = si.dwAllocationGranularity; #else ps = sysconf(_SC_PAGESIZE); if(ps < 1024 || (ps & 0x0fe0000ff)) // nKB && < 16MB ps = getpagesize(); if (map_unit) *map_unit = ps; #endif if (ps < 1024 || (ps & 0x0fe0000ff)) // nKB && < 16MB ps = 1024; return ps; } static int get_log_config(const std::string& root, hg_log_type* type, std::string* path) { std::string me(root + PATH_SEPARATOR + "config" + PATH_SEPARATOR + "debug.cfg"); int lv = LOG_LEVEL_ALL; hg_log_type tp = LOG_TYPE_FILE; if (!type) type = &tp; *type = LOG_TYPE_FILE; if (ini_.load(me.c_str()) == 0) { std::string val(ini_.get("log", "type")); if (val == "console") *type = LOG_TYPE_CONSOLE; else if (val == "none") *type = LOG_TYPE_NONE; else *type = LOG_TYPE_FILE; if (*type == LOG_TYPE_FILE && path) { *path = ini_.get("log", "path"); } val = ini_.get("log", "level"); if (val == "debug") lv = LOG_LEVEL_DEBUG_INFO; else if (val == "warning") lv = LOG_LEVEL_WARNING; else if (val == "fatal") lv = LOG_LEVEL_FATAL; } else create_folder((root + PATH_SEPARATOR + "config").c_str()); return lv; } std::string local_data_path(void) { static std::string local_data_path(""); static bool load_first = true; if (load_first) { simple_ini first; load_first = false; if (first.load((get_scanner_path() + "first.cfg").c_str()) == 0) { std::string env = first.get("constraints", "local_data_path"); if (env.length()) local_data_path = env; } } std::string home(local_data_path); if (home.empty()) { #if defined(WIN32) || defined(_WIN64) std::string env("LOCALAPPDATA"), lead(""); #else std::string env("HOME"), lead("."); #endif char* tmp = getenv(env.c_str()); if (tmp) home = tmp; home += PATH_SEPARATOR + lead; } #ifdef OEM_HANWANG home += "HanvonScan"; #elif defined(OEM_LISICHENG) home += "LanxumScan"; #elif defined(OEM_CANGTIAN) home += "CumTennScan"; #elif defined(OEM_ZHONGJING) home += "MicrotekScan"; #elif defined(OEM_ZIGUANG) home += "UniScan"; #elif defined(OEM_DELI) home += "DeliScan"; #elif defined(OEM_NEUTRAL) home += "NeuScan"; #else home += "HuaGoScan"; #endif; create_folder(home.c_str()); return home; } std::string temporary_path(void) { return simple_ini::temporary_path(); } std::string log_file_path(void) { return log_cls::instance()->get_log_file_path(true); } int init(void) { char* file = nullptr; std::string path(""); hg_log_type type = LOG_TYPE_FILE; int level = get_log_config(local_data_path(), &type, &path); if (type == LOG_TYPE_FILE) { std::string name(""), paths[] = { local_data_path(), pe_path(&name), get_scanner_path(), temporary_path()}; int ind = 0; if (!path.empty() && create_folder(path.c_str())) ind = sizeof(paths) / sizeof(paths[0]) + 2; for (; ind < sizeof(paths) / sizeof(paths[0]); ++ind) { path = paths[ind] + PATH_SEPARATOR + "Log"; if (create_folder(path.c_str())) break; } if(ind == sizeof(paths) / sizeof(paths[0])) { VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "# Try PE, scanner and temporary path failed(%d), log to console\n", errno); type = LOG_TYPE_CONSOLE; } if (type == LOG_TYPE_FILE) { if (name.empty()) path += std::string(PATH_SEPARATOR) + "scanner.log"; else path += PATH_SEPARATOR + name + ".log"; file = &path[0]; VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "# Log to file: '%s'\n", path.c_str()); } } log_cls::instance()->set_log_level(level); return log_cls::instance()->set_log_type(type, file); } void unint(void) { std::string now(log_cls::g_time_tag + hg_log::current_time() + log_cls::g_time_tag + " exited.\n"); log(now.c_str()); log((log_divider + "\n\n\n\n").c_str()); log_cls::clear(); } void log(int level, const char* info) { if (lcb_) lcb_(level, info); else if (log_cls::instance()->is_log_level_enabled(level)) log_cls::instance()->log(info); } bool is_log_level_enabled(int level) { return log_cls::instance()->is_log_level_enabled(level); } void log(const char* info) { log_cls::instance()->log(info); } float GetMemoryUsage(int pid) { #ifdef WIN32 uint64_t mem = 0, vmem = 0; PROCESS_MEMORY_COUNTERS pmc; HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc))) { mem = pmc.WorkingSetSize; vmem = pmc.PagefileUsage; } CloseHandle(process); return mem / 1024.0 / 1024.0;//byte TO MB #else char file_name[64] = { 0 }; FILE* fd; char line_buff[512] = { 0 }; sprintf(file_name, "/proc/%d/status", pid); fd = fopen(file_name, "r"); if (nullptr == fd) return 0; char name[64]; int vmrss = 0; for (int i = 0; i < VMRSS_LINE - 1; i++) fgets(line_buff, sizeof(line_buff), fd); fgets(line_buff, sizeof(line_buff), fd); sscanf(line_buff, "%s %d", name, &vmrss); fclose(fd); return vmrss / 1024.0;//KB TO MB #endif } float GetAppMemoryUsage() { return GetMemoryUsage(getpid()); } const char* lang_load(uint32_t id) { int err = 0; const char *lang = lang_load_string(id, &err); if (err != 0) { return ""; } return lang; } } #ifdef EXPORT_AS_C } #endif #if defined(WIN32) || defined(_WIN64) void hg_debug_log(int level, const char* info) { hg_log::log(level, info); } #endif