utils.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. #include <windows.h>
  2. #include <uxtheme.h>
  3. #include "utils.h"
  4. #include "api.h"
  5. #include <time.h>
  6. #include <string>
  7. #include <functional>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <list>
  11. #include <fstream>
  12. #include <sstream>
  13. #include <shlwapi.h>
  14. #include <winamp/wa_ipc.h>
  15. #include <winamp/dsp.h>
  16. #include "resource/resource.h"
  17. extern winampDSPModule module;
  18. // Config file
  19. char IniName[MAX_PATH] = {0},
  20. IniEncName[MAX_PATH] = {0},
  21. IniDir[MAX_PATH] = {0},
  22. PluginDir[MAX_PATH] = {0};
  23. wchar_t IniDirW[MAX_PATH] = {0},
  24. PluginDirW[MAX_PATH] = {0},
  25. SharedDirW[MAX_PATH] = {0};
  26. HANDLE NextTracks[NUM_OUTPUTS] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
  27. HANDLE SaveEncoded[NUM_OUTPUTS] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
  28. static bool IsVista = false,
  29. checked = false;
  30. bool IsVistaUp() {
  31. if (checked == false) {
  32. OSVERSIONINFO version = {0};
  33. version.dwOSVersionInfoSize = sizeof(version);
  34. if (!GetVersionEx(&version)) ZeroMemory(&version, sizeof(OSVERSIONINFO));
  35. IsVista = (version.dwMajorVersion >= 6);
  36. checked = true;
  37. }
  38. return IsVista;
  39. }
  40. UINT ver = -1;
  41. UINT GetWinampVersion(HWND winamp)
  42. {
  43. if(ver == -1)
  44. {
  45. return (ver = SendMessage(winamp, WM_WA_IPC, 0, IPC_GETVERSION));
  46. }
  47. return ver;
  48. }
  49. char* LocalisedStringA(UINT uID, char *str, size_t maxlen) {
  50. if (WASABI_API_LNG) {
  51. if (!str) {
  52. return WASABI_API_LNGSTRING(uID);
  53. } else {
  54. return WASABI_API_LNGSTRING_BUF(uID, str, maxlen);
  55. }
  56. } else {
  57. __declspec(thread) static char *tmp;
  58. char* strtmp = 0;
  59. if (!str) {
  60. if (!tmp) tmp = (char *)malloc(1024*sizeof(char));
  61. strtmp = tmp;
  62. maxlen = 1024;
  63. } else {
  64. strtmp = str;
  65. }
  66. LoadStringA(module.hDllInstance, uID, strtmp, maxlen);
  67. return strtmp;
  68. }
  69. }
  70. wchar_t* LocalisedString(UINT uID, wchar_t *str, size_t maxlen) {
  71. if (WASABI_API_LNG) {
  72. if (!str) {
  73. return WASABI_API_LNGSTRINGW(uID);
  74. } else {
  75. return WASABI_API_LNGSTRINGW_BUF(uID, str, maxlen);
  76. }
  77. } else {
  78. __declspec(thread) static wchar_t *tmp;
  79. wchar_t* strtmp = 0;
  80. if (!str) {
  81. if (!tmp) tmp = (wchar_t *)malloc(1024*sizeof(wchar_t));
  82. strtmp = tmp;
  83. maxlen = 1024;
  84. } else {
  85. strtmp = str;
  86. }
  87. LoadStringW(module.hDllInstance, uID, strtmp, maxlen);
  88. return strtmp;
  89. }
  90. }
  91. HWND LocalisedCreateDialog(HINSTANCE instance, UINT dialog_id, HWND hWndParent, DLGPROC DlgProc, LPARAM user_id) {
  92. if (WASABI_API_LNG) {
  93. return WASABI_API_CREATEDIALOGPARAMW(dialog_id, hWndParent, DlgProc, user_id);
  94. } else {
  95. return CreateDialogParamW(instance, MAKEINTRESOURCEW(dialog_id), hWndParent, DlgProc, user_id);
  96. }
  97. }
  98. INT_PTR LocalisedDialogBox(HINSTANCE hDllInstance, UINT dialog_id, HWND hWndParent, DLGPROC lpDialogFunc) {
  99. if (WASABI_API_LNG) {
  100. return WASABI_API_DIALOGBOXW(dialog_id, hWndParent, lpDialogFunc);
  101. } else {
  102. return DialogBoxW(hDllInstance, MAKEINTRESOURCEW(dialog_id), hWndParent, lpDialogFunc);
  103. }
  104. }
  105. // about the most reliable way i can find to get the Winamp window as it could
  106. // have been started with the /CLASS= parameter which then means it won't be
  107. // 'Winamp v1.x' so instead go for a fixed child window which will always be
  108. // there (and deals with other apps who create a 'fake' Winamp window (like AIMP)
  109. // and there are two versions to cope with classic or modern skins being used.
  110. HWND hwndWinamp = 0;
  111. BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
  112. char name[24];
  113. GetClassName(hwnd,name,24);
  114. // this check will only work for classic skins
  115. if (!strnicmp(name, "Winamp PE", 24)) {
  116. HWND child = GetWindow(GetWindow(hwnd, GW_CHILD), GW_CHILD);
  117. GetClassName(child, name, 24);
  118. // this check improves reliability of this check against players
  119. // like KMPlayer which also create a fake playlist editor window
  120. if (!strnicmp(name, "WinampVis", 24) || strnicmp(name, "TSkinPanel", 24)) {
  121. hwndWinamp = GetWindow(hwnd, GW_OWNER);
  122. return FALSE;
  123. }
  124. } else if (!strnicmp(name, "BaseWindow_RootWnd", 24)) {
  125. // this check will only work for modern skins
  126. HWND child = GetWindow(GetWindow(hwnd, GW_CHILD), GW_CHILD);
  127. GetClassName(child, name, 24);
  128. if (!strnicmp(name, "Winamp PE", 24)) {
  129. hwndWinamp = GetWindow(hwnd, GW_OWNER);
  130. return FALSE;
  131. }
  132. } else if (!strnicmp(name, "Winamp v1.x", 24)) {
  133. // this check will fail if /CLASS= was used on Winamp
  134. HWND child = GetWindow(hwnd, GW_CHILD);
  135. GetClassName(child, name, 24);
  136. if (!strnicmp(name, "WinampVis", 24)) {
  137. hwndWinamp = hwnd;
  138. return FALSE;
  139. }
  140. }
  141. return TRUE;
  142. }
  143. HWND GetWinampHWND(HWND winamp) {
  144. // if no HWND is passed then attemp to find it
  145. if (!IsWindow(winamp)) {
  146. // but only do the enumeration again if we have an invalid HWND cached
  147. if (!IsWindow(hwndWinamp)) {
  148. hwndWinamp = 0;
  149. EnumThreadWindows(GetCurrentThreadId(), EnumWindowsProc, 0);
  150. }
  151. return hwndWinamp;
  152. } else {
  153. return (hwndWinamp = winamp);
  154. }
  155. }
  156. HINSTANCE GetMyInstance() {
  157. MEMORY_BASIC_INFORMATION mbi = {0};
  158. if (VirtualQuery(GetMyInstance, &mbi, sizeof(mbi))) {
  159. return (HINSTANCE)mbi.AllocationBase;
  160. }
  161. return NULL;
  162. }
  163. char* GetIniDirectory(HWND winamp) {
  164. if (!IniDir[0]) {
  165. // this gets the string of the full ini file path
  166. strncpy(IniDir, (char*)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETINIDIRECTORY), MAX_PATH);
  167. }
  168. return IniDir;
  169. }
  170. wchar_t* GetIniDirectoryW(HWND winamp) {
  171. if (!IniDirW[0]) {
  172. // this gets the string of the full ini file path
  173. wcsncpy(IniDirW, (wchar_t*)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETINIDIRECTORYW), MAX_PATH);
  174. }
  175. return IniDirW;
  176. }
  177. char* GetPluginDirectory(HWND winamp) {
  178. // this gets the string of the full plug-in folder path
  179. strncpy(PluginDir, (char*)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORY), MAX_PATH);
  180. return PluginDir;
  181. }
  182. wchar_t* GetPluginDirectoryW(HWND winamp) {
  183. // this gets the string of the full plug-in folder path
  184. wcsncpy(PluginDirW, (wchar_t*)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORYW), MAX_PATH);
  185. return PluginDirW;
  186. }
  187. wchar_t* GetSharedDirectoryW(HWND winamp) {
  188. // this gets the string of the full shared dll folder path
  189. wchar_t* str = (wchar_t*)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETSHAREDDLLDIRECTORYW);
  190. if (str > (wchar_t*)65536) {
  191. wcsncpy(SharedDirW, str, MAX_PATH);
  192. } else {
  193. // and on older versions of Winamp we revert to the plug-ins folder path
  194. wcsncpy(SharedDirW, GetPluginDirectoryW(winamp), MAX_PATH);
  195. }
  196. return SharedDirW;
  197. }
  198. void GetDefaultNextTracksLogFile(HWND winamp, int bufferLen, wchar_t* buffer, int index) {
  199. snwprintf(buffer, bufferLen, L"%s\\Plugins\\dsp_sc_nexttracks_%d.log", GetIniDirectoryW(winamp), index+1);
  200. }
  201. char* GetSCIniFile(HWND winamp) {
  202. if (!IniName[0]) {
  203. // allows support for multiple instances of the dsp_sc.dll
  204. // without the settings being saved into the same section
  205. char dll_name[MAX_PATH] = {"dsp_sc"};
  206. if (GetModuleFileName(module.hDllInstance, dll_name, MAX_PATH)) {
  207. PathStripPath(dll_name);
  208. PathRemoveExtension(dll_name);
  209. }
  210. snprintf(IniName, MAX_PATH, "%s\\Plugins\\%s.ini", GetIniDirectory(winamp), dll_name);
  211. }
  212. return IniName;
  213. }
  214. wchar_t* GetSCLogFile(HWND winamp, int bufferLen, wchar_t* logFile, int index) {
  215. snwprintf(logFile, bufferLen, L"%s\\Plugins\\dsp_sc_%d.log", GetIniDirectoryW(winamp), index + 1);
  216. return logFile;
  217. }
  218. char* CreateLogFileMessage(char* buffer, wchar_t* message, int* len) {
  219. SYSTEMTIME sysTime;
  220. GetLocalTime(&sysTime);
  221. char d[100], t[100], msg[1024];
  222. GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, "yyyy'-'MM'-'dd", d, 99);
  223. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, "HH':'mm':'ss", t, 99);
  224. std::string utf8 = ConvertToUTF8(message);
  225. char* m = (char*)utf8.c_str();
  226. char* n = msg;
  227. while (m && *m) {
  228. if (m && *m && *m == '\n') {
  229. *n = ' ';
  230. } else if (m) {
  231. if (n) *n = *m;
  232. }
  233. m = CharNext(m);
  234. n = CharNext(n);
  235. }
  236. *n = 0;
  237. *len = snprintf(buffer, 1024, "%s %s\t%s\r\n", d, t, msg);
  238. return buffer;
  239. }
  240. void StartNextTracks(int index, wchar_t* file) {
  241. NextTracks[index] = CreateFileW(file, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0);
  242. if (NextTracks[index] != INVALID_HANDLE_VALUE) {
  243. // reset the file on loading things
  244. SetFilePointer(NextTracks[index], 0, NULL, FILE_BEGIN);
  245. SetEndOfFile(NextTracks[index]);
  246. }
  247. }
  248. void WriteNextTracks(int index, HWND winamp, std::vector<int> nextListIdx, std::vector<std::wstring> nextList, bool xml) {
  249. if (NextTracks[index] != INVALID_HANDLE_VALUE) {
  250. DWORD written;
  251. // reset the file so if there are no tracks then that'll be set
  252. SetFilePointer(NextTracks[index], 0, NULL, FILE_BEGIN);
  253. SetEndOfFile(NextTracks[index]);
  254. std::stringstream s;
  255. if (xml) {
  256. s << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<nexttracks>\n";
  257. }
  258. if (!nextList.empty()) {
  259. std::vector<std::wstring>::const_iterator i = nextList.begin();
  260. std::vector<int>::const_iterator idx = nextListIdx.begin();
  261. for (int count = 1; i != nextList.end(); ++i, ++idx, count++) {
  262. wchar_t *file=(wchar_t*)SendMessage(module.hwndParent, WM_WA_IPC, (*idx), IPC_GETPLAYLISTFILEW);
  263. if (xml) {
  264. std::string filepath = ConvertToUTF8Escaped(file);
  265. s << "\t<file seq=\"" << count << "\">" << filepath << "</file>\n\t";
  266. std::string next = ConvertToUTF8Escaped((*i).c_str());
  267. s << "<title seq=\"" << count << "\">" << next << "</title>\n";
  268. } else {
  269. std::string rawfilepath = ConvertToUTF8(file);
  270. WriteFile(NextTracks[index], rawfilepath.c_str(), rawfilepath.length(), &written, 0);
  271. WriteFile(NextTracks[index], "\r\n", 2, &written, 0);
  272. }
  273. }
  274. }
  275. if (xml) {
  276. s << "</nexttracks>\n";
  277. WriteFile(NextTracks[index], s.str().data(), s.str().length(), &written, 0);
  278. }
  279. }
  280. }
  281. void StopNextTracks(int index) {
  282. if (NextTracks[index] != INVALID_HANDLE_VALUE) {
  283. CloseHandle(NextTracks[index]);
  284. NextTracks[index] = INVALID_HANDLE_VALUE;
  285. }
  286. }
  287. void StartSaveEncoded(int index, wchar_t* file) {
  288. SaveEncoded[index] = CreateFileW(file, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0);
  289. if (SaveEncoded[index] != INVALID_HANDLE_VALUE) {
  290. // reset the file on loading things
  291. SetFilePointer(SaveEncoded[index], 0, NULL, FILE_BEGIN);
  292. SetEndOfFile(SaveEncoded[index]);
  293. }
  294. }
  295. void WriteSaveEncoded(int index, LPCVOID buffer, int bufferLen) {
  296. if (SaveEncoded[index] != INVALID_HANDLE_VALUE) {
  297. DWORD written;
  298. WriteFile(SaveEncoded[index], buffer, bufferLen, &written, 0);
  299. }
  300. }
  301. void StopSaveEncoded(int index) {
  302. if (SaveEncoded[index] != INVALID_HANDLE_VALUE) {
  303. CloseHandle(SaveEncoded[index]);
  304. SaveEncoded[index] = INVALID_HANDLE_VALUE;
  305. }
  306. }
  307. void StartLogging(int index, int clearOnStart) {
  308. wchar_t name[MAX_PATH];
  309. logFiles[index] = CreateFileW(GetSCLogFile(module.hwndParent, ARRAYSIZE(name), name, index), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0);
  310. if (logFiles[index] != INVALID_HANDLE_VALUE) {
  311. // clear the file when started
  312. if (clearOnStart) {
  313. SetFilePointer(logFiles[index], 0, NULL, FILE_BEGIN);
  314. SetEndOfFile(logFiles[index]);
  315. } else {
  316. SetFilePointer(logFiles[index], 0, NULL, FILE_END);
  317. }
  318. int len = 0;
  319. DWORD written;
  320. char buf[1024];
  321. CreateLogFileMessage(buf, L"Logging starting", &len);
  322. WriteFile(logFiles[index], buf, len, &written, 0);
  323. }
  324. }
  325. void StopLogging(int index) {
  326. if (logFiles[index] != INVALID_HANDLE_VALUE) {
  327. int len = 0;
  328. DWORD written;
  329. char buf[1024];
  330. CreateLogFileMessage(buf, L"Logging stopping\r\n", &len);
  331. WriteFile(logFiles[index], buf, len, &written, 0);
  332. CloseHandle(logFiles[index]);
  333. }
  334. logFiles[index] = INVALID_HANDLE_VALUE;
  335. }
  336. BOOL IsDirectMouseWheelMessage(const UINT uMsg) {
  337. static UINT WINAMP_WM_DIRECT_MOUSE_WHEEL = WM_NULL;
  338. if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL) {
  339. WINAMP_WM_DIRECT_MOUSE_WHEEL = RegisterWindowMessageW(L"WINAMP_WM_DIRECT_MOUSE_WHEEL");
  340. if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
  341. return FALSE;
  342. }
  343. return (WINAMP_WM_DIRECT_MOUSE_WHEEL == uMsg);
  344. }
  345. HWND ActiveChildWindowFromPoint(HWND hwnd, POINTS cursor_s, const int *controls, size_t controlsCount) {
  346. POINT pt = {0};
  347. RECT controlRect = {0};
  348. POINTSTOPOINT(pt, cursor_s);
  349. while (controlsCount--) {
  350. HWND controlWindow = GetDlgItem(hwnd, controls[controlsCount]);
  351. if (NULL != controlWindow &&
  352. FALSE != GetClientRect(controlWindow, &controlRect)) {
  353. MapWindowPoints(controlWindow, HWND_DESKTOP, (POINT*)&controlRect, 2);
  354. if (FALSE != PtInRect(&controlRect, pt)) {
  355. unsigned long windowStyle;
  356. windowStyle = (unsigned long)GetWindowLongPtrW(controlWindow, GWL_STYLE);
  357. if (WS_VISIBLE == ((WS_VISIBLE | WS_DISABLED) & windowStyle))
  358. return controlWindow;
  359. break;
  360. }
  361. }
  362. }
  363. return NULL;
  364. }
  365. BOOL DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam) {
  366. if (FALSE != IsDirectMouseWheelMessage(uMsg)) {
  367. const int controls[] = {
  368. IDC_MUSSLIDER,
  369. IDC_MUS2SLIDER,
  370. IDC_MICSLIDER,
  371. IDC_FADESLIDER,
  372. IDC_MICFADESLIDER,
  373. };
  374. HWND targetWindow = ActiveChildWindowFromPoint(hwnd, MAKEPOINTS(lParam), controls, ARRAYSIZE(controls));
  375. if (NULL != targetWindow) {
  376. SendMessage(targetWindow, WM_MOUSEWHEEL, wParam, lParam);
  377. SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (long)TRUE);
  378. return TRUE;
  379. }
  380. }
  381. return FALSE;
  382. }
  383. static HCURSOR link_hand_cursor;
  384. LRESULT link_handlecursor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  385. LRESULT ret = CallWindowProcW((WNDPROC)GetPropW(hwndDlg, L"link_proc"), hwndDlg, uMsg, wParam, lParam);
  386. // override the normal cursor behaviour so we have a hand to show it is a link
  387. if (uMsg == WM_SETCURSOR) {
  388. if ((HWND)wParam == hwndDlg) {
  389. if (!link_hand_cursor) {
  390. link_hand_cursor = LoadCursor(NULL, IDC_HAND);
  391. }
  392. SetCursor(link_hand_cursor);
  393. return TRUE;
  394. }
  395. }
  396. return ret;
  397. }
  398. void link_startsubclass(HWND hwndDlg, UINT id) {
  399. HWND ctrl = GetDlgItem(hwndDlg, id);
  400. if (!GetPropW(ctrl, L"link_proc")) {
  401. SetPropW(ctrl, L"link_proc", (HANDLE)SetWindowLongPtrW(ctrl, GWLP_WNDPROC, (LONG_PTR)link_handlecursor));
  402. }
  403. }
  404. BOOL link_handledraw(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  405. if (uMsg == WM_DRAWITEM) {
  406. DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
  407. if (di->CtlType == ODT_BUTTON) {
  408. wchar_t wt[123];
  409. int y;
  410. RECT r;
  411. // due to the fun of theming and owner drawing we have to get the background colour
  412. if (isthemethere){
  413. HTHEME hTheme = OpenThemeData(hwndDlg, L"Tab");
  414. if (hTheme) {
  415. DrawThemeParentBackground(di->hwndItem, di->hDC, &di->rcItem);
  416. CloseThemeData(hTheme);
  417. }
  418. }
  419. HPEN hPen, hOldPen;
  420. GetDlgItemTextW(hwndDlg, wParam, wt, ARRAYSIZE(wt));
  421. // draw text
  422. SetTextColor(di->hDC, (di->itemState & ODS_SELECTED) ? RGB(220, 0, 0) : RGB(0, 0, 220));
  423. r = di->rcItem;
  424. r.left += 2;
  425. DrawTextW(di->hDC, wt, -1, &r, DT_VCENTER | DT_SINGLELINE);
  426. memset(&r, 0, sizeof(r));
  427. DrawTextW(di->hDC, wt, -1, &r, DT_SINGLELINE | DT_CALCRECT);
  428. // draw underline
  429. y = di->rcItem.bottom - ((di->rcItem.bottom - di->rcItem.top) - (r.bottom - r.top)) / 2 - 1;
  430. hPen = CreatePen(PS_SOLID, 0, (di->itemState & ODS_SELECTED) ? RGB(220, 0, 0) : RGB(0, 0, 220));
  431. hOldPen = (HPEN) SelectObject(di->hDC, hPen);
  432. MoveToEx(di->hDC, di->rcItem.left + 2, y, NULL);
  433. LineTo(di->hDC, di->rcItem.right + 2 - ((di->rcItem.right - di->rcItem.left) - (r.right - r.left)), y);
  434. SelectObject(di->hDC, hOldPen);
  435. DeleteObject(hPen);
  436. return TRUE;
  437. }
  438. }
  439. return FALSE;
  440. }
  441. #include <map>
  442. class xmlEscapes: public std::map<char,std::string>
  443. {
  444. public:
  445. xmlEscapes() {
  446. (*this)['<'] = "&lt;";
  447. (*this)['>'] = "&gt;";
  448. (*this)['&'] = "&amp;";
  449. (*this)['\''] = "&apos;";
  450. (*this)['"'] = "&quot;";
  451. }
  452. };
  453. static const xmlEscapes gsXmlEscapes;
  454. // this will only be receiving an already converted
  455. // string so no need to do the commented part again
  456. char* escapeXML(const char* s) {
  457. static char result[2048] = {0};
  458. memset(&result, 0, 2048);
  459. int len = strlen(s);
  460. for (int x = 0, y = 0; x < len; x++)
  461. {
  462. xmlEscapes::const_iterator i = gsXmlEscapes.find(s[x]);
  463. if (i != gsXmlEscapes.end()) {
  464. strcat(&result[y-1], (*i).second.c_str());
  465. y += (*i).second.size();
  466. } else if (s[x] >= 0 && s[x] <= 31 && s[x] != 9 && s[x] != 10 && s[x] != 13) {
  467. // strip out characters which aren't supported by the DNAS
  468. // (only allow backspace, linefeed and carriage return)
  469. #ifdef DEBUG
  470. result[y] = '\xEF';
  471. y++;
  472. result[y] = '\xBF';
  473. y++;
  474. result[y] = '\xBD';
  475. y++;
  476. #endif
  477. } else if ((x < len - 2) && s[x] == '\xEF' && s[x+1] == '\xBF' && s[x+2] == '\xBF') {
  478. // and any UTF-8 boms which are in there (seen it happen!)
  479. x+=2;
  480. #ifdef DEBUG
  481. result[y] = '\xEF';
  482. y++;
  483. result[y] = '\xBF';
  484. y++;
  485. result[y] = '\xBD';
  486. y++;
  487. #endif
  488. } else {
  489. result[y] = s[x];
  490. y++;
  491. }
  492. }
  493. return result;
  494. }
  495. char* ConvertToUTF8Escaped(const wchar_t *str) {
  496. static char utf8tmp[1024] = {0};
  497. memset(&utf8tmp, 0, sizeof(utf8tmp));
  498. WideCharToMultiByte(CP_UTF8, 0, str, -1, utf8tmp, sizeof(utf8tmp), 0, 0);
  499. return escapeXML(utf8tmp);
  500. }
  501. char* ConvertToUTF8(const wchar_t *str) {
  502. static char utf8tmp2[1024] = {0};
  503. memset(&utf8tmp2, 0, sizeof(utf8tmp2));
  504. WideCharToMultiByte(CP_UTF8, 0, str, -1, utf8tmp2, sizeof(utf8tmp2), 0, 0);
  505. return utf8tmp2;
  506. }
  507. int ConvertFromUTF8(const char *src, wchar_t *dest, int destlen) {
  508. if (destlen == 0)
  509. return MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, destlen);
  510. int converted = MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, destlen-1);
  511. if (!converted)
  512. return 0;
  513. dest[converted]=0;
  514. return converted+1;
  515. }
  516. DWORD GetPrivateProfileStringUTF8(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName) {
  517. char tmp[MAX_PATH] = {0};
  518. GetPrivateProfileString(lpAppName, lpKeyName, lpDefault, tmp, nSize, lpFileName);
  519. return ConvertFromUTF8(tmp, lpReturnedString, nSize);
  520. }
  521. void ShowWindowDlgItem(HWND hDlg, int nIDDlgItem, int nCmdShow) {
  522. ShowWindow(GetDlgItem(hDlg, nIDDlgItem), nCmdShow);
  523. }
  524. void EnableWindowDlgItem(HWND hDlg, int nIDDlgItem, BOOL bEnable) {
  525. EnableWindow(GetDlgItem(hDlg, nIDDlgItem), bEnable);
  526. }
  527. template<typename S,typename F>
  528. std::vector<S> tokenizer_if(const S &ins,F isdelimiter) throw()
  529. {
  530. std::vector<S> result;
  531. S accum;
  532. for(typename S::const_iterator i = ins.begin(); i != ins.end(); ++i)
  533. {
  534. if (!isdelimiter(*i))
  535. {
  536. accum.push_back(*i);// was +=
  537. }
  538. else
  539. {
  540. if (!accum.empty())
  541. {
  542. result.push_back(accum);
  543. accum = S();
  544. }
  545. }
  546. }
  547. if (!accum.empty())
  548. result.push_back(accum);
  549. return result;
  550. }
  551. template<typename S>
  552. inline std::vector<S> tokenizer(const S &ins,typename S::value_type delim) throw()
  553. { return tokenizer_if(ins,bind1st(std::equal_to<typename S::value_type>(),delim)); }
  554. extern char sourceVersion[64];
  555. bool CompareVersions(char *verStr)
  556. {
  557. bool needsUpdating = false;
  558. if (verStr && *verStr)
  559. {
  560. std::vector<std::string> newVerStr = tokenizer(std::string(verStr), '.');
  561. std::vector<std::string> curVerStr = tokenizer(std::string(sourceVersion), '.');
  562. int newVer[] = {::atoi(newVerStr[0].c_str()), ::atoi(newVerStr[1].c_str()), ::atoi(newVerStr[2].c_str()), ::atoi(newVerStr[3].c_str())},
  563. curVer[] = {::atoi(curVerStr[0].c_str()), ::atoi(curVerStr[1].c_str()), ::atoi(curVerStr[2].c_str()), ::atoi(curVerStr[3].c_str())};
  564. // look to compare from major to minor parts of the version strings
  565. // 2.x.x.x vs 3.x.x.x
  566. if (newVer[0] > curVer[0]) {
  567. needsUpdating = true;
  568. }
  569. // 2.0.x.x vs 2.2.x.x
  570. else if((newVer[0] == curVer[0]) && (newVer[1] > curVer[1])) {
  571. needsUpdating = true;
  572. }
  573. // 2.0.0.x vs 2.0.1.x
  574. else if((newVer[0] == curVer[0]) && (newVer[1] == curVer[1]) && (newVer[2] > curVer[2])) {
  575. needsUpdating = true;
  576. }
  577. // 2.0.0.29 vs 2.0.0.30
  578. else if((newVer[0] == curVer[0]) && (newVer[1] == curVer[1]) && (newVer[2] == curVer[2]) && (newVer[3] > curVer[3])) {
  579. needsUpdating = true;
  580. }
  581. }
  582. return needsUpdating;
  583. }