text: ﻿#include "stdafx.h"
  #include "tool.h"
  
  #include <shlwapi.h>
  #include <shlobj.h>
  #include <io.h>
  #include <fcntl.h>
  #include <sys/stat.h>
  #include <shellapi.h>
  #include <GdiPlus.h>
  
  #include "base/util/string_util.h"
  #include "base/file/file_util.h"
  #include "base/thread/framework_thread.h"
  #include "base/macros.h"
  #include "base/win32/path_util.h"
  
  UINT g_show_wnd_forgroud_message = 0;
  
  namespace shared
  {
  namespace tools
  {
  const wchar_t KShowWndForgroudMessageID[] = L"ShowWndForgroudMessageIdentifer";
  
  //////////////////////////////////////////////////////
  // 系统相关
  int GetOSVersion()
  {
  	static int os_version_ = -1;
  	if (os_version_ < 0)
  	{
  		OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };
  		if (!::GetVersionEx(&ovi))
  			return -1;
  
  		os_version_ = (ovi.dwMajorVersion * 100 + ovi.dwMinorVersion);
  	}
  	return os_version_;
  }
  
  std::string GetOSVersionString()
  {
  	int ver = GetOSVersion();
  	switch (ver)
  	{
  	case 500:
  		return "Windows 2000";
  	case 501:
  		return "Windows XP";
  	case 502:
  		return "Windows Server 2003";
  	case 600:
  		return "Windows Vista";
  	case 601:
  		return "Windows 7";
  	case 602:
  		return "Windows 8";
  	default:
  		return nbase::StringPrintf("[%d]", ver);
  	}
  }
  
  typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
  LPFN_ISWOW64PROCESS fnIsWow64Process;
  bool IsWow64()
  {
  	BOOL is_wow64 = FALSE;
  	fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
  		GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
  
  	if(NULL != fnIsWow64Process)
  	{
  		if (!fnIsWow64Process(GetCurrentProcess(),&is_wow64))
  			return false;
  	}
  
  	return is_wow64 ? true : false;
  }
  
  //////////////////////////////////////////////////////
  // 字符串处理
  std::string FormatTime(nbase::Time::TimeStruct	t)
  {
  	return nbase::StringPrintf("%04u-%02u-%02u %02u:%02u:%02u", 
  		t.year(), t.month(), t.day_of_month(),
  		t.hour(), t.minute(), t.second());
  }
  
  std::wstring FormatBytes(double bytes)
  {
  	if (bytes < 1024 * 1024)
  		return nbase::StringPrintf(L"%.2fKB", bytes / 1024);
  	else if (bytes < 1024 * 1024 * 1024)
  		return nbase::StringPrintf(L"%.2fMB", bytes / 1024 / 1024);
  	else
  		return nbase::StringPrintf(L"%.2fGB", bytes / 1024 / 1024 / 1024);
  }
  
  std::wstring FormatBps(double bytes)
  {
  	double bits = bytes * 8;
  	
  	if (bits < 100000)
  		return nbase::StringPrintf(L"%dbps", (int)bits);
  	else if (bits < 1024 * 1024)
  		return nbase::StringPrintf(L"%dKbps", (int)(bits / 1024));
  	else if (bits < 1024 * 1024 * 1024)
  		return nbase::StringPrintf(L"%.2fMbps", bits / 1024 / 1024);
  	else
  		return nbase::StringPrintf(L"%.2fGbps", bits / 1024 / 1024 / 1024);
  }
  
  void SplitString(const std::string &str, const std::string &seperator, std::vector<std::string> &array) 
  {
  	array.clear();
  	if (str.empty() || seperator.empty())
  		return;
  
  	size_t position;
  	std::string tmp_str = str;
  
  	position = tmp_str.find(seperator.c_str());        
  	while (position != tmp_str.npos)
  	{
  		if (position)
  			array.push_back(tmp_str.substr(0, position));
  		tmp_str.erase(0, position + seperator.length());
  		position = tmp_str.find(seperator);
  	}
  
  	if (!tmp_str.empty())
  		array.push_back(tmp_str);
  }
  
  void SplitString(const std::wstring &str, const std::wstring &seperator, std::vector<std::wstring> &array) 
  {
  	array.clear();
  	if (str.empty() || seperator.empty())
  		return;
  
  	size_t position;
  	std::wstring tmp_str = str;
  
  	position = tmp_str.find(seperator.c_str());        
  	while (position != tmp_str.npos)
  	{
  		if (position)
  			array.push_back(tmp_str.substr(0, position));
  		tmp_str.erase(0, position + seperator.length());
  		position = tmp_str.find(seperator);
  	}
  
  	if (!tmp_str.empty())
  		array.push_back(tmp_str);
  }
  
  std::string StringReverse(const std::string &input)
  {
  	int len = input.size();
  	std::string output;
  	output.resize(len);
  	for (int i = 0; i < len; i++)
  	{
  		output[i] = input[len - 1 - i];
  	}
  
  	return output;
  }
  
  std::string FilterUCS4(const std::string& str, bool replace_spaces)
  {
  	if (GetOSVersion() >= 602)
  	{
  		return str;
  	}
  	bool ret = true;
  	std::string str_out;
  	for (UINT i=0;i<str.size();)
  	{
  		UINT single_char = str.at(i);
  		single_char &= 0xff;
  		//int char_count = GetUtf8CharCount(single_char);
  		if (single_char >= 0xf0)//过滤0xffff+
  		{
  			i += 4;
  			if (single_char >= 0xf8)
  			{
  				i++;
  			}
  			if (single_char >= 0xfc)
  			{
  				i++;
  			}
  			ret = false;
  			if (replace_spaces)
  			{
  				str_out += " ";
  			}
  			continue;
  		} 
  		else
  		{
  			if (single_char == 0xe2 && i+2 < str.size())//过滤其他无法显示的字符表情 0x26xx为表情符 0x2700-0x27bf为印刷符
  			{
  				UINT ch_u = 0x2000;
  				UINT single_char_temp = str.at(i+1);
  				single_char_temp &= 0x3f;
  				ch_u += single_char_temp<<6;
  				single_char_temp = str.at(i+2);
  				single_char_temp &= 0x3f;
  				ch_u += single_char_temp;
  				if (GetOSVersion() >= 600)//win7 vista
  				{
  					if (ch_u == 0x2614 || ch_u == 0x2615 || ch_u == 0x2618 || ch_u == 0x2619
  						|| ch_u == 0x2670 || ch_u == 0x2670 || ch_u == 0x2670
  						|| (ch_u >= 0x267e && ch_u < 0x27c0) )
  					{
  						i += 3;
  						ret = false;
  						if (replace_spaces)
  						{
  							str_out += " ";
  						}
  						continue;
  					}
  				} 
  				else//xp
  				{
  					if ((ch_u >= 0x2614 && ch_u <= 0x2619) || (ch_u >= 0x267e && ch_u < 0x27c0))
  					{
  						i += 3;
  						ret = false;
  						if (replace_spaces)
  						{
  							str_out += " ";
  						}
  						continue;
  					}
  				}
  			}
  			str_out += str.at(i);
  			i++;
  		}
  	}
  	return str_out;
  }
  
  UTF8String FormatSQLText(const UTF8String &sql_text)
  {
  	UTF8String formated_text(sql_text);
  	//SQL标准规定，在字符串中，单引号需要使用逃逸字符，即在一行中使用两个单引号。
  	nbase::StringReplaceAll("'", "''", formated_text);
  	return formated_text;
  }
  
  //////////////////////////////////////////////////////
  // 文件处理
  std::wstring GetSpecialFolder(int id)
  {
  	std::wstring path;
  
  	LPITEMIDLIST idl;		
  	LPMALLOC shell_malloc;
  	if (SHGetMalloc(&shell_malloc) == S_OK)
  	{
  		if (SHGetSpecialFolderLocation(NULL, id , &idl) == S_OK)
  		{
  			WCHAR *dir = new WCHAR[MAX_PATH];
  			SHGetPathFromIDList(idl, dir);
  			shell_malloc->Free(idl);
  			path = dir;
  			delete dir;
  		}
  		shell_malloc->Release();
  	}
  
  	return path;
  }
  
  std::wstring GetResourcePath(void)
  {
  	std::wstring app_path = nbase::win32::GetCurrentModuleDirectory();
  	return app_path + L"res\\";
  }
  
  void MakeExtendPath(std::wstring &path)
  {
  	std::wstring temp = nbase::StringPrintf(L"\\\\?\\%s", path.c_str());
  	path = temp;
  }
  
  // 清空达到一定长度的文件
  void ClearFile(const wchar_t *path, long file_length_limit)
  {
  	int fd;
  	if ((fd = _wopen(path, O_CREAT | O_RDWR | O_APPEND, _S_IREAD | _S_IWRITE)) < 0)
  		return;
  
  	long len = _filelength(fd);
  	_close(fd);
  	if (len < file_length_limit)
  		return;
  
  	if ((fd = _wopen(path, O_CREAT | O_RDWR | O_TRUNC, _S_IREAD | _S_IWRITE)) >= 0)
  		_close(fd);
  }
  
  bool FilePathIsExist(const std::string &utf8_filepath_in, bool is_directory)
  {
  	std::wstring filepath_in = nbase::UTF8ToUTF16(utf8_filepath_in);
  	return nbase::FilePathIsExist(filepath_in, is_directory);
  }
  
  bool FindFile(const std::wstring &dir,const std::wstring &file_desc,std::wstring &file_path)
  {
  	WIN32_FIND_DATAW find_data;
  	HANDLE file_handle;
  
  	file_handle = ::FindFirstFileW(nbase::StringPrintf(L"%s%s",dir.c_str(),L"*.*").c_str(),&find_data);
  	if (file_handle != INVALID_HANDLE_VALUE)
  	{
  		do 
  		{
  			if (find_data.cFileName == nbase::StringPrintf(L"%s.lnk",file_desc.c_str()))
  			{
  				file_path = nbase::StringPrintf(L"%s%s",dir.c_str(),find_data.cFileName);
  				::FindClose(file_handle);
  				return true;
  			}
  			// 如果是子文件夹
  			if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && find_data.cFileName[0] != '.')
  			{
  				std::wstring in_dir = nbase::StringPrintf(L"%s%s\\",dir.c_str(),find_data.cFileName);
  				// 递归遍历
  				if(FindFile(in_dir,file_desc,file_path))
  					return true;
  			}
  		} while (::FindNextFileW(file_handle,&find_data));
  
  		::FindClose(file_handle);
  		return false;
  	}
  	else
  	{
  		return false;
  	}
  }
  
  std::wstring EnsureValidFileName(const std::wstring &file_name, const std::wstring &find /* = L"/:*?<>|" */, const std::wstring &replace /* = L"_" */)
  {
  	std::wstring valid = file_name;
  	const size_t replace_len = replace.length();
  	const wchar_t *find_ptr = find.c_str();
  	const wchar_t *replace_ptr = replace.c_str();
  
  	for (size_t pos = valid.find_first_of(find_ptr, 0); pos != std::wstring::npos && pos < valid.length(); pos = valid.find_first_of(find_ptr, pos))
  	{
  		valid.replace(pos, 1, replace_ptr, replace_len);
  		pos += replace_len;
  	}
  
  	return valid;
  }
  
  //////////////////////////////////////////////////////
  // 数学相关
  int CalcAvg(const std::vector<int> &vec, bool is_revise/* = true*/)
  {
  	if (vec.empty())
  		return 0;
  
  	int sum = 0;
  	size_t count = vec.size();
  
  	if (count <= 5 || !is_revise)
  	{
  		for (size_t i = 0; i < count; i++)
  		{
  			sum += vec[i];
  		}
  		return sum / count;
  	}
  	// 去掉最小值和最大值
  	else
  	{
  		std::vector<int>::const_iterator minIt = std::min_element(vec.begin(), vec.end());
  		std::vector<int>::const_iterator maxIt = std::max_element(vec.begin(), vec.end());
  
  		if (minIt == maxIt)
  			return *minIt;
  
  		for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
  		{
  			if (it == minIt || it == maxIt)
  				continue;
  
  			sum += *it;
  		}
  		return sum / (count - 2);
  	}
  }
  
  int CalcStDev(const std::vector<int> &vec)
  {
  	if (vec.empty())
  		return 0;
  
  	int avg = CalcAvg(vec);
  
  	double square_sum = 0;
  	size_t count = vec.size();
  	for (size_t i = 0; i < count; i++)
  	{
  		int diff = abs(vec[i] - avg);
  		square_sum += pow((double)diff, 2);
  	}
  	square_sum = square_sum / count;
  
  	return (int)(sqrt(square_sum));
  }
  
  void SafeOpenUrl(const std::wstring &url, int show_cmd)
  {
  	std::wstring url_temp = url;
  	std::wstring url_trim = nbase::StringTrimLeft(url_temp.c_str());
  	url_trim = nbase::StringTrimRight(url_trim.c_str());
  	HINSTANCE result = ::ShellExecute(NULL, _T("open"), url_trim.c_str(), NULL, NULL, show_cmd);	
  	if ((DWORD)result <= 32)
  	{
  		::ShellExecute(NULL, _T("open"), _T("IEXPLORE.EXE"), url_trim.c_str(), NULL, show_cmd);
  	}
  }
  
  void SafeOpenUrlEx(const std::string &url, int show_cmd)
  {
  	std::string url_temp = url;
  	std::wstring open_url = nbase::UTF8ToUTF16(url_temp);
  	SafeOpenUrl(open_url, show_cmd);
  }
  
  bool RunAppWithRedirection(const std::wstring &app_path, const std::wstring &app_cmd, std::string &output)
  {
  	SECURITY_ATTRIBUTES sa;
  	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  	sa.lpSecurityDescriptor = NULL;
  	sa.bInheritHandle = TRUE;
  
  	// ChildIn_Write是子进程的输入句柄，ChildIn_Read是父进程用于写入子进程输入的句柄   
  	// ChildOut_Write是子进程的输出句柄，ChildOut_Read是父进程用于读取子进程输出的句柄 
  	HANDLE child_in_read = NULL;
  	HANDLE child_in_write = NULL;
  	HANDLE child_out_read = NULL;
  	HANDLE child_out_write = NULL;
  	BOOL ret1 = CreatePipe(&child_in_read, &child_in_write, &sa, 0);
  	BOOL ret2 = SetHandleInformation(child_in_write, HANDLE_FLAG_INHERIT, 0);
  	BOOL ret3 = CreatePipe(&child_out_read, &child_out_write, &sa, 0);
  	BOOL ret4 = SetHandleInformation(child_out_read, HANDLE_FLAG_INHERIT, 0);
  	
  	if (!ret1 || !ret2 || !ret3 || !ret4)
  	{
  		::CloseHandle(child_in_read);
  		::CloseHandle(child_in_write);
  		::CloseHandle(child_out_read);
  		::CloseHandle(child_out_write);
  		return false;
  	}
  
  	STARTUPINFO si = {0};
  	si.cb = sizeof(STARTUPINFO);
  	si.hStdError = child_out_write;
  	si.hStdOutput = child_out_write;
  	si.hStdInput = child_in_read;
  	si.dwFlags |= STARTF_USESTDHANDLES;   
  	PROCESS_INFORMATION pi;
  
  	if (!CreateProcess(app_path.c_str(), (LPWSTR)app_cmd.c_str(), NULL, NULL, TRUE, 
  		CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
  	{
  		::CloseHandle(child_in_read);
  		::CloseHandle(child_in_write);
  		::CloseHandle(child_out_read);
  		::CloseHandle(child_out_write);
  		return false;
  	}
  	::CloseHandle(child_in_write);
  	::CloseHandle(child_out_write);
  
  	output.clear();
  	while (true)
  	{
  		char buf[32 * 1024] = {0};
  		DWORD len;
  		if (::ReadFile(child_out_read, buf, 32 * 1024, &len, NULL) == FALSE)
  			break;
  		output.append(buf, len);
  	}
  	::CloseHandle(child_in_read);
  	::CloseHandle(child_out_read);
  
  	return true;
  }
  
  std::string GenerateTimeStamp()
  {
  	nbase::TimeDelta time_delta = nbase::TimeDelta::FromMicroseconds(nbase::Time::Now().ToInternalValue());
  	std::string ret = nbase::StringPrintf("%I64u",time_delta.ToMilliseconds());
  	return ret;
  }
  
  BOOL DllRegisterServer(LPCTSTR lpszFileName, BOOL bUnregister)
  {
  	typedef HRESULT (WINAPI * FREG)();
  
  	HMODULE hDLL = ::LoadLibrary(lpszFileName);
  	if (NULL == hDLL)
  		return FALSE;
  
  	CHAR * lpszFuncName;
  	if (!bUnregister)
  		lpszFuncName = "DllRegisterServer";
  	else
  		lpszFuncName = "DllUnregisterServer";
  
  	BOOL bRet = FALSE;
  	FREG lpfunc = (FREG)::GetProcAddress(hDLL, lpszFuncName);
  	if (lpfunc != NULL)
  	{
  		lpfunc();
  		bRet = TRUE;
  	}
  
  	::FreeLibrary(hDLL);
  
  	return bRet;
  }
  
  BOOL DllRegisterServer(LPCTSTR lpszFileName)
  {
  	return DllRegisterServer(lpszFileName, FALSE);
  }
  
  BOOL DllUnregisterServer(LPCTSTR lpszFileName)
  {
  	return DllRegisterServer(lpszFileName, TRUE);
  }
  
  void RegisterShowWndForgroudMessage()
  {
  	g_show_wnd_forgroud_message = ::RegisterWindowMessage(KShowWndForgroudMessageID);
  }
  
  UINT GetShowWndForgroudMessageID()
  {
  	return g_show_wnd_forgroud_message;
  }
  
  bool GetImageCLSID(const wchar_t* format, CLSID* pCLSID)
  {
  	UINT num = 0; 
  	UINT size = 0; 
  	Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL; 
  	Gdiplus::GetImageEncodersSize(&num, &size); 
  
  	if (size == 0) 
  		return false; 
  
  	pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
  	if(pImageCodecInfo == NULL) 
  		return false; 
  	Gdiplus::GetImageEncoders(num, size, pImageCodecInfo); 
  
  	for (UINT i = 0; i < num; ++i) 
  	{
  		if( wcscmp(pImageCodecInfo[i].MimeType, format) == 0 ) 
  		{ 
  			*pCLSID = pImageCodecInfo[i].Clsid; 
  			free(pImageCodecInfo); 
  			return true; 
  		} 
  	}
  	free(pImageCodecInfo); 
  
  	return false; 
  }
  
  void File::GetFolder( const std::wstring &dir, StringVector &out, bool full_path /*= false*/ )
  {
  	std::wstring path = dir + L"\\*.*";
  
  	WIN32_FIND_DATAW fd;
  	HANDLE hFind = ::FindFirstFileW(path.c_str(), &fd);
  
  	DWORD attr = 0;
  	while(hFind != INVALID_HANDLE_VALUE)
  	{
  		attr = fd.dwFileAttributes;
  		if(attr & FILE_ATTRIBUTE_HIDDEN) {
  		}
  		else if(attr & FILE_ATTRIBUTE_DIRECTORY)
  		{
  			wchar_t* name = fd.cFileName;
  			if( wcscmp(name, L".") == 0 || wcscmp(name, L"..") == 0 ){	
  			}
  			else
  			{
  				if(full_path)
  					out.push_back( dir + L"\\" + name );
  				else
  					out.push_back( name );
  			}
  		}
  		
  		BOOL bRet = ::FindNextFileW(hFind, &fd);
  		if(!bRet)
  			break;
  	}
  
  	::FindClose(hFind);
  }
  
  void File::GetFile( const std::wstring &dir, std::vector<FileItem> &out, bool full_path /*= false*/ )
  {
  	std::wstring path = dir + L"\\*.*";
  
  	WIN32_FIND_DATAW fd;
  	HANDLE hFind = ::FindFirstFileW(path.c_str(), &fd);
  
  	DWORD attr = 0;
  	while(hFind != INVALID_HANDLE_VALUE)
  	{
  		attr = fd.dwFileAttributes;
  		if(attr & FILE_ATTRIBUTE_HIDDEN || attr & FILE_ATTRIBUTE_DIRECTORY){
  		}
  		else
  		{
  			FileItem fi = { fd.cFileName, fd.nFileSizeLow };
  			if(full_path)
  				fi.file_ = dir + L"\\" + fd.cFileName;
  			out.push_back(fi);
  		}
  
  		BOOL bRet = ::FindNextFileW(hFind, &fd);
  		if(!bRet)
  			break;
  	}
  
  	::FindClose(hFind);
  }
  
  
  }//namespace tools
  }//namespace shared