summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/mir_buffer.h518
-rw-r--r--utils/mir_fonts.cpp67
-rw-r--r--utils/mir_fonts.h6
-rw-r--r--utils/mir_options.cpp447
-rw-r--r--utils/mir_options.h71
-rw-r--r--utils/mir_smileys.cpp479
-rw-r--r--utils/mir_smileys.h63
-rw-r--r--utils/scope.h106
-rw-r--r--utils/utf8_helpers.h587
9 files changed, 2344 insertions, 0 deletions
diff --git a/utils/mir_buffer.h b/utils/mir_buffer.h
new file mode 100644
index 0000000000..6c58b538d2
--- /dev/null
+++ b/utils/mir_buffer.h
@@ -0,0 +1,518 @@
+/*
+Copyright (C) 2005-2009 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __MIR_BUFFER_H__
+# define __MIR_BUFFER_H__
+
+#include <windows.h>
+
+#include <m_variables.h>
+#include <m_timezones.h>
+
+template<class T>
+inline size_t __blen(const T *str)
+{
+ return 0;
+}
+
+template<>
+inline size_t __blen<char>(const char *str)
+{
+ return mir_strlen(str);
+}
+
+template<>
+inline size_t __blen<wchar_t>(const wchar_t *str)
+{
+ return mir_wstrlen(str);
+}
+
+template<class T>
+inline T * __bTranslate(const T *str)
+{
+ return 0;
+}
+
+template<>
+inline char * __bTranslate<char>(const char *str)
+{
+ return Translate(str);
+}
+
+template<>
+inline wchar_t * __bTranslate<wchar_t>(const wchar_t *str)
+{
+ return TranslateW(str);
+}
+
+
+template<class O, class D>
+inline void __bcopy(D *dest, const O *orig, size_t len)
+{
+}
+
+inline void __bcopy(char *dest, const char *orig, size_t len)
+{
+ strncpy(dest, orig, len);
+}
+
+inline void __bcopy(WCHAR *dest, const WCHAR *orig, size_t len)
+{
+ wcsncpy(dest, orig, len);
+}
+
+inline void __bcopy(WCHAR *dest, const char *orig, size_t len)
+{
+ MultiByteToWideChar(CallService("LangPack/GetCodePage", 0, 0), 0, orig, (int)len, dest, (int)len);
+}
+
+inline void __bcopy(char *dest, const WCHAR *orig, size_t len)
+{
+ WideCharToMultiByte(CallService("LangPack/GetCodePage", 0, 0), 0, orig, (int)len, dest, (int)len, NULL, NULL);
+}
+
+
+
+template<class T>
+class Buffer
+{
+ public:
+ size_t len;
+ T *str;
+
+ Buffer() : str(NULL), size(0), len(0)
+ {
+ alloc(1);
+ pack();
+ }
+
+ Buffer(T in) : str(NULL), size(0), len(0)
+ {
+ if (in == NULL)
+ {
+ alloc(1);
+ pack();
+ }
+ else
+ {
+ str = in;
+ size = len = __blen(str);
+ }
+ }
+
+ ~Buffer()
+ {
+ free();
+ }
+
+ void pack()
+ {
+ if (str != NULL)
+ memset(&str[len], 0, sizeof(str[len]));
+ }
+
+ void alloc(size_t total)
+ {
+ if (total > size)
+ {
+ size = total + 256 - total % 256;
+ if (str == NULL)
+ str = (T *) mir_alloc(size * sizeof(T));
+ else
+ str = (T *) mir_realloc(str, size * sizeof(T));
+ }
+ }
+
+ void free()
+ {
+ if (str != NULL)
+ {
+ mir_free(str);
+ str = NULL;
+ len = size = 0;
+ }
+ }
+
+ void clear()
+ {
+ len = 0;
+ pack();
+ }
+
+ void append(T app)
+ {
+ alloc(len + 1 + 1);
+
+ str[len] = app;
+ len++;
+ pack();
+ }
+
+ void appendn(size_t n, T app)
+ {
+ alloc(len + n + 1);
+
+ for (; n > 0; n--)
+ {
+ str[len] = app;
+ len++;
+ }
+ pack();
+ }
+
+ void append(const char *app, size_t appLen = -1)
+ {
+ if (app == NULL)
+ return;
+ if (appLen == -1)
+ appLen = __blen(app);
+
+ size_t total = len + appLen + 1;
+ alloc(total);
+
+ __bcopy(&str[len], app, appLen);
+ len += appLen;
+ pack();
+ }
+
+ void append(const WCHAR *app, size_t appLen = -1)
+ {
+ if (app == NULL)
+ return;
+ if (appLen == -1)
+ appLen = __blen(app);
+
+ size_t total = len + appLen + 1;
+ alloc(total);
+
+ __bcopy(&str[len], app, appLen);
+ len += appLen;
+ pack();
+ }
+
+ void append(const Buffer<char> &app)
+ {
+ if (app.str == NULL)
+ return;
+ size_t appLen = app.len;
+
+ size_t total = len + appLen + 1;
+ alloc(total);
+
+ __bcopy(&str[len], app.str, appLen);
+ len += appLen;
+ pack();
+ }
+
+ void append(const Buffer<WCHAR> &app)
+ {
+ size_t appLen = app.len;
+
+ size_t total = len + appLen + 1;
+ alloc(total);
+
+ __bcopy(&str[len], app.str , appLen);
+ len += appLen;
+ pack();
+ }
+
+ void appendPrintf(const T *app, ...)
+ {
+ size_t total = len + 512;
+ alloc(total);
+
+ va_list arg;
+ va_start(arg, app);
+ total = __bvsnprintf<T>(&str[len], size - len - 1, app, arg); //!!!!!!!!!!!!
+ if (total < 0)
+ total = size - len - 1;
+ len += total;
+ pack();
+ }
+
+ void insert(size_t pos, T *app, size_t appLen = -1)
+ {
+ if (pos > len)
+ pos = len;
+ if (pos < 0)
+ pos = 0;
+
+ if (appLen == -1)
+ appLen = __blen(app);
+
+ alloc(len + appLen + 1);
+
+ if (pos < len)
+ memmove(&str[pos + appLen], &str[pos], (len - pos) * sizeof(T));
+ memmove(&str[pos], app, appLen * sizeof(T));
+
+ len += appLen;
+ pack();
+ }
+
+ void replace(size_t start, size_t end, T *app, size_t appLen = -1)
+ {
+ if (start > len)
+ start = len;
+ if (start < 0)
+ start = 0;
+
+ if (end > len)
+ end = len;
+ if (end < start)
+ end = start;
+
+ if (appLen == -1)
+ appLen = __blen(app);
+
+ size_t oldLen = end - start;
+ if (oldLen < appLen)
+ alloc(len + appLen - oldLen + 1);
+
+ if (end < len && oldLen != appLen)
+ memmove(&str[start + appLen], &str[end], (len - end) * sizeof(T));
+ memmove(&str[start], app, appLen * sizeof(T));
+
+ len += appLen - oldLen;
+ pack();
+ }
+
+ void replaceAll(T find, T replace)
+ {
+ for(size_t i = 0; i < len; i++)
+ if (str[len] == find)
+ str[len] = replace;
+ pack();
+ }
+
+ void translate()
+ {
+ if (str == NULL || len == 0)
+ return;
+
+ str[len] = 0;
+ T *tmp = __bTranslate(str);
+ len = __blen(tmp);
+ alloc(len + 1);
+ memmove(str, tmp, len * sizeof(T));
+ pack();
+ }
+
+ void reverse()
+ {
+ for(size_t i = 0; i < len/2; i++)
+ {
+ T tmp = str[i];
+ str[i] = str[len-i-1];
+ str[len-i-1] = tmp;
+ }
+ }
+
+ T *appender(size_t appLen)
+ {
+ alloc(len + appLen + 1);
+ T *ret = &str[len];
+ len += appLen;
+ return ret;
+ }
+
+ T *lock(size_t maxSize)
+ {
+ alloc(len + maxSize + 1);
+ return &str[len];
+ }
+
+ void release()
+ {
+ len += max(__blen(&str[len]), size - len - 1);
+ }
+
+ T *detach()
+ {
+ T *ret = str;
+ str = NULL;
+ len = 0;
+ return ret;
+ }
+
+ void trimRight()
+ {
+ if (str == NULL)
+ return;
+
+ int e;
+ for(e = len-1; e >= 0 && (str[e] == (T)' '
+ || str[e] == (T)'\t'
+ || str[e] == (T)'\r'
+ || str[e] == (T)'\n'); e--) ;
+ len = e+1;
+ pack();
+ }
+
+ void trimLeft()
+ {
+ if (str == NULL)
+ return;
+
+ int s;
+ for(s = 0; str[s] == (T)' '
+ || str[s] == (T)'\t'
+ || str[s] == (T)'\r'
+ || str[s] == (T)'\n'; s++) ;
+ if (s > 0)
+ {
+ memmove(str, &str[s], (len - s) * sizeof(T));
+ len -= s;
+ }
+ pack();
+ }
+
+ void trim()
+ {
+ trimRight();
+ trimLeft();
+ }
+
+ Buffer<T>& operator+=(const char *txt)
+ {
+ append(txt);
+ return *this;
+ }
+
+ Buffer<T>& operator+=(const WCHAR *txt)
+ {
+ append(txt);
+ return *this;
+ }
+
+ Buffer<T>& operator+=(const Buffer<T> &txt)
+ {
+ append(txt);
+ return *this;
+ }
+
+ Buffer<T>& operator=(const char *txt)
+ {
+ clear();
+ append(txt);
+ return *this;
+ }
+
+ Buffer<T>& operator=(const WCHAR *txt)
+ {
+ clear();
+ append(txt);
+ return *this;
+ }
+
+ Buffer<T>& operator=(const Buffer<T> &txt)
+ {
+ clear();
+ append(txt);
+ return *this;
+ }
+
+
+ private:
+ size_t size;
+};
+
+
+static void ReplaceVars(Buffer<TCHAR> *buffer, MCONTACT hContact, TCHAR **variables, int numVariables)
+{
+ if (buffer->len < 3)
+ return;
+
+ if (numVariables < 0)
+ return;
+
+ for(size_t i = buffer->len - 1; i > 0; i--)
+ {
+ if (buffer->str[i] == _T('%'))
+ {
+ // Find previous
+ size_t j;
+ for(j = i - 1; j > 0 && ((buffer->str[j] >= _T('a') && buffer->str[j] <= _T('z'))
+ || (buffer->str[j] >= _T('A') && buffer->str[j] <= _T('Z'))
+ || buffer->str[j] == _T('-')
+ || buffer->str[j] == _T('_')); j--) ;
+
+ if (buffer->str[j] == _T('%'))
+ {
+ size_t foundLen = i - j + 1;
+ if (foundLen == 9 && _tcsncmp(&buffer->str[j], _T("%contact%"), 9) == 0)
+ {
+ buffer->replace(j, i + 1, pcli->pfnGetContactDisplayName(hContact, 0));
+ }
+ else if (foundLen == 6 && _tcsncmp(&buffer->str[j], _T("%date%"), 6) == 0)
+ {
+ TCHAR tmp[128];
+ TimeZone_ToStringT(time(NULL), _T("d s"), tmp, _countof(tmp));
+ buffer->replace(j, i + 1, tmp);
+ }
+ else
+ {
+ for(int k = 0; k < numVariables; k += 2)
+ {
+ size_t len = mir_tstrlen(variables[k]);
+ if (foundLen == len + 2 && _tcsncmp(&buffer->str[j]+1, variables[k], len) == 0)
+ {
+ buffer->replace(j, i + 1, variables[k + 1]);
+ break;
+ }
+ }
+ }
+ }
+
+ i = j;
+ if (i == 0)
+ break;
+ }
+ else if (buffer->str[i] == _T('\\') && i+1 <= buffer->len-1 && buffer->str[i+1] == _T('n'))
+ {
+ buffer->str[i] = _T('\r');
+ buffer->str[i+1] = _T('\n');
+ }
+ }
+}
+
+
+static void ReplaceTemplate(Buffer<TCHAR> *out, MCONTACT hContact, TCHAR *templ, TCHAR **vars, int numVars)
+{
+
+ if (ServiceExists(MS_VARS_FORMATSTRING))
+ {
+ TCHAR *tmp = variables_parse_ex(templ, NULL, hContact, vars, numVars);
+ if (tmp != NULL)
+ {
+ out->append(tmp);
+ mir_free(tmp);
+ out->pack();
+ return;
+ }
+ }
+
+ out->append(templ);
+ ReplaceVars(out, hContact, vars, numVars);
+ out->pack();
+}
+
+
+#endif // __MIR_BUFFER_H__
diff --git a/utils/mir_fonts.cpp b/utils/mir_fonts.cpp
new file mode 100644
index 0000000000..0ef14e3c6d
--- /dev/null
+++ b/utils/mir_fonts.cpp
@@ -0,0 +1,67 @@
+#include <windows.h>
+
+#include <m_system.h>
+#include <m_fontservice.h>
+#include <win2k.h>
+
+#include "mir_fonts.h"
+
+int FontService_RegisterFont(const char *pszDbModule, const char *pszDbName, const TCHAR *pszSection, const TCHAR *pszDescription, const TCHAR *pszBackgroundGroup, const TCHAR *pszBackgroundName, int position, BOOL bAllowEffects, LOGFONT *plfDefault, COLORREF clrDefault)
+{
+ FontIDT fid = { 0 };
+ fid.cbSize = sizeof(fid);
+ mir_strncpy(fid.dbSettingsGroup, pszDbModule, sizeof(fid.dbSettingsGroup)); /* buffer safe */
+ mir_strncpy(fid.prefix, pszDbName, sizeof(fid.prefix)); /* buffer safe */
+ mir_tstrncpy(fid.group, pszSection, _countof(fid.group)); /* buffer safe */
+ mir_tstrncpy(fid.name, pszDescription, _countof(fid.name)); /* buffer safe */
+ mir_tstrncpy(fid.backgroundGroup, pszBackgroundGroup, _countof(fid.backgroundGroup)); /* buffer safe */
+ mir_tstrncpy(fid.backgroundName, pszBackgroundName, _countof(fid.backgroundName)); /* buffer safe */
+ fid.flags = FIDF_ALLOWREREGISTER;
+ if (bAllowEffects) fid.flags |= FIDF_ALLOWEFFECTS;
+ fid.order = position;
+ if (plfDefault != NULL) {
+ fid.flags |= FIDF_DEFAULTVALID;
+ fid.deffontsettings.colour = clrDefault;
+ fid.deffontsettings.size = (char)plfDefault->lfHeight;
+ if (plfDefault->lfItalic) fid.deffontsettings.style |= DBFONTF_ITALIC;
+ if (plfDefault->lfWeight != FW_NORMAL) fid.deffontsettings.style |= DBFONTF_BOLD;
+ if (plfDefault->lfUnderline) fid.deffontsettings.style |= DBFONTF_UNDERLINE;
+ if (plfDefault->lfStrikeOut) fid.deffontsettings.style |= DBFONTF_STRIKEOUT;
+ fid.deffontsettings.charset = plfDefault->lfCharSet;
+ mir_tstrncpy(fid.deffontsettings.szFace, plfDefault->lfFaceName, _countof(fid.deffontsettings.szFace)); /* buffer safe */
+ }
+ FontRegisterT(&fid);
+ return 0;
+}
+
+int FontService_GetFont(const TCHAR *pszSection, const TCHAR *pszDescription, COLORREF *pclr, LOGFONT *plf)
+{
+ FontIDT fid = { 0 };
+ mir_tstrncpy(fid.group, pszSection, _countof(fid.group)); /* buffer sfae */
+ mir_tstrncpy(fid.name, pszDescription, _countof(fid.name)); /* buffer safe */
+ *pclr = (COLORREF)CallService(MS_FONT_GETT, (WPARAM)&fid, (LPARAM)plf); /* uses fallback font on error */
+ return (int)*pclr == -1;
+}
+
+int FontService_RegisterColor(const char *pszDbModule, const char *pszDbName, const TCHAR *pszSection, const TCHAR *pszDescription, COLORREF clrDefault)
+{
+ ColourIDT cid = { 0 };
+ cid.cbSize = sizeof(cid);
+ cid.defcolour = clrDefault;
+ mir_strncpy(cid.dbSettingsGroup, pszDbModule, sizeof(cid.dbSettingsGroup)); /* buffer safe */
+ mir_strncpy(cid.setting, pszDbName, sizeof(cid.setting)); /* buffer safe */
+ mir_tstrncpy(cid.group, pszSection, _countof(cid.group)); /* buffer safe */
+ mir_tstrncpy(cid.name, pszDescription, _countof(cid.name)); /* buffer safe */
+ ColourRegisterT(&cid);
+ return 0;
+}
+
+int FontService_GetColor(const TCHAR *pszSection, const TCHAR *pszDescription, COLORREF *pclr)
+{
+ ColourIDT cid = { 0 };
+ cid.cbSize = sizeof(cid);
+ _tcsncpy_s(cid.group, pszSection, _TRUNCATE);
+ _tcsncpy_s(cid.name, pszDescription, _TRUNCATE);
+ *pclr = (COLORREF)CallService(MS_COLOUR_GETT, (WPARAM)&cid, 0);
+ return (int)*pclr == -1;
+}
diff --git a/utils/mir_fonts.h b/utils/mir_fonts.h
new file mode 100644
index 0000000000..b85b82ce74
--- /dev/null
+++ b/utils/mir_fonts.h
@@ -0,0 +1,6 @@
+
+int FontService_RegisterFont(const char *pszDbModule, const char *pszDbName, const TCHAR *pszSection, const TCHAR *pszDescription, const TCHAR* pszBackgroundGroup, const TCHAR* pszBackgroundName, int position, BOOL bAllowEffects, LOGFONT *plfDefault, COLORREF clrDefault);
+int FontService_GetFont(const TCHAR *pszSection, const TCHAR *pszDescription, COLORREF *pclr, LOGFONT *plf);
+
+int FontService_RegisterColor(const char *pszDbModule,const char *pszDbName,const TCHAR *pszSection,const TCHAR *pszDescription,COLORREF clrDefault);
+int FontService_GetColor(const TCHAR *pszSection,const TCHAR *pszDescription,COLORREF *pclr);
diff --git a/utils/mir_options.cpp b/utils/mir_options.cpp
new file mode 100644
index 0000000000..acf9ff9531
--- /dev/null
+++ b/utils/mir_options.cpp
@@ -0,0 +1,447 @@
+/*
+Copyright (C) 2005-2009 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <tchar.h>
+
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_utils.h>
+#include <m_langpack.h>
+#include <m_protocols.h>
+#include <m_protosvc.h>
+#include <m_system.h>
+
+#include "mir_options.h"
+
+static TCHAR* MyDBGetContactSettingTString(MCONTACT hContact, char* module, char* setting, TCHAR* out, size_t len, TCHAR *def)
+{
+ DBVARIANT dbv = { 0 };
+
+ out[0] = _T('\0');
+
+ if (!db_get_ts(hContact, module, setting, &dbv)) {
+ mir_tstrncpy(out, dbv.ptszVal, (int)len);
+ db_free(&dbv);
+ }
+ else {
+ if (def != NULL)
+ mir_tstrncpy(out, def, (int)len);
+ }
+
+ return out;
+}
+
+
+static TCHAR dbPath[MAX_PATH] = { 0 }; // database profile path (read at startup only)
+
+
+static int PathIsAbsolute(const TCHAR *path)
+{
+ if (!path || !(mir_tstrlen(path) > 2))
+ return 0;
+ if ((path[1] == _T(':') && path[2] == _T('\\')) || (path[0] == _T('\\') && path[1] == _T('\\')))
+ return 1;
+ return 0;
+}
+
+static void PathToRelative(TCHAR *pOut, size_t outSize, const TCHAR *pSrc)
+{
+ if (!PathIsAbsolute(pSrc))
+ mir_tstrncpy(pOut, pSrc, (int)outSize);
+ else {
+ if (dbPath[0] == _T('\0')) {
+ char tmp[1024];
+ CallService(MS_DB_GETPROFILEPATH, _countof(tmp), (LPARAM)tmp);
+ mir_sntprintf(dbPath, _T("%S\\"), tmp);
+ }
+
+ size_t len = mir_tstrlen(dbPath);
+ if (!_tcsnicmp(pSrc, dbPath, len))
+ len = 0;
+ mir_tstrncpy(pOut, pSrc + len, outSize);
+ }
+}
+
+static void PathToAbsolute(TCHAR *pOut, size_t outSize, const TCHAR *pSrc)
+{
+ if (PathIsAbsolute(pSrc) || !isalnum(pSrc[0]))
+ mir_tstrncpy(pOut, pSrc, (int)outSize);
+ else {
+ if (dbPath[0] == _T('\0')) {
+ char tmp[1024];
+ CallService(MS_DB_GETPROFILEPATH, _countof(tmp), (LPARAM)tmp);
+ mir_sntprintf(dbPath, _T("%S\\"), tmp);
+ }
+
+ mir_sntprintf(pOut, outSize, _T("%s%s"), dbPath, pSrc);
+ }
+}
+
+static void LoadOpt(OptPageControl *ctrl, char *module)
+{
+ if (ctrl->var == NULL)
+ return;
+
+ TCHAR tmp[1024];
+ switch (ctrl->type) {
+ case CONTROL_CHECKBOX:
+ *((BYTE *)ctrl->var) = db_get_b(NULL, module, ctrl->setting, ctrl->dwDefValue);
+ break;
+
+ case CONTROL_SPIN:
+ *((WORD *)ctrl->var) = db_get_w(NULL, module, ctrl->setting, ctrl->dwDefValue);
+ break;
+
+ case CONTROL_COLOR:
+ *((COLORREF *)ctrl->var) = (COLORREF)db_get_dw(NULL, module, ctrl->setting, ctrl->dwDefValue);
+ break;
+
+ case CONTROL_RADIO:
+ *((WORD *)ctrl->var) = db_get_w(NULL, module, ctrl->setting, ctrl->dwDefValue);
+ break;
+
+ case CONTROL_COMBO:
+ *((WORD *)ctrl->var) = db_get_w(NULL, module, ctrl->setting, ctrl->dwDefValue);
+ break;
+
+ case CONTROL_PROTOCOL_LIST:
+ break;
+
+ case CONTROL_TEXT:
+ MyDBGetContactSettingTString(NULL, module, ctrl->setting, ((TCHAR *)ctrl->var), min(ctrl->max <= 0 ? 1024 : ctrl->max, 1024), ctrl->tszDefValue == NULL ? NULL : TranslateTS(ctrl->tszDefValue));
+ break;
+
+ case CONTROL_INT:
+ *((int *)ctrl->var) = (int)db_get_dw(NULL, module, ctrl->setting, ctrl->dwDefValue);
+ break;
+
+ case CONTROL_FILE:
+ MyDBGetContactSettingTString(NULL, module, ctrl->setting, tmp, 1024, ctrl->tszDefValue == NULL ? NULL : ctrl->tszDefValue);
+ PathToAbsolute(((TCHAR *)ctrl->var), min(ctrl->max <= 0 ? 1024 : ctrl->max, 1024), tmp);
+ break;
+
+ case CONTROL_COMBO_TEXT:
+ case CONTROL_COMBO_ITEMDATA:
+ MyDBGetContactSettingTString(NULL, module, ctrl->setting, ((TCHAR *)ctrl->var), min(ctrl->max <= 0 ? 1024 : ctrl->max, 1024), ctrl->tszDefValue == NULL ? NULL : TranslateTS(ctrl->tszDefValue));
+ break;
+ }
+}
+
+void LoadOpts(OptPageControl *controls, int controlsSize, char *module)
+{
+ for (int i = 0; i < controlsSize; i++)
+ LoadOpt(&controls[i], module);
+}
+
+INT_PTR CALLBACK SaveOptsDlgProc(OptPageControl *controls, int controlsSize, char *module, HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ TCHAR tmp[1024];
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ for (int i = 0; i < controlsSize; i++) {
+ OptPageControl *ctrl = &controls[i];
+
+ if (GetDlgItem(hwndDlg, ctrl->nID) == NULL)
+ continue;
+
+ switch (ctrl->type) {
+ case CONTROL_CHECKBOX:
+ CheckDlgButton(hwndDlg, ctrl->nID, db_get_b(NULL, module, ctrl->setting, ctrl->dwDefValue) == 1 ? BST_CHECKED : BST_UNCHECKED);
+ break;
+
+ case CONTROL_SPIN:
+ SendDlgItemMessage(hwndDlg, ctrl->nIDSpin, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, ctrl->nID), 0);
+ SendDlgItemMessage(hwndDlg, ctrl->nIDSpin, UDM_SETRANGE, 0, MAKELONG(ctrl->max, ctrl->min));
+ SendDlgItemMessage(hwndDlg, ctrl->nIDSpin, UDM_SETPOS, 0, MAKELONG(db_get_w(NULL, module, ctrl->setting, ctrl->dwDefValue), 0));
+ break;
+
+ case CONTROL_COLOR:
+ SendDlgItemMessage(hwndDlg, ctrl->nID, CPM_SETCOLOUR, 0, (COLORREF)db_get_dw(NULL, module, ctrl->setting, ctrl->dwDefValue));
+ break;
+
+ case CONTROL_RADIO:
+ CheckDlgButton(hwndDlg, ctrl->nID, db_get_w(NULL, module, ctrl->setting, ctrl->dwDefValue) == ctrl->value ? BST_CHECKED : BST_UNCHECKED);
+ break;
+
+ case CONTROL_COMBO:
+ SendDlgItemMessage(hwndDlg, ctrl->nID, CB_SETCURSEL, db_get_w(NULL, module, ctrl->setting, ctrl->dwDefValue), 0);
+ break;
+
+ case CONTROL_PROTOCOL_LIST:
+ {
+ // Fill list view
+ HWND hwndProtocols = GetDlgItem(hwndDlg, ctrl->nID);
+ LVCOLUMN lvc;
+ LVITEM lvi;
+
+ ListView_SetExtendedListViewStyle(hwndProtocols, LVS_EX_CHECKBOXES);
+
+ memset(&lvc, 0, sizeof(lvc));
+ lvc.mask = LVCF_FMT;
+ lvc.fmt = LVCFMT_IMAGE | LVCFMT_LEFT;
+ ListView_InsertColumn(hwndProtocols, 0, &lvc);
+
+ memset(&lvi, 0, sizeof(lvi));
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iSubItem = 0;
+ lvi.iItem = 1000;
+
+ int count;
+ PROTOACCOUNT **protos;
+ Proto_EnumAccounts(&count, &protos);
+
+ for (int k = 0; k < count; k++) {
+ PROTOACCOUNT *p = protos[k];
+ if (p->szModuleName == NULL || p->szModuleName[0] == '\0')
+ continue;
+
+ if (ctrl->allowProtocol != NULL && !ctrl->allowProtocol(p->szModuleName))
+ continue;
+
+ char *setting = (char *)mir_alloc(128 * sizeof(char));
+ mir_snprintf(setting, 128, ctrl->setting, p->szModuleName);
+
+ BOOL show = (BOOL)db_get_b(NULL, module, setting, ctrl->dwDefValue);
+
+ lvi.lParam = (LPARAM)setting;
+ lvi.pszText = p->tszAccountName;
+ lvi.iItem = ListView_InsertItem(hwndProtocols, &lvi);
+ ListView_SetItemState(hwndProtocols, lvi.iItem, INDEXTOSTATEIMAGEMASK(show ? 2 : 1), LVIS_STATEIMAGEMASK);
+ }
+
+ ListView_SetColumnWidth(hwndProtocols, 0, LVSCW_AUTOSIZE);
+ ListView_Arrange(hwndProtocols, LVA_ALIGNLEFT | LVA_ALIGNTOP);
+ }
+ break;
+
+ case CONTROL_TEXT:
+ SetDlgItemText(hwndDlg, ctrl->nID, MyDBGetContactSettingTString(NULL, module, ctrl->setting, tmp, 1024, ctrl->tszDefValue == NULL ? NULL : TranslateTS(ctrl->tszDefValue)));
+ SendDlgItemMessage(hwndDlg, ctrl->nID, EM_LIMITTEXT, min(ctrl->max <= 0 ? 1024 : ctrl->max, 1024), 0);
+ break;
+
+ case CONTROL_INT:
+ SetDlgItemInt(hwndDlg, ctrl->nID, db_get_dw(NULL, module, ctrl->setting, ctrl->dwDefValue), ctrl->min <= 0);
+ SendDlgItemMessage(hwndDlg, ctrl->nID, EM_LIMITTEXT, 9, 0);
+ break;
+
+ case CONTROL_FILE:
+ MyDBGetContactSettingTString(NULL, module, ctrl->setting, tmp, 1024, ctrl->tszDefValue == NULL ? NULL : ctrl->tszDefValue);
+ {
+ TCHAR abs[1024];
+ PathToAbsolute(abs, 1024, tmp);
+ SetDlgItemText(hwndDlg, ctrl->nID, abs);
+ }
+ SendDlgItemMessage(hwndDlg, ctrl->nID, EM_LIMITTEXT, min(ctrl->max <= 0 ? 1024 : ctrl->max, 1024), 0);
+ break;
+
+ case CONTROL_COMBO_TEXT:
+ MyDBGetContactSettingTString(NULL, module, ctrl->setting, tmp, 1024, ctrl->tszDefValue == NULL ? NULL : TranslateTS(ctrl->tszDefValue));
+ SendDlgItemMessage(hwndDlg, ctrl->nID, CB_SELECTSTRING, 0, (WPARAM)tmp);
+ break;
+
+ case CONTROL_COMBO_ITEMDATA:
+ MyDBGetContactSettingTString(NULL, module, ctrl->setting, tmp, 1024, ctrl->tszDefValue == NULL ? NULL : TranslateTS(ctrl->tszDefValue));
+ {
+ int count = SendDlgItemMessage(hwndDlg, ctrl->nID, CB_GETCOUNT, 0, 0);
+ int k;
+ for (k = 0; k < count; k++) {
+ TCHAR *id = (TCHAR *)SendDlgItemMessage(hwndDlg, ctrl->nID, CB_GETITEMDATA, (WPARAM)k, 0);
+ if (mir_tstrcmp(id, tmp) == 0)
+ break;
+ }
+ if (k < count)
+ SendDlgItemMessage(hwndDlg, ctrl->nID, CB_SETCURSEL, k, 0);
+ }
+ break;
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ for (int i = 0; i < controlsSize; i++) {
+ OptPageControl *ctrl = &controls[i];
+
+ if (LOWORD(wParam) == ctrl->nID) {
+ switch (ctrl->type) {
+ case CONTROL_TEXT:
+ case CONTROL_SPIN:
+ case CONTROL_INT:
+ // Don't make apply enabled during buddy set
+ if (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())
+ return 0;
+
+ break;
+
+ case CONTROL_COMBO_ITEMDATA:
+ case CONTROL_COMBO_TEXT:
+ case CONTROL_COMBO:
+ if (HIWORD(wParam) != CBN_SELCHANGE || (HWND)lParam != GetFocus())
+ return 0;
+ break;
+ }
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR lpnmhdr = (LPNMHDR)lParam;
+ if (lpnmhdr->idFrom == 0 && lpnmhdr->code == PSN_APPLY) {
+ for (int i = 0; i < controlsSize; i++) {
+ OptPageControl *ctrl = &controls[i];
+
+ if (GetDlgItem(hwndDlg, ctrl->nID) == NULL)
+ continue;
+
+ switch (ctrl->type) {
+ case CONTROL_CHECKBOX:
+ db_set_b(NULL, module, ctrl->setting, (BYTE)IsDlgButtonChecked(hwndDlg, ctrl->nID));
+ break;
+
+ case CONTROL_SPIN:
+ db_set_w(NULL, module, ctrl->setting, (WORD)SendDlgItemMessage(hwndDlg, ctrl->nIDSpin, UDM_GETPOS, 0, 0));
+ break;
+
+ case CONTROL_COLOR:
+ db_set_dw(NULL, module, ctrl->setting, (DWORD)SendDlgItemMessage(hwndDlg, ctrl->nID, CPM_GETCOLOUR, 0, 0));
+ break;
+
+ case CONTROL_RADIO:
+ if (IsDlgButtonChecked(hwndDlg, ctrl->nID))
+ db_set_w(NULL, module, ctrl->setting, (BYTE)ctrl->value);
+ break;
+
+ case CONTROL_COMBO:
+ db_set_w(NULL, module, ctrl->setting, (WORD)SendDlgItemMessage(hwndDlg, ctrl->nID, CB_GETCURSEL, 0, 0));
+ break;
+
+ case CONTROL_PROTOCOL_LIST:
+ {
+ LVITEM lvi = { 0 };
+ lvi.mask = (UINT)LVIF_PARAM;
+
+ HWND hwndProtocols = GetDlgItem(hwndDlg, ctrl->nID);
+ int count = ListView_GetItemCount(hwndProtocols);
+ for (int k = 0; k < count; k++) {
+ lvi.iItem = k;
+ ListView_GetItem(hwndProtocols, &lvi);
+
+ char *setting = (char *)lvi.lParam;
+ db_set_b(NULL, module, setting, (BYTE)ListView_GetCheckState(hwndProtocols, k));
+ }
+ }
+ break;
+
+ case CONTROL_TEXT:
+ GetDlgItemText(hwndDlg, ctrl->nID, tmp, _countof(tmp));
+ db_set_ts(NULL, module, ctrl->setting, tmp);
+ break;
+
+ case CONTROL_INT:
+ BOOL trans;
+ {
+ int val = GetDlgItemInt(hwndDlg, ctrl->nID, &trans, ctrl->min <= 0);
+ if (!trans)
+ val = ctrl->dwDefValue;
+ if (ctrl->max != 0)
+ val = min(val, ctrl->max);
+ if (ctrl->min != 0)
+ val = max(val, ctrl->min);
+ db_set_dw(NULL, module, ctrl->setting, val);
+ }
+ break;
+
+ case CONTROL_FILE:
+ GetDlgItemText(hwndDlg, ctrl->nID, tmp, _countof(tmp));
+ {
+ TCHAR rel[1024];
+ PathToRelative(rel, 1024, tmp);
+ db_set_ts(NULL, module, ctrl->setting, rel);
+ }
+ break;
+
+ case CONTROL_COMBO_TEXT:
+ GetDlgItemText(hwndDlg, ctrl->nID, tmp, _countof(tmp));
+ db_set_ts(NULL, module, ctrl->setting, tmp);
+ break;
+
+ case CONTROL_COMBO_ITEMDATA:
+ int sel = SendDlgItemMessage(hwndDlg, ctrl->nID, CB_GETCURSEL, 0, 0);
+ db_set_ts(NULL, module, ctrl->setting, (TCHAR *)SendDlgItemMessage(hwndDlg, ctrl->nID, CB_GETITEMDATA, (WPARAM)sel, 0));
+ break;
+ }
+
+ LoadOpt(ctrl, module);
+ }
+
+ return TRUE;
+ }
+ else if (lpnmhdr->idFrom != 0 && lpnmhdr->code == LVN_ITEMCHANGED) {
+ // Changed for protocols
+ for (int i = 0; i < controlsSize; i++) {
+ OptPageControl *ctrl = &controls[i];
+
+ if (ctrl->type == CONTROL_PROTOCOL_LIST && ctrl->nID == lpnmhdr->idFrom) {
+ NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
+
+ if (IsWindowVisible(GetDlgItem(hwndDlg, ctrl->nID)) && ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ for (int i = 0; i < controlsSize; i++) {
+ OptPageControl *ctrl = &controls[i];
+
+ if (GetDlgItem(hwndDlg, ctrl->nID) == NULL)
+ continue;
+
+ switch (ctrl->type) {
+ case CONTROL_PROTOCOL_LIST:
+ LVITEM lvi = { 0 };
+ lvi.mask = (UINT)LVIF_PARAM;
+
+ HWND hwndProtocols = GetDlgItem(hwndDlg, ctrl->nID);
+ int count = ListView_GetItemCount(hwndProtocols);
+ for (i = 0; i < count; i++) {
+ lvi.iItem = i;
+ ListView_GetItem(hwndProtocols, &lvi);
+ mir_free((char *)lvi.lParam);
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
diff --git a/utils/mir_options.h b/utils/mir_options.h
new file mode 100644
index 0000000000..7c2634e9eb
--- /dev/null
+++ b/utils/mir_options.h
@@ -0,0 +1,71 @@
+/*
+Copyright (C) 2005-2009 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __MIR_OPTIONS_H__
+# define __MIR_OPTIONS_H__
+
+#include <windows.h>
+
+
+#define CONTROL_CHECKBOX 0 // Stored as BYTE
+#define CONTROL_SPIN 1 // Stored as WORD
+#define CONTROL_COLOR 2 // Stored as DWORD
+#define CONTROL_RADIO 3 // Stored as WORD
+#define CONTROL_COMBO 4 // Stored as WORD
+#define CONTROL_PROTOCOL_LIST 5 // Stored as BYTEs
+#define CONTROL_TEXT 6 // Stored as TCHARs, max len 1024
+#define CONTROL_COMBO_TEXT 7 // Stored as TCHARs, max len 1024
+#define CONTROL_COMBO_ITEMDATA 8 // Stored as TCHARs, max len 1024
+#define CONTROL_FILE 9 // Stored as TCHARs, max len 1024
+#define CONTROL_INT 10 // Stored as DWORD
+
+
+typedef BOOL(*FPAllowProtocol) (const char *proto);
+
+typedef struct {
+ void *var;
+ int type;
+ unsigned int nID;
+ char *setting;
+ union {
+ ULONG_PTR dwDefValue;
+ TCHAR *tszDefValue;
+ char *szDefValue;
+ };
+ union {
+ int nIDSpin;
+ int value;
+ FPAllowProtocol allowProtocol;
+ unsigned int checkboxID;
+ };
+ WORD min;
+ WORD max;
+} OptPageControl;
+
+INT_PTR CALLBACK SaveOptsDlgProc(OptPageControl *controls, int controlsSize, char *module, HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+void LoadOpts(OptPageControl *controls, int controlsSize, char *module);
+
+
+
+
+
+
+#endif // __MIR_OPTIONS_H__
diff --git a/utils/mir_smileys.cpp b/utils/mir_smileys.cpp
new file mode 100644
index 0000000000..bce1cc75ee
--- /dev/null
+++ b/utils/mir_smileys.cpp
@@ -0,0 +1,479 @@
+/*
+Copyright (C) 2005 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "mir_smileys.h"
+#include "utf8_helpers.h"
+
+#include <richedit.h>
+#include <m_smileyadd.h>
+#include <newpluginapi.h>
+#include <m_langpack.h>
+#include <m_clui.h>
+#include <m_database.h>
+#include <commctrl.h>
+#include <m_skin_eng.h>
+#include <tchar.h>
+
+// Prototypes
+
+#define TEXT_PIECE_TYPE_TEXT 0
+#define TEXT_PIECE_TYPE_SMILEY 1
+typedef struct
+{
+ int type;
+ int len;
+ union
+ {
+ struct
+ {
+ int start_pos;
+ };
+ struct
+ {
+ HICON smiley;
+ int smiley_width;
+ int smiley_height;
+ };
+ };
+}
+TextPiece;
+
+SortedList * ReplaceSmileys(const TCHAR *text, int text_size, const char *protocol, int *max_smiley_height);
+void DrawTextSmiley(HDC hdcMem, RECT free_rc, const TCHAR *szText, int len, SortedList *plText, UINT uTextFormat, int max_smiley_height);
+void DestroySmileyList(SortedList* p_list);
+SIZE GetTextSize(HDC hdcMem, const TCHAR *szText, SortedList *plText, UINT uTextFormat, int max_smiley_height);
+
+// Functions
+
+int InitContactListSmileys()
+{
+ // Register smiley category
+ if (ServiceExists(MS_SMILEYADD_REGISTERCATEGORY))
+ {
+ SMADD_REGCAT rc;
+
+ rc.cbSize = sizeof(rc);
+ rc.name = "clist";
+ rc.dispname = Translate("Contact List smileys");
+
+ CallService(MS_SMILEYADD_REGISTERCATEGORY, 0, (LPARAM)&rc);
+ }
+
+ return 0;
+}
+
+SmileysParseInfo Smileys_PreParse(const TCHAR* lpString, int nCount, const char *protocol)
+{
+ SmileysParseInfo info = (SmileysParseInfo)mir_calloc(sizeof(_SmileysParseInfo));
+
+ info->pieces = ReplaceSmileys(lpString, nCount, protocol, &info->max_height);
+
+ return info;
+}
+
+void Smileys_FreeParse(SmileysParseInfo parseInfo)
+{
+ if (parseInfo != NULL)
+ {
+ if (parseInfo->pieces != NULL)
+ DestroySmileyList(parseInfo->pieces);
+
+ mir_free(parseInfo);
+ }
+}
+
+int skin_DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat)
+{
+ if ((uFormat & DT_CALCRECT) == 0 && ServiceExists(MS_SKINENG_ALPHATEXTOUT))
+ {
+ COLORREF color = SetTextColor(hDC, 0);
+ SetTextColor(hDC, color);
+
+ return AlphaText(hDC, lpString, nCount, lpRect, uFormat, color);
+ }
+
+ return DrawText(hDC, lpString, nCount, lpRect, uFormat);
+}
+
+int skin_DrawIconEx(HDC hdc, int xLeft, int yTop, HICON hIcon, int cxWidth, int cyWidth,
+ UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags)
+{
+ if (ServiceExists(MS_SKINENG_DRAWICONEXFIX))
+ return mod_DrawIconEx_helper(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, istepIfAniCur, hbrFlickerFreeDraw, diFlags);
+ else
+ return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, istepIfAniCur, hbrFlickerFreeDraw, diFlags);
+}
+
+
+
+// Similar to DrawText win32 api function
+// Pass uFormat | DT_CALCRECT to calc rectangle to be returned by lpRect
+// parseInfo is optional (pass NULL and it will be calculated and deleted inside function
+int Smileys_DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat, const char *protocol, SmileysParseInfo parseInfo)
+{
+ SmileysParseInfo info;
+ int ret;
+
+ if (nCount < 0)
+ nCount = (int)mir_tstrlen(lpString);
+
+ // Get parse info
+ if (parseInfo == NULL)
+ info = Smileys_PreParse(lpString, nCount, protocol);
+ else
+ info = parseInfo;
+
+ if (uFormat & DT_CALCRECT)
+ {
+ SIZE text_size = GetTextSize(hDC, lpString, info->pieces, uFormat, info->max_height);
+
+ lpRect->bottom = min(lpRect->bottom, lpRect->top + text_size.cy);
+
+ if (text_size.cx < lpRect->right - lpRect->left)
+ {
+ if (uFormat & DT_RIGHT)
+ lpRect->left = lpRect->right - text_size.cx;
+ else
+ lpRect->right = lpRect->left + text_size.cx;
+ }
+
+ ret = text_size.cy;
+ }
+ else
+ {
+ // Clipping rgn
+ HRGN oldRgn = CreateRectRgn(0, 0, 1, 1);
+ if (GetClipRgn(hDC, oldRgn) != 1)
+ {
+ DeleteObject(oldRgn);
+ oldRgn = NULL;
+ }
+
+ HRGN rgn = CreateRectRgnIndirect(lpRect);
+ ExtSelectClipRgn(hDC, rgn, RGN_AND);
+
+ // Draw
+ if (info->pieces == NULL)
+ {
+ ret = skin_DrawText(hDC, lpString, nCount, lpRect, uFormat);
+ }
+ else
+ {
+ RECT rc = *lpRect;
+
+ SIZE text_size = GetTextSize(hDC, lpString, info->pieces, uFormat, info->max_height);
+
+ if (text_size.cx < rc.right - rc.left)
+ {
+ if (uFormat & DT_RIGHT)
+ rc.left = rc.right - text_size.cx;
+ else
+ rc.right = rc.left + text_size.cx;
+ }
+
+ ret = text_size.cy;
+
+ DrawTextSmiley(hDC, rc, lpString, nCount, info->pieces, uFormat, info->max_height);
+ }
+
+ // Clipping rgn
+ SelectClipRgn(hDC, oldRgn);
+ DeleteObject(rgn);
+ if (oldRgn) DeleteObject(oldRgn);
+ }
+
+
+ // Free parse info
+ if (parseInfo == NULL)
+ Smileys_FreeParse(info);
+
+ return ret;
+}
+
+
+
+SIZE GetTextSize(HDC hdcMem, const TCHAR *szText, SortedList *plText, UINT uTextFormat, int max_smiley_height)
+{
+ SIZE text_size;
+
+ if (szText == NULL) {
+ text_size.cy = 0;
+ text_size.cx = 0;
+ }
+ else {
+ RECT text_rc = { 0, 0, 0x7FFFFFFF, 0x7FFFFFFF };
+
+ // Always need cy...
+ DrawText(hdcMem, szText, -1, &text_rc, DT_CALCRECT | uTextFormat);
+ text_size.cy = text_rc.bottom - text_rc.top;
+
+ if (plText == NULL)
+ text_size.cx = text_rc.right - text_rc.left;
+ else {
+ if (!(uTextFormat & DT_RESIZE_SMILEYS))
+ text_size.cy = max(text_size.cy, max_smiley_height);
+
+ text_size.cx = 0;
+
+ // See each item of list
+ for (int i = 0; i < plText->realCount; i++) {
+ TextPiece *piece = (TextPiece *)plText->items[i];
+
+ if (piece->type == TEXT_PIECE_TYPE_TEXT) {
+ RECT rc = { 0, 0, 0x7FFFFFFF, 0x7FFFFFFF };
+
+ DrawText(hdcMem, &szText[piece->start_pos], piece->len, &rc, DT_CALCRECT | uTextFormat);
+ text_size.cx = text_size.cx + rc.right - rc.left;
+ }
+ else {
+ double factor;
+
+ if ((uTextFormat & DT_RESIZE_SMILEYS) && piece->smiley_height > text_size.cy)
+ factor = text_size.cy / (double)piece->smiley_height;
+ else
+ factor = 1;
+
+ text_size.cx = text_size.cx + (LONG)(factor * piece->smiley_width);
+ }
+ }
+ }
+ }
+
+ return text_size;
+}
+
+void DrawTextSmiley(HDC hdcMem, RECT free_rc, const TCHAR *szText, int len, SortedList *plText, UINT uTextFormat, int max_smiley_height)
+{
+ if (szText == NULL)
+ return;
+
+ uTextFormat &= ~DT_RIGHT;
+
+ // Draw list
+ int i;
+ int pos_x = 0;
+ int row_height, text_height;
+ RECT tmp_rc = free_rc;
+
+ if (uTextFormat & DT_RTLREADING)
+ i = plText->realCount - 1;
+ else
+ i = 0;
+
+ // Get real height of the line
+ text_height = skin_DrawText(hdcMem, _T("A"), 1, &tmp_rc, DT_CALCRECT | uTextFormat);
+ if (uTextFormat & DT_RESIZE_SMILEYS)
+ row_height = text_height;
+ else
+ row_height = max(text_height, max_smiley_height);
+
+ // Just draw ellipsis
+ if (free_rc.right <= free_rc.left)
+ {
+ skin_DrawText(hdcMem, _T("..."), 3, &free_rc, uTextFormat & ~DT_END_ELLIPSIS);
+ }
+ else
+ {
+ // Draw text and smileys
+ for (; i < plText->realCount && i >= 0 && pos_x < free_rc.right - free_rc.left && len > 0; i += (uTextFormat & DT_RTLREADING ? -1 : 1))
+ {
+ TextPiece *piece = (TextPiece *)plText->items[i];
+ RECT text_rc = free_rc;
+
+ if (uTextFormat & DT_RTLREADING)
+ text_rc.right -= pos_x;
+ else
+ text_rc.left += pos_x;
+
+ if (piece->type == TEXT_PIECE_TYPE_TEXT)
+ {
+ text_rc.top += (row_height - text_height) >> 1;
+
+ tmp_rc = text_rc;
+ tmp_rc.right += 50;
+ skin_DrawText(hdcMem, &szText[piece->start_pos], min(len, piece->len), &tmp_rc, DT_CALCRECT | (uTextFormat & ~DT_END_ELLIPSIS));
+ pos_x += tmp_rc.right - tmp_rc.left;
+
+ if (uTextFormat & DT_RTLREADING)
+ text_rc.left = max(text_rc.left, text_rc.right - (tmp_rc.right - tmp_rc.left));
+
+ skin_DrawText(hdcMem, &szText[piece->start_pos], min(len, piece->len), &text_rc, uTextFormat);
+ len -= piece->len;
+ }
+ else
+ {
+ double factor;
+
+ if (len < piece->len)
+ {
+ len = 0;
+ }
+ else
+ {
+ len -= piece->len;
+
+ if ((uTextFormat & DT_RESIZE_SMILEYS) && piece->smiley_height > row_height)
+ {
+ factor = row_height / (double)piece->smiley_height;
+ }
+ else
+ {
+ factor = 1;
+ }
+
+ if (uTextFormat & DT_RTLREADING)
+ text_rc.left = max(text_rc.right - (LONG)(piece->smiley_width * factor), text_rc.left);
+
+ if ((LONG)(piece->smiley_width * factor) <= text_rc.right - text_rc.left)
+ {
+ text_rc.top += (row_height - (LONG)(piece->smiley_height * factor)) >> 1;
+
+ skin_DrawIconEx(hdcMem, text_rc.left, text_rc.top, piece->smiley,
+ (LONG)(piece->smiley_width * factor), (LONG)(piece->smiley_height * factor), 0, NULL, DI_NORMAL);
+ }
+ else
+ {
+ text_rc.top += (row_height - text_height) >> 1;
+ skin_DrawText(hdcMem, _T("..."), 3, &text_rc, uTextFormat);
+ }
+
+ pos_x += (LONG)(piece->smiley_width * factor);
+ }
+ }
+ }
+ }
+}
+
+
+void DestroySmileyList(SortedList* p_list)
+{
+ if (p_list == NULL)
+ return;
+
+ if (p_list->items != NULL)
+ {
+ int i;
+ for (i = 0; i < p_list->realCount; i++)
+ {
+ TextPiece *piece = (TextPiece *)p_list->items[i];
+
+ if (piece != NULL)
+ {
+ if (piece->type == TEXT_PIECE_TYPE_SMILEY)
+ DestroyIcon(piece->smiley);
+
+ mir_free(piece);
+ }
+ }
+ }
+
+ List_Destroy(p_list);
+}
+
+
+
+// Generete the list of smileys / text to be drawn
+SortedList * ReplaceSmileys(const TCHAR *text, int text_size, const char *protocol, int *max_smiley_height)
+{
+ *max_smiley_height = 0;
+
+ if (text[0] == '\0' || !ServiceExists(MS_SMILEYADD_BATCHPARSE))
+ return NULL;
+
+ // Parse it!
+ SMADD_BATCHPARSE2 sp = { sizeof(sp) };
+ sp.Protocolname = protocol;
+ sp.str = (TCHAR*)text;
+ sp.flag = SAFL_TCHAR;
+ SMADD_BATCHPARSERES *spres = (SMADD_BATCHPARSERES *)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp);
+ if (spres == NULL)
+ // Did not find a simley
+ return NULL;
+
+ // Lets add smileys
+ SortedList *plText = List_Create(0, 10);
+
+ const TCHAR *next_text_pos = text;
+ const TCHAR *last_text_pos = _tcsninc(text, text_size);
+
+ for (unsigned int i = 0; i < sp.numSmileys; i++) {
+ TCHAR* start = _tcsninc(text, spres[i].startChar);
+ TCHAR* end = _tcsninc(start, spres[i].size);
+
+ if (spres[i].hIcon != NULL) { // For defective smileypacks
+ // Add text
+ if (start > next_text_pos) {
+ TextPiece *piece = (TextPiece *)mir_calloc(sizeof(TextPiece));
+
+ piece->type = TEXT_PIECE_TYPE_TEXT;
+ piece->start_pos = next_text_pos - text;
+ piece->len = start - next_text_pos;
+
+ List_Insert(plText, piece, plText->realCount);
+ }
+
+ // Add smiley
+ {
+ BITMAP bm;
+ ICONINFO icon;
+ TextPiece *piece = (TextPiece *)mir_calloc(sizeof(TextPiece));
+
+ piece->type = TEXT_PIECE_TYPE_SMILEY;
+ piece->len = end - start;
+ piece->smiley = spres[i].hIcon;
+
+ piece->smiley_width = 16;
+ piece->smiley_height = 16;
+ if (GetIconInfo(piece->smiley, &icon))
+ {
+ if (GetObject(icon.hbmColor, sizeof(BITMAP), &bm))
+ {
+ piece->smiley_width = bm.bmWidth;
+ piece->smiley_height = bm.bmHeight;
+ }
+
+ DeleteObject(icon.hbmMask);
+ DeleteObject(icon.hbmColor);
+ }
+
+ *max_smiley_height = max(piece->smiley_height, *max_smiley_height);
+
+ List_Insert(plText, piece, plText->realCount);
+ }
+
+ next_text_pos = end;
+ }
+ }
+
+ // Add rest of text
+ if (last_text_pos > next_text_pos)
+ {
+ TextPiece *piece = (TextPiece *)mir_calloc(sizeof(TextPiece));
+
+ piece->type = TEXT_PIECE_TYPE_TEXT;
+ piece->start_pos = next_text_pos - text;
+ piece->len = last_text_pos - next_text_pos;
+
+ List_Insert(plText, piece, plText->realCount);
+ }
+
+ CallService(MS_SMILEYADD_BATCHFREE, 0, (LPARAM)spres);
+
+ return plText;
+}
diff --git a/utils/mir_smileys.h b/utils/mir_smileys.h
new file mode 100644
index 0000000000..781ccfa9fb
--- /dev/null
+++ b/utils/mir_smileys.h
@@ -0,0 +1,63 @@
+/*
+Copyright (C) 2005 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __MIR_SMILEYS_H__
+# define __MIR_SMILEYS_H__
+
+#include <windows.h>
+#include <m_system.h>
+
+// Init settings needed to draw smileys using the contact list itens
+// To use then, pass "clist" as the protocol name
+// Need to be called on ME_SYSTEM_MODULESLOADED
+int InitContactListSmileys();
+
+
+// Pre-parse smileys
+typedef struct _SmileysParseInfo
+{
+ SortedList *pieces;
+ int max_height;
+} *SmileysParseInfo;
+
+SmileysParseInfo Smileys_PreParse(LPCSTR lpString, int nCount, const char *protocol);
+void Smileys_FreeParse(SmileysParseInfo parseInfo);
+
+// TODO:
+// SmileysParseInfo Smileys_PreParseW(HDC hDC, LPCWSTR lpString, int nCount, const char *protocol);
+
+
+#define DT_RESIZE_SMILEYS 0x10000000
+
+// Similar to DrawText win32 api function
+// Pass uFormat | DT_CALCRECT to calc rectangle to be returned by lpRect
+// parseInfo is optional (pass NULL and it will be calculated and deleted inside function)
+int Smileys_DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat, const char *protocol, SmileysParseInfo parseInfo);
+
+// TODO:
+// int Smileys_DrawTextW(HDC hDC, LPCWSTR lpString, int nCount, LPRECT lpRect, UINT uFormat, const char *protocol, SmileysParseInfo parseInfo);
+
+
+int skin_DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat);
+int skin_DrawIconEx(HDC hdc, int xLeft, int yTop, HICON hIcon, int cxWidth, int cyWidth, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags);
+
+
+
+#endif // __MIR_SMILEYS_H__
diff --git a/utils/scope.h b/utils/scope.h
new file mode 100644
index 0000000000..961484e4d7
--- /dev/null
+++ b/utils/scope.h
@@ -0,0 +1,106 @@
+/*
+Copyright (C) 2009 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __SCOPE_H__
+# define __SCOPE_H__
+
+
+#define DEFINE_SCOPED_TYPE(_NAME_, _DELETE_) \
+ template<class T> \
+ class _NAME_ \
+ { \
+ _NAME_(_NAME_ &); \
+ _NAME_ & operator=(_NAME_ &); \
+ \
+ public: \
+ _NAME_(T *t = NULL) : p(t) {} \
+ \
+ ~_NAME_() \
+ { \
+ release(); \
+ } \
+ \
+ T * operator=(T *t) \
+ { \
+ release(); \
+ p = t; \
+ return t; \
+ } \
+ \
+ operator T*() const \
+ { \
+ return p; \
+ } \
+ \
+ bool operator==(T *t) const \
+ { \
+ return p == t; \
+ } \
+ \
+ bool operator!=(T *t) const \
+ { \
+ return p != t; \
+ } \
+ \
+ T *get() const \
+ { \
+ return p; \
+ } \
+ \
+ void release() \
+ { \
+ if (p != NULL) \
+ dealoc(p); \
+ p = NULL; \
+ } \
+ \
+ T* detach() \
+ { \
+ T *ret = p; \
+ p = NULL; \
+ return ret; \
+ } \
+ \
+ protected: \
+ T *p; \
+ \
+ void dealoc(T *ptr) \
+ { \
+ _DELETE_; \
+ } \
+ }; \
+ \
+ template<typename T> \
+ inline bool operator==(T* p, const _NAME_<T> &b) { \
+ return p == b.get(); \
+ } \
+ \
+ template<typename T> \
+ inline bool operator!=(T* p, const _NAME_<T> &b) { \
+ return p != b.get(); \
+ }
+
+DEFINE_SCOPED_TYPE(scoped_ptr, delete ptr)
+DEFINE_SCOPED_TYPE(scoped_array, delete[] ptr)
+DEFINE_SCOPED_TYPE(scoped_free, free(ptr))
+DEFINE_SCOPED_TYPE(scoped_mir_free, mir_free(ptr))
+
+
+#endif // __SCOPE_H__
diff --git a/utils/utf8_helpers.h b/utils/utf8_helpers.h
new file mode 100644
index 0000000000..25e243c203
--- /dev/null
+++ b/utils/utf8_helpers.h
@@ -0,0 +1,587 @@
+/*
+Copyright (C) 2009 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __UTF8_HELPERS_H__
+# define __UTF8_HELPERS_H__
+
+#include <windows.h>
+#include <newpluginapi.h>
+#include <m_system.h>
+
+
+class TcharToUtf8
+{
+public:
+ TcharToUtf8(const char *str) : utf8(NULL)
+ {
+ int size = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+ if (size <= 0)
+ throw _T("Could not convert string to WCHAR");
+
+ WCHAR *tmp = (WCHAR *) mir_alloc(size * sizeof(WCHAR));
+ if (tmp == NULL)
+ throw _T("mir_alloc returned NULL");
+
+ MultiByteToWideChar(CP_ACP, 0, str, -1, tmp, size);
+
+ init(tmp);
+
+ mir_free(tmp);
+ }
+
+
+ TcharToUtf8(const WCHAR *str) : utf8(NULL)
+ {
+ init(str);
+ }
+
+
+ ~TcharToUtf8()
+ {
+ if (utf8 != NULL)
+ mir_free(utf8);
+ }
+
+ char *detach()
+ {
+ char *ret = utf8;
+ utf8 = NULL;
+ return ret;
+ }
+
+ const char * get() const
+ {
+ return utf8;
+ }
+
+ operator const char *() const
+ {
+ return utf8;
+ }
+
+ const char & operator[](int pos) const
+ {
+ return utf8[pos];
+ }
+
+private:
+ char *utf8;
+
+ void init(const WCHAR *str)
+ {
+ int size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
+ if (size <= 0)
+ throw _T("Could not convert string to UTF8");
+
+ utf8 = (char *) mir_alloc(size);
+ if (utf8 == NULL)
+ throw _T("mir_alloc returned NULL");
+
+ WideCharToMultiByte(CP_UTF8, 0, str, -1, utf8, size, NULL, NULL);
+ }
+};
+
+
+
+class Utf8ToTchar
+{
+public:
+ Utf8ToTchar(const char *str) : tchar(NULL)
+ {
+ if (str == NULL)
+ return;
+
+ int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ if (size <= 0)
+ throw _T("Could not convert string to WCHAR");
+
+ WCHAR *tmp = (WCHAR *) mir_alloc(size * sizeof(WCHAR));
+ if (tmp == NULL)
+ throw _T("mir_alloc returned NULL");
+
+ MultiByteToWideChar(CP_UTF8, 0, str, -1, tmp, size);
+
+#ifdef UNICODE
+
+ tchar = tmp;
+
+#else
+
+ size = WideCharToMultiByte(CP_ACP, 0, tmp, -1, NULL, 0, NULL, NULL);
+ if (size <= 0)
+ {
+ mir_free(tmp);
+ throw _T("Could not convert string to ACP");
+ }
+
+ tchar = (TCHAR *) mir_alloc(size * sizeof(char));
+ if (tchar == NULL)
+ {
+ mir_free(tmp);
+ throw _T("mir_alloc returned NULL");
+ }
+
+ WideCharToMultiByte(CP_ACP, 0, tmp, -1, tchar, size, NULL, NULL);
+
+ mir_free(tmp);
+
+#endif
+ }
+
+ ~Utf8ToTchar()
+ {
+ if (tchar != NULL)
+ mir_free(tchar);
+ }
+
+ TCHAR *detach()
+ {
+ TCHAR *ret = tchar;
+ tchar = NULL;
+ return ret;
+ }
+
+ TCHAR * get() const
+ {
+ return tchar;
+ }
+
+ operator TCHAR *() const
+ {
+ return tchar;
+ }
+
+ TCHAR & operator[](int pos)
+ {
+ return tchar[pos];
+ }
+
+private:
+ TCHAR *tchar;
+};
+
+
+class CharToTchar
+{
+public:
+ CharToTchar(const char *str) : tchar(NULL)
+ {
+ if (str == NULL)
+ return;
+
+#ifdef UNICODE
+
+ tchar = mir_a2u(str);
+
+#else
+
+ tchar = str;
+
+#endif
+ }
+
+
+ ~CharToTchar()
+ {
+#ifdef UNICODE
+ if (tchar != NULL)
+ mir_free(tchar);
+#endif
+ }
+
+ TCHAR *detach()
+ {
+#ifdef UNICODE
+ TCHAR *ret = tchar;
+#else
+ TCHAR *ret = (tchar == NULL ? NULL : mir_strdup(tchar));
+#endif
+
+ tchar = NULL;
+ return ret;
+ }
+
+ const TCHAR * get() const
+ {
+ return tchar;
+ }
+
+ operator const TCHAR *() const
+ {
+ return tchar;
+ }
+
+ const TCHAR & operator[](int pos) const
+ {
+ return tchar[pos];
+ }
+
+private:
+#ifdef UNICODE
+ TCHAR *tchar;
+#else
+ const TCHAR *tchar;
+#endif
+};
+
+
+class WcharToTchar
+{
+public:
+ WcharToTchar(const WCHAR *str) : tchar(NULL)
+ {
+ if (str == NULL)
+ return;
+
+#ifdef UNICODE
+
+ tchar = str;
+
+#else
+
+ tchar = mir_u2a(str);
+
+#endif
+ }
+
+
+ ~WcharToTchar()
+ {
+#ifndef UNICODE
+ if (tchar != NULL)
+ mir_free(tchar);
+#endif
+ }
+
+ TCHAR *detach()
+ {
+#ifdef UNICODE
+ TCHAR *ret = (tchar == NULL ? NULL : mir_wstrdup(tchar));
+#else
+ TCHAR *ret = tchar;
+#endif
+
+ tchar = NULL;
+ return ret;
+ }
+
+ const TCHAR * get() const
+ {
+ return tchar;
+ }
+
+ operator const TCHAR *() const
+ {
+ return tchar;
+ }
+
+ const TCHAR & operator[](int pos) const
+ {
+ return tchar[pos];
+ }
+
+private:
+#ifdef UNICODE
+ const TCHAR *tchar;
+#else
+ TCHAR *tchar;
+#endif
+};
+
+
+
+
+class CharToWchar
+{
+public:
+ CharToWchar(const char *str) : wchar(NULL)
+ {
+ if (str == NULL)
+ return;
+
+ wchar = mir_a2u(str);
+ }
+
+
+ ~CharToWchar()
+ {
+ if (wchar != NULL)
+ mir_free(wchar);
+ }
+
+ WCHAR *detach()
+ {
+ WCHAR *ret = wchar;
+ wchar = NULL;
+ return ret;
+ }
+
+ const WCHAR * get() const
+ {
+ return wchar;
+ }
+
+ operator const WCHAR *() const
+ {
+ return wchar;
+ }
+
+ const WCHAR & operator[](int pos) const
+ {
+ return wchar[pos];
+ }
+
+private:
+ WCHAR *wchar;
+};
+
+
+
+class TcharToChar
+{
+public:
+ TcharToChar(const TCHAR *str) : val(NULL)
+ {
+ if (str == NULL)
+ return;
+
+#ifdef UNICODE
+
+ val = mir_u2a(str);
+
+#else
+
+ val = str;
+
+#endif
+ }
+
+
+ ~TcharToChar()
+ {
+#ifdef UNICODE
+ if (val != NULL)
+ mir_free(val);
+#endif
+ }
+
+ char *detach()
+ {
+#ifdef UNICODE
+ char *ret = val;
+#else
+ char *ret = (val == NULL ? NULL : mir_strdup(val));
+#endif
+
+ val = NULL;
+ return ret;
+ }
+
+ const char * get() const
+ {
+ return val;
+ }
+
+ operator const char *() const
+ {
+ return val;
+ }
+
+ const char & operator[](int pos) const
+ {
+ return val[pos];
+ }
+
+private:
+#ifdef UNICODE
+ char *val;
+#else
+ const char *val;
+#endif
+};
+
+
+class TcharToWchar
+{
+public:
+ TcharToWchar(const TCHAR *str) : val(NULL)
+ {
+ if (str == NULL)
+ return;
+
+#ifdef UNICODE
+
+ val = str;
+
+#else
+
+ val = mir_a2u(str);
+
+#endif
+ }
+
+
+ ~TcharToWchar()
+ {
+#ifndef UNICODE
+ if (val != NULL)
+ mir_free(val);
+#endif
+ }
+
+ WCHAR *detach()
+ {
+#ifdef UNICODE
+ WCHAR *ret = (val == NULL ? NULL : mir_wstrdup(val));
+#else
+ WCHAR *ret = val;
+#endif
+
+ val = NULL;
+ return ret;
+ }
+
+ const WCHAR * get() const
+ {
+ return val;
+ }
+
+ operator const WCHAR *() const
+ {
+ return val;
+ }
+
+ const WCHAR & operator[](int pos) const
+ {
+ return val[pos];
+ }
+
+private:
+#ifdef UNICODE
+ const WCHAR *val;
+#else
+ WCHAR *val;
+#endif
+};
+
+
+
+
+class BstrToTchar
+{
+public:
+ BstrToTchar() : bstr(NULL)
+#ifndef UNICODE
+ , tchar(NULL)
+#endif
+ {
+ }
+
+ BstrToTchar(const WCHAR *str) : bstr(NULL)
+#ifndef UNICODE
+ , tchar(NULL)
+#endif
+ {
+ if (str == NULL)
+ return;
+
+ bstr = SysAllocString(str);
+ }
+
+ BstrToTchar(const char *str) : bstr(NULL)
+#ifndef UNICODE
+ , tchar(NULL)
+#endif
+ {
+ if (str == NULL)
+ return;
+
+ bstr = SysAllocString(CharToWchar(str));
+ }
+
+
+ ~BstrToTchar()
+ {
+ if (bstr != NULL)
+ SysFreeString(bstr);
+
+#ifndef UNICODE
+ freeTchar();
+#endif
+ }
+
+ BSTR detach()
+ {
+ BSTR ret = bstr;
+ bstr = NULL;
+ return ret;
+ }
+
+ operator const TCHAR *()
+ {
+#ifdef UNICODE
+
+ return bstr;
+
+#else
+
+ if (tchar == NULL)
+ tchar = mir_u2a(bstr);
+
+ return tchar;
+
+#endif
+ }
+
+ operator const BSTR() const
+ {
+ return bstr;
+ }
+
+ operator BSTR *()
+ {
+#ifndef UNICODE
+ freeTchar();
+#endif
+
+ return &bstr;
+ }
+
+private:
+ BSTR bstr;
+
+#ifndef UNICODE
+
+ TCHAR *tchar;
+
+ void freeTchar()
+ {
+ if (tchar != NULL)
+ {
+ mir_free(tchar);
+ tchar = NULL;
+ }
+ }
+
+#endif
+};
+
+
+#endif // __UTF8_HELPERS_H__