From a33833212f040272fc6c97047c8cb335b6f5405a Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 24 Jul 2012 06:41:19 +0000 Subject: SimpleAR, SimpleStatusMsg, SmileyAdd, SpellChecker: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1149 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/SmileyAdd/AniSmileyObject.cpp | 450 ------ plugins/SmileyAdd/Res/resource.rc | 214 +++ plugins/SmileyAdd/SmileyAdd_10.vcxproj | 84 +- plugins/SmileyAdd/SmileyAdd_10.vcxproj.filters | 79 +- plugins/SmileyAdd/SmileyBase.cpp | 391 ----- plugins/SmileyAdd/SmileyBase.h | 127 -- plugins/SmileyAdd/anim.cpp | 184 --- plugins/SmileyAdd/anim.h | 87 -- plugins/SmileyAdd/bkstring.cpp | 215 --- plugins/SmileyAdd/bkstring.h | 270 ---- plugins/SmileyAdd/customsmiley.cpp | 172 --- plugins/SmileyAdd/customsmiley.h | 85 -- plugins/SmileyAdd/dlgboxsubclass.cpp | 568 ------- plugins/SmileyAdd/docs/smileyadd-translation.txt | 54 + plugins/SmileyAdd/download.cpp | 292 ---- plugins/SmileyAdd/download.h | 28 - plugins/SmileyAdd/general.cpp | 299 ---- plugins/SmileyAdd/general.h | 232 --- plugins/SmileyAdd/imagecache.cpp | 775 ---------- plugins/SmileyAdd/imagecache.h | 166 -- plugins/SmileyAdd/main.cpp | 225 --- plugins/SmileyAdd/options.cpp | 728 --------- plugins/SmileyAdd/options.h | 60 - plugins/SmileyAdd/regexp/Matcher.cpp | 178 --- plugins/SmileyAdd/regexp/Matcher.h | 248 --- plugins/SmileyAdd/regexp/Pattern.cpp | 1709 --------------------- plugins/SmileyAdd/regexp/Pattern.h | 1663 -------------------- plugins/SmileyAdd/regexp/WCMatcher.cpp | 181 --- plugins/SmileyAdd/regexp/WCMatcher.h | 234 --- plugins/SmileyAdd/regexp/WCPattern.cpp | 1747 ---------------------- plugins/SmileyAdd/regexp/WCPattern.h | 1663 -------------------- plugins/SmileyAdd/regexp/test.cpp | 38 - plugins/SmileyAdd/resource.h | 49 - plugins/SmileyAdd/resource.rc | 214 --- plugins/SmileyAdd/richcall.cpp | 554 ------- plugins/SmileyAdd/services.cpp | 590 -------- plugins/SmileyAdd/services.h | 48 - plugins/SmileyAdd/smileyadd-translation.txt | 54 - plugins/SmileyAdd/smileyroutines.cpp | 610 -------- plugins/SmileyAdd/smileyroutines.h | 49 - plugins/SmileyAdd/smileys.cpp | 1146 -------------- plugins/SmileyAdd/smileys.h | 287 ---- plugins/SmileyAdd/smltool.cpp | 785 ---------- plugins/SmileyAdd/smltool.h | 45 - plugins/SmileyAdd/src/AniSmileyObject.cpp | 450 ++++++ plugins/SmileyAdd/src/SmileyBase.cpp | 391 +++++ plugins/SmileyAdd/src/SmileyBase.h | 127 ++ plugins/SmileyAdd/src/anim.cpp | 184 +++ plugins/SmileyAdd/src/anim.h | 87 ++ plugins/SmileyAdd/src/bkstring.cpp | 215 +++ plugins/SmileyAdd/src/bkstring.h | 270 ++++ plugins/SmileyAdd/src/customsmiley.cpp | 172 +++ plugins/SmileyAdd/src/customsmiley.h | 85 ++ plugins/SmileyAdd/src/dlgboxsubclass.cpp | 568 +++++++ plugins/SmileyAdd/src/download.cpp | 292 ++++ plugins/SmileyAdd/src/download.h | 28 + plugins/SmileyAdd/src/general.cpp | 299 ++++ plugins/SmileyAdd/src/general.h | 232 +++ plugins/SmileyAdd/src/imagecache.cpp | 775 ++++++++++ plugins/SmileyAdd/src/imagecache.h | 166 ++ plugins/SmileyAdd/src/main.cpp | 225 +++ plugins/SmileyAdd/src/options.cpp | 728 +++++++++ plugins/SmileyAdd/src/options.h | 60 + plugins/SmileyAdd/src/regexp/Matcher.cpp | 178 +++ plugins/SmileyAdd/src/regexp/Matcher.h | 248 +++ plugins/SmileyAdd/src/regexp/Pattern.cpp | 1709 +++++++++++++++++++++ plugins/SmileyAdd/src/regexp/Pattern.h | 1663 ++++++++++++++++++++ plugins/SmileyAdd/src/regexp/WCMatcher.cpp | 181 +++ plugins/SmileyAdd/src/regexp/WCMatcher.h | 234 +++ plugins/SmileyAdd/src/regexp/WCPattern.cpp | 1747 ++++++++++++++++++++++ plugins/SmileyAdd/src/regexp/WCPattern.h | 1663 ++++++++++++++++++++ plugins/SmileyAdd/src/regexp/test.cpp | 38 + plugins/SmileyAdd/src/resource.h | 49 + plugins/SmileyAdd/src/richcall.cpp | 554 +++++++ plugins/SmileyAdd/src/services.cpp | 590 ++++++++ plugins/SmileyAdd/src/services.h | 48 + plugins/SmileyAdd/src/smileyroutines.cpp | 610 ++++++++ plugins/SmileyAdd/src/smileyroutines.h | 49 + plugins/SmileyAdd/src/smileys.cpp | 1146 ++++++++++++++ plugins/SmileyAdd/src/smileys.h | 287 ++++ plugins/SmileyAdd/src/smltool.cpp | 785 ++++++++++ plugins/SmileyAdd/src/smltool.h | 45 + plugins/SmileyAdd/src/version.h | 3 + plugins/SmileyAdd/version.h | 3 - 84 files changed, 17519 insertions(+), 17542 deletions(-) delete mode 100644 plugins/SmileyAdd/AniSmileyObject.cpp create mode 100644 plugins/SmileyAdd/Res/resource.rc delete mode 100644 plugins/SmileyAdd/SmileyBase.cpp delete mode 100644 plugins/SmileyAdd/SmileyBase.h delete mode 100644 plugins/SmileyAdd/anim.cpp delete mode 100644 plugins/SmileyAdd/anim.h delete mode 100644 plugins/SmileyAdd/bkstring.cpp delete mode 100644 plugins/SmileyAdd/bkstring.h delete mode 100644 plugins/SmileyAdd/customsmiley.cpp delete mode 100644 plugins/SmileyAdd/customsmiley.h delete mode 100644 plugins/SmileyAdd/dlgboxsubclass.cpp create mode 100644 plugins/SmileyAdd/docs/smileyadd-translation.txt delete mode 100644 plugins/SmileyAdd/download.cpp delete mode 100644 plugins/SmileyAdd/download.h delete mode 100644 plugins/SmileyAdd/general.cpp delete mode 100644 plugins/SmileyAdd/general.h delete mode 100644 plugins/SmileyAdd/imagecache.cpp delete mode 100644 plugins/SmileyAdd/imagecache.h delete mode 100644 plugins/SmileyAdd/main.cpp delete mode 100644 plugins/SmileyAdd/options.cpp delete mode 100644 plugins/SmileyAdd/options.h delete mode 100644 plugins/SmileyAdd/regexp/Matcher.cpp delete mode 100644 plugins/SmileyAdd/regexp/Matcher.h delete mode 100644 plugins/SmileyAdd/regexp/Pattern.cpp delete mode 100644 plugins/SmileyAdd/regexp/Pattern.h delete mode 100644 plugins/SmileyAdd/regexp/WCMatcher.cpp delete mode 100644 plugins/SmileyAdd/regexp/WCMatcher.h delete mode 100644 plugins/SmileyAdd/regexp/WCPattern.cpp delete mode 100644 plugins/SmileyAdd/regexp/WCPattern.h delete mode 100644 plugins/SmileyAdd/regexp/test.cpp delete mode 100644 plugins/SmileyAdd/resource.h delete mode 100644 plugins/SmileyAdd/resource.rc delete mode 100644 plugins/SmileyAdd/richcall.cpp delete mode 100644 plugins/SmileyAdd/services.cpp delete mode 100644 plugins/SmileyAdd/services.h delete mode 100644 plugins/SmileyAdd/smileyadd-translation.txt delete mode 100644 plugins/SmileyAdd/smileyroutines.cpp delete mode 100644 plugins/SmileyAdd/smileyroutines.h delete mode 100644 plugins/SmileyAdd/smileys.cpp delete mode 100644 plugins/SmileyAdd/smileys.h delete mode 100644 plugins/SmileyAdd/smltool.cpp delete mode 100644 plugins/SmileyAdd/smltool.h create mode 100644 plugins/SmileyAdd/src/AniSmileyObject.cpp create mode 100644 plugins/SmileyAdd/src/SmileyBase.cpp create mode 100644 plugins/SmileyAdd/src/SmileyBase.h create mode 100644 plugins/SmileyAdd/src/anim.cpp create mode 100644 plugins/SmileyAdd/src/anim.h create mode 100644 plugins/SmileyAdd/src/bkstring.cpp create mode 100644 plugins/SmileyAdd/src/bkstring.h create mode 100644 plugins/SmileyAdd/src/customsmiley.cpp create mode 100644 plugins/SmileyAdd/src/customsmiley.h create mode 100644 plugins/SmileyAdd/src/dlgboxsubclass.cpp create mode 100644 plugins/SmileyAdd/src/download.cpp create mode 100644 plugins/SmileyAdd/src/download.h create mode 100644 plugins/SmileyAdd/src/general.cpp create mode 100644 plugins/SmileyAdd/src/general.h create mode 100644 plugins/SmileyAdd/src/imagecache.cpp create mode 100644 plugins/SmileyAdd/src/imagecache.h create mode 100644 plugins/SmileyAdd/src/main.cpp create mode 100644 plugins/SmileyAdd/src/options.cpp create mode 100644 plugins/SmileyAdd/src/options.h create mode 100644 plugins/SmileyAdd/src/regexp/Matcher.cpp create mode 100644 plugins/SmileyAdd/src/regexp/Matcher.h create mode 100644 plugins/SmileyAdd/src/regexp/Pattern.cpp create mode 100644 plugins/SmileyAdd/src/regexp/Pattern.h create mode 100644 plugins/SmileyAdd/src/regexp/WCMatcher.cpp create mode 100644 plugins/SmileyAdd/src/regexp/WCMatcher.h create mode 100644 plugins/SmileyAdd/src/regexp/WCPattern.cpp create mode 100644 plugins/SmileyAdd/src/regexp/WCPattern.h create mode 100644 plugins/SmileyAdd/src/regexp/test.cpp create mode 100644 plugins/SmileyAdd/src/resource.h create mode 100644 plugins/SmileyAdd/src/richcall.cpp create mode 100644 plugins/SmileyAdd/src/services.cpp create mode 100644 plugins/SmileyAdd/src/services.h create mode 100644 plugins/SmileyAdd/src/smileyroutines.cpp create mode 100644 plugins/SmileyAdd/src/smileyroutines.h create mode 100644 plugins/SmileyAdd/src/smileys.cpp create mode 100644 plugins/SmileyAdd/src/smileys.h create mode 100644 plugins/SmileyAdd/src/smltool.cpp create mode 100644 plugins/SmileyAdd/src/smltool.h create mode 100644 plugins/SmileyAdd/src/version.h delete mode 100644 plugins/SmileyAdd/version.h (limited to 'plugins/SmileyAdd') diff --git a/plugins/SmileyAdd/AniSmileyObject.cpp b/plugins/SmileyAdd/AniSmileyObject.cpp deleted file mode 100644 index 42a63d3549..0000000000 --- a/plugins/SmileyAdd/AniSmileyObject.cpp +++ /dev/null @@ -1,450 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "SmileyBase.h" -#include "m_smileyadd.h" -#include "smileys.h" -#include "options.h" - -#include - - -class CAniSmileyObject; - -static int CompareAniSmiley(const CAniSmileyObject* p1, const CAniSmileyObject* p2) -{ - return (int)((char*)p2 - (char*)p1); -} - -static LIST regAniSmileys(10, CompareAniSmiley); - -static UINT_PTR timerId; -static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD); - -static void CALLBACK sttMainThreadCallback( PVOID ) -{ - if (timerId == 0xffffffff) - timerId = SetTimer(NULL, 0, 100, (TIMERPROC)timerProc); -} - - -class CAniSmileyObject : public ISmileyBase -{ -private: - typedef enum { animStdOle, animDrctRichEd, animHpp } AnimType; - - POINTL m_rectOrig; - SIZEL m_rectExt; - - COLORREF m_bkg; - - SmileyType* m_sml; - ImageBase* m_img; - unsigned m_nFramePosition; - - long m_counter; - unsigned m_richFlags; - long m_lastObjNum; - - AnimType m_animtype; - bool m_allowAni; - -public: - CAniSmileyObject(SmileyType* sml, COLORREF clr, bool ishpp) - { - m_allowAni = false; - m_animtype = ishpp ? animHpp : animStdOle; - m_bkg = clr; - - m_rectOrig.x = 0; - m_rectOrig.y = 0; - m_rectExt.cx = 0; - m_rectExt.cy = 0; - - m_richFlags = 0; - m_lastObjNum = 0; - - m_sml = sml; - m_img = NULL; - m_nFramePosition = 0; - m_counter = 0; - } - - ~CAniSmileyObject(void) - { - UnloadSmiley(); - } - - void LoadSmiley(void) - { - if (m_img != NULL) return; - - m_img = m_sml->CreateCachedImage(); - if (m_img && m_img->IsAnimated() && opt.AnimateDlg) - { - m_nFramePosition = 0; - m_img->SelectFrame(m_nFramePosition); - long frtm = m_img->GetFrameDelay(); - m_counter = frtm / 10 + ((frtm % 10) >= 5); - - regAniSmileys.insert(this); - if (timerId == 0) - { - timerId = 0xffffffff; - CallFunctionAsync(sttMainThreadCallback, NULL); - } - } - else - m_nFramePosition = m_sml->GetStaticFrame(); - } - - void UnloadSmiley(void) - { - regAniSmileys.remove(this); - - if (timerId && (timerId+1) && regAniSmileys.getCount() == 0) - { - KillTimer(NULL, timerId); - timerId = 0; - } - if (m_img) m_img->Release(); - m_img = NULL; - } - - void GetDrawingProp(void) - { - if (m_hwnd == NULL) return; - - IRichEditOle* RichEditOle; - if (SendMessage(m_hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) - return; - - REOBJECT reObj = {0}; - reObj.cbStruct = sizeof(REOBJECT); - - HRESULT hr = RichEditOle->GetObject(m_lastObjNum, &reObj, REO_GETOBJ_NO_INTERFACES); - if (hr == S_OK && reObj.dwUser == (DWORD)(ISmileyBase*)this && reObj.clsid == CLSID_NULL) - { - m_richFlags = reObj.dwFlags; - } - else - { - long objectCount = RichEditOle->GetObjectCount(); - for (long i = objectCount; i--; ) - { - HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_NO_INTERFACES); - if (FAILED(hr)) continue; - - if (reObj.dwUser == (DWORD)(ISmileyBase*)this && reObj.clsid == CLSID_NULL) - { - m_lastObjNum = i; - m_richFlags = reObj.dwFlags; - break; - } - } - } - RichEditOle->Release(); - - if ((m_richFlags & REO_SELECTED) == 0) - { - CHARRANGE sel; - SendMessage(m_hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - if (reObj.cp >= sel.cpMin && reObj.cp < sel.cpMax) - m_richFlags |= REO_INVERTEDSELECT; - else - m_richFlags &= ~REO_INVERTEDSELECT; - } - } - - - void DoDirectDraw(HDC hdc) - { - HBITMAP hBmp = CreateCompatibleBitmap(hdc, m_rectExt.cx, m_rectExt.cy); - HDC hdcMem = CreateCompatibleDC(hdc); - HANDLE hOld = SelectObject(hdcMem, hBmp); - - RECT rc; - rc.left = m_rectExt.cx - m_sizeExtent.cx; - rc.top = m_rectExt.cy - m_sizeExtent.cy; - rc.right = rc.left + m_sizeExtent.cx; - rc.bottom = rc.top + m_sizeExtent.cy; - - HBRUSH hbr = CreateSolidBrush(m_bkg); - RECT frc = { 0, 0, m_rectExt.cx, m_rectExt.cy }; - FillRect(hdcMem, &frc, hbr); - DeleteObject(hbr); - - m_img->DrawInternal(hdcMem, rc.left, rc.top, m_sizeExtent.cx - 1, m_sizeExtent.cy - 1); - - if (m_richFlags & REO_SELECTED) - { - HBRUSH hbr = CreateSolidBrush(m_bkg ^ 0xFFFFFF); - FrameRect(hdcMem, &rc, hbr); - DeleteObject(hbr); - } - - if (m_richFlags & REO_INVERTEDSELECT) - InvertRect(hdcMem, &rc); - - BitBlt(hdc, m_rectOrig.x, m_rectOrig.y, m_rectExt.cx, m_rectExt.cy, hdcMem, 0, 0, SRCCOPY); - - SelectObject(hdcMem, hOld); - DeleteObject(hBmp); - DeleteDC(hdcMem); - } - - void DrawOnRichEdit(void) - { - HDC hdc = GetDC(m_hwnd); - if (RectVisible(hdc, &m_orect)) - { - RECT crct; - GetClientRect(m_hwnd, &crct); - - HRGN hrgnOld = CreateRectRgnIndirect(&crct); - int res = GetClipRgn(hdc, hrgnOld); - - HRGN hrgn = CreateRectRgnIndirect(&crct); - SelectClipRgn(hdc, hrgn); - DeleteObject(hrgn); - - DoDirectDraw(hdc); - - SelectClipRgn(hdc, res < 1 ? NULL : hrgnOld); - DeleteObject(hrgnOld); - } - else - { - m_visible = false; - m_allowAni = false; - UnloadSmiley(); - } - ReleaseDC(m_hwnd, hdc); - } - - void DrawOnHPP(void) - { - FVCNDATA_NMHDR nmh = {0}; - nmh.code = NM_FIREVIEWCHANGE; - nmh.hwndFrom = m_hwnd; - - nmh.cbSize = sizeof(nmh); - nmh.bEvent = FVCN_PREFIRE; - nmh.bAction = FVCA_DRAW; - nmh.rcRect = m_orect; - SendMessage(GetParent(m_hwnd), WM_NOTIFY, (WPARAM)m_hwnd, (LPARAM)&nmh); - - switch (nmh.bAction) - { - case FVCA_DRAW: - // support for pseudo-edit mode and event details - m_animtype = m_dirAniAllow ? animDrctRichEd : animStdOle; - GetDrawingProp(); - DrawOnRichEdit(); - break; - - case FVCA_CUSTOMDRAW: - m_rectExt.cy = nmh.rcRect.bottom - nmh.rcRect.top; - m_rectExt.cx = nmh.rcRect.right - nmh.rcRect.left; - m_rectOrig.x = nmh.rcRect.left; - m_rectOrig.y = nmh.rcRect.top; - - m_bkg = nmh.clrBackground; - - DoDirectDraw(nmh.hDC); - - nmh.bEvent = FVCN_POSTFIRE; - SendMessage(GetParent(m_hwnd), WM_NOTIFY, (WPARAM)m_hwnd, (LPARAM)&nmh); - break; - - case FVCA_SKIPDRAW: - break; - - case FVCA_NONE: - m_visible = false; - break; - - default: - break; - } - } - - void ProcessTimerTick(void) - { - if (m_visible && m_img && --m_counter <= 0) - { - m_nFramePosition = m_img->SelectNextFrame(m_nFramePosition); - long frtm = m_img->GetFrameDelay(); - m_counter = frtm / 10 + ((frtm % 10) >= 5); - - switch (m_animtype) - { - case animStdOle: - if (m_allowAni) SendOnViewChange(); - else - { - m_visible = false; - UnloadSmiley(); - } - m_allowAni = false; - break; - - case animDrctRichEd: - DrawOnRichEdit(); - break; - - case animHpp: - DrawOnHPP(); - break; - } - } - } - - void SetPosition(HWND hwnd, LPCRECT lpRect) - { - ISmileyBase::SetPosition(hwnd, lpRect); - - m_allowAni = m_visible; - - if (m_visible) LoadSmiley(); - else UnloadSmiley(); - - if (lpRect == NULL) return; - if (m_animtype == animStdOle) - { - m_animtype = animDrctRichEd; - GetDrawingProp(); - } - - if (lpRect->top == -1) - { - m_rectOrig.x = lpRect->left; - m_rectOrig.y = lpRect->bottom - m_sizeExtent.cy; - m_rectExt.cy = m_sizeExtent.cy; - } - else if (lpRect->bottom == -1) - { - m_rectOrig.x = lpRect->left; - m_rectOrig.y = lpRect->top; - } - else - { - m_rectOrig.x = lpRect->left; - m_rectOrig.y = lpRect->top; - m_rectExt.cy = lpRect->bottom - lpRect->top; - } - } - - STDMETHOD(Close)(DWORD dwSaveOption) - { - m_visible = false; - UnloadSmiley(); - - return ISmileyBase::Close(dwSaveOption); - } - - STDMETHOD(Draw)(DWORD dwAspect, LONG, void*, DVTARGETDEVICE*, HDC, - HDC hdc, LPCRECTL pRectBounds, LPCRECTL /* pRectWBounds */, - BOOL (__stdcall *)(ULONG_PTR), ULONG_PTR) - { - if (dwAspect != DVASPECT_CONTENT) return DV_E_DVASPECT; - if (pRectBounds == NULL) return E_INVALIDARG; - - LoadSmiley(); - - if (m_img == NULL) return E_FAIL; - - m_sizeExtent.cx = pRectBounds->right - pRectBounds->left; - m_sizeExtent.cy = pRectBounds->bottom - pRectBounds->top; - - m_rectExt = m_sizeExtent; - - switch (m_animtype) - { - case animDrctRichEd: - { - m_rectExt.cy = pRectBounds->bottom - m_rectOrig.y; - RECT frc = { 0, 0, m_sizeExtent.cx - 1, m_sizeExtent.cy - 1 }; - - HBITMAP hBmp = CreateCompatibleBitmap(hdc, frc.right, frc.bottom); - HDC hdcMem = CreateCompatibleDC(hdc); - HANDLE hOld = SelectObject(hdcMem, hBmp); - - HBRUSH hbr = CreateSolidBrush(m_bkg); - FillRect(hdcMem, &frc, hbr); - DeleteObject(hbr); - - m_img->DrawInternal(hdcMem, 0, 0, frc.right, frc.bottom); - - BitBlt(hdc, pRectBounds->left, pRectBounds->top, frc.right, frc.bottom, hdcMem, 0, 0, SRCCOPY); - - SelectObject(hdcMem, hOld); - DeleteObject(hBmp); - DeleteDC(hdcMem); - } - GetDrawingProp(); - break; - - case animHpp: - m_orect = *(LPRECT)pRectBounds; - - default: - m_img->DrawInternal(hdc, pRectBounds->left, pRectBounds->top, - m_sizeExtent.cx - 1, m_sizeExtent.cy - 1); - break; - } - - m_allowAni = true; - m_visible = true; - - return S_OK; - } - - STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL* psizel) - { - HRESULT hr = ISmileyBase::SetExtent(dwDrawAspect, psizel); - if (hr == S_OK) m_rectExt = m_sizeExtent; - return hr; - } -}; - -ISmileyBase* CreateAniSmileyObject(SmileyType* sml, COLORREF clr, bool ishpp) -{ - if (!sml->IsValid()) return NULL; - - CAniSmileyObject *obj = new CAniSmileyObject(sml, clr, ishpp); - return obj; -} - -static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD) -{ - for (int i=0; iProcessTimerTick(); -} - -void DestroyAniSmileys(void) -{ - if (timerId && (timerId+1)) - { - KillTimer(NULL, timerId); - timerId = 0; - } - regAniSmileys.destroy(); -} - diff --git a/plugins/SmileyAdd/Res/resource.rc b/plugins/SmileyAdd/Res/resource.rc new file mode 100644 index 0000000000..b055a7299b --- /dev/null +++ b/plugins/SmileyAdd/Res/resource.rc @@ -0,0 +1,214 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\src\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include +#include "..\src\version.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPT_SMILEYS DIALOGEX 0, 0, 320, 256 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Smiley Categories",IDC_STATIC,6,3,310,102 + CONTROL "",IDC_CATEGORYLIST,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_CHECKBOXES | WS_BORDER | WS_HSCROLL | WS_TABSTOP,14,13,104,83 + CONTROL "Specify Smiley Pack for each category",IDC_USESTDPACK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,124,11,165,11 + EDITTEXT IDC_FILENAME,124,25,185,12,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES + PUSHBUTTON "...",IDC_BROWSE,296,15,13,11 + LTEXT "Name:",IDC_STATIC,125,42,30,8 + LTEXT "",IDC_LIBNAME,159,41,150,11,SS_SUNKEN | SS_PATHELLIPSIS + LTEXT "Author:",IDC_STATIC,125,56,30,8 + LTEXT "",IDC_LIBAUTHOR,159,55,104,11,SS_SUNKEN | SS_PATHELLIPSIS + LTEXT "Version:",IDC_STATIC,125,70,30,8 + LTEXT "",IDC_LIBVERSION,159,70,104,11,SS_SUNKEN | SS_PATHELLIPSIS + PUSHBUTTON "Preview",IDC_SMLOPTBUTTON,270,55,37,25 + EDITTEXT IDC_NEWCATEGORY,126,85,129,13,ES_AUTOHSCROLL + PUSHBUTTON "+",IDC_ADDCATEGORY,263,84,17,15 + PUSHBUTTON "-",IDC_DELETECATEGORY,290,84,16,14 + GROUPBOX "Display",IDC_STATIC,6,106,310,54 + CONTROL "Replace only smileys surrounded by spaces",IDC_SPACES, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,16,115,198,12,WS_EX_RTLREADING + CONTROL "Scale smiley to textheight",IDC_SCALETOTEXTHEIGHT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,128,147,10 + CONTROL "Animate",IDC_ANIMATEDLG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,218,116,98,10 + CONTROL "Disable custom smileys",IDC_DISABLECUSTOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,138,147,10 + GROUPBOX "Smiley Selector",IDC_STATIC,6,160,310,46 + CONTROL "Surround inserted smiley with spaces",IDC_APPENDSPACES, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,171,235,10 + CONTROL "Use first smiley for selection size",IDC_SCALEALLSMILEYS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,182,209,10 + CONTROL "IEView style window",IDC_IEVIEWSTYLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,193,198,10 + CONTROL "",IDC_SELCLR,"ColourPicker",WS_TABSTOP,260,170,50,11 + CONTROL "Animate",IDC_ANIMATESEL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,218,193,98,10 + GROUPBOX "Input Area",IDC_STATIC,6,208,145,42 + CONTROL "Enable Smileys",IDC_INPUTSMILEYS,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,15,219,130,12 + CONTROL "Don't replace at cursor",IDC_DCURSORSMILEY,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,15,231,130,12 + GROUPBOX "Built-In Message Dialog Support",IDC_STATIC,154,208,162,42 + CONTROL "Disable",IDC_PLUGENABLED,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,240,217,69,12 + COMBOBOX IDC_SMLBUT,159,230,55,35,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Smiley Button",IDC_STATIC,161,219,72,8 + EDITTEXT IDC_MAXCUSTSMSZ,165,128,30,15,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE + CONTROL "",IDC_MAXCUSTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,182,129,11,12 + LTEXT "Max ""Custom Smiley"" height",IDC_STATIC,198,132,118,8 + CONTROL "High Quality smiley scaling",IDC_HQSCALING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,148,148,10 + EDITTEXT IDC_MINSMSZ,165,144,30,15,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE + CONTROL "",IDC_MINSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,182,145,11,12 + LTEXT "Min smiley height",IDC_STATIC,198,148,118,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPT_SMILEYS, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 316 + TOPMARGIN, 3 + BOTTOMMARGIN, 250 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Boris Krasnovskiy" + VALUE "FileDescription", "SmileyAdd Miranda Plugin" + VALUE "FileVersion", __VERSION_STRING + VALUE "InternalName", "SmileyAdd" + VALUE "LegalCopyright", "Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved" + VALUE "OriginalFilename", "SmileyAdd.dll" + VALUE "ProductName", " SmileyAdd Miranda Plugin" + VALUE "ProductVersion", __VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_SMILINGICON ICON "smiley.ICO" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\src\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include \r\n" + "#include ""..\\src\\version.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/SmileyAdd/SmileyAdd_10.vcxproj b/plugins/SmileyAdd/SmileyAdd_10.vcxproj index 02e45a54e2..e2f39c008e 100644 --- a/plugins/SmileyAdd/SmileyAdd_10.vcxproj +++ b/plugins/SmileyAdd/SmileyAdd_10.vcxproj @@ -72,8 +72,8 @@ Disabled - ..\..\include;..\ExternalAPI;regexp;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;_WIN32_WINDOWS=0x0410;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\ExternalAPI;src\regexp;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Fast @@ -99,8 +99,8 @@ Disabled - ..\..\include;..\ExternalAPI;regexp;%(AdditionalIncludeDirectories) - WIN64;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\ExternalAPI;src\regexp;%(AdditionalIncludeDirectories) + WIN64;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Fast @@ -128,8 +128,8 @@ OnlyExplicitInline Size false - ..\..\include;..\ExternalAPI;regexp;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;_WIN32_WINDOWS=0x0410;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\ExternalAPI;src\regexp;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true false false @@ -160,8 +160,8 @@ Full OnlyExplicitInline Size - ..\..\include;..\ExternalAPI;regexp;%(AdditionalIncludeDirectories) - WIN64;NDEBUG;_WINDOWS;_USRDLL;_WIN32_WINDOWS=0x0410;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\ExternalAPI;src\regexp;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true false false @@ -188,47 +188,41 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + diff --git a/plugins/SmileyAdd/SmileyAdd_10.vcxproj.filters b/plugins/SmileyAdd/SmileyAdd_10.vcxproj.filters index a8e064601d..082e876df4 100644 --- a/plugins/SmileyAdd/SmileyAdd_10.vcxproj.filters +++ b/plugins/SmileyAdd/SmileyAdd_10.vcxproj.filters @@ -13,121 +13,104 @@ {f30ee13d-9b85-424d-bdb9-c991748ed97c} ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - {8efee3ee-a59a-4e9b-a0a4-b82a7481a40f} - - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Resource Files - - - Resource Files - - - Documents - - - Documents - - - Documents - - \ No newline at end of file diff --git a/plugins/SmileyAdd/SmileyBase.cpp b/plugins/SmileyAdd/SmileyBase.cpp deleted file mode 100644 index 28bd767153..0000000000 --- a/plugins/SmileyAdd/SmileyBase.cpp +++ /dev/null @@ -1,391 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "SmileyBase.h" - -#include - -static void HiMetricToPixel(const SIZEL * lpSizeInHiMetric, LPSIZEL lpSizeInPix) -{ - HDC hDCScreen = GetDC(NULL); - const int nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX); - const int nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY); - ReleaseDC(NULL, hDCScreen); - - lpSizeInPix->cx = (lpSizeInHiMetric->cx * nPixelsPerInchX + (2540/2)) / 2540; - lpSizeInPix->cy = (lpSizeInHiMetric->cy * nPixelsPerInchY + (2540/2)) / 2540; -} - -static int CompareISmileyBase(const ISmileyBase* p1, const ISmileyBase* p2) -{ - return (int)((char*)p2 - (char*)p1); -} - -static LIST regSmileys(10, CompareISmileyBase); - -// {105C56DF-6455-4705-A501-51F1CCFCF688} -const GUID IID_ISmileyAddSmiley = -{ 0x105c56df, 0x6455, 0x4705, { 0xa5, 0x1, 0x51, 0xf1, 0xcc, 0xfc, 0xf6, 0x88 } }; - -// {58B32D03-1BD2-4840-992E-9AE799FD4ADE} -const GUID IID_ITooltipData = -{ 0x58b32d03, 0x1bd2, 0x4840, { 0x99, 0x2e, 0x9a, 0xe7, 0x99, 0xfd, 0x4a, 0xde } }; - -ISmileyBase::ISmileyBase(void) -{ - m_spAdviseSink = NULL; - m_spClientSite = NULL; - m_spAdviseHolder = NULL; - m_lRefCount = 1; - m_advf = 0; - m_smltxt = NULL; - m_hwnd = NULL; - m_visible = false; - m_dirAniAllow = false; - - memset(&m_sizeExtent, 0, sizeof(m_sizeExtent)); - memset(&m_sizeExtentHiM, 0, sizeof(m_sizeExtentHiM)); - memset(&m_orect, 0, sizeof(m_orect)); - - regSmileys.insert(this); -} - -ISmileyBase::~ISmileyBase(void) -{ - free(m_smltxt); - - Close(OLECLOSE_NOSAVE); - - if (m_spClientSite) - { - m_spClientSite->Release(); - m_spClientSite = NULL; - } - if (m_spAdviseHolder) - { - m_spAdviseHolder->Release(); - m_spAdviseHolder = NULL; - } -} - -void ISmileyBase::OnClose(void) -{ - if (m_spAdviseHolder) m_spAdviseHolder->SendOnClose(); -} - -void ISmileyBase::SendOnViewChange(void) -{ - if (m_spAdviseSink) m_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1); - if (m_advf & ADVF_ONLYONCE) - { - m_spAdviseSink->Release(); - m_spAdviseSink = NULL; - m_advf = 0; - } -} - -bool ISmileyBase::QueryHitPointSpecial(int x, int y, HWND hwnd, TCHAR** smltxt) -{ - bool result = m_visible && m_hwnd == hwnd; - if (result) - { - result = x >= m_orect.left && x <= m_orect.right && - y >= m_orect.top && y <= m_orect.bottom; - } - if (result) *smltxt = m_smltxt; - return result; -} - -void ISmileyBase::SetHint(TCHAR* smltxt) -{ - m_smltxt = _tcsdup(smltxt); -} - - -void ISmileyBase::SetPosition(HWND hwnd, LPCRECT lpRect) -{ - m_hwnd = hwnd; - if (lpRect == NULL || (lpRect->top == -1 && lpRect->bottom == -1)) - { - m_visible = false; - } - else - { - m_visible = true; - m_dirAniAllow = true; - m_orect.left = lpRect->left; - m_orect.right = lpRect->left + m_sizeExtent.cx; - if (lpRect->top == -1) - { - m_orect.top = lpRect->bottom - m_sizeExtent.cy; - m_orect.bottom = lpRect->bottom; - } - else if (lpRect->bottom == -1) - { - m_orect.top = lpRect->top; - m_orect.bottom = lpRect->top + m_sizeExtent.cy;; - } - else - { - m_orect.top = lpRect->bottom - m_sizeExtent.cy; - m_orect.bottom = lpRect->bottom; - } - } -} - - -// -// IUnknown members -// -ULONG ISmileyBase::AddRef(void) -{ return InterlockedIncrement(&m_lRefCount); } - -ULONG ISmileyBase::Release(void) -{ - LONG count = InterlockedDecrement(&m_lRefCount); - if(count == 0) - delete this; - return count; -} - - -HRESULT ISmileyBase::QueryInterface(REFIID iid, void ** ppvObject) -{ - // check to see what interface has been requested - if (ppvObject == NULL) return E_POINTER; - if (iid == IID_ISmileyAddSmiley) - *ppvObject = this; - else if (iid == IID_ITooltipData) - *ppvObject = static_cast(this); - else if (iid == IID_IViewObject) - *ppvObject = static_cast(this); - else if (iid == IID_IOleObject) - *ppvObject = static_cast(this); - else if (iid == IID_IUnknown) - *ppvObject = this; - else if (iid == IID_IViewObject2) - *ppvObject = static_cast(this); - else - { - *ppvObject = NULL; - return E_NOINTERFACE; - } - AddRef(); - return S_OK; -} - -// -// IOleObject members -// -HRESULT ISmileyBase::SetClientSite(IOleClientSite *pClientSite) -{ - if (m_spClientSite != NULL) m_spClientSite->Release(); - m_spClientSite = pClientSite; - if (m_spClientSite != NULL) m_spClientSite->AddRef(); - return S_OK; -} - -HRESULT ISmileyBase::GetClientSite(IOleClientSite **ppClientSite) -{ - if (ppClientSite == NULL) return E_POINTER; - *ppClientSite = m_spClientSite; - if (m_spClientSite != NULL) m_spClientSite->AddRef(); - return S_OK; -} - -HRESULT ISmileyBase::SetHostNames(LPCOLESTR /* szContainerApp */, LPCOLESTR /* szContainerObj */) -{ return S_OK; } - -HRESULT ISmileyBase::Close(DWORD /* dwSaveOption */) -{ - regSmileys.remove(this); - - if (m_spAdviseSink) m_spAdviseSink->Release(); - m_spAdviseSink = NULL; - - return S_OK; -} - -HRESULT ISmileyBase::SetMoniker(DWORD /* dwWhichMoniker */, IMoniker* /* pmk */) -{ return E_NOTIMPL; } - -HRESULT ISmileyBase::GetMoniker(DWORD /* dwAssign */, DWORD /* dwWhichMoniker */, IMoniker** /* ppmk */) -{ return E_NOTIMPL; } - -HRESULT ISmileyBase::InitFromData(IDataObject* /* pDataObject */, BOOL /* fCreation */, DWORD /* dwReserved */) -{ return E_NOTIMPL; } - -HRESULT ISmileyBase::GetClipboardData(DWORD /* dwReserved */, IDataObject** /* ppDataObject */) -{ return E_NOTIMPL; } - -HRESULT ISmileyBase::DoVerb(LONG /* iVerb */, LPMSG /* pMsg */, IOleClientSite* /* pActiveSite */, LONG /* lindex */, - HWND /* hwndParent */, LPCRECT /* lprcPosRect */) -{ - return E_NOTIMPL; -} - -HRESULT ISmileyBase::EnumVerbs(IEnumOLEVERB** /*ppEnumOleVerb*/) { return E_NOTIMPL; } -HRESULT ISmileyBase::Update(void) { return S_OK; } -HRESULT ISmileyBase::IsUpToDate(void) { return S_OK; } - -HRESULT ISmileyBase::GetUserClassID(CLSID *pClsid) -{ - if (!pClsid) return E_POINTER; - *pClsid = CLSID_NULL; - return S_OK; -} - -HRESULT ISmileyBase::GetUserType(DWORD /*dwFormOfType*/, LPOLESTR* /*pszUserType*/) -{ return E_NOTIMPL; } - -HRESULT ISmileyBase::SetExtent(DWORD dwDrawAspect, SIZEL* psizel) -{ - if (dwDrawAspect != DVASPECT_CONTENT) return E_FAIL; - if (psizel == NULL) return E_POINTER; - - HiMetricToPixel(psizel, &m_sizeExtent); - m_sizeExtentHiM = *psizel; - return S_OK; -} - -HRESULT ISmileyBase::GetExtent(DWORD dwDrawAspect, SIZEL *psizel) -{ - if (dwDrawAspect != DVASPECT_CONTENT) return E_FAIL; - if (psizel == NULL) return E_POINTER; - - *psizel = m_sizeExtentHiM; - return S_OK; -} - -HRESULT ISmileyBase::Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection) -{ - HRESULT hr = S_OK; - if (m_spAdviseHolder == NULL) - hr = CreateOleAdviseHolder(&m_spAdviseHolder); - if (SUCCEEDED(hr)) - hr = m_spAdviseHolder->Advise(pAdvSink, pdwConnection); - else - m_spAdviseHolder = NULL; - return hr; -} - -HRESULT ISmileyBase::Unadvise(DWORD dwConnection) -{ - return m_spAdviseHolder ? m_spAdviseHolder->Unadvise(dwConnection) : E_FAIL; -} - -HRESULT ISmileyBase::EnumAdvise(IEnumSTATDATA **ppEnumAdvise) -{ - if (ppEnumAdvise == NULL) return E_POINTER; - return m_spAdviseHolder ? m_spAdviseHolder->EnumAdvise(ppEnumAdvise) : E_FAIL; -} - -HRESULT ISmileyBase::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus) -{ - if (pdwStatus == NULL) return E_POINTER; - if (dwAspect == DVASPECT_CONTENT) - { - *pdwStatus = OLEMISC_STATIC | OLEMISC_INVISIBLEATRUNTIME | - OLEMISC_CANTLINKINSIDE | OLEMISC_NOUIACTIVATE; - return S_OK; - } - else - { - *pdwStatus = 0; - return E_FAIL; - } -} - -HRESULT ISmileyBase::SetColorScheme(LOGPALETTE* /* pLogpal */) -{ return E_NOTIMPL; } - -// -// IViewObject members -// -HRESULT ISmileyBase::SetAdvise(DWORD aspect, DWORD advf, IAdviseSink* pAdvSink) -{ - if (aspect != DVASPECT_CONTENT) return DV_E_DVASPECT; - m_advf = advf; - if (m_spAdviseSink) m_spAdviseSink->Release(); - m_spAdviseSink = pAdvSink; - if (advf & ADVF_PRIMEFIRST) SendOnViewChange(); - return S_OK; -} -HRESULT ISmileyBase::GetAdvise(DWORD* /*pAspects*/, DWORD* /*pAdvf*/, IAdviseSink** ppAdvSink) -{ - if (!ppAdvSink) return E_POINTER; - *ppAdvSink = m_spAdviseSink; - if (m_spAdviseSink) m_spAdviseSink->AddRef(); - return S_OK; -} -HRESULT ISmileyBase::Freeze(DWORD, long, void*, DWORD*) { return E_NOTIMPL; } -HRESULT ISmileyBase::Unfreeze(DWORD) { return E_NOTIMPL; } -HRESULT ISmileyBase::GetColorSet(DWORD, long, void*, DVTARGETDEVICE*, HDC, - LOGPALETTE**) { return E_NOTIMPL; } - -// -// IViewObject2 members -// -HRESULT ISmileyBase::GetExtent(DWORD aspect, long, DVTARGETDEVICE*, SIZEL* pSize) -{ - if (pSize == NULL) return E_POINTER; - if (aspect != DVASPECT_CONTENT) return DV_E_DVASPECT; - *pSize = m_sizeExtent; - return S_OK; -} - - -// -// ITooltipData members -// -HRESULT ISmileyBase::SetTooltip(BSTR /* bstrHint */) -{ - return S_OK; -} - -HRESULT ISmileyBase::GetTooltip(BSTR *bstrHint) -{ - if (bstrHint == NULL) return E_POINTER; - *bstrHint = SysAllocString(T2W_SM(m_smltxt)); - return S_OK; -} - - -void CloseSmileys(void) -{ - for (int i=regSmileys.getCount(); i--;) - { - regSmileys[i]->OnClose(); - regSmileys[i]->Close(OLECLOSE_NOSAVE); - } -} - -int CheckForTip(int x, int y, HWND hwnd, TCHAR** smltxt) -{ - for (int i=0; iQueryHitPointSpecial(x, y, hwnd, smltxt)) return i; - - return -1; -} - -void DestroySmileyBase(void) -{ - regSmileys.destroy(); -} - diff --git a/plugins/SmileyAdd/SmileyBase.h b/plugins/SmileyAdd/SmileyBase.h deleted file mode 100644 index 3cdf244007..0000000000 --- a/plugins/SmileyAdd/SmileyBase.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#pragma once -#include -#include - -#define OLEIVERB_SETOWNER (-24) - -EXTERN_C const IID IID_ITooltipData; - -class ITooltipData : public IUnknown -{ -public: - STDMETHOD(SetTooltip) (BSTR bstrHint) PURE; - STDMETHOD(GetTooltip) (BSTR * bstrHint) PURE; -}; - - -EXTERN_C const IID IID_ISmileyAddSmiley; - -class ISmileyBase : - public IOleObject, public IViewObject2, public ITooltipData -{ -protected: - IOleAdviseHolder* m_spAdviseHolder; - IAdviseSink* m_spAdviseSink; - IOleClientSite* m_spClientSite; - DWORD m_advf; - LONG m_lRefCount; - - SIZEL m_sizeExtent; - SIZEL m_sizeExtentHiM; - RECT m_orect; - - TCHAR* m_smltxt; - HWND m_hwnd; - - bool m_visible; - bool m_dirAniAllow; - -public: - ISmileyBase(void); - virtual ~ISmileyBase(void); - - void OnClose(void); - void SendOnViewChange(void); - - bool QueryHitPointSpecial(int x, int y, HWND hwnd, TCHAR** smltxt); - void SetHint(TCHAR* smltxt); - - virtual void SetPosition(HWND hwnd, LPCRECT lpRect); - - // - // IUnknown members - // - STDMETHOD_(ULONG, AddRef)(void); - STDMETHOD_(ULONG, Release)(void); - STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); - - // - // IOleObject members - // - STDMETHOD(SetClientSite)(IOleClientSite *pClientSite); - STDMETHOD(GetClientSite)(IOleClientSite **ppClientSite); - STDMETHOD(SetHostNames)(LPCOLESTR /* szContainerApp */, LPCOLESTR /* szContainerObj */); - STDMETHOD(Close)(DWORD /* dwSaveOption */); - STDMETHOD(SetMoniker)(DWORD /* dwWhichMoniker */, IMoniker* /* pmk */); - STDMETHOD(GetMoniker)(DWORD /* dwAssign */, DWORD /* dwWhichMoniker */, IMoniker** /* ppmk */); - STDMETHOD(InitFromData)(IDataObject* /* pDataObject */, BOOL /* fCreation */, DWORD /* dwReserved */); - STDMETHOD(GetClipboardData)(DWORD /* dwReserved */, IDataObject** /* ppDataObject */); - STDMETHOD(DoVerb)(LONG /*iVerb*/, LPMSG /* pMsg */, IOleClientSite* /* pActiveSite */, LONG /* lindex */, - HWND /*hwndParent*/, LPCRECT /*lprcPosRect*/); - STDMETHOD(EnumVerbs)(IEnumOLEVERB** /*ppEnumOleVerb*/); - STDMETHOD(Update)(void); - STDMETHOD(IsUpToDate)(void); - STDMETHOD(GetUserClassID)(CLSID *pClsid); - STDMETHOD(GetUserType)(DWORD /*dwFormOfType*/, LPOLESTR* /*pszUserType*/); - STDMETHOD(SetExtent)(DWORD /*dwDrawAspect*/, SIZEL* /*psizel*/); - STDMETHOD(GetExtent)(DWORD dwDrawAspect, SIZEL *psizel); - STDMETHOD(Advise)(IAdviseSink *pAdvSink, DWORD *pdwConnection); - STDMETHOD(Unadvise)(DWORD dwConnection); - STDMETHOD(EnumAdvise)(IEnumSTATDATA **ppEnumAdvise); - STDMETHOD(GetMiscStatus)(DWORD dwAspect, DWORD *pdwStatus); - STDMETHOD(SetColorScheme)(LOGPALETTE* /* pLogpal */); - - // - // IViewObject members - // - STDMETHOD(SetAdvise)(DWORD aspect, DWORD advf, IAdviseSink* pAdvSink); - STDMETHOD(GetAdvise)(DWORD* /*pAspects*/, DWORD* /*pAdvf*/, IAdviseSink** ppAdvSink); - STDMETHOD(Freeze)(DWORD, long, void*, DWORD*); - STDMETHOD(Unfreeze)(DWORD); - STDMETHOD(GetColorSet)(DWORD, long, void*, DVTARGETDEVICE*, HDC, - LOGPALETTE**); - - // - // IViewObject2 members - // - STDMETHOD(GetExtent)(DWORD aspect, long, DVTARGETDEVICE*, SIZEL* pSize); - - // - // ITooltipData members - // - STDMETHOD(SetTooltip)(BSTR bstrHint); - STDMETHOD(GetTooltip)(BSTR * bstrHint); - -}; - -int CheckForTip(int x, int y, HWND hwnd, TCHAR** smltxt); -void CloseSmileys(void); - diff --git a/plugins/SmileyAdd/anim.cpp b/plugins/SmileyAdd/anim.cpp deleted file mode 100644 index 5352383821..0000000000 --- a/plugins/SmileyAdd/anim.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2006 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "anim.h" - -#include - -Animate::Animate(SmileyType *sml, RECT& rect, HDC hdcMem, HBRUSH hbr, bool clip) - : m_sml(sml), m_img(NULL), - m_nFramePosition(0), m_sel(false), m_clip(clip), - m_offset(0), m_running(false), - m_hdcMem(hdcMem), m_hbr(hbr) -{ - m_cliprect = rect; -} - - -Animate::~Animate() -{ - if (m_img) m_img->Release(); -} - - -void Animate::StartAnimation(void) -{ - m_img = m_sml->CreateCachedImage(); - - if (m_img && m_img->IsAnimated()) - { - m_img->SelectFrame(m_nFramePosition); - long frtm = m_img->GetFrameDelay(); - m_counter = frtm / 10 + ((frtm % 10) >= 5); - } -} - - -void Animate::ProcessTimerTick(HWND hwnd) -{ - if (m_running && m_img->IsAnimated() && --m_counter <= 0) - { - m_nFramePosition = m_img->SelectNextFrame(m_nFramePosition); - - long frtm = m_img->GetFrameDelay(); - m_counter = frtm / 10 + ((frtm % 10) >= 5); - - HDC hdc = GetDC(hwnd); - DrawFrame(hdc); - ReleaseDC(hwnd, hdc); - } -} - - -void Animate::DrawFrame(HDC hdc) -{ - long width = m_cliprect.right - m_cliprect.left; - long height = m_cliprect.bottom - m_cliprect.top; - - RECT frc = { 0, 0, width, height }; - FillRect(m_hdcMem, &frc, m_hbr); - - m_img->Draw(m_hdcMem, frc, m_clip); - - BitBlt(hdc, m_cliprect.left, m_cliprect.top, width, height, m_hdcMem, 0, 0, SRCCOPY); - - if (m_sel) - DrawFocusRect(hdc, &m_cliprect); -} - - -void Animate::Draw(HDC hdc) -{ - if (m_running) - { - m_img->Draw(hdc, m_cliprect, m_clip); - - if (m_sel) - DrawFocusRect(hdc, &m_cliprect); - } -} - - -void Animate::SetOffset(int off, int wsize) -{ - const int dy = m_offset - off; - - m_cliprect.top += dy; - m_cliprect.bottom += dy; - - m_offset = off; - - m_running = m_cliprect.top >= 0 && m_cliprect.top < wsize; - if (m_running) - { - if (m_img == NULL) - { - StartAnimation(); - if (m_img == NULL) m_running = false; - } - } - else - { - if (m_img) m_img->Release(); - m_img = NULL; - } -} - - -void Animate::SetSel(int x, int y) -{ - m_sel = x >= m_cliprect.left && x < m_cliprect.right && - y >= m_cliprect.top && y < m_cliprect.bottom; -} - - -AnimatedPack::AnimatedPack(HWND hwnd, int wsize, SIZE& sel, COLORREF bkg) - : m_AniList(40), m_hwnd(hwnd), m_wsize(wsize) -{ - HDC hdc = GetDC(hwnd); - - m_hBmp = CreateCompatibleBitmap(hdc, sel.cx, sel.cy); - m_hdcMem = CreateCompatibleDC(hdc); - m_hOld = (HBITMAP)SelectObject(m_hdcMem, m_hBmp); - m_hbr = CreateSolidBrush(bkg); - - ReleaseDC(hwnd, hdc); -} - - -AnimatedPack::~AnimatedPack() -{ - DeleteObject(m_hbr); - SelectObject(m_hdcMem, m_hOld); - DeleteObject(m_hBmp); - DeleteDC(m_hdcMem); -} - - -void AnimatedPack::Add(SmileyType *sml, RECT rect, bool clip) -{ - m_AniList.insert(new Animate(sml, rect, m_hdcMem, m_hbr, clip)); -} - - -void AnimatedPack::Draw(HDC hdc) -{ - for (int i=0; i. -*/ - -#ifndef anim_h -#define anim_h - -#include "smileys.h" - -class Animate -{ -private: - - ImageBase *m_img; - SmileyType *m_sml; - - HDC m_hdcMem; - HBRUSH m_hbr; - - RECT m_cliprect; - - unsigned m_nFramePosition; - int m_offset; - int m_counter; - bool m_running; - bool m_sel; - bool m_clip; - - void DrawFrame(HDC hdc); - -public: - - Animate(SmileyType *sml, RECT &rect, HDC hdcMem, HBRUSH hbr, bool clip); - Animate(const Animate& an); - ~Animate(); - - void Draw(HDC hdc); - - void StartAnimation(void); - void SetOffset(int off, int wsize); - void SetSel(int x, int y); - - void ProcessTimerTick(HWND hwnd); -}; - -class AnimatedPack -{ -private: - OBJLIST m_AniList; - - HWND m_hwnd; - int m_wsize; - - HBRUSH m_hbr; - HBITMAP m_hBmp; - HDC m_hdcMem; - HBITMAP m_hOld; - - static unsigned CALLBACK AnimateThreadFunc ( void* arg ); - -public: - AnimatedPack(HWND hwnd, int wsize, SIZE& sel, COLORREF bkg); - ~AnimatedPack(); - - void Add(SmileyType *sml, RECT rect, bool clip); - void Draw(HDC hdc); - void SetOffset(int off); - void SetSel(RECT& rect); - - void ProcessTimerTick(HWND hwnd); -}; - -#endif diff --git a/plugins/SmileyAdd/bkstring.cpp b/plugins/SmileyAdd/bkstring.cpp deleted file mode 100644 index 2973783abc..0000000000 --- a/plugins/SmileyAdd/bkstring.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef __GNUC__ -# ifdef _DEBUG -# define _CRTDBG_MAP_ALLOC -# include -# include -# else -# include -# endif -#endif - -#include -#include - -#include "bkstring.h" - - -bkstring::~bkstring() { if (sizeAlloced) free(buf); } - -void bkstring::reserve(size_type len) -{ - if (len >= sizeAlloced || sizeAlloced == 0) - { - if (sizeAlloced == 0) buf = NULL; - buf = (value_type*)realloc(buf, (len+1) * sizeof(value_type)); - if (sizeAlloced == 0) buf[0] = 0; - sizeAlloced = len+1; - } -} - -void bkstring::appendfmt(const value_type *fmt, ...) -{ - areserve(_tcslen(fmt)*2); - - va_list vararg; - va_start(vararg, fmt); - for (;;) - { - int len = _vsntprintf(buf + lenBuf, sizeAlloced - lenBuf - 1, fmt, vararg); - if (len < 0) - reserve(sizeAlloced + 256); - else - { - lenBuf += len; - buf[lenBuf] = 0; - break; - } - } - va_end(vararg); -} - -bkstring& bkstring::append(const value_type* _Ptr) -{ - size_type len = _tcslen(_Ptr); - areserve(len); - memcpy(buf+lenBuf, _Ptr, (len+1)*sizeof(value_type)); - lenBuf += len; - return *this; -} - -bkstring& bkstring::append(const value_type* _Ptr, size_type _Count) -{ - size_type len = min(_tcslen(_Ptr), _Count); - areserve(len); - memcpy(buf+lenBuf, _Ptr, len*sizeof(value_type)); - lenBuf += len; - buf[lenBuf] = 0; - return *this; -} - -bkstring& bkstring::append(const bkstring& _Str, size_type _Off, size_type _Count) -{ - size_type len = min(_Count, _Str.size() - _Off); - areserve(len); - memcpy(buf+lenBuf, _Str.c_str()+_Off, len*sizeof(value_type)); - lenBuf += len; - buf[lenBuf] = 0; - return *this; -} - -bkstring& bkstring::append(const bkstring& _Str) -{ - size_type len = _Str.size(); - areserve(len); - memcpy(buf+lenBuf, _Str.c_str(), len*sizeof(value_type)); - lenBuf += len; - buf[lenBuf] = 0; - return *this; -} - -bkstring& bkstring::append(size_type _Count, value_type _Ch) -{ - areserve(_Count); - for(size_type i=0; i<_Count; ++i) buf[lenBuf+i] = _Ch; - lenBuf += _Count; - buf[lenBuf] = 0; - return *this; -} - - -bkstring& bkstring::assign(const value_type* _Ptr, size_type _Count) -{ - if (_Count == 0 && sizeAlloced == 0) - { - buf = (TCHAR*)_T(""); - } - else - { - reserve(_Count); - memcpy(buf, _Ptr, _Count*sizeof(value_type)); - buf[_Count] = 0; - lenBuf = _Count; - } - return *this; -} - -bkstring& bkstring::assign(const bkstring& _Str, size_type _Off, size_type _Count) -{ - size_type len = min(_Count, _Str.size() - _Off); - if (len == 0 && sizeAlloced == 0) - { - buf = (TCHAR*)_T(""); - } - else - { - reserve(len); - memcpy(buf, _Str.c_str() + _Off, len*sizeof(value_type)); - lenBuf = len; - buf[len] = 0; - } - return *this; -} - -bkstring& bkstring::assign(size_type _Count, value_type _Ch) -{ - reserve(_Count); - for(size_type i=0; i<_Count; ++i) buf[i] = _Ch; - buf[_Count] = 0; - lenBuf = _Count; - return *this; -} - -bkstring::size_type bkstring::find(value_type _Ch, size_type _Off) const -{ - for (size_type i=_Off; i<=lenBuf; ++i) - if (buf[i] == _Ch) return i; - return (size_type)npos; -} - -bkstring::size_type bkstring::find(const value_type* _Ptr, size_type _Off) const -{ - if (_Off > lenBuf) return (size_type)npos; - - value_type* pstr = _tcsstr(buf+_Off, _Ptr); - return pstr ? pstr - buf : npos; -} - -bkstring::size_type bkstring::find_last_of(value_type _Ch, size_type _Off) const -{ - for (size_type i=(_Off == npos ? lenBuf : _Off); i--;) - if (buf[i] == _Ch) return i; - return (size_type)npos; -} - -bkstring& bkstring::insert(size_type _P0, const value_type* _Ptr, size_type _Count) -{ - size_type len = _tcslen(_Ptr); - if (_Count < len) len = _Count; - areserve(len); - value_type *p = buf + _P0; - memmove(p+len, p, (lenBuf-_P0+1)*sizeof(value_type)); - memcpy(p, _Ptr, _Count*sizeof(value_type)); - lenBuf += len; - return *this; -} - -bkstring& bkstring::insert(size_type _P0, size_type _Count, value_type _Ch) -{ - areserve(_Count); - value_type *p = buf + _P0; - memmove(p+_Count, p, (lenBuf-_P0+1)*sizeof(value_type)); - for(size_type i=0; i<_Count; ++i) p[i] = _Ch; - lenBuf += _Count; - return *this; -} - -bkstring& bkstring::erase(size_type _Pos, size_type _Count) -{ - if (_Pos < lenBuf) - { - const size_type len = min(lenBuf - _Pos, _Count); - value_type *p = buf + _Pos; - lenBuf -= len; - memmove(p, p+len, (lenBuf - _Pos)*sizeof(value_type)); - buf[lenBuf] = 0; - } - return *this; -} diff --git a/plugins/SmileyAdd/bkstring.h b/plugins/SmileyAdd/bkstring.h deleted file mode 100644 index eb164f74e2..0000000000 --- a/plugins/SmileyAdd/bkstring.h +++ /dev/null @@ -1,270 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#pragma once - -#include -#include - -#ifndef min -#define min(A, B) ((A) < (B) ? (A) : (B)) -#endif - -class bkstring -{ -public: - typedef size_t size_type; - typedef TCHAR value_type; - typedef value_type* iterator; - typedef const value_type* const_iterator; - -#if defined(_MSC_VER) && (_MSC_VER <= 1200) - enum { npos = -1 }; -#else - static const size_type npos = size_type(-1); -#endif - -private: - value_type* buf; - size_type sizeAlloced; - size_type lenBuf; - - void areserve(size_type len) { reserve(lenBuf + len); } - -public: - - explicit bkstring() : buf((TCHAR*)_T("")), sizeAlloced(0), lenBuf(0) - {} - - bkstring(const value_type* _Ptr, size_type _Count) : sizeAlloced(0), lenBuf(0) - { assign(_Ptr, _Count); } - - bkstring(const value_type* _Ptr) : sizeAlloced(0), lenBuf(0) - { assign(_Ptr); } - - bkstring(size_type _Count, value_type _Ch) : sizeAlloced(0), lenBuf(0) - { assign(_Count, _Ch); } - - bkstring(const bkstring& _Str) : sizeAlloced(0), lenBuf(0) - { assign(_Str); } - - bkstring(const bkstring& _Str, size_type _Off, size_type _Count) : sizeAlloced(0), lenBuf(0) - { assign(_Str, _Off, _Count); } - - ~bkstring(); - - size_type size(void) const { return lenBuf; } - const value_type* c_str(void) const { return buf; } - - void clear(void) { if (lenBuf) { lenBuf = 0; buf[0] = 0; } } - void insert(const value_type *txt); - void reserve(size_type len); - - bkstring& assign(const value_type* _Ptr) - { return assign(_Ptr, _tcslen(_Ptr)); } - - bkstring& assign(const bkstring& _Str) - { return assign(_Str, 0, (size_type)npos); } - - bkstring& assign(const value_type* _Ptr, size_type _Count); - bkstring& assign(const bkstring& _Str, size_type off, size_type _Count); - bkstring& assign(size_type _Count, value_type _Ch); - - bkstring& append(const value_type* _Ptr); - bkstring& append(const value_type* _Ptr, size_type _Count); - bkstring& append(const bkstring& _Str, size_type _Off, size_type _Count); - bkstring& append(const bkstring& _Str); - bkstring& append(size_type _Count, value_type _Ch); - - int compare(const bkstring& _Str) const - { return _tcscmp(buf, _Str.c_str()); } - - int compare(size_type _Pos1, size_type _Num1, const bkstring& _Str) const - { return _tcsncmp(&buf[_Pos1], _Str.c_str(), _Num1); } - - int compare(size_type _Pos1, size_type _Num1, const bkstring& _Str, size_type _Off, size_type _Count) const - { return _tcsncmp(&buf[_Pos1], _Str.c_str()+_Off, min(_Num1, _Count)); } - - int compare(const value_type* _Ptr) const - { return _tcscmp(buf, _Ptr); } - - int compare(size_type _Pos1, size_type _Num1, const value_type* _Ptr) const - { return _tcsncmp(&buf[_Pos1], _Ptr, _Num1); } - - int compare(size_type _Pos1, size_type _Num1, const value_type* _Ptr, size_type _Num2) const - { return _tcsncmp(&buf[_Pos1], _Ptr, min(_Num1, _Num2)); } - - int comparei(const bkstring& _Str) const - { return _tcsicmp(buf, _Str.c_str()); } - - int comparei(size_type _Pos1, size_type _Num1, const bkstring& _Str) const - { return _tcsnicmp(&buf[_Pos1], _Str.c_str(), _Num1); } - - int comparei(size_type _Pos1, size_type _Num1, const bkstring& _Str, size_type _Off, size_type _Count) const - { return _tcsnicmp(&buf[_Pos1], _Str.c_str()+_Off, min(_Num1, _Count)); } - - int comparei(const value_type* _Ptr) const - { return _tcsicmp(buf, _Ptr); } - - int comparei(size_type _Pos1, size_type _Num1, const value_type* _Ptr) const - { return _tcsnicmp(&buf[_Pos1], _Ptr, _Num1); } - - int comparei(size_type _Pos1, size_type _Num1, const value_type* _Ptr, size_type _Num2) const - { return _tcsnicmp(&buf[_Pos1], _Ptr, min(_Num1, _Num2)); } - - bool empty(void) const { return lenBuf == 0; }; - bkstring& erase(size_type _Pos = 0, size_type _Count = npos); - - size_type find(value_type _Ch, size_type _Off = 0) const; - size_type find(const value_type* _Ptr, size_type _Off = 0) const; - size_type find(bkstring& _Str, size_type _Off = 0) const - { return find(_Str.c_str(), _Off); } - - size_type find_last_of(value_type _Ch, size_type _Off = npos) const; - - bkstring& insert(size_type _P0, const value_type* _Ptr) - { return insert(_P0, _Ptr, _tcslen(_Ptr)); } - - bkstring& insert(size_type _P0, const bkstring& _Str) - { return insert(_P0, _Str.c_str(), _Str.size()); }; - - bkstring& insert(size_type _P0, const value_type* _Ptr, size_type _Count); - bkstring& insert(size_type _P0, size_type _Count, value_type _Ch); - - bkstring substr(size_type _Off = 0, size_type _Count = npos) const - { return bkstring(*this, _Off, _Count); } - - bkstring& operator = (const bkstring& _Str) - { return assign(_Str); } - - bkstring& operator =(const value_type* _Ptr) - { return assign(_Ptr); } - - bkstring& operator = (const value_type _Ch) - { return assign(1, _Ch); } - - bkstring& operator +=(const bkstring& _Str) - { return append(_Str); } - - bkstring& operator += (const value_type* _Ptr) - { return append(_Ptr); } - - bkstring& operator += (const value_type _Ch) - { return append(1, _Ch); } - - value_type& operator[] (int ind) const - { return buf[ind]; } - - friend bkstring operator+ (const bkstring& _Str1, const bkstring& _Str2) - { bkstring s(_Str1); return s.append(_Str2); } - - friend bkstring operator+ (const bkstring& _Str1, const value_type* _Ptr2) - { bkstring s(_Str1); return s.append(_Ptr2); } - - friend bkstring operator+(const value_type* _Ptr1, const bkstring& _Str2) - { bkstring s(_Ptr1); return s.append(_Str2); } - - friend bkstring operator+ (const bkstring& _Str1, const value_type _Ch) - { bkstring s(_Str1); return s.append(1, _Ch); } - - friend bool operator==(const bkstring& _Str1, const bkstring& _Str2) - { return _Str1.compare(_Str2) == 0; } - - friend bool operator==(const bkstring& _Str1, const value_type* _Ptr2) - { return _Str1.compare(_Ptr2) == 0; } - - friend bool operator==(const value_type* _Ptr1, const bkstring& _Str2) - { return _Str2.compare(_Ptr1) == 0; } - - friend bool operator!=(const bkstring& _Str1, const bkstring& _Str2) - { return _Str1.compare(_Str2) != 0; } - - friend bool operator!=(const bkstring& _Str1, const value_type* _Ptr2) - { return _Str1.compare(_Ptr2) != 0; } - - friend bool operator!=(const value_type* _Ptr1, const bkstring& _Str2) - { return _Str2.compare(_Ptr1) != 0; } - - friend bool operator<(const bkstring& _Str1, const bkstring& _Str2) - { return _Str1.compare(_Str2) < 0; } - - friend bool operator<(const bkstring& _Str1, const value_type* _Ptr2) - { return _Str1.compare(_Ptr2) < 0; } - - friend bool operator<(const value_type* _Ptr1, const bkstring& _Str2) - { return _Str2.compare(_Ptr1) > 0; } - - friend bool operator>(const bkstring& _Str1, const bkstring& _Str2) - { return _Str1.compare(_Str2) > 0; } - - friend bool operator>(const bkstring& _Str1, const value_type* _Ptr2) - { return _Str1.compare(_Ptr2) > 0; } - - friend bool operator>(const value_type* _Ptr1, const bkstring& _Str2) - { return _Str2.compare(_Ptr1) < 0; } - - friend bool operator<=(const bkstring& _Str1, const bkstring& _Str2) - { return _Str1.compare(_Str2) <= 0; } - - friend bool operator<=(const bkstring& _Str1, const value_type* _Ptr2) - { return _Str1.compare(_Ptr2) <= 0; } - - friend bool operator<=(const value_type* _Ptr1, const bkstring& _Str2) - { return _Str2.compare(_Ptr1) >= 0; } - - friend bool operator>=(const bkstring& _Str1, const bkstring& _Str2) - { return _Str1.compare(_Str2) >= 0; } - - friend bool operator>=(const bkstring& _Str1, const value_type* _Ptr2) - { return _Str1.compare(_Ptr2) >= 0; } - - friend bool operator>=(const value_type* _Ptr1, const bkstring& _Str2) - { return _Str2.compare(_Ptr1) <= 0; } - - friend bool operator==(const value_type _Ch1, const bkstring& _Str2) - { return (_Str2.size() == 1) && (_Str2[0] == _Ch1); } - - friend bool operator==(const bkstring& _Str1, const value_type _Ch2) - { return (_Str1.size() == 1) && (_Str1[0] == _Ch2); } - - friend bool operator!=(const value_type _Ch1, const bkstring& _Str2) - { return (_Str2.size() != 1) || (_Str2[0] != _Ch1); } - - friend bool operator!=(const bkstring& _Str1, const value_type _Ch2) - { return (_Str1.size() != 1) || (_Str1[0] != _Ch2); } - - iterator begin(void) - { return buf; } - - const_iterator begin(void) const - { return buf; } - - iterator end(void) - { return buf + lenBuf; } - - const_iterator end(void) const - { return buf + lenBuf; } - - // Custom extentions - - void appendfmt(const value_type *fmt, ...); - - size_type sizebytes(void) const { return lenBuf * sizeof(value_type); } -}; - -//const bkstring::size_type bkstring::npos = -1; diff --git a/plugins/SmileyAdd/customsmiley.cpp b/plugins/SmileyAdd/customsmiley.cpp deleted file mode 100644 index f125f015db..0000000000 --- a/plugins/SmileyAdd/customsmiley.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "customsmiley.h" - -SmileyPackCListType g_SmileyPackCStore; - - -bool SmileyPackCListType::AddSmileyPack(HANDLE hContact, TCHAR* dir) -{ - bool res = true; - if (GetSmileyPack(hContact) == NULL) - { - SmileyPackCType *smileyPack = new SmileyPackCType; - - res = smileyPack->LoadSmileyDir(dir); - if (res) - { - smileyPack->SetId(hContact); - m_SmileyPacks.insert(smileyPack); - } - else - delete smileyPack; - } - return res; -} - - -bool SmileyPackCListType::AddSmiley(HANDLE hContact, TCHAR* path) -{ - SmileyPackCType* smpack = GetSmileyPack(hContact); - if (smpack == NULL) - { - smpack = new SmileyPackCType; - - smpack->SetId(hContact); - m_SmileyPacks.insert(smpack); - } - return smpack->LoadSmiley(path); -} - - -SmileyPackCType* SmileyPackCListType::GetSmileyPack(HANDLE id) -{ - for (int i = 0; i < m_SmileyPacks.getCount(); i++) - { - if (m_SmileyPacks[i].GetId() == id) return &m_SmileyPacks[i]; - } - return NULL; -} - - -SmileyCType::SmileyCType(const bkstring& fullpath, const TCHAR* filepath) -{ - LoadFromResource(fullpath, 0); - CreateTriggerText(T2A_SM(filepath)); -} - -bool SmileyCType::CreateTriggerText(char* text) -{ - UrlDecode(text); - - int len = (int)strlen(text); - if (len == 0) return false; - - int reslen = Netlib_GetBase64DecodedBufferSize(len)+1; - char* res = (char*)alloca(reslen); - - NETLIBBASE64 nlb = { text, len, ( PBYTE )res, reslen }; - if (!CallService(MS_NETLIB_BASE64DECODE, 0, LPARAM( &nlb ))) return false; - res[nlb.cbDecoded] = 0; - - TCHAR *txt = mir_utf8decodeT(res); - - if (txt == NULL) return false; - - m_TriggerText = txt; - mir_free(txt); - - return true; -} - - -// -// SmileyPackCType -// - -bool SmileyPackCType::LoadSmileyDir(TCHAR* dir) -{ - bkstring dirs = dir; - dirs += _T("\\*.*"); - - _tfinddata_t c_file; - INT_PTR hFile = _tfindfirst((TCHAR*)dirs.c_str(), &c_file); - if (hFile > -1L) - { - do { - if (c_file.name[0] != '.') - { - bkstring fullpath = dir; - fullpath = fullpath + _T("\\") + c_file.name; - TCHAR* div = _tcsrchr(c_file.name, '.'); - if (div) - { - *div = 0; - SmileyCType *smlc = new SmileyCType(fullpath, c_file.name); - if (smlc->GetTriggerText().empty()) - delete smlc; - else - m_SmileyList.insert(smlc); - } - } - } while( _tfindnext( hFile, &c_file ) == 0 ); - _findclose( hFile ); - AddTriggersToSmileyLookup(); - return true; - } - return false; -} - - -bool SmileyPackCType::LoadSmiley(TCHAR* path) -{ - bkstring dirs = path; - bkstring::size_type slash = dirs.find_last_of('\\'); - bkstring::size_type dot = dirs.find_last_of('.'); - - bkstring name = dirs.substr(slash+1, dot - slash - 1); - - for (int i=0; i < m_SmileyList.getCount(); i++) - { - if (m_SmileyList[i].GetTriggerText() == name) - { - m_SmileyList[i].LoadFromResource(dirs, 0); - return true; - } - } - - m_SmileyList.insert(new SmileyCType(dirs, (TCHAR*)name.c_str())); - - bkstring empty; - m_SmileyLookup.insert(new SmileyLookup( - m_SmileyList[m_SmileyList.getCount()-1].GetTriggerText(), false, m_SmileyList.getCount()-1, empty)); - - return true; -} - - -void SmileyPackCType::AddTriggersToSmileyLookup(void) -{ - bkstring empty; - for (int dist=0; dist. -*/ - -#include "general.h" -#include "smileys.h" - -#ifndef SMILEYADD_CUSTOMSMILEY_H_ -#define SMILEYADD_CUSTOMSMILEY_H_ - -class SmileyCType : public SmileyType -{ -public: - SmileyCType(const bkstring& fullpath, const TCHAR* filepath); - - bool CreateTriggerText(char* text); -}; - -class SmileyPackCType -{ -public: - typedef SMOBJLIST SmileyVectorType; - typedef SMOBJLIST SmileyLookupType; - -private: - SmileyVectorType m_SmileyList; - SmileyLookupType m_SmileyLookup; - - HANDLE m_id; - - void InsertLookup(SmileyCType& sml, bkstring& lk, bool first); - void AddTriggersToSmileyLookup(void); - -public: - SmileyVectorType& GetSmileyList(void) { return m_SmileyList; } - SmileyLookupType& GetSmileyLookup(void) { return m_SmileyLookup; } - - int SmileyCount(void) const { return m_SmileyList.getCount(); } - - SmileyCType* GetSmiley(unsigned index) { return &m_SmileyList[index]; } - - HANDLE GetId(void) { return m_id; } - void SetId(HANDLE id) { m_id = id; } - - bool LoadSmileyDir(TCHAR* dir); - bool LoadSmiley(TCHAR* path); -}; - - -class SmileyPackCListType -{ -public: - typedef SMOBJLIST SmileyPackVectorType; - -private: - SmileyPackVectorType m_SmileyPacks; - -public: - int NumberOfSmileyPacks(void) { return m_SmileyPacks.getCount(); } - - bool AddSmileyPack(HANDLE hContact, TCHAR* dir); - bool AddSmiley(HANDLE hContact, TCHAR* path); - - void ClearAndFreeAll(void) { m_SmileyPacks.destroy(); } - - SmileyPackCType* GetSmileyPack(HANDLE id); -}; - -extern SmileyPackCListType g_SmileyPackCStore; - -#endif diff --git a/plugins/SmileyAdd/dlgboxsubclass.cpp b/plugins/SmileyAdd/dlgboxsubclass.cpp deleted file mode 100644 index 03a0a6e5fd..0000000000 --- a/plugins/SmileyAdd/dlgboxsubclass.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2012 Boris Krasnovskiy All Rights Reserved -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "smileyroutines.h" -#include "services.h" -#include "options.h" - -//***************************************************// -// DISCLAIMER!!! -// we are not supposed to use this object, so be aware -typedef struct NewMessageWindowLParam -{ - HANDLE hContact; - int isSend; - const char *szInitialText; -} -msgData; -// this is an undocumented object!!!!!!! -// subject to change in miranda versions...!!!!!! -// DISCLAIMER!!! -//***************************************************// - -extern HINSTANCE g_hInst; - -static HHOOK g_hMessageHookPre = NULL; -static HANDLE g_hMutex = NULL; -static HANDLE g_hHookMsgWnd = NULL; - -static LRESULT CALLBACK MessageDlgSubclas(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - - -//type definitions -class MsgWndData -{ -public: - HWND hwnd; - char ProtocolName[52]; - HWND REdit; - HWND QuoteB; - HWND MEdit; - HWND MOK; - HWND LButton; - mutable HWND hSmlButton; - mutable HBITMAP hSmlBmp; - mutable HICON hSmlIco; - int idxLastChar; - WNDPROC wpOrigWndProc; - HANDLE hContact; - bool doSmileyReplace; - bool doSmileyButton; - bool OldButtonPlace; - bool isSplit; - bool isSend; - - MsgWndData() - { - ProtocolName[0] = 0; - REdit = NULL; - QuoteB = NULL; - MEdit = NULL; - MOK = NULL; - LButton = NULL; - hSmlButton = NULL; - hSmlBmp = NULL; - hSmlIco = NULL; - idxLastChar = 0; - hContact = NULL; - doSmileyReplace = false; - doSmileyButton = false; - OldButtonPlace = false; - isSplit = false; - isSend = false; - wpOrigWndProc = NULL; - } - - MsgWndData(const MsgWndData &dsb) - { - *this = dsb; - dsb.hSmlBmp = NULL; - dsb.hSmlIco = NULL; - dsb.hSmlButton = NULL; - } - - - ~MsgWndData() - { - clear(); - } - - void clear(void) - { - if (hSmlBmp != NULL) DeleteObject(hSmlBmp); - if (hSmlIco != NULL) DestroyIcon(hSmlIco); - if (hSmlButton != NULL) DestroyWindow(hSmlButton); - hSmlBmp = NULL; - hSmlIco = NULL; - hSmlButton = NULL; - } - - RECT CalcSmileyButtonPos(void) - { - RECT rect; - POINT pt; - - if (OldButtonPlace) - { - if (isSplit && DBGetContactSettingByte(NULL, "SRMsg", "ShowQuote", FALSE)) - { - GetWindowRect(QuoteB, &rect); - pt.x = rect.right + 12; - } - else - { - GetWindowRect(MEdit, &rect); - pt.x = rect.left; - } - GetWindowRect(MOK, &rect); - pt.y = rect.top; - } - else - { - GetWindowRect(LButton, &rect); - pt.y = rect.top; - - if ((GetWindowLongPtr(LButton, GWL_STYLE) & WS_VISIBLE) != 0) - pt.x = rect.left - 28; - else - pt.x = rect.left; - } - - ScreenToClient(GetParent(LButton), &pt); - rect.bottom += pt.y - rect.top; - rect.right += pt.x - rect.left; - rect.top = pt.y; - rect.left = pt.x; - - return rect; - } - - //helper function - //identifies the message dialog - bool IsMessageSendDialog(HWND hwnd) - { - TCHAR szClassName[32] = _T(""); - - GetClassName(hwnd, szClassName, SIZEOF(szClassName)); - if (_tcscmp(szClassName, _T("#32770"))) return false; - - if ((REdit = GetDlgItem(hwnd, MI_IDC_LOG)) != NULL) - { - GetClassName(REdit, szClassName, SIZEOF(szClassName)); - if (_tcscmp(szClassName, _T("RichEdit20A")) != 0 && - _tcscmp(szClassName, _T("RichEdit20W")) != 0 && - _tcscmp(szClassName, _T("RICHEDIT50W")) != 0) return false; - } - else return false; - - if ((MEdit = GetDlgItem(hwnd, MI_IDC_MESSAGE)) != NULL) - { - GetClassName(MEdit, szClassName, SIZEOF(szClassName)); - if (_tcscmp(szClassName, _T("Edit")) != 0 && - _tcscmp(szClassName, _T("RichEdit20A")) != 0 && - _tcscmp(szClassName, _T("RichEdit20W")) != 0 && - _tcscmp(szClassName, _T("RICHEDIT50W")) != 0) return false; - } - else return false; - - QuoteB = GetDlgItem(hwnd, MI_IDC_QUOTE); - - if ((LButton = GetDlgItem(hwnd, MI_IDC_ADD)) == NULL) - return false; - - if (GetDlgItem(hwnd, MI_IDC_NAME) == NULL) - return false; - if ((MOK = GetDlgItem(hwnd, IDOK)) == NULL) - return false; - - return true; - } - - void CreateSmileyButton(void) - { - doSmileyButton = opt.ButtonStatus != 0; - OldButtonPlace = opt.ButtonStatus == 2; - - SmileyPackType* SmileyPack = GetSmileyPack(ProtocolName, hContact); - doSmileyButton &= SmileyPack != NULL && SmileyPack->VisibleSmileyCount() != 0; - - bool showButtonLine; - if (IsOldSrmm()) - { - isSplit = DBGetContactSettingByte(NULL,"SRMsg","Split", TRUE) != 0; - - doSmileyReplace = (isSplit || !isSend); - doSmileyButton &= isSplit || isSend; - showButtonLine = DBGetContactSettingByte(NULL, "SRMsg", "ShowButtonLine", TRUE) != 0; - } - else - { - doSmileyReplace = true; - OldButtonPlace = false; - showButtonLine = DBGetContactSettingByte(NULL, "SRMM", "ShowButtonLine", TRUE) != 0; - } - - doSmileyButton &= OldButtonPlace || showButtonLine; - - if (ProtocolName[0] != 0) - { - INT_PTR cap = CallProtoService(ProtocolName, PS_GETCAPS, PFLAGNUM_1, 0); - doSmileyButton &= ((cap & (PF1_IMSEND | PF1_CHAT)) != 0); - doSmileyReplace &= ((cap & (PF1_IMRECV | PF1_CHAT)) != 0); - } - - if (doSmileyButton && opt.PluginSupportEnabled) - { - //create smiley button - RECT rect = CalcSmileyButtonPos(); - - hSmlButton = CreateWindowEx( - WS_EX_LEFT | WS_EX_NOPARENTNOTIFY | WS_EX_TOPMOST, - MIRANDABUTTONCLASS, - _T("S"), - WS_CHILD|WS_VISIBLE|WS_TABSTOP, // window style - rect.left, // horizontal position of window - rect.top, // vertical position of window - rect.bottom - rect.top + 1, // window width - rect.bottom - rect.top + 1, // window height - GetParent(LButton), // handle to parent or owner window - (HMENU) IDC_SMLBUTTON, // menu handle or child identifier - NULL, // handle to application instance - NULL); // window-creation data - - // Conversion to bitmap done to prevent Miranda from scaling the image - SmileyType* sml = FindButtonSmiley(SmileyPack); - if (sml != NULL) - { - hSmlBmp = sml->GetBitmap(GetSysColor(COLOR_BTNFACE), 0, 0); - SendMessage(hSmlButton, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hSmlBmp); - } - else - { - hSmlIco = GetDefaultIcon(); - SendMessage(hSmlButton, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hSmlIco); - } - - SendMessage(hSmlButton, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Show Smiley Selection Window"), 0); - SendMessage(hSmlButton, BUTTONSETASFLATBTN, TRUE, 0); - } - } -}; - -static int CompareMsgWndData(const MsgWndData* p1, const MsgWndData* p2) -{ - return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); -} -static LIST g_MsgWndList(10, CompareMsgWndData); - - -bool IsOldSrmm(void) -{ - return ServiceExists(MS_MSG_GETWINDOWCLASS) == 0; -} - - -int UpdateSrmmDlg(WPARAM wParam, LPARAM /* lParam */) -{ - WaitForSingleObject(g_hMutex, 2000); - for (int i=0; ihContact == (HANDLE)wParam) - { - SendMessage(g_MsgWndList[i]->hwnd, WM_SETREDRAW, FALSE, 0); - SendMessage(g_MsgWndList[i]->hwnd, DM_OPTIONSAPPLIED, 0, 0); - SendMessage(g_MsgWndList[i]->hwnd, WM_SETREDRAW, TRUE, 0); - } - } - ReleaseMutex(g_hMutex); - - return 0; -} - - -//find the dialog info in the stored list -static MsgWndData* IsMsgWnd(HWND hwnd) -{ - WaitForSingleObject(g_hMutex, 2000); - MsgWndData* res = g_MsgWndList.find((MsgWndData*)&hwnd); - ReleaseMutex(g_hMutex); - - return res; -} - - -static void MsgWndDetect(HWND hwndDlg, HANDLE hContact, msgData* datm) -{ - MsgWndData dat; - - if (dat.IsMessageSendDialog(hwndDlg)) - { - dat.hwnd = hwndDlg; - if (datm != NULL) - { - dat.isSend = datm->isSend != 0; - dat.hContact = datm->hContact; - } - else - dat.hContact = hContact; - - // Get the protocol for this contact to display correct smileys. - char *protonam = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, - (WPARAM)DecodeMetaContact(dat.hContact), 0); - - if (protonam) - { - strncpy(dat.ProtocolName, protonam, sizeof(dat.ProtocolName)); - dat.ProtocolName[sizeof(dat.ProtocolName)-1] = 0; - } - - WaitForSingleObject(g_hMutex, 2000); - - MsgWndData* msgwnd = g_MsgWndList.find((MsgWndData*)&hwndDlg); - if (msgwnd == NULL) - { - msgwnd = new MsgWndData(dat); - g_MsgWndList.insert(msgwnd); - } - else - msgwnd = NULL; - ReleaseMutex(g_hMutex); - - if (msgwnd != NULL) - { - msgwnd->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)MessageDlgSubclas); - msgwnd->CreateSmileyButton(); - if (hContact == NULL) SetRichCallback(msgwnd->REdit, msgwnd->hContact, true, true); - } - } -} - - -//global subclass function for all dialogs -static LRESULT CALLBACK MessageDlgSubclas(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - MsgWndData* dat = IsMsgWnd(hwnd); - if (dat == NULL) return 0; - - switch(uMsg) - { - case DM_OPTIONSAPPLIED: - dat->clear(); - dat->CreateSmileyButton(); - break; - - case DM_APPENDTOLOG: - if (opt.PluginSupportEnabled) - { - //get length of text now before things can get added... - GETTEXTLENGTHEX gtl; - gtl.codepage = 1200; - gtl.flags = GTL_PRECISE | GTL_NUMCHARS; - dat->idxLastChar = (int)SendMessage(dat->REdit, EM_GETTEXTLENGTHEX, (WPARAM) >l, 0); - } - break; - } - - LRESULT result = CallWindowProc(dat->wpOrigWndProc, hwnd, uMsg, wParam, lParam); - - if (!opt.PluginSupportEnabled) return result; - - switch(uMsg) - { - case WM_DESTROY: - WaitForSingleObject(g_hMutex, 2000); - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)dat->wpOrigWndProc); - { - int ind = g_MsgWndList.getIndex((MsgWndData*)&hwnd); - if ( ind != -1 ) - { - delete g_MsgWndList[ind]; - g_MsgWndList.remove(ind); - } - } - ReleaseMutex(g_hMutex); - break; - - case WM_SIZE: - if (dat->doSmileyButton) - { - RECT rect = dat->CalcSmileyButtonPos(); - SetWindowPos(dat->hSmlButton, NULL, rect.left, rect.top, - 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); - } - break; - - case DM_APPENDTOLOG: - if (dat->doSmileyReplace) - { - SmileyPackCType* smcp; - SmileyPackType* SmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact, &smcp); - if (SmileyPack != NULL) - { - const CHARRANGE sel = { dat->idxLastChar, LONG_MAX }; - ReplaceSmileys(dat->REdit, SmileyPack, smcp, sel, false, false, false); - } - } - break; - - case DM_REMAKELOG: - if (dat->doSmileyReplace) - { - SmileyPackCType* smcp; - SmileyPackType* SmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact, &smcp); - if (SmileyPack != NULL) - { - static const CHARRANGE sel = { 0, LONG_MAX }; - ReplaceSmileys(dat->REdit, SmileyPack, smcp, sel, false, false, false); - } - } - break; - - case WM_COMMAND: - if (LOWORD(wParam) == IDC_SMLBUTTON && - HIWORD(wParam) == BN_CLICKED) - { - SmileyToolWindowParam *stwp = new SmileyToolWindowParam; - stwp->pSmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact); - - stwp->hWndParent = hwnd; - stwp->hWndTarget = dat->MEdit; - stwp->targetMessage = EM_REPLACESEL; - stwp->targetWParam = TRUE; - - RECT rect; - GetWindowRect(dat->hSmlButton, &rect); - - if (dat->OldButtonPlace) - { - stwp->direction = 3; - stwp->xPosition = rect.left; - stwp->yPosition = rect.top + 4; - } - else - { - stwp->direction = 0; - stwp->xPosition = rect.left; - stwp->yPosition = rect.top + 24; - } - - mir_forkthread(SmileyToolThread, stwp); - } - - if (LOWORD(wParam) == MI_IDC_ADD && - HIWORD(wParam) == BN_CLICKED && - dat->doSmileyButton) - { - RECT rect = dat->CalcSmileyButtonPos(); - SetWindowPos(dat->hSmlButton, NULL, rect.left, rect.top, - 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); - } - break; - } - - return result; -} - -static int MsgDlgHook(WPARAM, LPARAM lParam) -{ - const MessageWindowEventData *wndEvtData = (MessageWindowEventData*)lParam; - switch(wndEvtData->uType) - { - case MSG_WINDOW_EVT_OPENING: - MsgWndDetect(wndEvtData->hwndWindow, wndEvtData->hContact, NULL); - if (wndEvtData->cbSize >= sizeof(MessageWindowEventData)) - { - SetRichOwnerCallback(wndEvtData->hwndWindow, wndEvtData->hwndInput, wndEvtData->hwndLog); - - if (wndEvtData->hwndLog) - SetRichCallback(wndEvtData->hwndLog, wndEvtData->hContact, false, false); - if (wndEvtData->hwndInput) - SetRichCallback(wndEvtData->hwndInput, wndEvtData->hContact, false, false); - } - break; - - case MSG_WINDOW_EVT_OPEN: - if (wndEvtData->cbSize >= sizeof(MessageWindowEventData)) - { - SetRichOwnerCallback(wndEvtData->hwndWindow, wndEvtData->hwndInput, wndEvtData->hwndLog); - if (wndEvtData->hwndLog) - SetRichCallback(wndEvtData->hwndLog, wndEvtData->hContact, true, true); - if (wndEvtData->hwndInput) - { - SetRichCallback(wndEvtData->hwndInput, wndEvtData->hContact, true, true); - SendMessage(wndEvtData->hwndInput, WM_REMAKERICH, 0, 0); - } - } - break; - - case MSG_WINDOW_EVT_CLOSE: - if (wndEvtData->cbSize >= sizeof(MessageWindowEventData) && wndEvtData->hwndLog) - { - CloseRichCallback(wndEvtData->hwndLog, true); - CloseRichOwnerCallback(wndEvtData->hwndWindow, true); - } - break; - } - return 0; -} - - -//global subclass function for all dialogs -static LRESULT CALLBACK MsgDlgHookProcPre(int code, WPARAM wParam, LPARAM lParam) -{ - const CWPSTRUCT *msg = (CWPSTRUCT*)lParam; - - if (code == HC_ACTION && msg->message == WM_INITDIALOG) - MsgWndDetect(msg->hwnd, NULL, (msgData*)msg->lParam); - - return CallNextHookEx(g_hMessageHookPre, code, wParam, lParam); -} - - -void InstallDialogBoxHook(void) -{ - g_hMutex = CreateMutex(NULL, FALSE, NULL); - - g_hHookMsgWnd = HookEvent(ME_MSG_WINDOWEVENT, MsgDlgHook); - - // Hook message API - if (g_hHookMsgWnd == NULL) - g_hMessageHookPre = SetWindowsHookEx(WH_CALLWNDPROC, MsgDlgHookProcPre, - NULL, GetCurrentThreadId()); -} - - -void RemoveDialogBoxHook(void) -{ - if (g_hHookMsgWnd) UnhookEvent(g_hHookMsgWnd); - if (g_hMessageHookPre) UnhookWindowsHookEx(g_hMessageHookPre); - - WaitForSingleObject(g_hMutex, 2000); - for (int i=0; i. -*/ - -#include "general.h" -#include "m_smileyadd.h" -#include "m_folders.h" - -extern HANDLE hEvent1; -HANDLE hNetlibUser; -static HANDLE hFolder, hFolderHook; - -struct QueueElem -{ - bkstring url; - bkstring fname; - bool needext; - - QueueElem(bkstring& purl, bkstring& pfname, bool ne) - : url(purl), fname(pfname), needext(ne) {} -}; - -static HANDLE g_hDlMutex; -static OBJLIST dlQueue(10); - -static TCHAR cachepath[MAX_PATH]; -static bool threadRunning; - -bool InternetDownloadFile(const char *szUrl, char* szDest, HANDLE &hHttpDwnl) -{ - int result = 0xBADBAD; - char* szRedirUrl = NULL; - NETLIBHTTPREQUEST nlhr = {0}; - - // initialize the netlib request - nlhr.cbSize = sizeof(nlhr); - nlhr.requestType = REQUEST_GET; - nlhr.flags = NLHRF_NODUMP; - nlhr.szUrl = (char*)szUrl; - nlhr.nlc = hHttpDwnl; - - if (CallService(MS_SYSTEM_GETVERSION, 0, 0) >= PLUGIN_MAKE_VERSION(0,9,0,5)) - nlhr.flags |= NLHRF_HTTP11 | NLHRF_PERSISTENT | NLHRF_REDIRECT; - - // change the header so the plugin is pretended to be IE 6 + WinXP - nlhr.headersCount = 2; - nlhr.headers=(NETLIBHTTPHEADER*)alloca(sizeof(NETLIBHTTPHEADER)*nlhr.headersCount); - nlhr.headers[0].szName = "User-Agent"; - nlhr.headers[0].szValue = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; - nlhr.headers[1].szName = "Connection"; - nlhr.headers[1].szValue = "close"; - - while (result == 0xBADBAD) - { - // download the page - NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, - (WPARAM)hNetlibUser,(LPARAM)&nlhr); - - if (nlhrReply) - { - hHttpDwnl = nlhrReply->nlc; - // if the recieved code is 200 OK - if(nlhrReply->resultCode == 200) - { - char* delim = strrchr(szDest, '\\'); - if (delim) *delim = '\0'; - CallService(MS_UTILS_CREATEDIRTREE, 0, (LPARAM)szDest); - if (delim) *delim = '\\'; - int res = -1; - int fh = _open(szDest, _O_BINARY | _O_WRONLY | _O_CREAT, _S_IREAD | _S_IWRITE); - if (fh != -1) - { - res = _write(fh, nlhrReply->pData, nlhrReply->dataLength); - _close(fh); - } - if (res < 0) - remove(szDest); - else - result = 0; - } - // if the recieved code is 302 Moved, Found, etc - // workaround for url forwarding - else if(nlhrReply->resultCode == 302 || nlhrReply->resultCode == 301 || nlhrReply->resultCode == 307) // page moved - { - // get the url for the new location and save it to szInfo - // look for the reply header "Location" - for (int i=0; iheadersCount; i++) - { - if (!strcmp(nlhrReply->headers[i].szName, "Location")) - { - size_t rlen = 0; - if (nlhrReply->headers[i].szValue[0] == '/') - { - const char* szPath; - const char* szPref = strstr(szUrl, "://"); - szPref = szPref ? szPref + 3 : szUrl; - szPath = strchr(szPref, '/'); - rlen = szPath != NULL ? szPath - szUrl : strlen(szUrl); - } - - szRedirUrl = (char*)mir_realloc(szRedirUrl, - rlen + strlen(nlhrReply->headers[i].szValue)*3 + 1); - - strncpy(szRedirUrl, szUrl, rlen); - strcpy(szRedirUrl+rlen, nlhrReply->headers[i].szValue); - - nlhr.szUrl = szRedirUrl; - break; - } - } - } - else - result = 1; - } - else - { - hHttpDwnl = NULL; - result = 1; - } - - CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)nlhrReply); - } - - mir_free(szRedirUrl); - - return result == 0; -} - - -void __cdecl SmileyDownloadThread(void*) -{ - bool needext = false; - HANDLE hHttpDwnl = NULL; - WaitForSingleObject(g_hDlMutex, 3000); - while (!Miranda_Terminated() && dlQueue.getCount()) - { - ReleaseMutex(g_hDlMutex); - if (_taccess(dlQueue[0].fname.c_str(), 0) != 0) - { - InternetDownloadFile(T2A_SM(dlQueue[0].url.c_str()), T2A_SM(dlQueue[0].fname.c_str()), hHttpDwnl); - WaitForSingleObject(g_hDlMutex, 3000); - - bkstring fname(dlQueue[0].fname); - if (dlQueue[0].needext) { fname += GetImageExt(fname); needext = true; } - _trename(dlQueue[0].fname.c_str(), fname.c_str()); - } - else - WaitForSingleObject(g_hDlMutex, 3000); - - dlQueue.remove(0); - } - dlQueue.destroy(); - if (hHttpDwnl) Netlib_CloseHandle(hHttpDwnl); - threadRunning = false; - ReleaseMutex(g_hDlMutex); - - if (!Miranda_Terminated()) - { - if (needext) - CallServiceSync(MS_SMILEYADD_RELOAD, 0, 0); - else - NotifyEventHooks(hEvent1, 0, 0); - } -} - - -bool GetSmileyFile(bkstring& url, const bkstring& packstr) -{ - _TPattern * urlsplit = _TPattern::compile(_T(".*/(.*)")); - _TMatcher * m0 = urlsplit->createTMatcher(url); - - m0->findFirstMatch(); - - bkstring filename; - filename.appendfmt(_T("%s\\%s\\"), cachepath, packstr.c_str()); - size_t pathpos = filename.size(); - filename += m0->getGroup(1); - - delete m0; - delete urlsplit; - - bool needext = filename.find('.') == filename.npos; - if (needext) filename += _T(".*"); - - _tfinddata_t c_file; - INT_PTR hFile = _tfindfirst((TCHAR*)filename.c_str(), &c_file); - if (hFile > -1) - { - _findclose(hFile); - filename.erase(pathpos); - filename += c_file.name; - url = filename; - return false; - } - if (needext) filename.erase(filename.size()-1); - - WaitForSingleObject(g_hDlMutex, 3000); - dlQueue.insert(new QueueElem(url, filename, needext)); - ReleaseMutex(g_hDlMutex); - - if (!threadRunning) - { - threadRunning = true; - mir_forkthread(SmileyDownloadThread, NULL); - } - - url = filename; - return false; -} - -void GetDefaultSmileyCacheFolder(TCHAR* szPath, size_t cbLen) -{ - TCHAR *tmpPath = Utils_ReplaceVarsT(_T("%miranda_userdata%\\SmileyCache")); - if ((INT_PTR)tmpPath != CALLSERVICE_NOTFOUND) - { - mir_sntprintf(szPath, cbLen, _T("%s"), tmpPath); - mir_free(tmpPath); - } - else - { - char dbPath[MAX_PATH]; - CallService(MS_DB_GETPROFILEPATH, SIZEOF(dbPath), (LPARAM)dbPath); - mir_sntprintf(szPath, cbLen, _T("%s\\SmileyCache"), A2T_SM(dbPath)); - } -} - -int FolderChanged(WPARAM, LPARAM) -{ - FOLDERSGETDATA fgd = {0}; - fgd.cbSize = sizeof(FOLDERSGETDATA); - fgd.nMaxPathSize = SIZEOF(cachepath); - fgd.szPathT = cachepath; - if (CallService(MS_FOLDERS_GET_PATH, (WPARAM) hFolder, (LPARAM) &fgd)) - { - GetDefaultSmileyCacheFolder(cachepath, SIZEOF(cachepath)); - } - - return 0; -} - -void GetSmileyCacheFolder(void) -{ - TCHAR defaultPath[MAX_PATH]; - - GetDefaultSmileyCacheFolder(defaultPath, SIZEOF(defaultPath)); - - FOLDERSDATA fd = {0}; - fd.cbSize = sizeof(FOLDERSDATA); - strcpy(fd.szSection, "SmileyAdd"); - strcpy(fd.szName,"Smiley Cache"); - fd.szFormatT = defaultPath; - fd.flags = FF_TCHAR; - hFolder = (HANDLE)CallService(MS_FOLDERS_REGISTER_PATH, 0, (LPARAM) &fd); - - FolderChanged(0, 0); - - hFolderHook = HookEvent(ME_FOLDERS_PATH_CHANGED, FolderChanged); -} - -void DownloadInit(void) -{ - NETLIBUSER nlu = {0}; - nlu.cbSize = sizeof(nlu); - nlu.flags = NUF_OUTGOING|NUF_HTTPCONNS|NUF_NOHTTPSOPTION; - nlu.szSettingsModule = "SmileyAdd"; - nlu.szDescriptiveName = Translate("SmileyAdd HTTP connections"); - hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); - - GetSmileyCacheFolder(); - g_hDlMutex = CreateMutex(NULL, FALSE, NULL); -} - -void DownloadClose(void) -{ - UnhookEvent(hFolderHook); - CloseHandle(g_hDlMutex); - Netlib_CloseHandle(hNetlibUser); -} diff --git a/plugins/SmileyAdd/download.h b/plugins/SmileyAdd/download.h deleted file mode 100644 index bb83926acc..0000000000 --- a/plugins/SmileyAdd/download.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef SMILEYADD_DOWNLOAD_H_ -#define SMILEYADD_DOWNLOAD_H_ - -#include "general.h" - -bool GetSmileyFile(bkstring& url, const bkstring& packstr); -void DownloadInit(void); -void DownloadClose(void); - -#endif diff --git a/plugins/SmileyAdd/general.cpp b/plugins/SmileyAdd/general.cpp deleted file mode 100644 index 9e97737f8c..0000000000 --- a/plugins/SmileyAdd/general.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2012 Boris Krasnovskiy All Rights Reserved -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "m_metacontacts.h" - -#ifdef _MSC_VER -#include -#endif - -/* -#include "m_popup.h" -*/ -static ULONG_PTR g_gdiplusToken = 0; -static bool gdiPlusFail = false; - -// -// General functions -// -int CalculateTextHeight(HDC hdc, CHARFORMAT2* chf) -{ - HDC hcdc = CreateCompatibleDC(hdc); - - int logPixelsY = GetDeviceCaps(hdc, LOGPIXELSY); - HFONT hFont = CreateFont(-(chf->yHeight * logPixelsY / 1440), 0, 0, 0, - chf->wWeight, chf->dwEffects & CFE_ITALIC ? 1 : 0, 0, 0, - chf->bCharSet, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, - chf->szFaceName); - SelectObject(hcdc, hFont); - - SIZE fontSize; - GetTextExtentPoint32(hcdc, _T(")"), 1, &fontSize); - - DeleteObject(hFont); - DeleteDC(hcdc); - - return fontSize.cy; -} - - -HICON GetDefaultIcon(bool copy) -{ - HICON resIco = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"SmileyAdd_ButtonSmiley"); - if ( resIco == NULL || resIco == (HICON)CALLSERVICE_NOTFOUND ) - { - resIco = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_SMILINGICON), - IMAGE_ICON, 0, 0, copy ? 0 : LR_SHARED); - } - else - { - if (copy) - { - resIco = (HICON)CopyImage(resIco, IMAGE_ICON, 0, 0, 0); - CallService(MS_SKIN2_RELEASEICON, 0, (LPARAM)"SmileyAdd_ButtonSmiley"); - } - } - - return resIco; -} - - -const TCHAR* GetImageExt(bkstring &fname) -{ - const TCHAR* ext = _T(""); - - int fileId = _topen(fname.c_str(), O_RDONLY | _O_BINARY); - if (fileId != -1) - { - BYTE buf[6]; - - int bytes = _read(fileId, buf, sizeof(buf)); - if (bytes > 4) - { - if ( *(unsigned short*)buf == 0xd8ff ) - ext = _T("jpg"); - else if ( *(unsigned short*)buf == 0x4d42 ) - ext = _T("bmp"); - else if ( *(unsigned*)buf == 0x474e5089 ) - ext = _T("png"); - else if ( *(unsigned*)buf == 0x38464947 ) - ext = _T("gif"); - } - _close(fileId); - } - return ext; -} - - - -HICON ImageList_GetIconFixed (HIMAGELIST himl, INT i, UINT fStyle) -{ - ICONINFO ii; - HICON hIcon; - HBITMAP hOldDstBitmap; - HDC hdcDst; - - int cx, cy; - ImageList_GetIconSize(himl, &cx, &cy); - - hdcDst = CreateCompatibleDC(NULL); - - ii.fIcon = TRUE; - ii.xHotspot = 0; - ii.yHotspot = 0; - - /* draw mask*/ - ii.hbmMask = CreateBitmap (cx, cy, 1, 1, NULL); - hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask); - PatBlt(hdcDst, 0, 0, cx, cy, WHITENESS); - ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK); - - /* draw image*/ - ii.hbmColor = CreateBitmap (cx, cy, 1, 32, NULL); - SelectObject (hdcDst, ii.hbmColor); - PatBlt (hdcDst, 0, 0, cx, cy, BLACKNESS); - ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT); - - /* - * CreateIconIndirect requires us to deselect the bitmaps from - * the DCs before calling - */ - SelectObject(hdcDst, hOldDstBitmap); - - hIcon = CreateIconIndirect (&ii); - - DeleteObject (ii.hbmMask); - DeleteObject (ii.hbmColor); - DeleteDC (hdcDst); - - return hIcon; -} - -void pathToRelative(const bkstring& pSrc, bkstring& pOut) -{ - TCHAR szOutPath[MAX_PATH]; - CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)pSrc.c_str(), (LPARAM)szOutPath); - pOut = szOutPath; -} - -void pathToAbsolute(const bkstring& pSrc, bkstring& pOut) -{ - TCHAR szOutPath[MAX_PATH]; - - TCHAR* szVarPath = Utils_ReplaceVarsT(pSrc.c_str()); - if (szVarPath == (TCHAR*)CALLSERVICE_NOTFOUND || szVarPath == NULL) - { - TCHAR szExpPath[MAX_PATH]; - ExpandEnvironmentStrings(pSrc.c_str(), szExpPath, SIZEOF(szExpPath)); - CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)szExpPath, (LPARAM)szOutPath); - } - else - { - CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)szVarPath, (LPARAM)szOutPath); - mir_free(szVarPath); - } - pOut = szOutPath; -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// UrlDecode - converts URL chars like %20 into printable characters - -static int __fastcall SingleHexToDecimal(char c) -{ - if (c >= '0' && c <= '9') return c-'0'; - if (c >= 'a' && c <= 'f') return c-'a'+10; - if (c >= 'A' && c <= 'F') return c-'A'+10; - return -1; -} - -void UrlDecode(char* str) -{ - char* s = str, *d = str; - - while(*s) - { - if (*s == '%') - { - int digit1 = SingleHexToDecimal(s[1]); - if ( digit1 != -1 ) - { - int digit2 = SingleHexToDecimal(s[2]); - if ( digit2 != -1 ) - { - s += 3; - *d++ = (char)((digit1 << 4) | digit2); - continue; - } - } - } - *d++ = *s++; - } - - *d = 0; -} - - -bool InitGdiPlus(void) -{ - Gdiplus::GdiplusStartupInput gdiplusStartupInput; - - static const TCHAR errmsg[] = _T("GDI+ not installed.\n") - _T("GDI+ can be downloaded here: http://www.microsoft.com/downloads"); - -#ifdef _MSC_VER - __try -#endif - { - if (g_gdiplusToken == 0 && !gdiPlusFail) - { - Gdiplus::GdiplusStartup(&g_gdiplusToken, &gdiplusStartupInput, NULL); - } - } -#ifdef _MSC_VER - __except ( EXCEPTION_EXECUTE_HANDLER ) - { - gdiPlusFail = true; - ReportError(errmsg); - } -#endif - - return !gdiPlusFail; -} - -void DestroyGdiPlus(void) -{ - if (g_gdiplusToken != 0) - { - Gdiplus::GdiplusShutdown(g_gdiplusToken); -#ifdef _MSC_VER -#if 1200 < _MSC_VER - __FUnloadDelayLoadedDLL2("gdiplus.dll"); -#else - __FUnloadDelayLoadedDLL("gdiplus.dll"); -#endif -#endif - g_gdiplusToken = 0; - } -} - -HANDLE DecodeMetaContact(HANDLE hContact) -{ - if (hContact == NULL) return NULL; - HANDLE hReal = (HANDLE) CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM) hContact, 0); - if (hReal == NULL || hReal == (HANDLE)CALLSERVICE_NOTFOUND) - hReal = hContact; - - return hReal; -} - -bool IsSmileyProto(char* proto) -{ - return proto && (!metaProtoName || strcmp(proto, metaProtoName)) && - (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & (PF1_IM | PF1_CHAT)); -} - -void ReportError(const TCHAR* errmsg) -{ - static const TCHAR title[] = _T("Miranda SmileyAdd"); -/* - - POPUPDATAW pd = {0}; - - - _tcscpy(pd.lpwzContactName, title); - _tcscpy(pd.lpwzText, errmsg); - - pd.iSeconds = -1; - - - bool popupFail = PUAddPopUpW(&pd) != CALLSERVICE_NOTFOUND; - - if (popupFail) -*/ - MessageBox(NULL, errmsg, title, MB_OK | MB_ICONWARNING | MB_TOPMOST); -} - -#pragma warning( disable : 4786 ) -#undef _MT - -#include -#include diff --git a/plugins/SmileyAdd/general.h b/plugins/SmileyAdd/general.h deleted file mode 100644 index 8cc13c5619..0000000000 --- a/plugins/SmileyAdd/general.h +++ /dev/null @@ -1,232 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef _GENERAL_ -#define _GENERAL_ - -#define _HAS_EXCEPTIONS 0 -#define _SECURE_SCL 0 -#define _SECURE_SCL_THROWS 0 -#define __STDC_WANT_SECURE_LIB__ 0 -#define _STRALIGN_USE_SECURE_CRT 0 -#define _NO_EXCEPTIONS - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "bkstring.h" - -#undef _MT - -#pragma warning( push ) -#pragma warning( disable : 4530 ) -#pragma warning( disable : 4275 ) -#pragma warning( disable : 4390 ) - -#include -#include - -typedef WCPattern _TPattern; -typedef WCMatcher _TMatcher; -#define createTMatcher createWCMatcher - -#pragma warning( pop ) - -#define _MT - -#include "resource.h" - -#pragma warning( push ) -#pragma warning( disable : 4100 ) -#define MIRANDA_VER 0x0A00 -#define NETLIB_NOLOGGING -#define MIRANDA_CUSTOM_LP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#pragma warning( pop ) - -//globals, defined int main.cpp -extern HINSTANCE g_hInst; -extern char* metaProtoName; - -//some system and NT stuff... -#ifndef OPENFILENAME_SIZE_VERSION_400 -#define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME) -#endif - - -#define IDC_SMLBUTTON (WM_USER + 33) - -/////////////////////////////////////////////////// -// -//defines from miranda im sources (undocumented!) -// -#define MI_IDC_LOG 1001 //rich edit -#define MI_IDC_MESSAGE 1002 //edit control -#define MI_IDC_QUOTE 1034 //button control -#define MI_IDC_NAME 1009 //text control -#define MI_IDC_ADD 1070 //Add button. - -#define DM_REMAKELOG (WM_USER + 11) -#define DM_OPTIONSAPPLIED (WM_USER + 14) -#define DM_APPENDTOLOG (WM_USER + 17) - -#define WM_REMAKERICH (WM_USER + 0x3457) - -///////////////////////////////////////////////////// - -#define MAX_SMILEY_LENGTH 96 - -class A2W_SM -{ -public: - wchar_t* m_psz; - - A2W_SM(const char* psz, unsigned nCodePage = CP_ACP) - { - const int nLength = MultiByteToWideChar(nCodePage, 0, psz, -1, NULL, 0); - m_psz = new wchar_t[nLength]; - MultiByteToWideChar(nCodePage, 0, psz, -1, m_psz, nLength); - } - ~A2W_SM() { delete [] m_psz; } - operator wchar_t*() const { return m_psz; } -}; - - -class W2A_SM -{ -public: - char* m_psz; - - W2A_SM(const wchar_t* psz, unsigned nCodePage = CP_ACP) - { - const int nLength = WideCharToMultiByte(nCodePage, 0, psz, -1, NULL, 0, NULL, NULL); - m_psz = new char[nLength]; - WideCharToMultiByte(nCodePage, 0, psz, -1, m_psz, nLength, NULL, NULL); - } - ~W2A_SM() { delete [] m_psz; } - operator char*() const { return m_psz; } -}; - -#define T2A_SM (char*)W2A_SM -#define T2W_SM(p1) (wchar_t*)p1 -#define A2T_SM (wchar_t*)A2W_SM -#define W2T_SM(p1) (TCHAR*)p1 - -template struct SMOBJLIST : public OBJLIST -{ - SMOBJLIST() : OBJLIST(5) {}; - - SMOBJLIST& operator = (const SMOBJLIST& lst) - { - OBJLIST::destroy(); - return operator += (lst); - } - - SMOBJLIST& operator += (const SMOBJLIST& lst) - { - for (int i=0; i& lst) - { - for (int i=0; i::destroy(); - } -}; - -inline unsigned short GetWinVer(void) -{ - unsigned short ver = LOWORD(GetVersion()); - ver = (ver & 0xFF) << 8 | (ver >> 8); - return ver; -} - - -// init functions -void InstallDialogBoxHook(void); -void RemoveDialogBoxHook(void); -int UpdateSrmmDlg(WPARAM wParam, LPARAM lParam); -bool IsOldSrmm(void); - -//functions for general use (defined in general.cpp) -int CalculateTextHeight(HDC hdc, CHARFORMAT2* chf); -const TCHAR* GetImageExt(bkstring &fname); - -HANDLE DecodeMetaContact(HANDLE hContact); -bool IsSmileyProto(char* proto); - -HICON ImageList_GetIconFixed (HIMAGELIST himl, INT i, UINT fStyle); - -void pathToRelative(const bkstring& pSrc, bkstring& pOut); -void pathToAbsolute(const bkstring& pSrc, bkstring& pOut); - -bool InitGdiPlus(void); -void DestroyGdiPlus(void); - -void ReportError(const TCHAR* errmsg); -HICON GetDefaultIcon(bool copy = true); - -void CloseRichCallback(HWND hwnd, bool force); -void CloseRichOwnerCallback(HWND hwnd, bool force); -bool SetRichCallback(HWND hwnd, HANDLE hContact, bool subany, bool subnew); -void SetRichOwnerCallback(HWND hwnd, HWND hwndInput, HWND hwndLog); -void ProcessAllInputAreas(bool restoreText); -void RichEditData_Destroy(void); - -void CloseSmileys(void); -void DestroySmileyBase(void); -void DestroyAniSmileys(void); - -void UrlDecode(char* str); - -#endif diff --git a/plugins/SmileyAdd/imagecache.cpp b/plugins/SmileyAdd/imagecache.cpp deleted file mode 100644 index 8fdcea9003..0000000000 --- a/plugins/SmileyAdd/imagecache.cpp +++ /dev/null @@ -1,775 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "imagecache.h" -#include "options.h" - -typedef BOOL (WINAPI *tAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); -static tAlphaBlend pAlphaBlend; - -static FI_INTERFACE *fei; - -static HANDLE g_hMutexIm; -static OBJLIST g_imagecache(25, ImageType::CompareImg); - -static bkstring lastdllname; -static HMODULE lastmodule; -static time_t laststamp; -static UINT_PTR timerId; - -static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD) -{ - WaitForSingleObject(g_hMutexIm, 3000); - const time_t ts = time(NULL) - 10; - if ( lastmodule && ts > laststamp) - { - FreeLibrary(lastmodule); - lastmodule = NULL; - lastdllname.clear(); - } - - for (int i=g_imagecache.getCount(); i--; ) - g_imagecache[i].ProcessTimerTick(ts); - - if (g_imagecache.getCount() == 0) - { - g_imagecache.destroy(); - if (timerId && (timerId+1) && lastmodule == NULL) - { - KillTimer(NULL, timerId); - timerId = 0; - } - } - - ReleaseMutex(g_hMutexIm); -} - - -static void CALLBACK sttMainThreadCallback( PVOID ) -{ - if (timerId == 0xffffffff) - timerId = SetTimer(NULL, 0, 10000, (TIMERPROC)timerProc); -} - - -static HMODULE LoadDll(const bkstring& file) -{ - WaitForSingleObject(g_hMutexIm, 3000); - - if (lastdllname != file) - { - FreeLibrary(lastmodule); - lastdllname = file; - - lastmodule = LoadLibraryEx(file.c_str(), NULL, LOAD_LIBRARY_AS_DATAFILE); - - } - laststamp = time(NULL); - - ReleaseMutex(g_hMutexIm); - return lastmodule; -} - - - -ImageBase::ImageBase(unsigned id) -{ - m_id = id; - m_lRefCount = 1; - m_timestamp = 0; -} - -long ImageBase::AddRef(void) -{ - WaitForSingleObject(g_hMutexIm, 3000); - long cnt = ++m_lRefCount; - ReleaseMutex(g_hMutexIm); - return cnt; -} - -long ImageBase::Release(void) -{ - WaitForSingleObject(g_hMutexIm, 3000); - - long cnt = m_lRefCount; - if (cnt) m_lRefCount = --cnt; - if (cnt == 0) m_timestamp = time(NULL); - - ReleaseMutex(g_hMutexIm); - return cnt; -} - -void ImageBase::ProcessTimerTick(time_t ts) -{ - WaitForSingleObject(g_hMutexIm, 3000); - if (m_lRefCount == 0 && m_timestamp < ts ) - { - if (!g_imagecache.remove(this)) - delete this; - } - ReleaseMutex(g_hMutexIm); -} - -int ImageBase::CompareImg(const ImageBase* p1, const ImageBase* p2) -{ - unsigned id1 = p1->m_id; - unsigned id2 = p2->m_id; - - if (id1 == id2) return 0; - else return id1 < id2 ? -1 : 1; -} - -void ImageBase::Draw(HDC hdc, RECT& rc, bool clip) -{ - HRGN hrgn = NULL; - if (clip) - { - hrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); - SelectClipRgn(hdc, hrgn); - } - - SIZE iSize; - GetSize(iSize); - - const int sizeX = rc.right - rc.left; - const int sizeY = rc.bottom - rc.top; - - const int x = rc.left + (sizeX > iSize.cx || clip ? (sizeX - iSize.cx) / 2 : 0); - const int y = rc.top + (sizeY > iSize.cy || clip ? (sizeY - iSize.cy) / 2 : 0); - - const int scaleX = sizeX > iSize.cx || clip ? iSize.cx : sizeX; - const int scaleY = sizeY > iSize.cy || clip ? iSize.cy : sizeY; - - DrawInternal(hdc, x, y, scaleX, scaleY); - - if (clip) - { - SelectClipRgn(hdc, NULL); - DeleteObject(hrgn); - } -} - - -HBITMAP ImageBase::GetBitmap(COLORREF bkgClr, int sizeX, int sizeY) -{ - RECT rc = { 0, 0, sizeX, sizeY }; - - if (sizeX == 0 || sizeY == 0) - { - SIZE iSize; - GetSize(iSize); - - if (sizeX == 0) rc.right = iSize.cx; - if (sizeY == 0) rc.bottom = iSize.cy; - } - - HBRUSH hBkgBrush = CreateSolidBrush(bkgClr); - HDC hdc = GetDC(NULL); - HBITMAP hBmp = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); - HDC hdcMem = CreateCompatibleDC(hdc); - SelectObject(hdcMem, hBmp); - - FillRect(hdcMem, &rc, hBkgBrush); - - Draw(hdcMem, rc, false); - - DeleteDC(hdcMem); - ReleaseDC(NULL, hdc); - DeleteObject(hBkgBrush); - - return hBmp; -} - -int ImageBase::SelectNextFrame(const int frame) -{ - int res = (frame + 1) % GetFrameCount(); - SelectFrame(res); - return res; -} - - - -IconType::IconType(const unsigned id, const bkstring& file, const int index, const IcoTypeEnum type) - : ImageBase(id) -{ - m_SmileyIcon = NULL; - - switch (type) - { - case icoDll: - { - const HMODULE hModule = LoadDll(file); - if (hModule != NULL) - m_SmileyIcon = (HICON) LoadImage(hModule, MAKEINTRESOURCE(-index), IMAGE_ICON, 0, 0, 0); - } - break; - - case icoFile: - m_SmileyIcon = (HICON) LoadImage(NULL, file.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); - break; - - default: - ExtractIconEx(file.c_str(), index, NULL, &m_SmileyIcon, 1); - break; - } -} - -IconType::~IconType() -{ - DestroyIcon(m_SmileyIcon); -} - -void IconType::DrawInternal(HDC hdc, int x, int y, int sizeX, int sizeY) -{ - if (m_SmileyIcon != NULL) - DrawIconEx(hdc, x, y, m_SmileyIcon, sizeX, sizeY, 0, NULL, DI_NORMAL); -} - -HICON IconType::GetIcon(void) -{ - return (HICON)CopyImage(m_SmileyIcon, IMAGE_ICON, 0, 0, 0); -} - -void IconType::GetSize(SIZE& size) -{ - if (m_SmileyIcon != NULL) - { - ICONINFO ii; - BITMAP bm; - GetIconInfo(m_SmileyIcon, &ii); - GetObject(ii.hbmColor, sizeof(bm), &bm); - size.cx = bm.bmWidth; - size.cy = bm.bmHeight; - DeleteObject(ii.hbmMask); - DeleteObject(ii.hbmColor); - } -} - - - -ImageListItemType::ImageListItemType(const unsigned id, HIMAGELIST hImList, int index) - : ImageBase(id) -{ - m_index = index; - m_hImList = hImList; -} - -void ImageListItemType::DrawInternal(HDC hdc, int x, int y, int sizeX, int sizeY) -{ - SIZE iSize; - GetSize(iSize); - - if (sizeX >= iSize.cx && sizeY >= iSize.cy) - ImageList_Draw(m_hImList, m_index, hdc, x, y, ILD_TRANSPARENT); - else - { - HICON hIcon = ImageList_GetIconFixed(m_hImList, m_index, ILD_TRANSPARENT); - DrawIconEx(hdc, x, y, hIcon, sizeX, sizeY, 0, NULL, DI_NORMAL); - DestroyIcon(hIcon); - } -} - -HICON ImageListItemType::GetIcon(void) -{ - return ImageList_GetIconFixed(m_hImList, m_index, ILD_TRANSPARENT); -} - -void ImageListItemType::GetSize(SIZE& size) -{ - ImageList_GetIconSize(m_hImList, (int*)&size.cx, (int*)&size.cy); -} - -ImageType::ImageType(const unsigned id, const bkstring& file, IStream* pStream) - : ImageBase(id) -{ - m_bmp = NULL; - m_pPropertyItem = NULL; - m_nCurrentFrame = 0; - m_nFrameCount = 0; - - if (!InitGdiPlus()) return; - - if (pStream) - m_bmp = new Gdiplus::Bitmap(pStream); - else - m_bmp = new Gdiplus::Bitmap(T2W_SM(file.c_str())); - - if (m_bmp->GetLastStatus() != Gdiplus::Ok) - { - delete m_bmp; - m_bmp = NULL; - return; - } - - GUID pageGuid = Gdiplus::FrameDimensionTime; - m_nFrameCount = m_bmp->GetFrameCount(&pageGuid); - - if (IsAnimated()) - { - int nSize = m_bmp->GetPropertyItemSize(PropertyTagFrameDelay); - m_pPropertyItem = (Gdiplus::PropertyItem*) new char[nSize]; - m_bmp->GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem); - } -} - -ImageType::ImageType(const unsigned id, const bkstring& file, const int index, const IcoTypeEnum type) - : ImageBase(id) -{ - m_bmp = NULL; - m_pPropertyItem = NULL; - m_nCurrentFrame = 0; - m_nFrameCount = 0; - - if (!InitGdiPlus()) return; - - switch (type) - { - case icoDll: - { - const HMODULE hModule = LoadDll(file); - if (hModule != NULL) - { - HICON hIcon = (HICON) LoadImage(hModule, MAKEINTRESOURCE(-index), IMAGE_ICON, 0, 0, 0); - m_bmp = new Gdiplus::Bitmap(hIcon); - DestroyIcon(hIcon); - } - } - break; - - case icoFile: - m_bmp = new Gdiplus::Bitmap(T2W_SM(file.c_str())); - break; - - default: - HICON hIcon = NULL; - ExtractIconEx(file.c_str(), index, NULL, &hIcon, 1); - m_bmp = new Gdiplus::Bitmap(hIcon); - DestroyIcon(hIcon); - break; - } - - if (m_bmp->GetLastStatus() != Gdiplus::Ok) - { - delete m_bmp; - m_bmp = NULL; - return; - } -} - - -ImageType::~ImageType(void) -{ - if (m_pPropertyItem) delete[] m_pPropertyItem; - if (m_bmp) delete m_bmp; -} - -void ImageType::SelectFrame(int frame) -{ - if ((unsigned)frame >= (unsigned)m_nFrameCount) frame = 0; - if (IsAnimated() && frame != m_nCurrentFrame) - { - m_nCurrentFrame = frame; - GUID pageGuid = Gdiplus::FrameDimensionTime; - m_bmp->SelectActiveFrame(&pageGuid, frame); - } -} - - -void ImageType::DrawInternal(HDC hdc, int x, int y, int sizeX, int sizeY) -{ - if (m_bmp == NULL) return; - - WaitForSingleObject(g_hMutexIm, 3000); - { - Gdiplus::Graphics grp(hdc); -// if (opt.HQScaling) grp.SetInterpolationMode(Gdiplus::InterpolationModeBicubic); - grp.DrawImage(m_bmp, x, y, sizeX, sizeY); - } - ReleaseMutex(g_hMutexIm); -} - -int ImageType::GetFrameDelay(void) const -{ - return ((long*) m_pPropertyItem->value)[m_nCurrentFrame]; -} - -HICON ImageType::GetIcon(void) -{ - if (m_bmp == NULL) return NULL; - - HICON hIcon = NULL; - WaitForSingleObject(g_hMutexIm, 3000); - - m_bmp->GetHICON(&hIcon); - - ReleaseMutex(g_hMutexIm); - return hIcon; -} - - -void ImageType::GetSize(SIZE& size) -{ - if (m_bmp) - { - size.cx = m_bmp->GetWidth(); - size.cy = m_bmp->GetHeight(); - } - else - { - size.cx = 0; - size.cy = 0; - } -} - - -ImageFType::ImageFType(const unsigned id) - : ImageBase(id) -{ - m_bmp = NULL; -} - -ImageFType::ImageFType(const unsigned id, const bkstring& file) - : ImageBase(id) -{ - m_bmp = NULL; - - FREE_IMAGE_FORMAT fif = fei->FI_GetFileTypeT(file.c_str(), 0); - if (fif == FIF_UNKNOWN) - fif = fei->FI_GetFIFFromFilenameT(file.c_str()); - if (fif == FIF_UNKNOWN) return; - - FIBITMAP *dib = fei->FI_LoadT(fif, file.c_str(), 0); - if (dib == NULL) return; - - bool transp = fei->FI_IsTransparent(dib) != 0; - FREE_IMAGE_TYPE imt = fei->FI_GetImageType(dib); - unsigned bpp = fei->FI_GetBPP(dib); - - if (transp && bpp != 32 || imt == FIT_RGBA16) - { - FIBITMAP *tdib = fei->FI_ConvertTo32Bits(dib); - fei->FI_Unload(dib); - dib = tdib; - } - else if (!transp && bpp > 24) - { - FIBITMAP *tdib = fei->FI_ConvertTo24Bits(dib); - fei->FI_Unload(dib); - dib = tdib; - } - - m_bmp = fei->FI_CreateHBITMAPFromDIB(dib); - fei->FI_Unload(dib); - - if (transp) - fei->FI_Premultiply(m_bmp); -} - -ImageFType::~ImageFType() -{ - DeleteObject(m_bmp); -} - -void ImageFType::DrawInternal(HDC hdc, int x, int y, int sizeX, int sizeY) -{ - if (m_bmp == NULL) return; - - HDC hdcImg = CreateCompatibleDC(hdc); - HBITMAP oldBmp = (HBITMAP) SelectObject(hdcImg, m_bmp); - - BITMAP bm; - GetObject(m_bmp, sizeof(bm), &bm); - - if (bm.bmBitsPixel == 32 && pAlphaBlend) - { - BLENDFUNCTION bf = {0}; - bf.SourceConstantAlpha = 255; - bf.AlphaFormat = AC_SRC_ALPHA; - pAlphaBlend(hdc, x, y, sizeX, sizeY, hdcImg, 0, 0, bm.bmWidth, bm.bmHeight, bf); - } - else - { - BitBlt(hdc, x, y, sizeX, sizeY, hdcImg, 0, 0, SRCCOPY); - } - - SelectObject(hdcImg, oldBmp); - DeleteDC(hdcImg); -} - -HICON ImageFType::GetIcon(void) -{ - if (m_bmp == NULL) return NULL; - - HICON hIcon; - - BITMAP bm; - GetObject(m_bmp, sizeof(bm), &bm); - - ICONINFO ii; - ii.fIcon = TRUE; - ii.xHotspot = 0; - ii.yHotspot = 0; - - if (bm.bmBitsPixel == 32 && GetWinVer() < 0x0501) - { - int slen = bm.bmWidth * 4; - int len = bm.bmHeight * slen; - - BYTE* p = (BYTE*)mir_alloc(len); - BYTE* maskBits = (BYTE*)mir_calloc(len); - BYTE* colorBits = (BYTE*)mir_calloc(len); - - GetBitmapBits(m_bmp, len, p); - - for (int y = 0; y < bm.bmHeight; ++y) - { - int shift = y * slen; - BYTE *px = p + shift; - BYTE *color = colorBits + shift; - BYTE *mask = maskBits + shift; - - for (int x = 0; x < bm.bmWidth; ++x) - { - for(int i = 0; i < 4; i++) - { - mask[i] = px[3]; - color[i] = px[i]; - } - - px += 4; - mask += 4; - color += 4; - } - } - - ii.hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 32, maskBits); - ii.hbmColor = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 32, colorBits); - - hIcon = CreateIconIndirect(&ii); - - DeleteObject(ii.hbmMask); - DeleteObject(ii.hbmColor); - - mir_free(p); - mir_free(maskBits); - mir_free(colorBits); - } - else - { - ii.hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL); - ii.hbmColor = m_bmp; - hIcon = CreateIconIndirect(&ii); - DeleteObject(ii.hbmMask); - } - return hIcon; -} - -void ImageFType::GetSize(SIZE& size) -{ - if (m_bmp) - { - BITMAP bm; - GetObject(m_bmp, sizeof(bm), &bm); - size.cx = bm.bmWidth; - size.cy = bm.bmHeight; - } - else - { - size.cx = 0; - size.cy = 0; - } -} -/* -ImageFAniType::ImageFAniType(const unsigned id, const bkstring& file) -: ImageFType(id) -{ - m_fmbmp = NULL; - m_nCurrentFrame = -1; - m_FrameDelay = NULL; - - FREE_IMAGE_FORMAT fif = fei->FI_GetFileTypeT(file.c_str(), 0); - if (fif == FIF_UNKNOWN) - fif = fei->FI_GetFIFFromFilenameT(file.c_str()); - - m_fmbmp = fei->FI_OpenMultiBitmap(fif, T2A_SM(file.c_str()), FALSE, TRUE, TRUE, GIF_PLAYBACK); - if (m_fmbmp == NULL) return; - - m_nFrameCount = fei->FI_GetPageCount(m_fmbmp); - m_bmpl = (HBITMAP*)mir_calloc(m_nFrameCount*sizeof(HBITMAP)); - m_FrameDelay = (int*)mir_calloc(m_nFrameCount*sizeof(int)); - SelectFrame(0); -} - -ImageFAniType::~ImageFAniType() -{ - if (m_fmbmp) fei->FI_CloseMultiBitmap(m_fmbmp, 0); - for (int i=0; i= (unsigned)m_nFrameCount) frame = 0; - if (frame == m_nCurrentFrame) return; - m_nCurrentFrame = frame; - - if (m_bmpl[frame]) - { - m_bmp = m_bmpl[frame]; - return; - } - - FITAG *tag = NULL; - - FIBITMAP *dib = fei->FI_LockPage(m_fmbmp, frame); - if (dib == NULL) - return; - - if (fei->FI_GetMetadata(FIMD_ANIMATION, dib, "FrameTime", &tag)) - m_FrameDelay[frame] = *(LONG *)fei->FI_GetTagValue(tag) / 10; - - m_bmpl[frame] = m_bmp = fei->FI_CreateHBITMAPFromDIB(dib); - - if (fei->FI_IsTransparent(dib)) - fei->FI_Premultiply(m_bmp); - - fei->FI_UnlockPage(m_fmbmp, dib, FALSE); -} -*/ - -#pragma optimize("gt", on) - -// MurmurHash2, by Austin Appleby -unsigned int __fastcall hash( const void * key, unsigned int len ) -{ - // 'm' and 'r' are mixing constants generated offline. - // They're not really 'magic', they just happen to work well. - const unsigned int m = 0x5bd1e995; - const int r = 24; - - // Initialize the hash to a 'random' value - unsigned int h = len; - - // Mix 4 bytes at a time into the hash - const unsigned char * data = (const unsigned char *)key; - - while(len >= 4) - { - unsigned int k = *(unsigned int *)data; - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - data += 4; - len -= 4; - } - - // Handle the last few bytes of the input array - switch(len) - { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; - h *= m; - }; - - // Do a few final mixes of the hash to ensure the last few - // bytes are well-incorporated. - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} -#pragma optimize("", on) - - -void InitImageCache(void) -{ - g_hMutexIm = CreateMutex(NULL, FALSE, NULL); - CallService(MS_IMG_GETINTERFACE, FI_IF_VERSION, (LPARAM) &fei); - - pAlphaBlend = (tAlphaBlend) GetProcAddress(GetModuleHandleA("gdi32"), "GdiAlphaBlend"); - if (pAlphaBlend == NULL) - pAlphaBlend = (tAlphaBlend) GetProcAddress(LoadLibraryA("msimg32"), "AlphaBlend"); -} - -void DestroyImageCache(void) -{ - WaitForSingleObject(g_hMutexIm, 3000); - - if (timerId) KillTimer(NULL, timerId); - if (lastmodule) FreeLibrary(lastmodule); - - g_imagecache.destroy(); - - ReleaseMutex(g_hMutexIm); - CloseHandle(g_hMutexIm); -} - - -ImageBase* AddCacheImage(const bkstring& file, int index) -{ - bkstring tmpfile(file); tmpfile.appendfmt(_T("#%d"), index); - unsigned id = hash(tmpfile.c_str(), (unsigned int)tmpfile.size() * sizeof(TCHAR)); - - WaitForSingleObject(g_hMutexIm, 3000); - - ImageBase srch(id); - ImageBase *img = g_imagecache.find(&srch); - if (img == NULL) - { - bkstring::size_type ind = file.find_last_of('.'); - if (ind == file.npos) return NULL; - bkstring ext = file.substr(ind+1); - - if (ext.comparei(_T("dll")) == 0 || ext.comparei(_T("exe")) == 0) - img = opt.HQScaling ? (ImageBase*)new ImageType(id, file, index, icoDll) : (ImageBase*)new IconType(id, file, index, icoDll); - else if (ext.comparei(_T("ico")) == 0) - img = opt.HQScaling ? (ImageBase*)new ImageType(id, file, 0, icoFile) : (ImageBase*)new IconType(id, file, 0, icoFile); - else if (ext.comparei(_T("icl")) == 0) - img = opt.HQScaling ? (ImageBase*)new ImageType(id, file, index, icoIcl) : (ImageBase*)new IconType(id, file, index, icoIcl); - else if (ext.comparei(_T("gif")) == 0) - img = new ImageType(id, file, NULL); - else if (fei == NULL || ext.comparei(_T("tif")) == 0 || ext.comparei(_T("tiff")) == 0) - img = new ImageType(id, file, NULL); - else - img = opt.HQScaling ? (ImageBase*)new ImageType(id, file, NULL) : (ImageBase*)new ImageFType(id, file); - - g_imagecache.insert(img); - - if (timerId == 0) - { - timerId = 0xffffffff; - CallFunctionAsync(sttMainThreadCallback, NULL); - } - } - else - img->AddRef(); - - ReleaseMutex(g_hMutexIm); - - return img; -} diff --git a/plugins/SmileyAdd/imagecache.h b/plugins/SmileyAdd/imagecache.h deleted file mode 100644 index aa13e4981c..0000000000 --- a/plugins/SmileyAdd/imagecache.h +++ /dev/null @@ -1,166 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -#ifndef SMILEYADD_IMAGECACHE_H_ -#define SMILEYADD_IMAGECACHE_H_ - -#include "general.h" - - -class ImageBase -{ -protected: - unsigned m_id; - long m_lRefCount; - time_t m_timestamp; - -public: - - ImageBase(unsigned id); - virtual ~ImageBase() {} - - long AddRef(void); - long Release(void); - - void ProcessTimerTick(time_t ts); - - virtual void GetSize(SIZE& /* size */) {}; - virtual int GetFrameCount(void) const { return 0; } - virtual int GetFrameDelay(void) const { return 0; } - virtual HICON GetIcon(void) { return NULL; }; - virtual void DrawInternal(HDC /* dc */, int /* x */, int /* y */, int /* sizeX */, int /* sizeY */) {}; - virtual void SelectFrame(int /* frame */) {} - - bool IsAnimated(void) const { return GetFrameCount() > 1; } - HBITMAP GetBitmap(COLORREF bkgClr, int sizeX, int sizeY); - void Draw(HDC dc, RECT &rc, bool clip); - int SelectNextFrame(const int frame); - - static int CompareImg(const ImageBase* p1, const ImageBase* p2); -}; - - -typedef enum -{ - icoDll, - icoFile, - icoIcl -} -IcoTypeEnum; - - -class IconType : public ImageBase -{ -private: - HICON m_SmileyIcon; - -public: - IconType(const unsigned id, const bkstring& file, const int index, const IcoTypeEnum type); - ~IconType(); - - void DrawInternal(HDC dc, int x, int y, int sizeX, int sizeY); - HICON GetIcon(void); - void GetSize(SIZE& size); -}; - - -class ImageListItemType : public ImageBase -{ -private: - int m_index; - HIMAGELIST m_hImList; - -public: - ImageListItemType(const unsigned id, HIMAGELIST hImList, int index); - - void DrawInternal(HDC dc, int x, int y, int sizeX, int sizeY); - HICON GetIcon(void); - void GetSize(SIZE& size); -}; - - -class ImageType : public ImageBase -{ -private: - int m_nCurrentFrame; - int m_nFrameCount; - - Gdiplus::Bitmap* m_bmp; - Gdiplus::PropertyItem* m_pPropertyItem; - -public: - - ImageType(const unsigned id, const bkstring& file, IStream* pStream); - ImageType(const unsigned id, const bkstring& file, const int index, const IcoTypeEnum type); - ~ImageType(); - - void SelectFrame(int frame); - - void DrawInternal(HDC dc, int x, int y, int sizeX, int sizeY); - HICON GetIcon(void); - void GetSize(SIZE& size); - - int GetFrameDelay(void) const; - int GetFrameCount(void) const { return m_nFrameCount; } -}; - -class ImageFType : public ImageBase -{ -protected: - HBITMAP m_bmp; - -public: - - ImageFType(const unsigned id); - ImageFType(const unsigned id, const bkstring& file); - ~ImageFType(); - - void DrawInternal(HDC dc, int x, int y, int sizeX, int sizeY); - HICON GetIcon(void); - void GetSize(SIZE& size); -}; -/* -class ImageFAniType : public ImageFType -{ -private: - int m_nCurrentFrame; - int m_nFrameCount; - int *m_FrameDelay; - - FIMULTIBITMAP *m_fmbmp; - HBITMAP* m_bmpl; - -public: - - ImageFAniType(const unsigned id, const bkstring& file); - ~ImageFAniType(); - - void SelectFrame(int frame); - - int GetFrameDelay(void) const { return m_FrameDelay[m_nCurrentFrame]; } - int GetFrameCount(void) const { return m_nFrameCount; } -}; -*/ - - -ImageBase* AddCacheImage(const bkstring& file, int index); - -void InitImageCache(void); -void DestroyImageCache(void); - -#endif - diff --git a/plugins/SmileyAdd/main.cpp b/plugins/SmileyAdd/main.cpp deleted file mode 100644 index a2deb4399a..0000000000 --- a/plugins/SmileyAdd/main.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "smileys.h" -#include "customsmiley.h" -#include "services.h" -#include "options.h" -#include "download.h" -#include "imagecache.h" -#include "version.h" -#include "m_metacontacts.h" - -//globals -HINSTANCE g_hInst; -HANDLE hEvent1, hContactMenuItem; -extern LIST menuHandleArray; - -char* metaProtoName; - - - -//static globals -static HANDLE hHooks[7]; -static HANDLE hService[13]; -int hLangpack; - - -static const PLUGININFOEX pluginInfoEx = -{ - sizeof(PLUGININFOEX), - "SmileyAdd", - __VERSION_DWORD, - "Smiley support for Miranda Instant Messanger", - "Peacow, nightwish, bid, borkra", - "borkra@miranda-im.org", - "Copyright© 2004 - 2012 Boris Krasnovskiy, portions by Rein-Peter de Boer", - "http://nightly.miranda.im/", - // "http://nightly.miranda.im/", - UNICODE_AWARE, - // {BD542BB4-5AE4-4d0e-A435-BA8DBE39607F} - { 0xbd542bb4, 0x5ae4, 0x4d0e, { 0xa4, 0x35, 0xba, 0x8d, 0xbe, 0x39, 0x60, 0x7f } } -}; - -static SKINICONDESC skinDesc = -{ - sizeof(SKINICONDESC), "SmileyAdd", NULL, - "SmileyAdd_ButtonSmiley", NULL, -IDI_SMILINGICON -}; - - -extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD /* mirandaVersion */) -{ - return (PLUGININFOEX*)&pluginInfoEx; -} - -// MirandaInterfaces - returns the protocol interface to the core -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_SMILEY, MIID_LAST}; - -static int ModulesLoaded(WPARAM, LPARAM) -{ - char path[MAX_PATH]; - GetModuleFileNameA(g_hInst, path, MAX_PATH); - - skinDesc.pszDefaultFile = path; - skinDesc.pszDescription = LPGEN("Button Smiley"); - HANDLE hSkinIcon = Skin_AddIcon(&skinDesc); - - INT_PTR temp = CallService(MS_MC_GETPROTOCOLNAME, 0, 0); - metaProtoName = mir_strdup(temp == CALLSERVICE_NOTFOUND ? NULL : (char*)temp); - - CLISTMENUITEM mi = {0}; - mi.cbSize = sizeof(mi); - mi.flags = CMIF_ROOTPOPUP | CMIF_ICONFROMICOLIB; - mi.popupPosition = 2000070050; - mi.position = 2000070050; - mi.icolibItem = hSkinIcon; - mi.pszPopupName = (char*)-1; - mi.pszName = "Assign Smiley Category"; - hContactMenuItem = Menu_AddContactMenuItem(&mi); - - DownloadInit(); - - //install hooks if enabled - InstallDialogBoxHook(); - - g_SmileyCategories.AddAllProtocolsAsCategory(); - g_SmileyCategories.ClearAndLoadAll(); - - return 0; -} - -static int MirandaShutdown(WPARAM, LPARAM) -{ - CloseSmileys(); - return 0; -} - -extern "C" __declspec(dllexport) int Load(void) -{ - - mir_getLP(&pluginInfoEx); - - if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS)) - { - static const TCHAR errmsg[] = _T("Only one instance of SmileyAdd could be executed.\n") - _T("Remove duplicate instances from 'Plugins' directory"); - ReportError(TranslateTS(errmsg)); - - return 1; - } - - char temp[80]; - CallService(MS_SYSTEM_GETVERSIONTEXT, (WPARAM)SIZEOF(temp), (LPARAM)temp); - - - if (strstr(temp, "Unicode") == NULL) - { - ReportError(TranslateT("Please update SmileyAdd to ANSI Version")); - return 1; - } - - - InitImageCache(); - - g_SmileyCategories.SetSmileyPackStore(&g_SmileyPacks); - - opt.Load(); - - // create smiley events - hEvent1 = CreateHookableEvent(ME_SMILEYADD_OPTIONSCHANGED); - - hHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); - hHooks[1] = HookEvent(ME_SYSTEM_PRESHUTDOWN, MirandaShutdown); - hHooks[2] = HookEvent(ME_OPT_INITIALISE, SmileysOptionsInitialize); - hHooks[3] = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, RebuildContactMenu); - hHooks[4] = HookEvent(ME_SMILEYADD_OPTIONSCHANGED, UpdateSrmmDlg); - hHooks[5] = HookEvent(ME_PROTO_ACCLISTCHANGED, AccountListChanged); - hHooks[6] = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, DbSettingChanged); - - //create the smiley services - hService[0] = CreateServiceFunction(MS_SMILEYADD_REPLACESMILEYS, ReplaceSmileysCommand); - hService[1] = CreateServiceFunction(MS_SMILEYADD_GETSMILEYICON, GetSmileyIconCommand); - hService[2] = CreateServiceFunction(MS_SMILEYADD_SHOWSELECTION, ShowSmileySelectionCommand); - hService[3] = CreateServiceFunction(MS_SMILEYADD_GETINFO, GetInfoCommand); - hService[4] = CreateServiceFunction(MS_SMILEYADD_GETINFO2, GetInfoCommand2); - hService[5] = CreateServiceFunction(MS_SMILEYADD_PARSE, ParseText); - hService[6] = CreateServiceFunction(MS_SMILEYADD_REGISTERCATEGORY, RegisterPack); - hService[7] = CreateServiceFunction(MS_SMILEYADD_BATCHPARSE, ParseTextBatch); - hService[8] = CreateServiceFunction(MS_SMILEYADD_BATCHFREE, FreeTextBatch); - hService[9] = CreateServiceFunction(MS_SMILEYADD_CUSTOMCATMENU, CustomCatMenu); - hService[10] = CreateServiceFunction(MS_SMILEYADD_RELOAD, ReloadPack); - hService[11] = CreateServiceFunction(MS_SMILEYADD_LOADCONTACTSMILEYS, LoadContactSmileys); - - - hService[12] = CreateServiceFunction(MS_SMILEYADD_PARSEW, ParseTextW); - - - return 0; -} - - -extern "C" __declspec(dllexport) int Unload(void) -{ - int i; - - RemoveDialogBoxHook(); - - for (i=0; i. -*/ - -#include "general.h" -#include "options.h" -#include "smileys.h" -#include "customsmiley.h" -#include "services.h" - -//globals, defined int main.cpp -extern HINSTANCE g_hInst; -extern HANDLE hEvent1; -extern SmileyCategoryListType g_SmileyCategories; -extern SmileyPackListType g_SmileyPacks; - -OptionsType opt; - -#define UM_CHECKSTATECHANGE (WM_USER + 100) - -class OptionsDialogType -{ -private: - HWND m_hwndDialog; - SmileyCategoryListType tmpsmcat; - SmileyPackType smPack; - - void InitDialog(void); - void DestroyDialog(void); - void AddCategory(void); - void ApplyChanges(void); - void UpdateControls(bool force = false); - void SetChanged(void); - bool BrowseForSmileyPacks(int item); - void FilenameChanged(void); - void ShowSmileyPreview(void); - void PopulateSmPackList(void); - void UserAction(HTREEITEM hItem); - long GetSelProto(HTREEITEM hItem = NULL); - -public: - OptionsDialogType(HWND hWnd) { m_hwndDialog = hWnd; } - BOOL DialogProcedure(UINT msg, WPARAM wParam, LPARAM lParam); -}; - -static INT_PTR CALLBACK DlgProcSmileysOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); - -//Init and de-init functions, called from main -int SmileysOptionsInitialize(WPARAM addInfo, LPARAM) -{ - OPTIONSDIALOGPAGE odp = {0}; - odp.cbSize = sizeof(odp); - odp.position = 910000000; - odp.hInstance = g_hInst; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SMILEYS); - odp.pszTitle = LPGEN("Smileys"); - odp.pszGroup = LPGEN("Customize"); - odp.pfnDlgProc = DlgProcSmileysOptions; - odp.flags = ODPF_BOLDGROUPS; - Options_AddPage(addInfo, &odp); - - return 0; -} - - -// -// dialog procedure for the options dialog. creates or -// retrieves the options class and calls it -// -static INT_PTR CALLBACK DlgProcSmileysOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - OptionsDialogType* pOD; - INT_PTR Result; - - pOD = (OptionsDialogType*) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - if (pOD == NULL) - { - pOD = new OptionsDialogType(hwndDlg); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pOD); - } - - Result = pOD->DialogProcedure(msg, wParam, lParam); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result); - - if (msg == WM_NCDESTROY) - { - delete pOD; - } - - return Result; -} - - -//OptionsDialog class functions -BOOL OptionsDialogType::DialogProcedure(UINT msg, WPARAM wParam, LPARAM lParam) -{ - BOOL Result = FALSE; - - switch(msg) - { - case WM_INITDIALOG: - InitDialog(); - Result = TRUE; - break; - - case WM_DESTROY: - DestroyDialog(); - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_FILENAME: - switch(HIWORD(wParam)) - { - case EN_KILLFOCUS: - FilenameChanged(); - break; - - case EN_CHANGE: - if (GetFocus() == (HWND)lParam) SetChanged(); - break; - } - break; - - case IDC_BROWSE: - if (HIWORD(wParam) == BN_CLICKED) - { - if (BrowseForSmileyPacks(GetSelProto())) - { - UpdateControls(true); - SetChanged(); - } - } - break; - - case IDC_SMLOPTBUTTON: - if (HIWORD(wParam) == BN_CLICKED) ShowSmileyPreview(); - break; - - case IDC_USESTDPACK: - if (HIWORD(wParam) == BN_CLICKED) - { - PopulateSmPackList(); - SetChanged(); - } - break; - - case IDC_PLUGENABLED: - if (HIWORD(wParam) == BN_CLICKED) - { - BOOL en = IsDlgButtonChecked(m_hwndDialog, IDC_PLUGENABLED) == BST_UNCHECKED; - EnableWindow(GetDlgItem(m_hwndDialog, IDC_SMLBUT), en); - SetChanged(); - } - break; - - case IDC_ADDCATEGORY: - if (HIWORD(wParam) == BN_CLICKED) - { - AddCategory(); - } - break; - - case IDC_DELETECATEGORY: - if (HIWORD(wParam) == BN_CLICKED) - { - if (tmpsmcat.DeleteCustomCategory(GetSelProto())) - { - PopulateSmPackList(); - SetChanged(); - } - } - break; - - case IDC_SPACES: - case IDC_SCALETOTEXTHEIGHT: - case IDC_APPENDSPACES: - case IDC_SMLBUT: - case IDC_SCALEALLSMILEYS: - case IDC_IEVIEWSTYLE: - case IDC_ANIMATESEL: - case IDC_ANIMATEDLG: - case IDC_INPUTSMILEYS: - case IDC_DCURSORSMILEY: - case IDC_DISABLECUSTOM: - case IDC_HQSCALING: - if (HIWORD(wParam) == BN_CLICKED) SetChanged(); - break; - - case IDC_SELCLR: - if (HIWORD(wParam) == CPN_COLOURCHANGED) SetChanged(); - break; - - case IDC_MAXCUSTSMSZ: - case IDC_MINSMSZ: - if (HIWORD(wParam) == EN_CHANGE && GetFocus() == (HWND)lParam) SetChanged(); - break; - } - break; - - case UM_CHECKSTATECHANGE: - UserAction((HTREEITEM)lParam); - break; - - case WM_NOTIFY: - switch(((LPNMHDR)lParam)->idFrom) - { - case 0: - switch (((LPNMHDR)lParam)->code) - { - case PSN_APPLY: - ApplyChanges(); - break; - } - break; - - case IDC_CATEGORYLIST: - switch (((LPNMHDR)lParam)->code) - { - case NM_CLICK: - { - TVHITTESTINFO ht = {0}; - - DWORD dwpos = GetMessagePos(); - POINTSTOPOINT(ht.pt, MAKEPOINTS(dwpos)); - MapWindowPoints(HWND_DESKTOP, ((LPNMHDR)lParam)->hwndFrom, &ht.pt, 1); - - TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &ht); - if (TVHT_ONITEM & ht.flags) - FilenameChanged(); - if (TVHT_ONITEMSTATEICON & ht.flags) - PostMessage(m_hwndDialog, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.hItem); - } - - case TVN_KEYDOWN: - if (((LPNMTVKEYDOWN) lParam)->wVKey == VK_SPACE) - PostMessage(m_hwndDialog, UM_CHECKSTATECHANGE, 0, - (LPARAM)TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom)); - break; - - case TVN_SELCHANGEDA: - case TVN_SELCHANGEDW: - { - LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam; - if (pnmtv->itemNew.state & TVIS_SELECTED) - UpdateControls(); - } - break; - } - break; - } - break; - } - - return Result; -} - - -void OptionsDialogType::AddCategory(void) -{ - TCHAR cat[30]; - - GetDlgItemText(m_hwndDialog, IDC_NEWCATEGORY, cat, SIZEOF(cat)); - bkstring catd = cat; - - if (!catd.empty()) - { - tmpsmcat.AddCategory(cat, catd, smcCustom); - - PopulateSmPackList(); - SetChanged(); - } -} - - -void OptionsDialogType::UserAction(HTREEITEM hItem) -{ - HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); - - if (TreeView_GetCheckState(hLstView, hItem)) - { - if (!BrowseForSmileyPacks(GetSelProto(hItem))) - { - TreeView_SetCheckState(hLstView, hItem, TRUE) - } - } - else - { - tmpsmcat.GetSmileyCategory(GetSelProto(hItem))->ClearFilename(); - } - - if (hItem == TreeView_GetSelection(hLstView)) - UpdateControls(); - else - TreeView_SelectItem(hLstView, hItem); - - SetChanged(); -} - - -void OptionsDialogType::SetChanged(void) -{ - SendMessage(GetParent(m_hwndDialog), PSM_CHANGED, 0, 0); -} - - -void OptionsDialogType::UpdateControls(bool force) -{ - const SmileyCategoryType* smc = tmpsmcat.GetSmileyCategory(GetSelProto()); - if (smc == NULL) return; - - const bkstring& smf = smc->GetFilename(); - - SetDlgItemText(m_hwndDialog, IDC_FILENAME, smf.c_str()); - - if (smPack.GetFilename() != smf || force) - { - smPack.LoadSmileyFile(smf, false, true); - } - - HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); - TreeView_SetCheckState(hLstView, TreeView_GetSelection(hLstView), smPack.SmileyCount() != 0); - - SetDlgItemText(m_hwndDialog, IDC_LIBAUTHOR, smPack.GetAuthor().c_str()); - SetDlgItemText(m_hwndDialog, IDC_LIBVERSION, smPack.GetVersion().c_str()); - SetDlgItemText(m_hwndDialog, IDC_LIBNAME, TranslateTS(smPack.GetName().c_str())); -} - - -long OptionsDialogType::GetSelProto(HTREEITEM hItem) -{ - HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); - TVITEM tvi = {0}; - - tvi.mask = TVIF_PARAM; - tvi.hItem = hItem == NULL ? TreeView_GetSelection(hLstView) : hItem; - - TreeView_GetItem(hLstView, &tvi); - - return (long)tvi.lParam; -} - - -void OptionsDialogType::PopulateSmPackList(void) -{ - bool useOne = IsDlgButtonChecked(m_hwndDialog, IDC_USESTDPACK) == BST_UNCHECKED; - - HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); - - TreeView_SelectItem(hLstView, NULL); - TreeView_DeleteAllItems(hLstView); - - TVINSERTSTRUCT tvi = {0}; - tvi.hParent = TVI_ROOT; - tvi.hInsertAfter = TVI_LAST; - tvi.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_STATE | TVIF_SELECTEDIMAGE | TVIF_PARAM; - tvi.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_SELECTED; - - SmileyCategoryListType::SmileyCategoryVectorType& smc = *tmpsmcat.GetSmileyCategoryList(); - for (int i = 0; i < smc.getCount(); i++) - { - if (!useOne || !smc[i].IsProto()) - { - tvi.item.pszText = (TCHAR*)smc[i].GetDisplayName().c_str(); - if (!smc[i].IsProto()) - { - tvi.item.iImage = 0; - tvi.item.iSelectedImage = 0; - } - else - { - tvi.item.iImage = i; - tvi.item.iSelectedImage = i; - } - tvi.item.lParam = i; - tvi.item.state = - INDEXTOSTATEIMAGEMASK(smPack.LoadSmileyFile(smc[i].GetFilename(), true, true) ? 2 : 1); - - TreeView_InsertItem(hLstView, &tvi); - - smPack.Clear(); - } - } - TreeView_SelectItem(hLstView, TreeView_GetRoot(hLstView)); -} - -void OptionsDialogType::InitDialog(void) -{ - TranslateDialogDefault(m_hwndDialog); - - CheckDlgButton(m_hwndDialog, IDC_PLUGENABLED, opt.PluginSupportEnabled ? BST_UNCHECKED : BST_CHECKED); - CheckDlgButton(m_hwndDialog, IDC_SPACES, opt.EnforceSpaces ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_SCALETOTEXTHEIGHT, opt.ScaleToTextheight ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_USESTDPACK, opt.UseOneForAll ? BST_UNCHECKED : BST_CHECKED); - CheckDlgButton(m_hwndDialog, IDC_APPENDSPACES, opt.SurroundSmileyWithSpaces ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_SCALEALLSMILEYS, opt.ScaleAllSmileys ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_IEVIEWSTYLE, opt.IEViewStyle ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_ANIMATESEL, opt.AnimateSel ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_ANIMATEDLG, opt.AnimateDlg ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_INPUTSMILEYS, opt.InputSmileys ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_DCURSORSMILEY, opt.DCursorSmiley ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_DISABLECUSTOM, opt.DisableCustom ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwndDialog, IDC_HQSCALING, opt.HQScaling ? BST_CHECKED : BST_UNCHECKED); - - SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_ADDSTRING, 0, (LPARAM) TranslateT("Off")); - SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_ADDSTRING, 0, (LPARAM) TranslateT("Top")); - - if (IsOldSrmm()) - SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_ADDSTRING, 0, (LPARAM) TranslateT("Bottom")); - - SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_SETCURSEL, opt.ButtonStatus, 0); - EnableWindow(GetDlgItem(m_hwndDialog, IDC_SMLBUT), opt.PluginSupportEnabled); - - SendDlgItemMessage(m_hwndDialog, IDC_MAXCUSTSPIN, UDM_SETRANGE32, 0, 99); - SendDlgItemMessage(m_hwndDialog, IDC_MAXCUSTSPIN, UDM_SETPOS, 0, opt.MaxCustomSmileySize); - SendDlgItemMessage(m_hwndDialog, IDC_MAXCUSTSMSZ, EM_LIMITTEXT, 2, 0); - - SendDlgItemMessage(m_hwndDialog, IDC_MINSPIN, UDM_SETRANGE32, 0, 99); - SendDlgItemMessage(m_hwndDialog, IDC_MINSPIN, UDM_SETPOS, 0, opt.MinSmileySize); - SendDlgItemMessage(m_hwndDialog, IDC_MINSMSZ, EM_LIMITTEXT, 2, 0); - - SendDlgItemMessage(m_hwndDialog, IDC_SELCLR, CPM_SETCOLOUR, 0, opt.SelWndBkgClr); - SendDlgItemMessage(m_hwndDialog, IDC_SELCLR, CPM_SETDEFAULTCOLOUR, 0, GetSysColor(COLOR_WINDOW)); - - // Create and populate image list - HIMAGELIST hImList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), - ILC_MASK | ILC_COLOR32, g_SmileyCategories.NumberOfSmileyCategories(), 0); - - tmpsmcat = g_SmileyCategories; - - SmileyCategoryListType::SmileyCategoryVectorType& smc = *g_SmileyCategories.GetSmileyCategoryList(); - for (int i = 0; i < smc.getCount(); i++) - { - HICON hIcon = NULL; - if (smc[i].IsProto()) - { - hIcon=(HICON)CallProtoService(T2A_SM(smc[i].GetName().c_str()), PS_LOADICON, - PLI_PROTOCOL | PLIF_SMALL, 0); - if (hIcon == NULL || (INT_PTR)hIcon == CALLSERVICE_NOTFOUND) - { - hIcon=(HICON)CallProtoService(T2A_SM(smc[i].GetName().c_str()), PS_LOADICON, PLI_PROTOCOL, 0); - } - } - if (hIcon == NULL || hIcon == (HICON)CALLSERVICE_NOTFOUND) - hIcon = GetDefaultIcon(); - - ImageList_AddIcon(hImList, hIcon); - DestroyIcon(hIcon); - } - - HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); - TreeView_SetImageList(hLstView, hImList, TVSIL_NORMAL); - - PopulateSmPackList(); -} - -void OptionsDialogType::DestroyDialog(void) -{ - HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); - HIMAGELIST hImList = TreeView_SetImageList(hLstView, NULL, TVSIL_NORMAL); - ImageList_Destroy(hImList); -} - - -void OptionsDialogType::ApplyChanges(void) -{ - ProcessAllInputAreas(true); - CloseSmileys(); - - opt.PluginSupportEnabled = IsDlgButtonChecked(m_hwndDialog, IDC_PLUGENABLED) == BST_UNCHECKED; - opt.EnforceSpaces = IsDlgButtonChecked(m_hwndDialog, IDC_SPACES) == BST_CHECKED; - opt.ScaleToTextheight = IsDlgButtonChecked(m_hwndDialog, IDC_SCALETOTEXTHEIGHT) == BST_CHECKED; - opt.UseOneForAll = IsDlgButtonChecked(m_hwndDialog, IDC_USESTDPACK) == BST_UNCHECKED; - opt.SurroundSmileyWithSpaces = IsDlgButtonChecked(m_hwndDialog, IDC_APPENDSPACES) == BST_CHECKED; - opt.ScaleAllSmileys = IsDlgButtonChecked(m_hwndDialog, IDC_SCALEALLSMILEYS) == BST_CHECKED; - opt.IEViewStyle = IsDlgButtonChecked(m_hwndDialog, IDC_IEVIEWSTYLE) == BST_CHECKED; - opt.AnimateSel = IsDlgButtonChecked(m_hwndDialog, IDC_ANIMATESEL) == BST_CHECKED; - opt.AnimateDlg = IsDlgButtonChecked(m_hwndDialog, IDC_ANIMATEDLG) == BST_CHECKED; - opt.InputSmileys = IsDlgButtonChecked(m_hwndDialog, IDC_INPUTSMILEYS) == BST_CHECKED; - opt.DCursorSmiley = IsDlgButtonChecked(m_hwndDialog, IDC_DCURSORSMILEY) == BST_CHECKED; - opt.DisableCustom = IsDlgButtonChecked(m_hwndDialog, IDC_DISABLECUSTOM) == BST_CHECKED; - opt.HQScaling = IsDlgButtonChecked(m_hwndDialog, IDC_HQSCALING) == BST_CHECKED; - - opt.ButtonStatus = (unsigned)SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_GETCURSEL, 0, 0); - opt.SelWndBkgClr = (unsigned)SendDlgItemMessage(m_hwndDialog, IDC_SELCLR, CPM_GETCOLOUR, 0, 0); - opt.MaxCustomSmileySize = GetDlgItemInt(m_hwndDialog, IDC_MAXCUSTSMSZ, NULL, FALSE); - opt.MinSmileySize = GetDlgItemInt(m_hwndDialog, IDC_MINSMSZ, NULL, FALSE); - - opt.Save(); - - // Cleanup database - SmileyCategoryListType::SmileyCategoryVectorType& smc = *g_SmileyCategories.GetSmileyCategoryList(); - for (int i = 0; i < smc.getCount(); i++) - { - if (tmpsmcat.GetSmileyCategory(smc[i].GetName()) == NULL) - { - bkstring empty; - opt.WritePackFileName(empty, smc[i].GetName()); - } - } - - g_SmileyCategories = tmpsmcat; - g_SmileyCategories.SaveSettings(); - g_SmileyCategories.ClearAndLoadAll(); - - smPack.LoadSmileyFile(tmpsmcat.GetSmileyCategory(GetSelProto())->GetFilename(), false); - - NotifyEventHooks(hEvent1, 0, 0); - ProcessAllInputAreas(false); -} - -bool OptionsDialogType::BrowseForSmileyPacks(int item) -{ - OPENFILENAME ofn = {0}; - - TCHAR filename[MAX_PATH] = _T(""); - ofn.lpstrFile = filename; - ofn.nMaxFile = SIZEOF(filename); - - bkstring inidir; - SmileyCategoryType* smc = tmpsmcat.GetSmileyCategory(item); - if (smc->GetFilename().empty()) - { - pathToAbsolute(_T("Smileys"), inidir); - } - else - { - pathToAbsolute(smc->GetFilename(), inidir); - inidir.erase(inidir.find_last_of('\\')); - } - - ofn.lpstrInitialDir = inidir.c_str(); - ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; - ofn.hwndOwner = m_hwndDialog; - - TCHAR filter[512], *pfilter; - _tcscpy(filter, TranslateT("Smiley Packs")); - lstrcat(filter, _T(" (*.msl;*.asl;*.xep)")); - pfilter = filter + _tcslen(filter) + 1; - _tcscpy(pfilter, _T("*.msl;*.asl;*.xep")); - pfilter = pfilter + _tcslen(pfilter) + 1; - _tcscpy(pfilter, TranslateT("All Files")); - lstrcat(pfilter, _T(" (*.*)")); - pfilter = pfilter + _tcslen(pfilter) + 1; - _tcscpy(pfilter, _T("*.*")); - pfilter = pfilter + _tcslen(pfilter) + 1; - *pfilter = '\0'; - ofn.lpstrFilter = filter; - - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_READONLY | - OFN_EXPLORER | OFN_LONGNAMES | OFN_NOCHANGEDIR; - ofn.lpstrDefExt = _T("msl"); - - if (GetOpenFileName(&ofn)) - { - bkstring relpath; - pathToRelative(filename, relpath); - smc->SetFilename(relpath); - - return true; - } - - return false; -} - -void OptionsDialogType::FilenameChanged(void) -{ - TCHAR str[MAX_PATH]; - GetDlgItemText(m_hwndDialog, IDC_FILENAME, str, SIZEOF(str)); - - SmileyCategoryType* smc = tmpsmcat.GetSmileyCategory(GetSelProto()); - if (smc->GetFilename() != str) - { - bkstring temp(str); - smc->SetFilename(temp); - UpdateControls(); - } -} - -void OptionsDialogType::ShowSmileyPreview(void) -{ - RECT rect; - GetWindowRect(GetDlgItem(m_hwndDialog, IDC_SMLOPTBUTTON), &rect); - - SmileyToolWindowParam *stwp = new SmileyToolWindowParam; - stwp->pSmileyPack = &smPack; - stwp->hWndParent = m_hwndDialog; - stwp->hWndTarget = NULL; - stwp->targetMessage = 0; - stwp->targetWParam = 0; - stwp->xPosition = rect.left; - stwp->yPosition = rect.bottom + 4; - stwp->direction = 1; - stwp->hContact = NULL; - - mir_forkthread(SmileyToolThread, stwp); -} - - -void OptionsType::Save(void) -{ - DBWriteContactSettingByte(NULL, "SmileyAdd", "PluginSupportEnabled", PluginSupportEnabled); - DBWriteContactSettingByte(NULL, "SmileyAdd", "EnforceSpaces", EnforceSpaces); - DBWriteContactSettingByte(NULL, "SmileyAdd", "ScaleToTextheight", ScaleToTextheight); - DBWriteContactSettingByte(NULL, "SmileyAdd", "UseOneForAll", UseOneForAll); - DBWriteContactSettingByte(NULL, "SmileyAdd", "SurroundSmileyWithSpaces", SurroundSmileyWithSpaces); - DBWriteContactSettingByte(NULL, "SmileyAdd", "ScaleAllSmileys", ScaleAllSmileys); - DBWriteContactSettingByte(NULL, "SmileyAdd", "IEViewStyle", IEViewStyle); - DBWriteContactSettingByte(NULL, "SmileyAdd", "AnimateSel", AnimateSel); - DBWriteContactSettingByte(NULL, "SmileyAdd", "AnimateDlg", AnimateDlg); - DBWriteContactSettingByte(NULL, "SmileyAdd", "InputSmileys", InputSmileys); - DBWriteContactSettingByte(NULL, "SmileyAdd", "DCursorSmiley", DCursorSmiley); - DBWriteContactSettingByte(NULL, "SmileyAdd", "DisableCustom", DisableCustom); - DBWriteContactSettingByte(NULL, "SmileyAdd", "HQScaling", HQScaling); - DBWriteContactSettingByte(NULL, "SmileyAdd", "ButtonStatus", (BYTE)ButtonStatus); - DBWriteContactSettingDword(NULL, "SmileyAdd", "SelWndBkgClr", SelWndBkgClr); - DBWriteContactSettingDword(NULL, "SmileyAdd", "MaxCustomSmileySize", MaxCustomSmileySize); - DBWriteContactSettingDword(NULL, "SmileyAdd", "MinSmileySize", MinSmileySize); -} - - -void OptionsType::Load(void) -{ - PluginSupportEnabled = DBGetContactSettingByte(NULL, "SmileyAdd", "PluginSupportEnabled", TRUE) != 0; - EnforceSpaces = DBGetContactSettingByte(NULL, "SmileyAdd", "EnforceSpaces", FALSE) != 0; - ScaleToTextheight = DBGetContactSettingByte(NULL, "SmileyAdd", "ScaleToTextheight", FALSE) != 0; - UseOneForAll = DBGetContactSettingByte(NULL, "SmileyAdd", "UseOneForAll", TRUE) != 0; - SurroundSmileyWithSpaces = - DBGetContactSettingByte(NULL, "SmileyAdd", "SurroundSmileyWithSpaces", FALSE) != 0; - ScaleAllSmileys = DBGetContactSettingByte(NULL, "SmileyAdd", "ScaleAllSmileys", FALSE) != 0; - IEViewStyle = DBGetContactSettingByte(NULL, "SmileyAdd", "IEViewStyle", FALSE) != 0; - AnimateSel = DBGetContactSettingByte(NULL, "SmileyAdd", "AnimateSel", TRUE) != 0; - AnimateDlg = DBGetContactSettingByte(NULL, "SmileyAdd", "AnimateDlg", TRUE) != 0; - InputSmileys = DBGetContactSettingByte(NULL, "SmileyAdd", "InputSmileys", TRUE) != 0; - DCursorSmiley = DBGetContactSettingByte(NULL, "SmileyAdd", "DCursorSmiley", FALSE) != 0; - DisableCustom = DBGetContactSettingByte(NULL, "SmileyAdd", "DisableCustom", FALSE) != 0; - HQScaling = DBGetContactSettingByte(NULL, "SmileyAdd", "HQScaling", FALSE) != 0; - - ButtonStatus = DBGetContactSettingByte(NULL, "SmileyAdd", "ButtonStatus", 1); - SelWndBkgClr = DBGetContactSettingDword(NULL, "SmileyAdd", "SelWndBkgClr", GetSysColor(COLOR_WINDOW)); - MaxCustomSmileySize = DBGetContactSettingDword(NULL, "SmileyAdd", "MaxCustomSmileySize", 0); - MinSmileySize = DBGetContactSettingDword(NULL, "SmileyAdd", "MinSmileySize", 0); -} - - -void OptionsType::ReadPackFileName(bkstring& filename, const bkstring& name, - const bkstring& defaultFilename) -{ - DBVARIANT dbv; - bkstring settingKey = name + _T("-filename"); - - INT_PTR res = DBGetContactSettingTString(NULL, "SmileyAdd", T2A_SM(settingKey.c_str()), &dbv); - if (res == 0) - { - filename = dbv.ptszVal; - DBFreeVariant(&dbv); - } - else - filename = defaultFilename; -} - - -void OptionsType::WritePackFileName(const bkstring& filename, const bkstring& name) -{ - bkstring settingKey = name + _T("-filename"); - DBWriteContactSettingTString(NULL, "SmileyAdd", T2A_SM(settingKey.c_str()), - filename.c_str()); -} - - -void OptionsType::ReadCustomCategories(bkstring& cats) -{ - DBVARIANT dbv; - - INT_PTR res = DBGetContactSettingTString(NULL, "SmileyAdd", "CustomCategories", &dbv); - if (res == 0) - { - cats = dbv.ptszVal; - DBFreeVariant(&dbv); - } -} - - -void OptionsType::WriteCustomCategories(const bkstring& cats) -{ - if (cats.empty()) - DBDeleteContactSetting(NULL, "SmileyAdd", "CustomCategories"); - else - DBWriteContactSettingTString(NULL, "SmileyAdd", "CustomCategories", cats.c_str()); -} - - -void OptionsType::ReadContactCategory(HANDLE hContact, bkstring& cats) -{ - DBVARIANT dbv; - - INT_PTR res = DBGetContactSettingTString(hContact, "SmileyAdd", "CustomCategory", &dbv); - if (res == 0) - { - cats = dbv.ptszVal; - DBFreeVariant(&dbv); - } -} - - -void OptionsType::WriteContactCategory(HANDLE hContact, const bkstring& cats) -{ - if (cats.empty()) - DBDeleteContactSetting(hContact, "SmileyAdd", "CustomCategory"); - else - DBWriteContactSettingTString(hContact, "SmileyAdd", "CustomCategory", cats.c_str()); -} diff --git a/plugins/SmileyAdd/options.h b/plugins/SmileyAdd/options.h deleted file mode 100644 index 3b83b0dc8f..0000000000 --- a/plugins/SmileyAdd/options.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef SMILEYADD_OPTIONS_H_ -#define SMILEYADD_OPTIONS_H_ - -int SmileysOptionsInitialize(WPARAM wParam, LPARAM lParam); - -class OptionsType -{ -public: - bool PluginSupportEnabled; - bool EnforceSpaces; - bool ScaleToTextheight; - bool UseOneForAll; - bool SurroundSmileyWithSpaces; - bool ScaleAllSmileys; - bool IEViewStyle; - bool AnimateSel; - bool AnimateDlg; - bool InputSmileys; - bool DCursorSmiley; - bool DisableCustom; - bool HQScaling; - unsigned ButtonStatus; - unsigned SelWndBkgClr; - unsigned MaxCustomSmileySize; - unsigned MinSmileySize; - - void Load(void); - void Save(void); - static void ReadPackFileName(bkstring& filename, const bkstring& name, - const bkstring& defaultFilename); - static void ReadCustomCategories(bkstring& cats); - static void ReadContactCategory(HANDLE hContact, bkstring& cats); - static void WritePackFileName(const bkstring& filename, const bkstring& name); - static void WriteCustomCategories(const bkstring& cats); - static void WriteContactCategory(HANDLE hContact, const bkstring& cats); -}; - -extern OptionsType opt; - -#endif // SMILEYADD_OPTIONS_H_ - diff --git a/plugins/SmileyAdd/regexp/Matcher.cpp b/plugins/SmileyAdd/regexp/Matcher.cpp deleted file mode 100644 index ebd1f57850..0000000000 --- a/plugins/SmileyAdd/regexp/Matcher.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include -#include - -const int Matcher::MATCH_ENTIRE_STRING = 0x01; - -/* - Detailed documentation is provided in this class' header file - - @author Jeffery Stuart - @since November 2004 - @version 1.07.00 -*/ - -Matcher::Matcher(Pattern * pattern, const bkstring & text) -{ - pat = pattern; - str = &text; - gc = pattern->groupCount; - ncgc = -pattern->nonCapGroupCount; - flags = 0; - matchedSomething = false; - starts = new int[gc + ncgc]; - ends = new int[gc + ncgc]; - groups = new int[gc + ncgc]; - groupPos = new int[gc + ncgc]; - groupIndeces = new int[gc + ncgc]; - starts = starts + ncgc; - ends = ends + ncgc; - groups = groups + ncgc; - groupPos = groupPos + ncgc; - groupIndeces = groupIndeces + ncgc; - for (int i = 0; i < gc; ++i) starts[i] = ends[i] = 0; -} -Matcher::~Matcher() -{ - delete [] (starts - ncgc); - delete [] (ends - ncgc); - delete [] (groups - ncgc); - delete [] (groupIndeces - ncgc); - delete [] (groupPos - ncgc); -} -void Matcher::clearGroups() -{ - int i; - lm = 0; - for (i = 0; i < gc; ++i) groups[i] = starts[i] = ends[i] = -1; - for (i = 1; i <= ncgc; ++i) groups[0 - i] = -1; -} -bkstring Matcher::replaceWithGroups(const bkstring & str) -{ - bkstring ret = ""; - - bkstring t = str; - while (t.size() > 0) - { - if (t[0] == '\\') - { - t.erase(0, 1); - if (t.size() == 0) - { - ret += "\\"; - } - else if (t[0] < '0' || t[0] > '9') - { - ret += t[0]; - t.erase(0, 1); - } - else - { - int gn = 0; - while (t.size() > 0 && t[0] >= '0' && t[0] <= '9') - { - gn = gn * 10 + (t[0] - '0'); - t.erase(0, 1); - } - ret += getGroup(gn); - } - } - else - { - ret += t[0]; - t.erase(0, 1); - } - } - - return ret; -} -unsigned long Matcher::getFlags() const -{ - return flags; -} -const bkstring& Matcher::getText() const -{ - return *str; -} - -bool Matcher::matches() -{ - flags = MATCH_ENTIRE_STRING; - matchedSomething = false; - clearGroups(); - lm = 0; - return pat->head->match(*str, this, 0) == (int)str->size(); -} -bool Matcher::findFirstMatch() -{ - starts[0] = 0; - flags = 0; - clearGroups(); - start = 0; - lm = 0; - ends[0] = pat->head->match(*str, this, 0); - if (ends[0] >= 0) - { - matchedSomething = true; - return 1; - } - return 0; -} -bool Matcher::findNextMatch() -{ - int s = starts[0], e = ends[0]; - - if (!matchedSomething) return findFirstMatch(); - if (s == e) ++e; - flags = 0; - clearGroups(); - - starts[0] = e; - if (e >= (int)str->size()) return 0; - start = e; - lm = e; - ends[0] = pat->head->match(*str, this, e); - return ends[0] >= 0; -} -std::vector Matcher::findAll() -{ - std::vector ret; - reset(); - while (findNextMatch()) - { - ret.push_back(getGroup()); - } - return ret; -} - -void Matcher::reset() -{ - lm = 0; - clearGroups(); - matchedSomething = false; -} - -int Matcher::getStartingIndex(const int groupNum) const -{ - if (groupNum < 0 || groupNum >= gc) return -1; - return starts[groupNum]; -} -int Matcher::getEndingIndex(const int groupNum) const -{ - if (groupNum < 0 || groupNum >= gc) return -1; - return ends[groupNum]; -} -bkstring Matcher::getGroup(const int groupNum) const -{ - if (groupNum < 0 || groupNum >= gc) return ""; - if (starts[groupNum] < 0 || ends[groupNum] < 0) return ""; - return str->substr(starts[groupNum], ends[groupNum] - starts[groupNum]); -} -std::vector Matcher::getGroups(const bool includeGroupZero) const -{ - int i, start = (includeGroupZero ? 0 : 1); - std::vector ret; - - for (i = start; i < gc; ++i) ret.push_back(getGroup(i)); - return ret; -} - diff --git a/plugins/SmileyAdd/regexp/Matcher.h b/plugins/SmileyAdd/regexp/Matcher.h deleted file mode 100644 index 621184d8c2..0000000000 --- a/plugins/SmileyAdd/regexp/Matcher.h +++ /dev/null @@ -1,248 +0,0 @@ -#ifndef __MATCHER_H__ -#define __MATCHER_H__ - -#include "bkstring.h" -#include - -class Vector; -class NFANode; -class NFAStartNode; -class NFAEndNode; -class NFAGroupHeadNode; -class NFAGroupLoopNode; -class NFAGroupLoopPrologueNode; -class NFAGroupTailNode; -class NFALookBehindNode; -class NFAStartOfLineNode; -class NFAEndOfLineNode; -class NFAEndOfMatchNode; -class NFAReferenceNode; -class Pattern; - -/** - A matcher is a non thread-safe object used to scan strings using a given - {@link Pattern Pattern} object. Using a Matcher is the preferred - method for scanning strings. Matchers are not thread-safe. Matchers require - very little dynamic memory, hence one is encouraged to create several - instances of a matcher when necessary as opposed to sharing a single instance - of a matcher. -

- The most common methods needed by the matcher are matches, - findNextMatch, and getGroup. matches - and findNextMatch both return success or failure, and further - details can be gathered from their documentation. -

- Unlike Java's Matcher, this class allows you to change the string - you are matching against. This provides a small optimization, since you no - longer need multiple matchers for a single pattern in a single thread. -

- This class also provides an extremely handy method for replacing text with - captured data via the replaceWithGroups method. A typical - invocation looks like: -

-  char buf[10000];
-  bkstring str = "\\5 (user name \\1) uses \\7 for his/her shell and \\6 is their home directory";
-  FILE * fp = fopen("/etc/passwd", "r");
-  Pattern::registerPattern("entry", "[^:]+");
-  Pattern * p = Pattern::compile("^({entry}):({entry}):({entry}):({entry}):({entry}):({entry}):({entry})$",
-                                 Pattern::MULTILINE_MATCHING | Pattern::UNIX_LINE_MODE);
-  Matcher * m = p->createMatcher("");
-  while (fgets(buf, 9999, fp))
-  {
-    m->setString(buf);
-    if (m->matches())
-    {
-      printf("%s\n", m->replaceWithGroups(str).c_str());
-    }
-  }
-  fclose(fp);
-
-  
- Calling any of the following functions before first calling - matches, findFirstMatch, or - findNextMatch results in undefined behavior and may cause your - program to crash. - -
    -
  • replaceWithGroups -
  • getStartingIndex
  • -
  • getEndingIndex
  • -
  • getGroup
  • -
  • getGroups
  • -
- -

- The function findFirstMatch will attempt to find the first match - in the input string. The same results can be obtained by first calling - reset followed by findNextMatch. -

- To eliminate the necessity of looping through a string to find all the - matching substrings, findAll was created. The function will find - all matching substrings and return them in a vector. If you need - to examine specific capture groups within the substrings, then this method - should not be used. - - @author Jeffery Stuart - @since March 2003, Stable Since November 2004 - @version 1.07.00 - @memo Mutable object used on instances of a Pattern class - */ -class Matcher -{ - friend class NFANode; - friend class NFAStartNode; - friend class NFAEndNode; - friend class NFAGroupHeadNode; - friend class NFAGroupLoopNode; - friend class NFAGroupLoopPrologueNode; - friend class NFAGroupTailNode; - friend class NFALookBehindNode; - friend class NFAStartOfLineNode; - friend class NFAEndOfLineNode; - friend class NFAEndOfMatchNode; - friend class NFAReferenceNode; - friend class Pattern; - private: - /** - Creates a new matcher object against text using - pattern. - - @param pattern The pattern with which to search - @param text The text in which to search - */ - Matcher(Pattern * pattern, const bkstring & text); - protected: - /// The pattern we use to match - Pattern * pat; - /// The string in which we are matching - const bkstring* str; - /// The starting point of our match - int start; - /// An array of the starting positions for each group - int * starts; - /// An array of the ending positions for each group - int * ends; - /// An array of private data used by NFANodes during matching - int * groups; - /// An array of private data used by NFANodes during matching - int * groupIndeces; - /// An array of private data used by NFANodes during matching - int * groupPos; - /// The ending index of the last match - int lm; - /// The number of capturing groups we have - int gc; - /// The number of non-capturing groups we havew - int ncgc; - /// Whether or not we have matched something (used only by findFirstMatch and findNextMatch) - int matchedSomething; - /// The flags with which we were made - unsigned long flags; - /// Called by reset to clear the group arrays - void clearGroups(); - public: - /// Used internally by match to signify we want the entire string matched - const static int MATCH_ENTIRE_STRING; - public: - /// Cleans up the dynamic memory used by this matcher - ~Matcher(); - /** - Replaces the contents of str with the appropriate captured - text. str should have at least one back reference, otherwise - this function does nothing. - @param str The string in which to replace text - @return A string with all backreferences appropriately replaced - */ - bkstring replaceWithGroups(const bkstring & str); - /** - The flags currently being used by the matcher. - @return Zero - */ - unsigned long getFlags() const; - /** - The text being searched by the matcher. - @return the text being searched by the matcher. - */ - const bkstring& getText() const; - - /** - Scans the string from start to finish for a match. The entire string must - match for this function to return success. Group variables are - appropriately set and can be queried after this function returns. - - @return Success if and only if the entire string matches the pattern - */ - bool matches(); - /** - Scans the string for the first substring matching the pattern. The entire - string does not necessarily have to match for this function to return - success. Group variables are appropriately set and can be queried after - this function returns. - - @return Success if any substring matches the specified pattern - */ - bool findFirstMatch(); - /** - Scans the string for the next substring matching the pattern. If no calls - have been made to findFirstMatch of findNextMatch since the last call to - reset, matches, or setString, then this function's behavior results to - that of findFirstMatch. - - @return Success if another substring can be found that matches the pattern - */ - bool findNextMatch(); - /** - Returns a vector of every substring in order which matches the given - pattern. - - @return Every substring in order which matches the given pattern - */ - std::vector findAll(); - /** - Resets the internal state of the matcher - */ - void reset(); - /** - Same as getText. Left n for backwards compatibilty with old source code - @return Returns the string that is currently being used for matching - */ - inline const bkstring& getString() const { return *str; } - /** - Sets the string to scan - @param newStr The string to scan for subsequent matches - */ - inline void setString(const bkstring & newStr) { str = &newStr; reset(); } - - /** - Returns the starting index of the specified group. - @param groupNum The group to query - @return The starting index of the group if it was matched, -1 for an - invalid group or if the group was not matched - */ - int getStartingIndex(const int groupNum = 0) const; - /** - Returns the ending index of the specified group. - @param groupNum The group to query - @return The ending index of the group if it was matched, -1 for an - invalid group or if the group was not matched - */ - int getEndingIndex(const int groupNum = 0) const; - /** - Returns the specified group. An empty string ("") does not necessarily - mean the group was not matched. A group such as (a*b?) could be matched by - a zero length. If an empty string is returned, getStartingIndex can be - called to determine if the group was actually matched. - @param groupNum The group to query - @return The text of the group - */ - bkstring getGroup(const int groupNum = 0) const; - /** - Returns every capture group in a vector - - @param includeGroupZero Whether or not include capture group zero - @return Every capture group - */ - std::vector getGroups(const bool includeGroupZero = 0) const; -}; - -#endif diff --git a/plugins/SmileyAdd/regexp/Pattern.cpp b/plugins/SmileyAdd/regexp/Pattern.cpp deleted file mode 100644 index 4487dddd4b..0000000000 --- a/plugins/SmileyAdd/regexp/Pattern.cpp +++ /dev/null @@ -1,1709 +0,0 @@ -/** - From the author (Jeff Stuart) - " - Let me start by saying this file is pretty big. If you feel up to it, you can - try making changes yourself, but you would be better off to just email me at - stuart@cs.ucdavis.edu if you think there is a bug, or have something useful you - would like added. This project is very "near and dear" to me, so I am fairly - quick to make bug fixes. The header files for Pattern and Matcher are fairly - well documented and the function names are pretty self-explanatory, but if you - are having any trouble, feel free to email me at stuart@cs.ucdavis.edu. - - If you email me, make sure you put something like C++RE in the subject because - I tend to delete email if I don't recognize the name and the subject is - something like "I Need Your Help" or "Got A Second" or "I Found It". - " - */ - -/* - Detailed documentation is provided in this class' header file - - @author Jeffery Stuart - @since November 2004 - @version 1.07.00 -*/ - -#define to_lower(a) (char)(unsigned)CharLowerA((LPSTR)static_cast(a)) -#define is_alpha IsCharAlphaA - -#ifdef _WIN32 - #pragma warning(push) - #pragma warning(disable:4996) - #define str_icmp lstrcmpiA -#else - #define str_icmp strcasecmp -#endif - -#include -#include -#include -#include - -std::map Pattern::compiledPatterns; -std::map > Pattern::registeredPatterns; - -const int Pattern::MIN_QMATCH = 0x00000000; -const int Pattern::MAX_QMATCH = 0x7FFFFFFF; - -const unsigned long Pattern::CASE_INSENSITIVE = 0x01; -const unsigned long Pattern::LITERAL = 0x02; -const unsigned long Pattern::DOT_MATCHES_ALL = 0x04; -const unsigned long Pattern::MULTILINE_MATCHING = 0x08; -const unsigned long Pattern::UNIX_LINE_MODE = 0x10; - -Pattern::Pattern(const bkstring & rhs) -{ - matcher = NULL; - pattern = rhs; - curInd = 0; - groupCount = 0; - nonCapGroupCount = 0; - error = 0; - head = NULL; -} -// convenience function in case we want to add any extra debugging output -void Pattern::raiseError() -{ -/* switch (pattern[curInd - 1]) - { - case '*': - case ')': - case '+': - case '?': - case ']': - case '}': - fprintf(stderr, "%s\n%*c^\n", pattern.c_str(), curInd - 1, ' '); - fprintf(stderr, "Syntax Error near here. Possible unescaped meta character.\n"); - break; - default: - fprintf(stderr, "%s\n%*c^\n", pattern.c_str(), curInd - 1, ' '); - fprintf(stderr, "Syntax Error near here. \n"); - break; - }*/ - error = 1; -} -NFANode * Pattern::registerNode(NFANode * node) -{ - nodes[node] = 1; - return node; -} - -bkstring Pattern::classUnion (bkstring s1, bkstring s2) const -{ - char out[300]; - std::sort(s1.begin(), s1.end()); - std::sort(s2.begin(), s2.end()); - *std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), out) = 0; - return out; -} -bkstring Pattern::classIntersect (bkstring s1, bkstring s2) const -{ - char out[300]; - std::sort(s1.begin(), s1.end()); - std::sort(s2.begin(), s2.end()); - *std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), out) = 0; - return out; -} -bkstring Pattern::classNegate (bkstring s1) const -{ - char out[300]; - int i, ind = 0; - std::map m; - - for (i = 0; i < (int)s1.size(); ++i) m[s1[i]] = 1; - for (i = 0xFF; i >= 0; --i) if (m.find((char)i) == m.end()) out[ind++] = (char)i; - out[ind] = 0; - return bkstring(out, ind); -} -bkstring Pattern::classCreateRange(char low, char hi) const -{ - char out[300]; - int ind = 0; - while (low != hi) out[ind++] = low++; - out[ind++] = low; - return bkstring(out, ind); -} - -int Pattern::getInt(int start, int end) -{ - int ret = 0; - for (; start <= end; ++start) ret = ret * 10 + (pattern[start] - '0'); - return ret; -} -bool Pattern::quantifyCurly(int & sNum, int & eNum) -{ - bool good = 1; - int i, ci = curInd + 1; - int commaInd = ci, endInd = ci, len = (int)pattern.size(); - sNum = eNum = 0; - - while (endInd < len && pattern[endInd ] != '}') ++endInd; - while (commaInd < endInd && pattern[commaInd] != ',') ++commaInd; - if (endInd >= len) { raiseError(); return 0; } - for (i = ci; good && i < endInd; ++i) if (i != commaInd && !isdigit(pattern[i])) good = 0; - if (!good && commaInd < endInd) { raiseError(); return 0; } - if (!good) return 0; - /* so now everything in here is either a comma (and there is at most one comma) or a digit */ - if (commaInd == ci) // {,*} - { - if (endInd == commaInd + 1) { sNum = MIN_QMATCH; eNum = MAX_QMATCH; } // {,} = * - else { sNum = MIN_QMATCH; eNum = getInt(commaInd + 1, endInd - 1); } // {,+} - } - else if (commaInd == endInd - 1) { sNum = getInt(ci, commaInd - 1); eNum = MAX_QMATCH; } // {+,} - else if (commaInd == endInd) { sNum = getInt(ci, endInd - 1); eNum = sNum; } // {+} - else { sNum = getInt(ci, commaInd - 1); eNum = getInt(commaInd + 1, endInd - 1); } // {+,+} - curInd = endInd + 1; - return 1; -} -NFANode * Pattern::quantifyGroup(NFANode * start, NFANode * stop, const int gn) -{ - NFANode * newNode = NULL; - int type = 0; - - if (curInd < (int)pattern.size()) - { - char ch = (curInd + 1 >= (int)pattern.size()) ? -1 : pattern[curInd + 1]; - switch (pattern[curInd]) - { - case '*': - ++curInd; - switch (ch) - { - case '?': ++curInd; type = 1; break; - case '+': ++curInd; type = 2; break; - } - newNode = registerNode(new NFAGroupLoopPrologueNode(gn)); - newNode->next = registerNode(new NFAGroupLoopNode(start, MIN_QMATCH, MAX_QMATCH, gn, type)); - stop->next = newNode->next; - return newNode; - case '?': - ++curInd; - switch (ch) - { - case '?': ++curInd; type = 1; break; - case '+': ++curInd; type = 2; break; - } - newNode = registerNode(new NFAGroupLoopPrologueNode(gn)); - newNode->next = registerNode(new NFAGroupLoopNode(start, MIN_QMATCH, 1, gn, type)); - stop->next = newNode->next; - return newNode; - case '+': - ++curInd; - switch (ch) - { - case '?': ++curInd; type = 1; break; - case '+': ++curInd; type = 2; break; - } - newNode = registerNode(new NFAGroupLoopPrologueNode(gn)); - newNode->next = registerNode(new NFAGroupLoopNode(start, 1, MAX_QMATCH, gn, type)); - stop->next = newNode->next; - return newNode; - case '{': - { - int s, e; - if (quantifyCurly(s, e)) - { - ch = (curInd < (int)pattern.size()) ? pattern[curInd] : -1; - switch (ch) - { - case '?': ++curInd; type = 1; break; - case '+': ++curInd; type = 2; break; - } - newNode = registerNode(new NFAGroupLoopPrologueNode(gn)); - newNode->next = registerNode(new NFAGroupLoopNode(start, s, e, gn, type)); - stop->next = newNode->next; - return newNode; - } - } - default: - break; - } - } - return NULL; -} - -NFANode * Pattern::quantify(NFANode * newNode) -{ - if (curInd < (int)pattern.size()) - { - char ch = (curInd + 1 >= (int)pattern.size()) ? -1 : pattern[curInd + 1]; - switch (pattern[curInd]) - { - case '*': - ++curInd; - switch (ch) - { - case '?': ++curInd; newNode = registerNode(new NFALazyQuantifierNode (this, newNode, MIN_QMATCH, MAX_QMATCH)); break; - case '+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierNode(this, newNode, MIN_QMATCH, MAX_QMATCH)); break; - default: newNode = registerNode(new NFAGreedyQuantifierNode (this, newNode, MIN_QMATCH, MAX_QMATCH)); break; - } - break; - case '?': - ++curInd; - switch (ch) - { - case '?': ++curInd; newNode = registerNode(new NFALazyQuantifierNode (this, newNode, MIN_QMATCH, 1)); break; - case '+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierNode(this, newNode, MIN_QMATCH, 1)); break; - default: newNode = registerNode(new NFAGreedyQuantifierNode (this, newNode, MIN_QMATCH, 1)); break; - } - break; - case '+': - ++curInd; - switch (ch) - { - case '?': ++curInd; newNode = registerNode(new NFALazyQuantifierNode (this, newNode, 1, MAX_QMATCH)); break; - case '+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierNode(this, newNode, 1, MAX_QMATCH)); break; - default: newNode = registerNode(new NFAGreedyQuantifierNode (this, newNode, 1, MAX_QMATCH)); break; - } - break; - case '{': - { - int s, e; - if (quantifyCurly(s, e)) - { - ch = (curInd < (int)pattern.size()) ? pattern[curInd] : -1; - switch (ch) - { - case '?': ++curInd; newNode = registerNode(new NFALazyQuantifierNode (this, newNode, s, e)); break; - case '+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierNode(this, newNode, s, e)); break; - default: newNode = registerNode(new NFAGreedyQuantifierNode (this, newNode, s, e)); break; - } - } - } - break; - default: - break; - } - } - return newNode; -} -bkstring Pattern::parseClass() -{ - bkstring t, ret = ""; - char ch, c1, c2; - bool inv = 0, neg = 0, quo = 0; - - if (curInd < (int)pattern.size() && pattern[curInd] == '^') - { - ++curInd; - neg = 1; - } - while (curInd < (int)pattern.size() && pattern[curInd] != ']') - { - ch = pattern[curInd++]; - if (ch == '[') - { - t = parseClass(); - ret = classUnion(ret, t); - } - /*else if (ch == '-') - { - raiseError(); - curInd = pattern.size(); - }*/ - else if (ch == '&' && curInd < (int)pattern.size() && pattern[curInd] == '&') - { - if (pattern[++curInd] != '[') - { - raiseError(); - curInd = (int)pattern.size(); - } - else - { - ++curInd; - t = parseClass(); - ret = classIntersect(ret, t); - } - } - else if (ch == '\\') - { - t = parseEscape(inv, quo); - if (quo) - { - raiseError(); - curInd = (int)pattern.size(); - } - else if (inv || t.size() > 1) // cant be part of a range (a-z) - { - if (inv) t = classNegate(t); - ret = classUnion(ret, t); - } - else if (curInd < (int)pattern.size() && pattern[curInd] == '-') // part of a range (a-z) - { - c1 = t[0]; - ++curInd; - if (curInd >= (int)pattern.size()) raiseError(); - else - { - c2 = pattern[curInd++]; - if (c2 == '\\') - { - t = parseEscape(inv, quo); - if (quo) - { - raiseError(); - curInd = (int)pattern.size(); - } - else if (inv || t.size() > 1) raiseError(); - else ret = classUnion(ret, classCreateRange(c1, c2)); - } - else if (c2 == '[' || c2 == ']' || c2 == '-' || c2 == '&') - { - raiseError(); - curInd = (int)pattern.size(); - } - else ret = classUnion(ret, classCreateRange(c1, c2)); - } - } - else - { - ret = classUnion(ret, t); - } - } - else if (curInd < (int)pattern.size() && pattern[curInd] == '-') - { - c1 = ch; - ++curInd; - if (curInd >= (int)pattern.size()) raiseError(); - else - { - c2 = pattern[curInd++]; - if (c2 == '\\') - { - t = parseEscape(inv, quo); - if (quo) - { - raiseError(); - curInd = (int)pattern.size(); - } - else if (inv || t.size() > 1) raiseError(); - else ret = classUnion(ret, classCreateRange(c1, c2)); - } - else if (c2 == '[' || c2 == ']' || c2 == '-' || c2 == '&') - { - raiseError(); - curInd = (int)pattern.size(); - } - else - { - ret = classUnion(ret, classCreateRange(c1, c2)); - } - } - } - else - { - ret += " "; - ret[ret.size() - 1] = ch; - } - } - if (curInd >= (int)pattern.size() || pattern[curInd] != ']') - { - raiseError(); - ret = ""; - } - else - { - ++curInd; - if (neg) ret = classNegate(ret); - } - return ret; -} -bkstring Pattern::parsePosix() -{ - bkstring s7 = pattern.substr(curInd, 7); - if (s7 == "{Lower}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyz"; } - if (s7 == "{Upper}") { curInd += 7; return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } - if (s7 == "{Alpha}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; } - if (s7 == "{Digit}") { curInd += 7; return "0123456789"; } - if (s7 == "{Alnum}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; } - if (s7 == "{Punct}") { curInd += 7; return "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } - if (s7 == "{Graph}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } - if (s7 == "{Print}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } - if (s7 == "{Blank}") { curInd += 7; return " \t"; } - if (s7 == "{Space}") { curInd += 7; return " \t\n\x0B\f\r"; } - if (s7 == "{Cntrl}") - { - bkstring::value_type i; - bkstring s = " "; - - for (i = 0; i < 5; ++i) s += s; - s += " "; - for (i = 0; i <= 0x1F; ++i) s[i] = i; - s[0x20] = 0x7F; - curInd += 7; - return s; - } - if (s7 == "{ASCII}") - { - bkstring s(0x80, ' '); - for (int i = 0; i <= 0x7f; ++i) s[i] = (bkstring::value_type)i; - curInd += 7; - return s; - } - if (pattern.substr(curInd, 8) == "{XDigit}") { curInd += 8; return "abcdefABCDEF0123456789"; } - raiseError(); - return ""; -} -NFANode * Pattern::parseBackref() -{ - #define is_dig(x) ((x) >= '0' && (x) <= '9') - #define to_int(x) ((x) - '0') - int ci = curInd; - int oldRef = 0, ref = 0; - - while (ci < (int)pattern.size() && is_dig(pattern[ci]) && (ref < 10 || ref < groupCount)) - { - oldRef = ref; - ref = ref * 10 + to_int(pattern[ci++]); - } - if (ci == (int)pattern.size()) - { - oldRef = ref; - ++ci; - } - if (oldRef < 0 || ci <= curInd) - { - raiseError(); - return registerNode(new NFAReferenceNode(-1)); - } - curInd = ci; - return registerNode(new NFAReferenceNode(ref)); - - #undef is_dig - #undef to_int -} -bkstring Pattern::parseOctal() -{ - #define islowoc(x) ((x) >= '0' && (x) <= '3') - #define isoc(x) ((x) >= '0' && (x) <= '7') - #define fromoc(x) ((x) - '0') - int ci = curInd; - char ch1 = (ci + 0 < (int)pattern.size()) ? pattern[ci + 0] : -1; - char ch2 = (ci + 1 < (int)pattern.size()) ? pattern[ci + 1] : -1; - char ch3 = (ci + 2 < (int)pattern.size()) ? pattern[ci + 2] : -1; - bkstring s = " "; - - if (islowoc(ch1) && isoc(ch2)) - { - curInd += 2; - s[0] = fromoc(ch1) * 8 + fromoc(ch2); - if (isoc(ch3)) - { - ++curInd; - s[0] = s[0] * 8 + fromoc(ch3); - } - } - else if (isoc(ch1) && isoc(ch2)) - { - curInd += 2; - s[0] = fromoc(ch1) * 8 + fromoc(ch2); - } - else raiseError(); - - return s; - #undef islowoc - #undef isoc - #undef fromoc -} -bkstring Pattern::parseHex() -{ - #define to_low(x) (((x) >= 'A' && (x) <= 'Z') ? ((x) - 'A' + 'a') : (x)) - #define is_dig(x) ((x) >= '0' && (x) <= '9') - #define is_hex(x) (is_dig(x) || (to_low(x) >= 'a' && to_low(x) <= 'f')) - #define to_int(x) ((is_dig(x)) ? ((x) - '0') : (to_low(x) - 'a' + 10)) - - int ci = curInd; - char ch1 = (ci + 0 < (int)pattern.size()) ? pattern[ci + 0] : -1; - char ch2 = (ci + 1 < (int)pattern.size()) ? pattern[ci + 1] : -1; - bkstring s = " "; - - if (is_hex(ch1) && is_hex(ch2)) - { - curInd += 2; - s[0] = (to_int(ch1) << 4 & 0xF0) | (to_int(ch2) & 0x0F); - } - - return s; - #undef to_low - #undef is_dig - #undef is_hex - #undef to_int -} -bkstring Pattern::parseEscape(bool & inv, bool & quo) -{ - char ch = pattern[curInd++]; - bkstring classes = ""; - - if (curInd > (int)pattern.size()) - { - raiseError(); - return NULL; - } - - quo = 0; - inv = 0; - switch (ch) - { - case 'p': classes = parsePosix(); break; - case 'P': classes = "!!"; classes += parsePosix(); break; - case 'd': classes = "0123456789"; break; - case 'D': classes = "!!0123456789"; break; - case 's': classes = " \t\r\n\f"; break; - case 'S': classes = "!! \t\r\n\f"; break; - case 'w': classes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; break; - case 'W': classes = "!!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; break; - case '0': classes = parseOctal(); break; - case 'x': classes = parseHex(); break; - - case 'Q': quo = 1; break; - case 't': classes = "\t"; break; - case 'r': classes = "\r"; break; - case 'n': classes = "\n"; break; - case 'f': classes = "\f"; break; - case 'a': classes = "\a"; break; - case 'e': classes = "\r"; break; - default: classes = " "; classes[0] = ch; break; - } - if (classes.substr(0, 2) == "!!") - { - classes = classes.substr(2); - inv = 1; - } - return classes; -} -NFANode * Pattern::parseRegisteredPattern(NFANode ** end) -{ - int i, j; - bkstring s; - NFANode * ret = NULL; - for (i = curInd; i < (int)pattern.size() && pattern[i] != '}'; ++i) { } - if (pattern[i] != '}') { raiseError(); return NULL; } - if (i == curInd + 1) { raiseError(); return NULL; } // {} - if ( - !( - (pattern[curInd] >= 'a' && pattern[curInd] <= 'z') || - (pattern[curInd] >= 'A' && pattern[curInd] <= 'Z') || - (pattern[curInd] == '_') - ) - ) - { - raiseError(); - return NULL; - } - for (j = curInd; !error && j < i; ++j) - { - if ( - !( - (pattern[j] >= 'a' && pattern[j] <= 'z') || - (pattern[j] >= 'A' && pattern[j] <= 'Z') || - (pattern[j] >= '0' && pattern[j] <= '9') || - (pattern[j] == '_') - ) - ) - { - raiseError(); - return NULL; - } - } - s = pattern.substr(curInd, i - curInd); - if (registeredPatterns.find(s) == registeredPatterns.end()) raiseError(); - else - { - unsigned long oflags = flags; - bkstring op = pattern; - int ci = i + 1; - - pattern = registeredPatterns[s].first; - curInd = 0; - flags = registeredPatterns[s].second; - - --groupCount; - ret = parse(0, 0, end); - - pattern = op; - curInd = ci; - flags = oflags; - } - if (error) { *end = ret = NULL; } - return ret; -} - -// look behind should interpret everything as a literal (except \\) since the -// pattern must have a concrete length -NFANode * Pattern::parseBehind(const bool pos, NFANode ** end) -{ - bkstring t = ""; - while (curInd < (int)pattern.size() && pattern[curInd] != ')') - { - char ch = pattern[curInd++]; - t += " "; - if (ch == '\\') - { - if (curInd + 1 >= (int)pattern.size()) - { - raiseError(); - return *end = registerNode(new NFACharNode(' ')); - } - ch = pattern[curInd++]; - } - t[t.size() - 1] = ch; - } - if (curInd >= (int)pattern.size() || pattern[curInd] != ')') raiseError(); - else ++curInd; - return *end = registerNode(new NFALookBehindNode(t, pos)); -} -NFANode * Pattern::parseQuote() -{ - bool done = 0; - bkstring s = ""; - - while (!done) - { - if (curInd >= (int)pattern.size()) - { - raiseError(); - done = 1; - } - else if (pattern.substr(curInd, 2) == "\\E") - { - curInd += 2; - done = 1; - } - else if (pattern[curInd] == '\\') - { - s += " "; - s[s.size() - 1] = pattern[++curInd]; - ++curInd; - } - else - { - s += " "; - s[s.size() - 1] = pattern[curInd++]; - } - } - if ((flags & Pattern::CASE_INSENSITIVE) != 0) return registerNode(new NFACIQuoteNode(s)); - return registerNode(new NFAQuoteNode(s)); -} -NFANode * Pattern::parse(const bool inParen, const bool inOr, NFANode ** end) -{ - NFANode * start, * cur, * next = NULL; - bkstring t; - int grc = groupCount++; - bool inv, quo; - bool ahead = 0, pos = 0, noncap = 0, indep = 0; - unsigned long oldFlags = flags; - - if (inParen) - { - if (pattern[curInd] == '?') - { - ++curInd; - --groupCount; - if (pattern[curInd] == ':') { noncap = 1; ++curInd; grc = --nonCapGroupCount; } - else if (pattern[curInd] == '=') { ++curInd; ahead = 1; pos = 1; } - else if (pattern[curInd] == '!') { ++curInd; ahead = 1; pos = 0; } - else if (pattern.substr(curInd, 2) == "<=") { curInd += 2; return parseBehind(1, end); } - else if (pattern.substr(curInd, 2) == "') { ++curInd; indep = 1; } - else - { - bool negate = false, done = false; - while (!done) - { - if (curInd >= (int)pattern.size()) - { - raiseError(); - return NULL; - } - else if (negate) - { - switch (pattern[curInd]) - { - case 'i': flags &= ~Pattern::CASE_INSENSITIVE; break; - case 'd': flags &= ~Pattern::UNIX_LINE_MODE; break; - case 'm': flags &= ~Pattern::MULTILINE_MATCHING; break; - case 's': flags &= ~Pattern::DOT_MATCHES_ALL; break; - case ':': done = true; break; - case ')': - ++curInd; - *end = registerNode(new NFALookBehindNode("", true)); - return *end; - case '-': - default: raiseError(); return NULL; - } - } - else - { - switch (pattern[curInd]) - { - case 'i': flags |= Pattern::CASE_INSENSITIVE; break; - case 'd': flags |= Pattern::UNIX_LINE_MODE; break; - case 'm': flags |= Pattern::MULTILINE_MATCHING; break; - case 's': flags |= Pattern::DOT_MATCHES_ALL; break; - case ':': done = true; break; - case '-': negate = true; break; - case ')': - ++curInd; - *end = registerNode(new NFALookBehindNode("", true)); - return *end; - default: raiseError(); return NULL; - } - } - ++curInd; - } - noncap = 1; - grc = --nonCapGroupCount; - } - if (noncap) cur = start = registerNode(new NFAGroupHeadNode(grc)); - else cur = start = registerNode(new NFASubStartNode); - } - else cur = start = registerNode(new NFAGroupHeadNode(grc)); - } - else cur = start = registerNode(new NFASubStartNode); - while (curInd < (int)pattern.size()) - { - char ch = pattern[curInd++]; - - next = NULL; - if (error) return NULL; - switch (ch) - { - case '^': - if ((flags & Pattern::MULTILINE_MATCHING) != 0) next = registerNode(new NFAStartOfLineNode); - else next = registerNode(new NFAStartOfInputNode); - break; - case '$': - if ((flags & Pattern::MULTILINE_MATCHING) != 0) next = registerNode(new NFAEndOfLineNode); - else next = registerNode(new NFAEndOfInputNode(0)); - break; - case '|': - --groupCount; - cur->next = registerNode(new NFAAcceptNode); - cur = start = registerNode(new NFAOrNode(start, parse(inParen, 1))); - break; - case '\\': - if (curInd < (int)pattern.size()) - { - bool eoi = 0; - switch (pattern[curInd]) - { - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': next = parseBackref(); break; - case 'A': ++curInd; next = registerNode(new NFAStartOfInputNode); break; - case 'B': ++curInd; next = registerNode(new NFAWordBoundaryNode(0)); break; - case 'b': ++curInd; next = registerNode(new NFAWordBoundaryNode(1)); break; - case 'G': ++curInd; next = registerNode(new NFAEndOfMatchNode); break; - case 'Z': eoi = 1; - case 'z': ++curInd; next = registerNode(new NFAEndOfInputNode(eoi)); break; - default: - t = parseEscape(inv, quo); - if (!quo) - { - if (t.size() > 1 || inv) - { - if ((flags & Pattern::CASE_INSENSITIVE) != 0) next = registerNode(new NFACIClassNode(t, inv)); - else next = registerNode(new NFAClassNode(t, inv)); - } - else - { - next = registerNode(new NFACharNode(t[0])); - } - } - else - { - next = parseQuote(); - } - } - } - else raiseError(); - break; - case '[': - if ((flags & Pattern::CASE_INSENSITIVE) == 0) - { - NFAClassNode * clazz = new NFAClassNode(); - bkstring s = parseClass(); - for (int i = 0; i < (int)s.size(); ++i) clazz->vals[s[i]] = 1; - next = registerNode(clazz); - } - else - { - NFACIClassNode * clazz = new NFACIClassNode(); - bkstring s = parseClass(); - for (int i = 0; i < (int)s.size(); ++i) clazz->vals[to_lower(s[i])] = 1; - next = registerNode(clazz); - } - break; - case '.': - { - bool useN = 1, useR = 1; - NFAClassNode * clazz = new NFAClassNode(1); - if ((flags & Pattern::UNIX_LINE_MODE) != 0) useR = 0; - if ((flags & Pattern::DOT_MATCHES_ALL) != 0) useN = useR = 0; - if (useN) clazz->vals['\n'] = 1; - if (useR) clazz->vals['\r'] = 1; - next = registerNode(clazz); - } - break; - case '(': - { - NFANode * end, * t1, * t2; - t1 = parse(1, 0, &end); - if (!t1) raiseError(); - else if (t1->isGroupHeadNode() && (t2 = quantifyGroup(t1, end, grc)) != NULL) - { - cur->next = t2; - cur = t2->next; - } - else - { - cur->next = t1; - cur = end; - } - } - break; - case ')': - if (!inParen) raiseError(); - else if (inOr) - { - --curInd; - cur = cur->next = registerNode(new NFAAcceptNode); - flags = oldFlags; - return start; - } - else - { - if (ahead) - { - cur = cur->next = registerNode(new NFAAcceptNode); - flags = oldFlags; - return *end = registerNode(new NFALookAheadNode(start, pos)); - } - else if (indep) - { - cur = cur->next = registerNode(new NFAAcceptNode); - flags = oldFlags; - return *end = registerNode(new NFAPossessiveQuantifierNode(this, start, 1, 1)); - } - else // capping or noncapping, it doesnt matter - { - *end = cur = cur->next = registerNode(new NFAGroupTailNode(grc)); - next = quantifyGroup(start, *end, grc); - if (next) - { - start = next; - *end = next->next; - } - flags = oldFlags; - return start; - } - } - break; - case '{': // registered pattern - cur->next = parseRegisteredPattern(&next); - if (cur->next) cur = next; - break; - case '*': - case '+': - case '?': -// case '}': -// case ']': - raiseError(); - break; - default: - if ((flags & Pattern::CASE_INSENSITIVE) != 0) next = registerNode(new NFACICharNode(ch)); - else next = registerNode(new NFACharNode(ch)); - break; - } - if (next) - { - cur = cur->next = quantify(next); - } - } - if (inParen) raiseError(); - else - { - if (inOr) cur = cur->next = registerNode(new NFAAcceptNode); - if (end) *end = cur; - } - - flags = oldFlags; - if (error) return NULL; - - return start; -} - -Pattern * Pattern::compile(const bkstring & pattern, const unsigned long mode) -{ - Pattern * p = new Pattern(pattern); - NFANode * end; - - p->flags = mode; - if ((mode & Pattern::LITERAL) != 0) - { - p->head = p->registerNode(new NFAStartNode); - if ((mode & Pattern::CASE_INSENSITIVE) != 0) p->head->next = p->registerNode(new NFACIQuoteNode(pattern)); - else p->head->next = p->registerNode(new NFAQuoteNode(pattern)); - p->head->next->next = p->registerNode(new NFAEndNode); - } - else - { - p->head = p->parse(0, 0, &end); - if (!p->head) - { - delete p; - p = NULL; - } - else - { - if (!(p->head && p->head->isStartOfInputNode())) - { - NFANode * n = p->registerNode(new NFAStartNode); - n->next = p->head; - p->head = n; - } - end->next = p->registerNode(new NFAEndNode); - } - } - if (p != NULL) - { - p->matcher = new Matcher(p, ""); - } - - return p; -} - -Pattern * Pattern::compileAndKeep(const bkstring & pattern, const unsigned long mode) -{ - Pattern * ret = NULL; - std::map::iterator it = compiledPatterns.find(pattern); - - if (it != compiledPatterns.end()) - { - ret = it->second; - } - else - { - ret = compile(pattern, mode); - compiledPatterns[pattern] = ret; - } - - return ret; -} -bkstring Pattern::replace(const bkstring & pattern, const bkstring & str, - const bkstring & replacementText, const unsigned long mode) -{ - bkstring ret; - Pattern * p = Pattern::compile(pattern, mode); - if (p) - { - ret = p->replace(str, replacementText); - delete p; - } - return ret; -} - -std::vector Pattern::split(const bkstring & pattern, const bkstring & str, const bool keepEmptys, - const unsigned long limit, const unsigned long mode) -{ - std::vector ret; - Pattern * p = Pattern::compile(pattern, mode); - if (p) - { - ret = p->split(str, keepEmptys, limit); - delete p; - } - return ret; -} - -std::vector Pattern::findAll(const bkstring & pattern, const bkstring & str, const unsigned long mode) -{ - std::vector ret; - Pattern * p = Pattern::compile(pattern, mode); - if (p) - { - ret = p->findAll(str); - delete p; - } - return ret; -} - -bool Pattern::matches(const bkstring & pattern, const bkstring & str, const unsigned long mode) -{ - bool ret = 0; - Pattern * p = compile(pattern, mode); - - if (p) - { - ret = p->matches(str); - delete p; - } - - return ret; -} - -bool Pattern::registerPattern(const bkstring & name, const bkstring & pattern, const unsigned long mode) -{ - Pattern * p = Pattern::compile(pattern, mode); - if (!p) return 0; - Pattern::registeredPatterns[name] = std::make_pair(pattern, mode); - delete p; - return 1; -} - -void Pattern::unregisterPatterns() -{ - registeredPatterns.clear(); -} -void Pattern::clearPatternCache() -{ - std::map::iterator it; - for (it = compiledPatterns.begin(); it != compiledPatterns.end(); ++it) - { - delete it->second; - } - compiledPatterns.clear(); -} - -std::pair Pattern::findNthMatch(const bkstring & pattern, const bkstring & str, - const int matchNum, const unsigned long mode) -{ - std::pair ret; - Pattern * p = Pattern::compile(pattern, mode); - - ret.second = -1; - if (p) - { - int i = -1; - p->matcher->setString(str); - while (i < matchNum && p->matcher->findNextMatch()) { ++i; } - if (i == matchNum && p->matcher->getStartingIndex() >= 0) - { - ret.first = p->matcher->getGroup(0); - ret.second = p->matcher->getStartingIndex(); - } - delete p; - } - - return ret; -} - -Pattern::~Pattern() -{ - if (matcher) delete matcher; - for (std::map::iterator it = nodes.begin(); it != nodes.end(); ++it) - { - delete it->first; - } -} -bkstring Pattern::replace(const bkstring & str, const bkstring & replacementText) -{ - int li = 0; - bkstring ret = ""; - - matcher->setString(str); - while (matcher->findNextMatch()) - { - ret += str.substr(li, matcher->getStartingIndex() - li); - ret += matcher->replaceWithGroups(replacementText); - li = matcher->getEndingIndex(); - } - ret += str.substr(li); - - return ret; -} -std::vector Pattern::split(const bkstring & str, const bool keepEmptys, const unsigned long limit) -{ - unsigned long lim = (limit == 0 ? MAX_QMATCH : limit); - int li = 0; - std::vector ret; - - matcher->setString(str); - - while (matcher->findNextMatch() && ret.size() < lim) - { - if (matcher->getStartingIndex() == 0 && keepEmptys) ret.push_back(""); - if ((matcher->getStartingIndex() != matcher->getEndingIndex()) || keepEmptys) - { - if (li != matcher->getStartingIndex() || keepEmptys) - { - ret.push_back(str.substr(li, matcher->getStartingIndex() - li)); - } - li = matcher->getEndingIndex(); - } - } - if (li < (int)str.size()) ret.push_back(str.substr(li)); - - return ret; -} -std::vector Pattern::findAll(const bkstring & str) -{ - matcher->setString(str); - return matcher->findAll(); -} -bool Pattern::matches(const bkstring & str) -{ - matcher->setString(str); - return matcher->matches(); -} -unsigned long Pattern::getFlags() const -{ - return flags; -} -bkstring Pattern::getPattern() const -{ - return pattern; -} -Matcher * Pattern::createMatcher(const bkstring & str) -{ - return new Matcher(this, str); -} - -// NFANode - -NFANode::NFANode() { next = NULL; } -NFANode::~NFANode() { } -void NFANode::findAllNodes(std::map & soFar) -{ - if (soFar.find(this) == soFar.end()) return; - soFar[this] = 1; - if (next) next->findAllNodes(soFar); -} - -// NFACharNode - -NFACharNode::NFACharNode(const char c) { ch = c; } -int NFACharNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd < (int)str.size() && str[curInd] == ch) return next->match(str, matcher, curInd + 1); - return -1; -} - -// NFACICharNode - -NFACICharNode::NFACICharNode(const char c) { ch = to_lower(c); } -int NFACICharNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd < (int)str.size() && to_lower(str[curInd]) == ch) return next->match(str, matcher, curInd + 1); - return -1; -} - -// NFAStartNode - -NFAStartNode::NFAStartNode() { } -int NFAStartNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int ret = -1, ci = curInd; - - matcher->starts[0] = curInd; - if ((matcher->getFlags() & Matcher::MATCH_ENTIRE_STRING) == (unsigned int)Matcher::MATCH_ENTIRE_STRING) - { - if (curInd != 0) - { - matcher->starts[0] = -1; - return -1; - } - return next->match(str, matcher, 0); - } - while ((ret = next->match(str, matcher, ci)) == -1 && ci < (int)str.size()) - { - matcher->clearGroups(); - matcher->starts[0] = ++ci; - } - if (ret < 0) matcher->starts[0] = -1; - return ret; -} - -// NFAEndNode - -NFAEndNode::NFAEndNode() { } -int NFAEndNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - matcher->ends[0] = curInd; - if ((matcher->getFlags() & Matcher::MATCH_ENTIRE_STRING) != 0) - { - if (curInd == (int)str.size()) return curInd; - matcher->ends[0] = -1; - return -1; - } - return curInd; -} - -// NFAQuantifierNode - -void NFAQuantifierNode::findAllNodes(std::map & soFar) -{ - inner->findAllNodes(soFar); - NFANode::findAllNodes(soFar); -} -NFAQuantifierNode::NFAQuantifierNode(Pattern * pat, NFANode * internal, const int minMatch, const int maxMatch) -{ - inner = internal; - inner->next = pat->registerNode(new NFAAcceptNode); - min = (minMatch < Pattern::MIN_QMATCH) ? Pattern::MIN_QMATCH : minMatch; - max = (maxMatch > Pattern::MAX_QMATCH) ? Pattern::MAX_QMATCH : maxMatch; -} - -int NFAQuantifierNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int i0, i1, i2 = 0; - - i0 = i1 = curInd; - while (i2 < min) - { - - ++i2; - i1 = inner->match(str, matcher, i0); - if (i1 <= i0) return i1; // i1 < i0 means i1 is -1 - i0 = i1; - } - - return i1; -} -// NFAGreedyQuantifierNode - -NFAGreedyQuantifierNode::NFAGreedyQuantifierNode(Pattern * pat, NFANode * internal, const int minMatch, const int maxMatch) - : NFAQuantifierNode(pat, internal, minMatch, maxMatch) { } -int NFAGreedyQuantifierNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int t = NFAQuantifierNode::match(str, matcher, curInd); - if (t != -1) return matchInternal(str, matcher, t, min); - return t; -} -int NFAGreedyQuantifierNode::matchInternal(const bkstring & str, Matcher * matcher, const int curInd, const int soFar) const -{ - if (soFar >= max) return next->match(str, matcher, curInd); - - int i, j; - - i = inner->match(str, matcher, curInd); - if (i != -1) - { - j = matchInternal(str, matcher, i, soFar + 1); - if (j != -1) return j; - } - return next->match(str, matcher, curInd); -} - -// NFALazyQuantifierNode - -NFALazyQuantifierNode::NFALazyQuantifierNode(Pattern * pat, NFANode * internal, const int minMatch, const int maxMatch) - : NFAQuantifierNode(pat, internal, minMatch, maxMatch) { } -int NFALazyQuantifierNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int i, j, m = NFAQuantifierNode::match(str, matcher, curInd); - - if (m == -1) return -1; - - for (i = min; i < max; ++i) - { - j = next->match(str, matcher, m); - if (j == -1) - { - j = inner->match(str, matcher, m); - // if j < m, then j is -1, so we bail. - // if j == m, then we would just go and call next->match on the same index, - // but it already failed trying to match right there, so we know we can - // just bail - if (j <= m) return -1; - m = j; - } - else return j; - } - return next->match(str, matcher, m); -} - -// NFAPossessiveQuantifierNode - -NFAPossessiveQuantifierNode::NFAPossessiveQuantifierNode(Pattern * pat, NFANode * internal, const int minMatch, const int maxMatch) - : NFAQuantifierNode(pat, internal, minMatch, maxMatch) { } -int NFAPossessiveQuantifierNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int i, j, m = NFAQuantifierNode::match(str, matcher, curInd); - - if (m == -1) return -1; - for (i = min; i < max; ++i) - { - j = inner->match(str, matcher, m); - if (j <= m) return next->match(str, matcher, m); - m = j; - } - return next->match(str, matcher, m); -} - -// NFAAcceptNode - -NFAAcceptNode::NFAAcceptNode() { } -int NFAAcceptNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (!next) return curInd; - else return next->match(str, matcher, curInd); -} - -// NFAClassNode - -NFAClassNode::NFAClassNode(const bool invert) -{ - inv = invert; -} -NFAClassNode::NFAClassNode(const bkstring & clazz, const bool invert) -{ - inv = invert; - for (int i = 0; i < (int)clazz.size(); ++i) vals[clazz[i]] = 1; -} -int NFAClassNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd < (int)str.size() && ((vals.find(str[curInd]) != vals.end()) ^ inv)) - { - return next->match(str, matcher, curInd + 1); - } - return -1; -} - -// NFACIClassNode - -NFACIClassNode::NFACIClassNode(const bool invert) -{ - inv = invert; -} -NFACIClassNode::NFACIClassNode(const bkstring & clazz, const bool invert) -{ - inv = invert; - for (int i = 0; i < (int)clazz.size(); ++i) vals[to_lower(clazz[i])] = 1; -} -int NFACIClassNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd < (int)str.size() && ((vals.find(to_lower(str[curInd])) != vals.end()) ^ inv)) - { - return next->match(str, matcher, curInd + 1); - } - return -1; -} - -// NFASubStartNode - -NFASubStartNode::NFASubStartNode() { } -int NFASubStartNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - return next->match(str, matcher, curInd); -} - -// NFAOrNode - -NFAOrNode::NFAOrNode(NFANode * first, NFANode * second) : one(first), two(second) { } -void NFAOrNode::findAllNodes(std::map & soFar) -{ - if (one) one->findAllNodes(soFar); - if (two) two->findAllNodes(soFar); - NFANode::findAllNodes(soFar); -} -int NFAOrNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int ci = one->match(str, matcher, curInd); - - if (ci != -1) ci = next->match(str, matcher, ci); - if (ci != -1) return ci; - if (ci == -1) ci = two->match(str, matcher, curInd); - if (ci != -1) ci = next->match(str, matcher, ci); - return ci; -} - -// NFAQuoteNode - -NFAQuoteNode::NFAQuoteNode(const bkstring & quoted) : qStr(quoted) { } -int NFAQuoteNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd + qStr.size() > str.size()) return -1; - if (str.substr(curInd, qStr.size()) != qStr) return -1; - return next->match(str, matcher, curInd + qStr.size()); -} - -// NFACIQuoteNode - -NFACIQuoteNode::NFACIQuoteNode(const bkstring & quoted) : qStr(quoted) { } -int NFACIQuoteNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd + qStr.size() > str.size()) return -1; - if (str_icmp(str.substr(curInd, qStr.size()).c_str(), qStr.c_str())) return -1; - return next->match(str, matcher, qStr.size()); -} - -// NFALookAheadNode - -NFALookAheadNode::NFALookAheadNode(NFANode * internal, const bool positive) : NFANode(), pos(positive), inner(internal) { } -void NFALookAheadNode::findAllNodes(std::map & soFar) -{ - if (inner) inner->findAllNodes(soFar); - NFANode::findAllNodes(soFar); -} -int NFALookAheadNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - return ((inner->match(str, matcher, curInd) == -1) ^ pos) ? next->match(str, matcher, curInd) : -1; -} - -// NFALookBehindNode - -NFALookBehindNode::NFALookBehindNode(const bkstring & str, const bool positive) : pos(positive), mStr(str) { } -int NFALookBehindNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (pos) - { - if (curInd < (int)mStr.size()) return -1; - if (str.substr(curInd - mStr.size(), mStr.size()) == mStr) return next->match(str, matcher, curInd); - } - else - { - if (curInd < (int)mStr.size()) return next->match(str, matcher, curInd); - if (str.substr(curInd - mStr.size(), mStr.size()) == mStr) return -1; - return next->match(str, matcher, curInd); - } - return -1; -} - -// NFAStartOfLineNode - -NFAStartOfLineNode::NFAStartOfLineNode() { } -int NFAStartOfLineNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd == 0 || str[curInd - 1] == '\n' || str[curInd - 1] == '\r') - { - return next->match(str, matcher, curInd); - } - return -1; -} - -// NFAEndOfLineNode - -NFAEndOfLineNode::NFAEndOfLineNode() { } -int NFAEndOfLineNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd >= (int)str.size() || str[curInd] == '\n' || str[curInd] == '\r') - { - return next->match(str, matcher, curInd); - } - return -1; -} - -// NFAReferenceNode - -NFAReferenceNode::NFAReferenceNode(const int groupIndex) : gi(groupIndex) { } -int NFAReferenceNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int len = matcher->ends[gi] - matcher->starts[gi]; - int ni = -1; - if (gi < 1 || matcher->ends[gi] < matcher->starts[gi] || len == 0) ni = curInd; - else if (curInd + len > (int)str.size()) return -1; - else if (str.substr(curInd, len) != str.substr(matcher->starts[gi], len)) return -1; - else ni = curInd + len; - - return next->match(str, matcher, ni); -} - -// NFAStartOfInputNode - -NFAStartOfInputNode::NFAStartOfInputNode() { } -int NFAStartOfInputNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd == 0) return next->match(str, matcher, curInd); - return -1; -} - -// NFAEndOfInputNode - -NFAEndOfInputNode::NFAEndOfInputNode(const bool lookForTerm) : term(lookForTerm) { } -int NFAEndOfInputNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int len = (int)str.size(); - if (curInd == len) return next->match(str, matcher, curInd); - else if (term) - { - if (curInd == len - 1 && (str[curInd] == '\r' || str[curInd] == '\n')) - { - return next->match(str, matcher, curInd); - } - else if (curInd == len - 2 && str.substr(curInd, 2) == "\r\n") - { - return next->match(str, matcher, curInd); - } - } - return -1; -} - -// NFAWordBoundaryNode - -NFAWordBoundaryNode::NFAWordBoundaryNode(const bool positive) : pos(positive) { } -int NFAWordBoundaryNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int len = (int)str.size(); - - char c1 = (curInd - 1 < len && curInd > 0) ? str[curInd - 1] : '\n'; - char c2 = (curInd < len) ? str[curInd ] : '\n'; - - if (curInd == len) return next->match(str, matcher, curInd); - bool ok = is_alpha(c1) != is_alpha(c2); - if (ok && pos) return next->match(str, matcher, curInd); - return -1; -} - -// NFAEndOfMatchNode - -NFAEndOfMatchNode::NFAEndOfMatchNode() { } -int NFAEndOfMatchNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - if (curInd == matcher->lm) return next->match(str, matcher, curInd); - return -1; -} - -// NFAGroupHeadNode - -NFAGroupHeadNode::NFAGroupHeadNode(const int groupIndex) : gi(groupIndex) { } -int NFAGroupHeadNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int ret, o = matcher->starts[gi]; - - matcher->starts[gi] = curInd; - ret = next->match(str, matcher, curInd); - if (ret < 0) matcher->starts[gi] = o; - - return ret; -} - -// NFAGroupTailNode - -NFAGroupTailNode::NFAGroupTailNode(const int groupIndex) : gi(groupIndex) { } -int NFAGroupTailNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int ret, o = matcher->ends[gi]; - - matcher->ends[gi] = curInd; - ret = next->match(str, matcher, curInd); - if (ret < 0) matcher->ends[gi] = o; - - return ret; -} - -// NFAGroupLoopPrologueNode - -NFAGroupLoopPrologueNode::NFAGroupLoopPrologueNode(const int groupIndex) : gi(groupIndex) { } -int NFAGroupLoopPrologueNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int ret, o1 = matcher->groups[gi], o2 = matcher->groupPos[gi], o3 = matcher->groupIndeces[gi]; - - matcher->groups[gi] = 0; - matcher->groupPos[gi] = 0; - matcher->groupIndeces[gi] = -1; - ret = next->match(str, matcher, curInd); - if (ret < 0) - { - matcher->groups[gi] = o1; - matcher->groupPos[gi] = o2; - matcher->groupIndeces[gi] = o3; - } - - return ret; -} - -// NFAGroupLoopNode - -NFAGroupLoopNode::NFAGroupLoopNode(NFANode * internal, const int minMatch, const int maxMatch, - const int groupIndex, const int matchType) -{ - inner = internal; - min = minMatch; - max = maxMatch; - gi = groupIndex; - type = matchType; -} -void NFAGroupLoopNode::findAllNodes(std::map & soFar) -{ - if (inner) inner->findAllNodes(soFar); - NFANode::findAllNodes(soFar); -} -int NFAGroupLoopNode::match(const bkstring & str, Matcher * matcher, const int curInd) const -{ - bool b = (curInd > matcher->groupIndeces[gi]); - - if (b && matcher->groups[gi] < min) - { - ++matcher->groups[gi]; - int o = matcher->groupIndeces[gi]; - matcher->groupIndeces[gi] = curInd; - int ret = inner->match(str, matcher, curInd); - if (ret < 0) - { - matcher->groupIndeces[gi] = o; - --matcher->groups[gi]; - } - return ret; - } - else if (!b || matcher->groups[gi] >= max) - { - return next->match(str, matcher, curInd); - } - else - { - switch (type) - { - case 0: return matchGreedy(str, matcher, curInd); - case 1: return matchLazy(str, matcher, curInd); - case 2: return matchPossessive(str, matcher, curInd); - } - } - return -1; -} -int NFAGroupLoopNode::matchGreedy(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int o = matcher->groupIndeces[gi]; // save our info for backtracking - matcher->groupIndeces[gi] = curInd; // move along - ++matcher->groups[gi]; - int ret = inner->match(str, matcher, curInd); // match internally - if (ret < 0) - { // if we failed, then restore info and match next - --matcher->groups[gi]; - matcher->groupIndeces[gi] = o; - ret = next->match(str, matcher, curInd); - } - return ret; -} -int NFAGroupLoopNode::matchLazy(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int ret = next->match(str, matcher, curInd); // be lazy, just go on - if (ret < 0) - { - int o = matcher->groupIndeces[gi]; // save info for backtracking - matcher->groupIndeces[gi] = curInd; // advance our position - ++matcher->groups[gi]; - ret = inner->match(str, matcher, curInd); // match our internal stuff - if (ret < 0) // if we failed, then restore the info - { - --matcher->groups[gi]; - matcher->groupIndeces[gi] = o; - } - } - return ret; -} -int NFAGroupLoopNode::matchPossessive(const bkstring & str, Matcher * matcher, const int curInd) const -{ - int o = matcher->groupIndeces[gi]; // save info for backtracking - matcher->groupPos[gi] = matcher->groups[gi]; // set a flag stating we have matcher at least this much - matcher->groupIndeces[gi] = curInd; // move along - ++matcher->groups[gi]; - int ret = inner->match(str, matcher, curInd); // try and match again - if (ret < 0) - { // if we fail, back off, but to an extent - --matcher->groups[gi]; - matcher->groupIndeces[gi] = o; - if (matcher->groups[gi] == matcher->groupPos[gi]) ret = next->match(str, matcher, curInd); - } - return ret; -} - -#ifdef _WIN32 - #pragma warning(pop) -#endif diff --git a/plugins/SmileyAdd/regexp/Pattern.h b/plugins/SmileyAdd/regexp/Pattern.h deleted file mode 100644 index bb16ad90fa..0000000000 --- a/plugins/SmileyAdd/regexp/Pattern.h +++ /dev/null @@ -1,1663 +0,0 @@ -#ifndef __PATTERN_H__ -#define __PATTERN_H__ - -#ifdef _WIN32 - #pragma warning(disable:4786) -#endif - -#include -#include - -#include "bkstring.h" - -class Matcher; -class NFANode; -class NFAQuantifierNode; - -/** - This pattern class is very similar in functionality to Java's - java.util.regex.Pattern class. The pattern class represents an immutable - regular expression object. Instead of having a single object contain both the - regular expression object and the matching object, instead the two objects are - split apart. The {@link Matcher Matcher} class represents the maching - object. - - The Pattern class works primarily off of "compiled" patterns. A typical - instantiation of a regular expression looks like: - -

-  Pattern * p = Pattern::compile("a*b");
-  Matcher * m = p->createMatcher("aaaaaab");
-  if (m->matches()) ...
-  
- - However, if you do not need to use a pattern more than once, it is often times - okay to use the Pattern's static methods insteads. An example looks like this: - -
-  if (Pattern::matches("a*b", "aaaab")) { ... }
-  
- - This class does not currently support unicode. The unicode update for this - class is coming soon. - - This class is partially immutable. It is completely safe to call createMatcher - concurrently in different threads, but the other functions (e.g. split) should - not be called concurrently on the same Pattern. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Construct - - Matches - -
-   -
- Characters -
- x - - The character x -
- \\ - - The character \ -
- \0nn - - The character with octal ASCII value nn -
- \0nnn - - The character with octal ASCII value nnn -
- \xhh - - The character with hexadecimal ASCII value hh -
- \t - - A tab character -
- \r - - A carriage return character -
- \n - - A new-line character -
-   -
- Character Classes -
- [abc] - - Either a, b, or c -
- [^abc] - - Any character but a, b, or c -
- [a-zA-Z] - - Any character ranging from a thru z, or - A thru Z -
- [^a-zA-Z] - - Any character except those ranging from a thru - z, or A thru Z -
- [a\-z] - - Either a, -, or z -
- [a-z[A-Z]] - - Same as [a-zA-Z] -
- [a-z&&[g-i]] - - Any character in the intersection of a-z and - g-i -
- [a-z&&[^g-i]] - - Any character in a-z and not in g-i -
-   -
- Prefefined character classes -
- . - - Any character. Multiline matching must be compiled into the pattern for - . to match a \r or a \n. - Even if multiline matching is enabled, . will not - match a \r\n, only a \r or a \n. -
- \d - - [0-9] -
- \D - - [^\d] -
- \s - - [ \t\r\n\x0B] -
- \S - - [^\s] -
- \w - - [a-zA-Z0-9_] -
- \W - - [^\w] -
-   -
- POSIX character classes -
- \p{Lower} - - [a-z] -
- \p{Upper} - - [A-Z] -
- \p{ASCII} - - [\x00-\x7F] -
- \p{Alpha} - - [a-zA-Z] -
- \p{Digit} - - [0-9] -
- \p{Alnum} - - [\w&&[^_]] -
- \p{Punct} - - [!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~] -
- \p{XDigit} - - [a-fA-F0-9] -
-   -
- Boundary Matches -
- ^ - - The beginning of a line. Also matches the beginning of input. -
- $ - - The end of a line. Also matches the end of input. -
- \b - - A word boundary -
- \B - - A non word boundary -
- \A - - The beginning of input -
- \G - - The end of the previous match. Ensures that a "next" match will only - happen if it begins with the character immediately following the end of - the "current" match. -
- \Z - - The end of input. Will also match if there is a single trailing - \r\n, a single trailing \r, or a single - trailing \n. -
- \z - - The end of input -
-   -
- Greedy Quantifiers -
- x? - - x, either zero times or one time -
- x* - - x, zero or more times -
- x+ - - x, one or more times -
- x{n} - - x, exactly n times -
- x{n,} - - x, at least n times -
- x{,m} - - x, at most m times -
- x{n,m} - - x, at least n times and at most - m times -
-   -
- Possessive Quantifiers -
- x?+ - - x, either zero times or one time -
- x*+ - - x, zero or more times -
- x++ - - x, one or more times -
- x{n}+ - - x, exactly n times -
- x{n,}+ - - x, at least n times -
- x{,m}+ - - x, at most m times -
- x{n,m}+ - - x, at least n times and at most - m times -
-   -
- Reluctant Quantifiers -
- x?? - - x, either zero times or one time -
- x*? - - x, zero or more times -
- x+? - - x, one or more times -
- x{n}? - - x, exactly n times -
- x{n,}? - - x, at least n times -
- x{,m}? - - x, at most m times -
- x{n,m}? - - x, at least n times and at most - m times -
-   -
- Operators -
- xy - - x then y -
- x|y - - x or y -
- (x) - - x as a capturing group -
-   -
- Quoting -
- \Q - - Nothing, but treat every character (including \s) literally until a - matching \E -
- \E - - Nothing, but ends its matching \Q -
-   -
- Special Constructs -
- (?:x) - - x, but not as a capturing group -
- (?=x) - - x, via positive lookahead. This means that the - expression will match only if it is trailed by x. - It will not "eat" any of the characters matched by - x. -
- (?!x) - - x, via negative lookahead. This means that the - expression will match only if it is not trailed by - x. It will not "eat" any of the characters - matched by x. -
- (?<=x) - - x, via positive lookbehind. x - cannot contain any quantifiers. -
- (?x) - - x, via negative lookbehind. x - cannot contain any quantifiers. -
- (?>x) - - x{1}+ -
-   -
- Registered Expression Matching -
- {x} - - The registered pattern x -
- -
- - Begin Text Extracted And Modified From java.util.regex.Pattern documentation - -

Backslashes, escapes, and quoting

- -

The backslash character ('\') serves to introduce escaped - constructs, as defined in the table above, as well as to quote characters - that otherwise would be interpreted as unescaped constructs. Thus the - expression \\ matches a single backslash and \{ matches a - left brace. - -

It is an error to use a backslash prior to any alphabetic character that - does not denote an escaped construct; these are reserved for future - extensions to the regular-expression language. A backslash may be used - prior to a non-alphabetic character regardless of whether that character is - part of an unescaped construct. - -

It is necessary to double backslashes in string literals that represent - regular expressions to protect them from interpretation by a compiler. The - string literal "\b", for example, matches a single backspace - character when interpreted as a regular expression, while - "\\b" matches a word boundary. The string litera - "\(hello\)" is illegal and leads to a compile-time error; - in order to match the string (hello) the string literal - "\\(hello\\)" must be used. - -

Character Classes

- -

Character classes may appear within other character classes, and - may be composed by the union operator (implicit) and the intersection - operator (&&). - The union operator denotes a class that contains every character that is - in at least one of its operand classes. The intersection operator - denotes a class that contains every character that is in both of its - operand classes. - -

The precedence of character-class operators is as follows, from - highest to lowest: - -

- - - - - - - - - - - - - - - - -
1    Literal escape    \x
2    Rangea-z
3    Grouping[...]
4    Intersection[a-z&&[aeiou]]
5    Union[a-e][i-u]
- -

Note that a different set of metacharacters are in effect inside - a character class than outside a character class. For instance, the - regular expression . loses its special meaning inside a - character class, while the expression - becomes a range - forming metacharacter. - - - - -

Groups and capturing

- -

Capturing groups are numbered by counting their opening parentheses from - left to right. In the expression ((A)(B(C))), for example, there - are four such groups:

- -
- - - - - - - - - - -
1    ((A)(B(C)))
2    (A)
3    (B(C))
4    (C)
- -

Group zero always stands for the entire expression. - -

Capturing groups are so named because, during a match, each subsequence - of the input sequence that matches such a group is saved. The captured - subsequence may be used later in the expression, via a back reference, and - may also be retrieved from the matcher once the match operation is complete. - -

The captured input associated with a group is always the subsequence - that the group most recently matched. If a group is evaluated a second time - because of quantification then its previously-captured value, if any, will - be retained if the second evaluation fails. Matching the string - "aba" against the expression (a(b)?)+, for example, leaves - group two set to "b". All captured input is discarded at the - beginning of each match. - -

Groups beginning with (? are pure, non-capturing groups - that do not capture text and do not count towards the group total. - - -

Unicode support

- -

Coming Soon. - -

Comparison to Perl 5

- -

The Pattern engine performs traditional NFA-based matching - with ordered alternation as occurs in Perl 5. - -

Perl constructs not supported by this class:

- -
    - -
  • The conditional constructs (?{X}) and - (?(condition)X|Y), -

  • - -
  • The embedded code constructs (?{code}) - and (??{code}),

  • - -
  • The embedded comment syntax (?#comment), and

  • - -
  • The preprocessing operations \l \u, - \L, and \U.

  • - -
  • Embedded flags

  • - -
- -

Constructs supported by this class but not by Perl:

- -
    - -
  • Possessive quantifiers, which greedily match as much as they can - and do not back off, even when doing so would allow the overall match to - succeed.

  • - -
  • Character-class union and intersection as described - above.

  • - -
- -

Notable differences from Perl:

- -
    - -
  • In Perl, \1 through \9 are always interpreted - as back references; a backslash-escaped number greater than 9 is - treated as a back reference if at least that many subexpressions exist, - otherwise it is interpreted, if possible, as an octal escape. In this - class octal escapes must always begin with a zero. In this class, - \1 through \9 are always interpreted as back - references, and a larger number is accepted as a back reference if at - least that many subexpressions exist at that point in the regular - expression, otherwise the parser will drop digits until the number is - smaller or equal to the existing number of groups or it is one digit. -

  • - -
  • Perl uses the g flag to request a match that resumes - where the last match left off. This functionality is provided implicitly - by the Matcher class: Repeated invocations of the - find method will resume where the last match left off, - unless the matcher is reset.

  • - -
  • Perl is forgiving about malformed matching constructs, as in the - expression *a, as well as dangling brackets, as in the - expression abc], and treats them as literals. This - class also strict and will not compile a pattern when dangling characters - are encountered.

  • - -
- - -

For a more precise description of the behavior of regular expression - constructs, please see - Mastering Regular Expressions, 2nd Edition, Jeffrey E. F. Friedl, - O'Reilly and Associates, 2002. -

-

- - End Text Extracted And Modified From java.util.regex.Pattern documentation - -


- - @author Jeffery Stuart - @since March 2003, Stable Since November 2004 - @version 1.07.00 - @memo A class used to represent "PERL 5"-ish regular expressions - */ -class Pattern -{ - friend class Matcher; - friend class NFANode; - friend class NFAQuantifierNode; - private: - /** - This constructor should not be called directly. Those wishing to use the - Pattern class should instead use the {@link compile compile} method. - - @param rhs The pattern to compile - @memo Creates a new pattern from the regular expression in rhs. - */ - Pattern(const bkstring & rhs); - protected: - /** - This currently is not used, so don't try to do anything with it. - @memo Holds all the compiled patterns for quick access. - */ - static std::map compiledPatterns; - /** - Holds all of the registered patterns as strings. Due to certain problems - with compilation of patterns, especially with capturing groups, this seemed - to be the best way to do it. - */ - static std::map > registeredPatterns; - protected: - /** - Holds all the NFA nodes used. This makes deletion of a pattern, as well as - clean-up from an unsuccessful compile much easier and faster. - */ - std::map nodes; - /** - Used when methods like split are called. The matcher class uses a lot of - dynamic memeory, so having an instance increases speedup of certain - operations. - */ - Matcher * matcher; - /** - The front node of the NFA. - */ - NFANode * head; - /** - The actual regular expression we rerpesent - */ - bkstring pattern; - /** - Flag used during compilation. Once the pattern is successfully compiled, - error is no longer used. - */ - bool error; - /** - Used during compilation to keep track of the current index into - {@link pattern pattern}. Once the pattern is successfully - compiled, error is no longer used. - */ - int curInd; - /** - The number of capture groups this contains. - */ - int groupCount; - /** - The number of non-capture groups this contains. - */ - int nonCapGroupCount; - /** - The flags specified when this was compiled. - */ - unsigned long flags; - protected: - /** - Raises an error during compilation. Compilation will cease at that point - and compile will return NULL. - */ - void raiseError(); - /** - Convenience function for registering a node in nodes. - @param node The node to register - @return The registered node - */ - NFANode * registerNode(NFANode * node); - - /** - Calculates the union of two strings. This function will first sort the - strings and then use a simple selection algorithm to find the union. - @param s1 The first "class" to union - @param s2 The second "class" to union - @return A new string containing all unique characters. Each character - must have appeared in one or both of s1 and - s2. - */ - bkstring classUnion (bkstring s1, bkstring s2) const; - /** - Calculates the intersection of two strings. This function will first sort - the strings and then use a simple selection algorithm to find the - intersection. - @param s1 The first "class" to intersect - @param s2 The second "class" to intersect - @return A new string containing all unique characters. Each character - must have appeared both s1 and s2. - */ - bkstring classIntersect (bkstring s1, bkstring s2) const; - /** - Calculates the negation of a string. The negation is the set of all - characters between \x00 and \xFF not - contained in s1. - @param s1 The "class" to be negated. - @param s2 The second "class" to intersect - @return A new string containing all unique characters. Each character - must have appeared both s1 and s2. - */ - bkstring classNegate (bkstring s1) const; - /** - Creates a new "class" representing the range from low thru - hi. This function will wrap if low > - hi. This is a feature, not a buf. Sometimes it is useful - to be able to say [\x70-\x10] instead of [\x70-\x7F\x00-\x10]. - @param low The beginning character - @param hi The ending character - @return A new string containing all the characters from low thru hi. - */ - bkstring classCreateRange(char low, char hi) const; - - /** - Extracts a decimal number from the substring of member-variable - {@link pattern pattern} starting at start and - ending at end. - @param start The starting index in {@link pattern pattern} - @param end The last index in {@link pattern pattern} - @return The decimal number in {@link pattern pattern} - */ - int getInt(int start, int end); - /** - Parses a {n,m} string out of the member-variable - {@link pattern pattern} stores the result in sNum - and eNum. - @param sNum Output parameter. The minimum number of matches required - by the curly quantifier are stored here. - @param eNum Output parameter. The maximum number of matches allowed - by the curly quantifier are stored here. - @return Success/Failure. Fails when the curly does not have the proper - syntax - */ - bool quantifyCurly(int & sNum, int & eNum); - /** - Tries to quantify the currently parsed group. If the group being parsed - is indeed quantified in the member-variable - {@link pattern pattern}, then the NFA is modified accordingly. - @param start The starting node of the current group being parsed - @param stop The ending node of the current group being parsed - @param gn The group number of the current group being parsed - @return The node representing the starting node of the group. If the - group becomes quantified, then this node is not necessarily - a GroupHead node. - */ - NFANode * quantifyGroup(NFANode * start, NFANode * stop, const int gn); - - /** - Tries to quantify the last parsed expression. If the character was indeed - quantified, then the NFA is modified accordingly. - @param newNode The recently created expression node - @return The node representing the last parsed expression. If the - expression was quantified, return value != newNode - */ - NFANode * quantify(NFANode * newNode); - /** - Parses the current class being examined in - {@link pattern pattern}. - @return A string of unique characters contained in the current class being - parsed - */ - bkstring parseClass(); - /** - Parses the current POSIX class being examined in - {@link pattern pattern}. - @return A string of unique characters representing the POSIX class being - parsed - */ - bkstring parsePosix(); - /** - Returns a string containing the octal character being parsed - @return The string contained the octal value being parsed - */ - bkstring parseOctal(); - /** - Returns a string containing the hex character being parsed - @return The string contained the hex value being parsed - */ - bkstring parseHex(); - /** - Returns a new node representing the back reference being parsed - @return The new node representing the back reference being parsed - */ - NFANode * parseBackref(); - /** - Parses the escape sequence currently being examined. Determines if the - escape sequence is a class, a single character, or the beginning of a - quotation sequence. - @param inv Output parameter. Whether or not to invert the returned class - @param quo Output parameter. Whether or not this sequence starts a - quotation. - @return The characters represented by the class - */ - bkstring parseEscape(bool & inv, bool & quo); - /** - Parses a supposed registered pattern currently under compilation. If the - sequence of characters does point to a registered pattern, then the - registered pattern is appended to *end. The registered pattern - is parsed with the current compilation flags. - @param end The ending node of the thus-far compiled pattern - @return The new end node of the current pattern - */ - NFANode * parseRegisteredPattern(NFANode ** end); - /** - Parses a lookbehind expression. Appends the necessary nodes - *end. - @param pos Positive or negative look behind - @param end The ending node of the current pattern - @return The new end node of the current pattern - */ - NFANode * parseBehind(const bool pos, NFANode ** end); - /** - Parses the current expression and tacks on nodes until a \E is found. - @return The end of the current pattern - */ - NFANode * parseQuote(); - /** - Parses {@link pattern pattern}. This function is called - recursively when an or (|) or a group is encountered. - @param inParen Are we currently parsing inside a group - @param inOr Are we currently parsing one side of an or (|) - @param end The end of the current expression - @return The starting node of the NFA constructed from this parse - */ - NFANode * parse(const bool inParen = 0, const bool inOr = 0, NFANode ** end = NULL); - public: - /// We should match regardless of case - const static unsigned long CASE_INSENSITIVE; - /// We are implicitly quoted - const static unsigned long LITERAL; - /// @memo We should treat a . as [\x00-\x7F] - const static unsigned long DOT_MATCHES_ALL; - /** ^ and $ should anchor to the beginning and - ending of lines, not all input - */ - const static unsigned long MULTILINE_MATCHING; - /** When enabled, only instances of \n are recognized as - line terminators - */ - const static unsigned long UNIX_LINE_MODE; - /// The absolute minimum number of matches a quantifier can match (0) - const static int MIN_QMATCH; - /// The absolute maximum number of matches a quantifier can match (0x7FFFFFFF) - const static int MAX_QMATCH; - public: - /** - Call this function to compile a regular expression into a - Pattern object. Special values can be assigned to - mode when certain non-standard behaviors are expected from - the Pattern object. - @param pattern The regular expression to compile - @param mode A bitwise or of flags signalling what special behaviors are - wanted from this Pattern object - @return If successful, compile returns a Pattern - pointer. Upon failure, compile returns - NULL - */ - static Pattern * compile (const bkstring & pattern, - const unsigned long mode = 0); - /** - Dont use this function. This function will compile a pattern, and cache - the result. This will eventually be used as an optimization when people - just want to call static methods using the same pattern over and over - instead of first compiling the pattern and then using the compiled - instance for matching. - @param pattern The regular expression to compile - @param mode A bitwise or of flags signalling what special behaviors are - wanted from this Pattern object - @return If successful, compileAndKeep returns a - Pattern pointer. Upon failure, compile - returns NULL. - */ - static Pattern * compileAndKeep (const bkstring & pattern, - const unsigned long mode = 0); - - /** - Searches through replace and replaces all substrings matched - by pattern with str. str may - contain backreferences (e.g. \1) to capture groups. A typical - invocation looks like: -

- - Pattern::replace("(a+)b(c+)", "abcccbbabcbabc", "\\2b\\1"); - -

- which would replace abcccbbabcbabc with - cccbabbcbabcba. - @param pattern The regular expression - @param str The replacement text - @param replacementText The string in which to perform replacements - @param mode The special mode requested of the Pattern - during the replacement process - @return The text with the replacement string substituted where necessary - */ - static bkstring replace (const bkstring & pattern, - const bkstring & str, - const bkstring & replacementText, - const unsigned long mode = 0); - - /** - Splits the specified string over occurrences of the specified pattern. - Empty strings can be optionally ignored. The number of strings returned is - configurable. A typical invocation looks like: -

- - bkstring str(strSize, '\0');
- FILE * fp = fopen(fileName, "r");
- fread((char*)str.data(), strSize, 1, fp);
- fclose(fp);
-
- std::vector<bkstring> lines = Pattern::split("[\r\n]+", str, true);
-
-
- - @param pattern The regular expression - @param replace The string to split - @param keepEmptys Whether or not to keep empty strings - @param limit The maximum number of splits to make - @param mode The special mode requested of the Pattern - during the split process - @return All substrings of str split across pattern. - */ - static std::vector split (const bkstring & pattern, - const bkstring & str, - const bool keepEmptys = 0, - const unsigned long limit = 0, - const unsigned long mode = 0); - - /** - Finds all the instances of the specified pattern within the string. You - should be careful to only pass patterns with a minimum length of one. For - example, the pattern a* can be matched by an empty string, so - instead you should pass a+ since at least one character must - be matched. A typical invocation of findAll looks like: -

- - std::vector<td::string> numbers = Pattern::findAll("\\d+", string); - -

- - @param pattern The pattern for which to search - @param str The string to search - @param mode The special mode requested of the Pattern - during the find process - @return All instances of pattern in str - */ - static std::vector findAll (const bkstring & pattern, - const bkstring & str, - const unsigned long mode = 0); - - /** - Determines if an entire string matches the specified pattern - - @param pattern The pattern for to match - @param str The string to match - @param mode The special mode requested of the Pattern - during the replacement process - @return True if str is recognized by pattern - */ - static bool matches (const bkstring & pattern, - const bkstring & str, - const unsigned long mode = 0); - - /** - Registers a pattern under a specific name for use in later compilations. - A typical invocation and later use looks like: -

- - Pattern::registerPattern("ip", "(?:\\d{1,3}\\.){3}\\d{1,3}");
- Pattern * p1 = Pattern::compile("{ip}:\\d+");
- Pattern * p2 = Pattern::compile("Connection from ({ip}) on port \\d+");
-
-

- Multiple calls to registerPattern with the same - name will result in the pattern getting overwritten. - - @param name The name to give to the pattern - @param pattern The pattern to register - @param mode Any special flags to use when compiling pattern - @return Success/Failure. Fails only if pattern has invalid - syntax - */ - static bool registerPattern(const bkstring & name, - const bkstring & pattern, - const unsigned long mode = 0); - - /** - Clears the pattern registry - */ - static void unregisterPatterns(); - /** - Don't use - */ - static void clearPatternCache(); - - /** - Searches through a string for the nth match of the - given pattern in the string. Match indeces start at zero, not one. - A typical invocation looks like this: -

- - std::pair<bkstring, int> match = Pattern::findNthMatch("\\d{1,3}", "192.168.1.101:22", 1);
- printf("%s %i\n", match.first.c_str(), match.second);
-
- Output: 168 4
-
- - @param pattern The pattern for which to search - @param str The string to search - @param matchNum Which match to find - @param mode Any special flags to use during the matching process - @return A string and an integer. The string is the string matched. The - integer is the starting location of the matched string in - str. You can check for success/failure by making sure - that the integer returned is greater than or equal to zero. - */ - static std::pair findNthMatch (const bkstring & pattern, - const bkstring & str, - const int matchNum, - const unsigned long mode = 0); - public: - /** - Deletes all NFA nodes allocated during compilation - */ - ~Pattern(); - - bkstring replace (const bkstring & str, - const bkstring & replacementText); - std::vector split (const bkstring & str, const bool keepEmptys = 0, - const unsigned long limit = 0); - std::vector findAll (const bkstring & str); - bool matches (const bkstring & str); - /** - Returns the flags used during compilation of this pattern - @return The flags used during compilation of this pattern - */ - unsigned long getFlags () const; - /** - Returns the regular expression this pattern represents - @return The regular expression this pattern represents - */ - bkstring getPattern () const; - /** - Creates a matcher object using the specified string and this pattern. - @param str The string to match against - @return A new matcher using object using this pattern and the specified - string - */ - Matcher * createMatcher (const bkstring & str); -}; - -class NFANode -{ - friend class Matcher; - public: - NFANode * next; - NFANode(); - virtual ~NFANode(); - virtual void findAllNodes(std::map & soFar); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const = 0; - inline virtual bool isGroupHeadNode() const { return false; } - inline virtual bool isStartOfInputNode() const { return false; } -}; -class NFACharNode : public NFANode -{ - protected: - char ch; - public: - NFACharNode(const char c); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFACICharNode : public NFANode -{ - protected: - char ch; - public: - NFACICharNode(const char c); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAStartNode : public NFANode -{ - public: - NFAStartNode(); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAEndNode : public NFANode -{ - public: - NFAEndNode(); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAQuantifierNode : public NFANode -{ - public: - int min, max; - NFANode * inner; - virtual void findAllNodes(std::map & soFar); - NFAQuantifierNode(Pattern * pat, NFANode * internal, - const int minMatch = Pattern::MIN_QMATCH, - const int maxMatch = Pattern::MAX_QMATCH); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAGreedyQuantifierNode : public NFAQuantifierNode -{ - public: - NFAGreedyQuantifierNode(Pattern * pat, NFANode * internal, - const int minMatch = Pattern::MIN_QMATCH, - const int maxMatch = Pattern::MAX_QMATCH); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; - virtual int matchInternal(const bkstring & str, Matcher * matcher, const int curInd, const int soFar) const; -}; -class NFALazyQuantifierNode : public NFAQuantifierNode -{ - public: - NFALazyQuantifierNode(Pattern * pat, NFANode * internal, - const int minMatch = Pattern::MIN_QMATCH, - const int maxMatch = Pattern::MAX_QMATCH); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAPossessiveQuantifierNode : public NFAQuantifierNode -{ - public: - NFAPossessiveQuantifierNode(Pattern * pat, NFANode * internal, - const int minMatch = Pattern::MIN_QMATCH, - const int maxMatch = Pattern::MAX_QMATCH); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAAcceptNode : public NFANode -{ - public: - NFAAcceptNode(); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAClassNode : public NFANode -{ - public: - bool inv; - std::map vals; - NFAClassNode(const bool invert = 0); - NFAClassNode(const bkstring & clazz, const bool invert); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFACIClassNode : public NFANode -{ - public: - bool inv; - std::map vals; - NFACIClassNode(const bool invert = 0); - NFACIClassNode(const bkstring & clazz, const bool invert); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFASubStartNode : public NFANode -{ - public: - NFASubStartNode(); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAOrNode : public NFANode -{ - public: - NFANode * one; - NFANode * two; - NFAOrNode(NFANode * first, NFANode * second); - virtual void findAllNodes(std::map & soFar); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAQuoteNode : public NFANode -{ - public: - bkstring qStr; - NFAQuoteNode(const bkstring & quoted); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFACIQuoteNode : public NFANode -{ - public: - bkstring qStr; - NFACIQuoteNode(const bkstring & quoted); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFALookAheadNode : public NFANode -{ - public: - bool pos; - NFANode * inner; - NFALookAheadNode(NFANode * internal, const bool positive); - virtual void findAllNodes(std::map & soFar); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFALookBehindNode : public NFANode -{ - public: - bool pos; - bkstring mStr; - NFALookBehindNode(const bkstring & str, const bool positive); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAStartOfLineNode : public NFANode -{ - public: - NFAStartOfLineNode(); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAEndOfLineNode : public NFANode -{ - public: - NFAEndOfLineNode(); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAReferenceNode : public NFANode -{ - public: - int gi; - NFAReferenceNode(const int groupIndex); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAStartOfInputNode : public NFANode -{ - public: - NFAStartOfInputNode(); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; - inline virtual bool isStartOfInputNode() const { return true; } -}; -class NFAEndOfInputNode : public NFANode -{ - public: - bool term; - NFAEndOfInputNode(const bool lookForTerm); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAWordBoundaryNode : public NFANode -{ - public: - bool pos; - NFAWordBoundaryNode(const bool positive); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAEndOfMatchNode : public NFANode -{ - public: - NFAEndOfMatchNode(); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAGroupHeadNode : public NFANode -{ - public: - int gi; - NFAGroupHeadNode(const int groupIndex); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; - inline virtual bool isGroupHeadNode() const { return true; } -}; -class NFAGroupTailNode : public NFANode -{ - public: - int gi; - NFAGroupTailNode(const int groupIndex); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAGroupLoopPrologueNode : public NFANode -{ - public: - int gi; - NFAGroupLoopPrologueNode(const int groupIndex); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; -class NFAGroupLoopNode : public NFANode -{ - public: - int gi, min, max, type; - NFANode * inner; - NFAGroupLoopNode(NFANode * internal, const int minMatch, - const int maxMatch, const int groupIndex, const int matchType); - virtual void findAllNodes(std::map & soFar); - virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; - int matchGreedy(const bkstring & str, Matcher * matcher, const int curInd = 0) const; - int matchLazy(const bkstring & str, Matcher * matcher, const int curInd = 0) const; - int matchPossessive(const bkstring & str, Matcher * matcher, const int curInd = 0) const; -}; - -#endif - diff --git a/plugins/SmileyAdd/regexp/WCMatcher.cpp b/plugins/SmileyAdd/regexp/WCMatcher.cpp deleted file mode 100644 index bed5a1944b..0000000000 --- a/plugins/SmileyAdd/regexp/WCMatcher.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "WCMatcher.h" -#include "WCPattern.h" - -const int WCMatcher::MATCH_ENTIRE_STRING = 0x01; - -/* - Detailed documentation is provided in this class' header file - - @author Jeffery Stuart - @since November 2004 - @version 1.07.00 -*/ - -WCMatcher::WCMatcher(WCPattern * pattern, const bkstring & text) -{ - pat = pattern; - str = &text; - gc = pattern->groupCount; - ncgc = -pattern->nonCapGroupCount; - flags = 0; - matchedSomething = false; - starts = new int[gc + ncgc]; - ends = new int[gc + ncgc]; - groups = new int[gc + ncgc]; - groupPos = new int[gc + ncgc]; - groupIndeces = new int[gc + ncgc]; - starts = starts + ncgc; - ends = ends + ncgc; - groups = groups + ncgc; - groupPos = groupPos + ncgc; - groupIndeces = groupIndeces + ncgc; - for (int i = 0; i < gc; ++i) starts[i] = ends[i] = 0; -} -WCMatcher::~WCMatcher() -{ - delete [] (starts - ncgc); - delete [] (ends - ncgc); - delete [] (groups - ncgc); - delete [] (groupIndeces - ncgc); - delete [] (groupPos - ncgc); -} -void WCMatcher::clearGroups() -{ - int i; - lm = 0; - for (i = 0; i < gc; ++i) groups[i] = starts[i] = ends[i] = -1; - for (i = 1; i <= ncgc; ++i) groups[0 - i] = starts[0 - i] = ends[0 - i] = -1; -} -bkstring WCMatcher::replaceWithGroups(const bkstring & str) -{ - bkstring ret = L""; - - bkstring t = str; - while (t.size() > 0) - { - if (t[0] == (wchar_t)'\\') - { - t.erase(0, 1); - if (t.size() == 0) - { - ret += L"\\"; - } - else if (t[0] < (wchar_t)'0' || t[0] > (wchar_t)'9') - { - ret += t[0]; - t.erase(0, 1); - } - else - { - int gn = 0; - while (t.size() > 0 && t[0] >= (wchar_t)'0' && t[0] <= (wchar_t)'9') - { - gn = gn * 10 + (t[0] - (wchar_t)'0'); - t.erase(0, 1); - } - ret += getGroup(gn); - } - } - else - { - ret += t[0]; - t.erase(0, 1); - } - } - - return ret; -} -unsigned long WCMatcher::getFlags() const -{ - return flags; -} -const bkstring& WCMatcher::getText() const -{ - return *str; -} - -bool WCMatcher::matches() -{ - flags = MATCH_ENTIRE_STRING; - matchedSomething = false; - clearGroups(); - lm = 0; - return pat->head->match(*str, this, 0) == (int)str->size(); -} -bool WCMatcher::findFirstMatch() -{ - starts[0] = 0; - flags = 0; - clearGroups(); - start = 0; - lm = 0; - ends[0] = pat->head->match(*str, this, 0); - if (ends[0] >= 0) - { - matchedSomething = true; - return 1; - } - return 0; -} -bool WCMatcher::findNextMatch() -{ - int s = starts[0], e = ends[0]; - - if (!matchedSomething) return findFirstMatch(); - if (s == e) ++e; - flags = 0; - clearGroups(); - - starts[0] = e; - if (e >= (int)str->size()) return 0; - start = e; - lm = e; - ends[0] = pat->head->match(*str, this, e); - return ends[0] >= 0; -} -std::vector WCMatcher::findAll() -{ - std::vector ret; - reset(); - while (findNextMatch()) - { - ret.push_back(getGroup()); - } - return ret; -} - -void WCMatcher::reset() -{ - lm = 0; - clearGroups(); - matchedSomething = false; -} - -int WCMatcher::getStartingIndex(const int groupNum) const -{ - if (groupNum < 0 || groupNum >= gc) return -1; - return starts[groupNum]; -} -int WCMatcher::getEndingIndex(const int groupNum) const -{ - if (groupNum < 0 || groupNum >= gc) return -1; - return ends[groupNum]; -} -bkstring WCMatcher::getGroup(const int groupNum) const -{ - if (groupNum < 0 || groupNum >= gc) return L""; - if (starts[groupNum] < 0 || ends[groupNum] < 0) return L""; - return str->substr(starts[groupNum], ends[groupNum] - starts[groupNum]); -} -std::vector WCMatcher::getGroups(const bool includeGroupZero) const -{ - int i, start = (includeGroupZero ? 0 : 1); - std::vector ret; - - for (i = start; i < gc; ++i) - { - ret.push_back(getGroup(i)); - } - return ret; -} - diff --git a/plugins/SmileyAdd/regexp/WCMatcher.h b/plugins/SmileyAdd/regexp/WCMatcher.h deleted file mode 100644 index 23cc49e41f..0000000000 --- a/plugins/SmileyAdd/regexp/WCMatcher.h +++ /dev/null @@ -1,234 +0,0 @@ -#ifndef __WCMATCHER_H__ -#define __WCMATCHER_H__ - -#include "bkstring.h" -#include -#include - -/** - A matcher is a non thread-safe object used to scan strings using a given - {@link WCPattern WCPattern} object. Using a WCMatcher is the preferred - method for scanning strings. WCMatchers are not thread-safe. WCMatchers require - very little dynamic memory, hence one is encouraged to create several - instances of a matcher when necessary as opposed to sharing a single instance - of a matcher. -

- The most common methods needed by the matcher are matches, - findNextMatch, and getGroup. matches - and findNextMatch both return success or failure, and further - details can be gathered from their documentation. -

- Unlike Java's WCMatcher, this class allows you to change the string - you are matching against. This provides a small optimization, since you no - longer need multiple matchers for a single pattern in a single thread. -

- This class also provides an extremely handy method for replacing text with - captured data via the replaceWithGroups method. A typical - invocation looks like: -

-  wchar_t buf[10000];
-  bkstring str = "\\5 (user name \\1) uses \\7 for his/her shell and \\6 is their home directory";
-  FILE * fp = fopen("/etc/passwd", "r");
-  WCPattern::registerWCPattern("entry", "[^:]+");
-  WCPattern * p = WCPattern::compile("^({entry}):({entry}):({entry}):({entry}):({entry}):({entry}):({entry})$",
-                                 WCPattern::MULTILINE_MATCHING | WCPattern::UNIX_LINE_MODE);
-  WCMatcher * m = p->createWCMatcher("");
-  while (fgets(buf, 9999, fp))
-  {
-    m->setString(buf);
-    if (m->matches())
-    {
-      printf("%s\n", m->replaceWithGroups(str).c_str());
-    }
-  }
-  fclose(fp);
-
-  
- Calling any of the following functions before first calling - matches, findFirstMatch, or - findNextMatch results in undefined behavior and may cause your - program to crash. - -
    -
  • replaceWithGroups -
  • getStartingIndex
  • -
  • getEndingIndex
  • -
  • getGroup
  • -
  • getGroups
  • -
-
-

- The function findFirstMatch will attempt to find the first match - in the input string. The same results can be obtained by first calling - reset followed by findNextMatch. -

- To eliminate the necessity of looping through a string to find all the - matching substrings, findAll was created. The function will find - all matching substrings and return them in a vector. If you need - to examine specific capture groups within the substrings, then this method - should not be used. - - @author Jeffery Stuart - @since March 2003, Stable Since November 2004 - @version 1.05.00 - @memo Mutable object used on instances of a WCPattern class - */ -class WCMatcher -{ - friend class NFAUNode; - friend class NFAStartUNode; - friend class NFAEndUNode; - friend class NFAGroupHeadUNode; - friend class NFAGroupLoopUNode; - friend class NFAGroupLoopPrologueUNode; - friend class NFAGroupTailUNode; - friend class NFALookBehindUNode; - friend class NFAStartOfLineUNode; - friend class NFAEndOfLineUNode; - friend class NFAEndOfMatchUNode; - friend class NFAReferenceUNode; - friend class WCPattern; - private: - /** - Creates a new matcher object against text using - pattern. - - @param pattern The pattern with which to search - @param text The text in which to search - */ - WCMatcher(WCPattern * pattern, const bkstring & text); - protected: - /// The pattern we use to match - WCPattern * pat; - /// The string in which we are matching - const bkstring * str; - /// The starting point of our match - int start; - /// An array of the starting positions for each group - int * starts; - /// An array of the ending positions for each group - int * ends; - /// An array of private data used by NFAUNodes during matching - int * groups; - /// An array of private data used by NFAUNodes during matching - int * groupIndeces; - /// An array of private data used by NFAUNodes during matching - int * groupPos; - /// The ending index of the last match - int lm; - /// The number of capturing groups we have - int gc; - /// The number of non-capturing groups we havew - int ncgc; - /// Whether or not we have matched something (used only by findFirstMatch and findNextMatch) - int matchedSomething; - /// The flags with which we were made - unsigned long flags; - /// Called by reset to clear the group arrays - void clearGroups(); - public: - /// Used internally by match to signify we want the entire string matched - const static int MATCH_ENTIRE_STRING; - public: - /// Cleans up the dynamic memory used by this matcher - ~WCMatcher(); - /** - Replaces the contents of str with the appropriate captured - text. str should have at least one back reference, otherwise - this function does nothing. - @param str The string in which to replace text - @return A string with all backreferences appropriately replaced - */ - bkstring replaceWithGroups(const bkstring & str); - /** - The flags currently being used by the matcher. - @return Zero - */ - unsigned long getFlags() const; - /** - The text being searched by the matcher. - @return the text being searched by the matcher. - */ - const bkstring& getText() const; - - /** - Scans the string from start to finish for a match. The entire string must - match for this function to return success. Group variables are - appropriately set and can be queried after this function returns. - - @return Success if and only if the entire string matches the pattern - */ - bool matches(); - /** - Scans the string for the first substring matching the pattern. The entire - string does not necessarily have to match for this function to return - success. Group variables are appropriately set and can be queried after - this function returns. - - @return Success if any substring matches the specified pattern - */ - bool findFirstMatch(); - /** - Scans the string for the next substring matching the pattern. If no calls - have been made to findFirstMatch of findNextMatch since the last call to - reset, matches, or setString, then this function's behavior results to - that of findFirstMatch. - - @return Success if another substring can be found that matches the pattern - */ - bool findNextMatch(); - /** - Returns a vector of every substring in order which matches the given - pattern. - - @return Every substring in order which matches the given pattern - */ - std::vector findAll(); - /** - Resets the internal state of the matcher - */ - void reset(); - /** - Same as getText. Left n for backwards compatibilty with old source code - @return Returns the string that is currently being used for matching - */ - inline const bkstring& getString() const { return *str; } - /** - Sets the string to scan - @param newStr The string to scan for subsequent matches - */ - inline void setString(const bkstring & newStr) { str = &newStr; reset(); } - - /** - Returns the starting index of the specified group. - @param groupNum The group to query - @return The starting index of the group if it was matched, -1 for an - invalid group or if the group was not matched - */ - int getStartingIndex(const int groupNum = 0) const; - /** - Returns the ending index of the specified group. - @param groupNum The group to query - @return The ending index of the group if it was matched, -1 for an - invalid group or if the group was not matched - */ - int getEndingIndex(const int groupNum = 0) const; - /** - Returns the specified group. An empty string ("") does not necessarily - mean the group was not matched. A group such as (a*b?) could be matched by - a zero length. If an empty string is returned, getStartingIndex can be - called to determine if the group was actually matched. - @param groupNum The group to query - @return The text of the group - */ - bkstring getGroup(const int groupNum = 0) const; - /** - Returns every capture group in a vector - - @param includeGroupZero Whether or not include capture group zero - @return Every capture group - */ - std::vector getGroups(const bool includeGroupZero = 0) const; -}; - -#endif diff --git a/plugins/SmileyAdd/regexp/WCPattern.cpp b/plugins/SmileyAdd/regexp/WCPattern.cpp deleted file mode 100644 index 25f379f5e4..0000000000 --- a/plugins/SmileyAdd/regexp/WCPattern.cpp +++ /dev/null @@ -1,1747 +0,0 @@ -/** - From the author (Jeff Stuart) - " - Let me start by saying this file is pretty big. If you feel up to it, you can - try making changes yourself, but you would be better off to just email me at - stuart@cs.ucdavis.edu if you think there is a bug, or have something useful you - would like added. This project is very "near and dear" to me, so I am fairly quick - to make bug fixes. The header files for WCPattern and WCMatcher are fairly well - documented and the function names are pretty self-explanatory, but if you are having - any trouble, feel free to email me at stuart@cs.ucdavis.edu. - - If you email me, make sure you put something like C++RE in the subject because - I tend to delete email if I don't recognize the name and the subject is - something like "I Need Your Help" or "Got A Second" or "I Found It". - " - */ - -/* - Detailed documentation is provided in this class' header file - - @author Jeffery Stuart - @since November 2004 - @version 1.07.00 -*/ - -#ifdef _WIN32 - #pragma warning(push) - #pragma warning(disable:4996) -#endif - -#include -#include -#include -#include -#ifndef _WIN32 - #include -#endif - -std::map WCPattern::compiledWCPatterns; -std::map > WCPattern::registeredWCPatterns; - -const int WCPattern::MIN_QMATCH = 0x00000000; -const int WCPattern::MAX_QMATCH = 0x7FFFFFFF; - -const unsigned long WCPattern::CASE_INSENSITIVE = 0x01; -const unsigned long WCPattern::LITERAL = 0x02; -const unsigned long WCPattern::DOT_MATCHES_ALL = 0x04; -const unsigned long WCPattern::MULTILINE_MATCHING = 0x08; -const unsigned long WCPattern::UNIX_LINE_MODE = 0x10; - -#define to_lower(a) (wchar_t)(UINT_PTR)CharLowerW((LPWSTR)(unsigned)a) -#define is_alpha IsCharAlphaW - -#if defined(_WIN32) - #define str_icmp lstrcmpiW -#elif defined(__CYGWIN__) || defined(__APPLE__) - #include - static inline int str_icmp(const wchar_t * a, const wchar_t * b) - { - while (*a && *b) - { - const int t = (int)towlower(*a) - (int)tolower(*b); - if (t) return t; - ++a; ++b; - } - if (*a) - { - if (*b) return (int)towlower(*a) - (int)tolower(*b); - return 1; - } - else if (*b) return 1; - return 0; - } -#else - #define str_icmp wcscasecmp -#endif - -WCPattern::WCPattern(const bkstring & rhs) -{ - matcher = NULL; - pattern = rhs; - curInd = 0; - groupCount = 0; - nonCapGroupCount = 0; - error = 0; - head = NULL; -} -// convenience function in case we want to add any extra debugging output -void WCPattern::raiseError() -{ -/* switch (pattern[curInd - 1]) - { - case '*': - case ')': - case '+': - case '?': - case ']': - case '}': - fwprintf(stderr, L"%s\n%*c^\n", pattern.c_str(), curInd - 1, ' '); - fwprintf(stderr, L"Syntax Error near here. Possible unescaped meta character.\n"); - break; - default: - fwprintf(stderr, L"%s\n%*c^\n", pattern.c_str(), curInd - 1, ' '); - fwprintf(stderr, L"Syntax Error near here. \n"); - break; - }*/ - error = 1; -} -NFAUNode * WCPattern::registerNode(NFAUNode * node) -{ - nodes[node] = 1; - return node; -} - -bkstring WCPattern::classUnion (bkstring s1, bkstring s2) const -{ - wchar_t * out = new wchar_t[66000]; - std::sort(s1.begin(), s1.end()); - std::sort(s2.begin(), s2.end()); - wchar_t* p = std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), out); *p = 0; - bkstring ret = out; - delete [] out; - return ret; -} -bkstring WCPattern::classIntersect (bkstring s1, bkstring s2) const -{ - wchar_t * out = new wchar_t[66000]; - std::sort(s1.begin(), s1.end()); - std::sort(s2.begin(), s2.end()); - *std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), out) = 0; - bkstring ret = out; - delete [] out; - return ret; -} -bkstring WCPattern::classNegate (bkstring s1) const -{ - wchar_t * out = new wchar_t[66000]; - int i, ind = 0; - std::map m; - - for (i = 0; i < (int)s1.size(); ++i) m[s1[i]] = 1; - for (i = 0xFF; i >= 0; --i) if (m.find((wchar_t)i) == m.end()) out[ind++] = (wchar_t)i; - out[ind] = 0; - bkstring ret(out, ind); - delete [] out; - return ret; -} -bkstring WCPattern::classCreateRange(wchar_t low, wchar_t hi) const -{ - wchar_t out[300]; - int ind = 0; - while (low != hi) out[ind++] = low++; - out[ind++] = low; - return bkstring(out, ind); -} - -int WCPattern::getInt(int start, int end) -{ - int ret = 0; - for (; start <= end; ++start) ret = ret * 10 + (pattern[start] - (wchar_t)'0'); - return ret; -} -bool WCPattern::quantifyCurly(int & sNum, int & eNum) -{ - bool good = 1; - int i, ci = curInd + 1; - int commaInd = ci, endInd = ci, len = pattern.size(); - sNum = eNum = 0; - - while (endInd < len && pattern[endInd ] != (wchar_t)'}') ++endInd; - while (commaInd < endInd && pattern[commaInd] != (wchar_t)',') ++commaInd; - if (endInd >= len) { raiseError(); return 0; } - for (i = ci; good && i < endInd; ++i) if (i != commaInd && !isdigit(pattern[i])) good = 0; - if (!good && commaInd < endInd) { raiseError(); return 0; } - if (!good) return 0; - /* so now everything in here is either a comma (and there is at most one comma) or a digit */ - if (commaInd == ci) // {,*} - { - if (endInd == commaInd + 1) { sNum = MIN_QMATCH; eNum = MAX_QMATCH; } // {,} = * - else { sNum = MIN_QMATCH; eNum = getInt(commaInd + 1, endInd - 1); } // {,+} - } - else if (commaInd == endInd - 1) { sNum = getInt(ci, commaInd - 1); eNum = MAX_QMATCH; } // {+,} - else if (commaInd == endInd) { sNum = getInt(ci, endInd - 1); eNum = sNum; } // {+} - else { sNum = getInt(ci, commaInd - 1); eNum = getInt(commaInd + 1, endInd - 1); } // {+,+} - curInd = endInd + 1; - return 1; -} -NFAUNode * WCPattern::quantifyGroup(NFAUNode * start, NFAUNode * stop, const int gn) -{ - NFAUNode * newNode = NULL; - int type = 0; - - if (curInd < (int)pattern.size()) - { - wchar_t ch = (curInd + 1 >= (int)pattern.size()) ? USHRT_MAX : pattern[curInd + 1]; - switch (pattern[curInd]) - { - case (wchar_t)'*': - ++curInd; - switch (ch) - { - case (wchar_t)'?': ++curInd; type = 1; break; - case (wchar_t)'+': ++curInd; type = 2; break; - } - newNode = registerNode(new NFAGroupLoopPrologueUNode(gn)); - newNode->next = registerNode(new NFAGroupLoopUNode(start, MIN_QMATCH, MAX_QMATCH, gn, type)); - stop->next = newNode->next; - return newNode; - case (wchar_t)'?': - ++curInd; - switch (ch) - { - case (wchar_t)'?': ++curInd; type = 1; break; - case (wchar_t)'+': ++curInd; type = 2; break; - } - newNode = registerNode(new NFAGroupLoopPrologueUNode(gn)); - newNode->next = registerNode(new NFAGroupLoopUNode(start, MIN_QMATCH, 1, gn, type)); - stop->next = newNode->next; - return newNode; - case (wchar_t)'+': - ++curInd; - switch (ch) - { - case (wchar_t)'?': ++curInd; type = 1; break; - case (wchar_t)'+': ++curInd; type = 2; break; - } - newNode = registerNode(new NFAGroupLoopPrologueUNode(gn)); - newNode->next = registerNode(new NFAGroupLoopUNode(start, 1, MAX_QMATCH, gn, type)); - stop->next = newNode->next; - return newNode; - case (wchar_t)'{': - { - int s, e; - if (quantifyCurly(s, e)) - { - ch = (curInd < (int)pattern.size()) ? pattern[curInd] : USHRT_MAX; - switch (ch) - { - case (wchar_t)'?': ++curInd; type = 1; break; - case (wchar_t)'+': ++curInd; type = 2; break; - } - newNode = registerNode(new NFAGroupLoopPrologueUNode(gn)); - newNode->next = registerNode(new NFAGroupLoopUNode(start, s, e, gn, type)); - stop->next = newNode->next; - return newNode; - } - } - default: - break; - } - } - return NULL; -} - -NFAUNode * WCPattern::quantify(NFAUNode * newNode) -{ - if (curInd < (int)pattern.size()) - { - wchar_t ch = (curInd + 1 >= (int)pattern.size()) ? USHRT_MAX : pattern[curInd + 1]; - switch (pattern[curInd]) - { - case (wchar_t)'*': - ++curInd; - switch (ch) - { - case (wchar_t)'?': ++curInd; newNode = registerNode(new NFALazyQuantifierUNode (this, newNode, MIN_QMATCH, MAX_QMATCH)); break; - case (wchar_t)'+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierUNode(this, newNode, MIN_QMATCH, MAX_QMATCH)); break; - default: newNode = registerNode(new NFAGreedyQuantifierUNode (this, newNode, MIN_QMATCH, MAX_QMATCH)); break; - } - break; - case (wchar_t)'?': - ++curInd; - switch (ch) - { - case (wchar_t)'?': ++curInd; newNode = registerNode(new NFALazyQuantifierUNode (this, newNode, MIN_QMATCH, 1)); break; - case (wchar_t)'+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierUNode(this, newNode, MIN_QMATCH, 1)); break; - default: newNode = registerNode(new NFAGreedyQuantifierUNode (this, newNode, MIN_QMATCH, 1)); break; - } - break; - case (wchar_t)'+': - ++curInd; - switch (ch) - { - case (wchar_t)'?': ++curInd; newNode = registerNode(new NFALazyQuantifierUNode (this, newNode, 1, MAX_QMATCH)); break; - case (wchar_t)'+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierUNode(this, newNode, 1, MAX_QMATCH)); break; - default: newNode = registerNode(new NFAGreedyQuantifierUNode (this, newNode, 1, MAX_QMATCH)); break; - } - break; - case (wchar_t)'{': - { - int s, e; - if (quantifyCurly(s, e)) - { - ch = (curInd < (int)pattern.size()) ? pattern[curInd] : USHRT_MAX; - switch (ch) - { - case (wchar_t)'?': ++curInd; newNode = registerNode(new NFALazyQuantifierUNode (this, newNode, s, e)); break; - case (wchar_t)'+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierUNode(this, newNode, s, e)); break; - default: newNode = registerNode(new NFAGreedyQuantifierUNode (this, newNode, s, e)); break; - } - } - } - break; - default: - break; - } - } - return newNode; -} -bkstring WCPattern::parseClass() -{ - bkstring t, ret = L""; - wchar_t ch, c1, c2; - bool inv = 0, neg = 0, quo = 0; - - if (curInd < (int)pattern.size() && pattern[curInd] == (wchar_t)'^') - { - ++curInd; - neg = 1; - } - while (curInd < (int)pattern.size() && pattern[curInd] != (wchar_t)']') - { - ch = pattern[curInd++]; - if (ch == (wchar_t)'[') - { - t = parseClass(); - ret = classUnion(ret, t); - } - /*else if (ch == (wchar_t)'-') - { - raiseError(); - curInd = pattern.size(); - }*/ - else if (ch == (wchar_t)'&' && curInd < (int)pattern.size() && pattern[curInd] == (wchar_t)'&') - { - if (pattern[++curInd] != (wchar_t)'[') - { - raiseError(); - curInd = pattern.size(); - } - else - { - ++curInd; - t = parseClass(); - ret = classIntersect(ret, t); - } - } - else if (ch == (wchar_t)'\\') - { - t = parseEscape(inv, quo); - if (quo) - { - raiseError(); - curInd = pattern.size(); - } - else if (inv || t.size() > 1) // cant be part of a range (a-z) - { - if (inv) t = classNegate(t); - ret = classUnion(ret, t); - } - else if (curInd < (int)pattern.size() && pattern[curInd] == (wchar_t)'-') // part of a range (a-z) - { - c1 = t[0]; - ++curInd; - if (curInd >= (int)pattern.size()) raiseError(); - else - { - c2 = pattern[curInd++]; - if (c2 == (wchar_t)'\\') - { - t = parseEscape(inv, quo); - if (quo) - { - raiseError(); - curInd = pattern.size(); - } - else if (inv || t.size() > 1) raiseError(); - else ret = classUnion(ret, classCreateRange(c1, c2)); - } - else if (c2 == (wchar_t)'[' || c2 == (wchar_t)']' || c2 == (wchar_t)'-' || c2 == (wchar_t)'&') - { - raiseError(); - curInd = pattern.size(); - } - else ret = classUnion(ret, classCreateRange(c1, c2)); - } - } - else - { - ret = classUnion(ret, t); - } - } - else if (curInd < (int)pattern.size() && pattern[curInd] == (wchar_t)'-') - { - c1 = ch; - ++curInd; - if (curInd >= (int)pattern.size()) raiseError(); - else - { - c2 = pattern[curInd++]; - if (c2 == (wchar_t)'\\') - { - t = parseEscape(inv, quo); - if (quo) - { - raiseError(); - curInd = pattern.size(); - } - else if (inv || t.size() > 1) raiseError(); - else ret = classUnion(ret, classCreateRange(c1, c2)); - } - else if (c2 == (wchar_t)'[' || c2 == (wchar_t)']' || c2 == (wchar_t)'-' || c2 == (wchar_t)'&') - { - raiseError(); - curInd = pattern.size(); - } - else - { - ret = classUnion(ret, classCreateRange(c1, c2)); - } - } - } - else - { - ret += L" "; - ret[ret.size() - 1] = ch; - } - } - if (curInd >= (int)pattern.size() || pattern[curInd] != (wchar_t)']') - { - raiseError(); - ret = L""; - } - else - { - ++curInd; - if (neg) ret = classNegate(ret); - } - return ret; -} -bkstring WCPattern::parsePosix() -{ - bkstring s7 = pattern.substr(curInd, 7); - if (s7 == L"{Lower}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyz"; } - if (s7 == L"{Upper}") { curInd += 7; return L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } - if (s7 == L"{Alpha}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; } - if (s7 == L"{Digit}") { curInd += 7; return L"0123456789"; } - if (s7 == L"{Alnum}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; } - if (s7 == L"{Punct}") { curInd += 7; return L"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } - if (s7 == L"{Graph}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } - if (s7 == L"{Print}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } - if (s7 == L"{Blank}") { curInd += 7; return L" \t"; } - if (s7 == L"{Space}") { curInd += 7; return L" \t\n\x0B\f\r"; } - if (s7 == L"{Cntrl}") - { - bkstring::value_type i; - bkstring s = L" "; - - for (i = 0; i < 5; ++i) s += s; - s += L" "; - for (i = 0; i <= 0x1F; ++i) s[i] = i; - s[0x20] = 0x7F; - curInd += 7; - return s; - } - if (s7 == L"{ASCII}") - { - bkstring s(0x80, (wchar_t)' '); - for (bkstring::value_type i = 0; i <= 0x7f; ++i) s[i] = i; - curInd += 7; - return s; - } - if (pattern.substr(curInd, 8) == L"{XDigit}") { curInd += 8; return L"abcdefABCDEF0123456789"; } - raiseError(); - return L""; -} -NFAUNode * WCPattern::parseBackref() -{ - #define is_dig(x) ((x) >= (wchar_t)'0' && (x) <= (wchar_t)'9') - #define to_int(x) ((x) - (wchar_t)'0') - int ci = curInd; - int oldRef = 0, ref = 0; - - while (ci < (int)pattern.size() && is_dig(pattern[ci]) && (ref < 10 || ref < groupCount)) - { - oldRef = ref; - ref = ref * 10 + to_int(pattern[ci++]); - } - if (ci == (int)pattern.size()) - { - oldRef = ref; - ++ci; - } - if (oldRef < 0 || ci <= curInd) - { - raiseError(); - return registerNode(new NFAReferenceUNode(-1)); - } - curInd = ci; - return registerNode(new NFAReferenceUNode(ref)); - - #undef is_dig - #undef to_int -} -bkstring WCPattern::parseOctal() -{ - #define islowoc(x) ((x) >= (wchar_t)'0' && (x) <= (wchar_t)'3') - #define isoc(x) ((x) >= (wchar_t)'0' && (x) <= (wchar_t)'7') - #define fromoc(x) ((x) - (wchar_t)'0') - int ci = curInd; - wchar_t ch1 = (ci + 0 < (int)pattern.size()) ? pattern[ci + 0] : USHRT_MAX; - wchar_t ch2 = (ci + 1 < (int)pattern.size()) ? pattern[ci + 1] : USHRT_MAX; - wchar_t ch3 = (ci + 2 < (int)pattern.size()) ? pattern[ci + 2] : USHRT_MAX; - bkstring s = L" "; - - if (islowoc(ch1) && isoc(ch2)) - { - curInd += 2; - s[0] = fromoc(ch1) * 8 + fromoc(ch2); - if (isoc(ch3)) - { - ++curInd; - s[0] = s[0] * 8 + fromoc(ch3); - } - } - else if (isoc(ch1) && isoc(ch2)) - { - curInd += 2; - s[0] = fromoc(ch1) * 8 + fromoc(ch2); - } - else raiseError(); - - return s; - #undef islowoc - #undef isoc - #undef fromoc -} -bkstring WCPattern::parseHex() -{ - #define to_low(x) (((x) >= (wchar_t)'A' && (x) <= (wchar_t)'Z') ? ((x) - (wchar_t)'A' + (wchar_t)'a') : (x)) - #define is_dig(x) ((x) >= (wchar_t)'0' && (x) <= (wchar_t)'9') - #define is_hex(x) (is_dig(x) || (to_low(x) >= (wchar_t)'a' && to_low(x) <= (wchar_t)'f')) - #define to_int(x) ((is_dig(x)) ? ((x) - (wchar_t)'0') : (to_low(x) - (wchar_t)'a' + 10)) - - int ci = curInd; - wchar_t ch1 = (ci + 0 < (int)pattern.size()) ? pattern[ci + 0] : USHRT_MAX; - wchar_t ch2 = (ci + 1 < (int)pattern.size()) ? pattern[ci + 1] : USHRT_MAX; - wchar_t ch3 = (ci + 2 < (int)pattern.size()) ? pattern[ci + 2] : USHRT_MAX; - wchar_t ch4 = (ci + 3 < (int)pattern.size()) ? pattern[ci + 3] : USHRT_MAX; - bkstring s = L" "; - - if (is_hex(ch1) && is_hex(ch2) && is_hex(ch3) && is_hex(ch4)) - { - curInd += 2; - s[0] = (to_int(ch1) << 12 & 0xF000) | (to_int(ch2) << 8 & 0x0F00) | - (to_int(ch3) << 4 & 0x0F00) | (to_int(ch4) & 0x000F); - } - else if (is_hex(ch1) && is_hex(ch2)) - { - curInd += 2; - s[0] = (to_int(ch1) << 4 & 0xF0) | (to_int(ch2) & 0x0F); - } - - return s; - #undef to_low - #undef is_dig - #undef is_hex - #undef to_int -} -bkstring WCPattern::parseEscape(bool & inv, bool & quo) -{ - wchar_t ch = pattern[curInd++]; - bkstring classes = L""; - - if (curInd > (int)pattern.size()) - { - raiseError(); - return NULL; - } - - quo = 0; - inv = 0; - switch (ch) - { - case (wchar_t)'p': classes = parsePosix(); break; - case (wchar_t)'P': classes = L"!!"; classes += parsePosix(); break; - case (wchar_t)'d': classes = L"0123456789"; break; - case (wchar_t)'D': classes = L"!!0123456789"; break; - case (wchar_t)'s': classes = L" \t\r\n\f"; break; - case (wchar_t)'S': classes = L"!! \t\r\n\f"; break; - case (wchar_t)'w': classes = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; break; - case (wchar_t)'W': classes = L"!!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; break; - case (wchar_t)'0': classes = parseOctal(); break; - case (wchar_t)'x': classes = parseHex(); break; - - case (wchar_t)'Q': quo = 1; break; - case (wchar_t)'t': classes = L"\t"; break; - case (wchar_t)'r': classes = L"\r"; break; - case (wchar_t)'n': classes = L"\n"; break; - case (wchar_t)'f': classes = L"\f"; break; - case (wchar_t)'a': classes = L"\a"; break; - case (wchar_t)'e': classes = L"\r"; break; - default: classes = L" "; classes[0] = ch; break; - } - if (classes.substr(0, 2) == L"!!") - { - classes = classes.substr(2); - inv = 1; - } - return classes; -} -NFAUNode * WCPattern::parseRegisteredWCPattern(NFAUNode ** end) -{ - int i, j; - bkstring s; - NFAUNode * ret = NULL; - for (i = curInd; i < (int)pattern.size() && pattern[i] != (wchar_t)'}'; ++i) { } - if (pattern[i] != (wchar_t)'}') { raiseError(); return NULL; } - if (i == curInd + 1) { raiseError(); return NULL; } // {} - if ( - !( - (pattern[curInd] >= (wchar_t)'a' && pattern[curInd] <= (wchar_t)'z') || - (pattern[curInd] >= (wchar_t)'A' && pattern[curInd] <= (wchar_t)'Z') || - (pattern[curInd] == (wchar_t)'_') - ) - ) - { - raiseError(); - return NULL; - } - for (j = curInd; !error && j < i; ++j) - { - if ( - !( - (pattern[j] >= (wchar_t)'a' && pattern[j] <= (wchar_t)'z') || - (pattern[j] >= (wchar_t)'A' && pattern[j] <= (wchar_t)'Z') || - (pattern[j] >= (wchar_t)'0' && pattern[j] <= (wchar_t)'9') || - (pattern[j] == (wchar_t)'_') - ) - ) - { - raiseError(); - return NULL; - } - } - s = pattern.substr(curInd, i - curInd); - if (registeredWCPatterns.find(s) == registeredWCPatterns.end()) raiseError(); - else - { - unsigned long oflags = flags; - bkstring op = pattern; - int ci = i + 1; - - pattern = registeredWCPatterns[s].first; - curInd = 0; - flags = registeredWCPatterns[s].second; - - --groupCount; - ret = parse(0, 0, end); - - pattern = op; - curInd = ci; - flags = oflags; - } - if (error) { *end = ret = NULL; } - return ret; -} - -// look behind should interpret everything as a literal (except \\) since the -// pattern must have a concrete length -NFAUNode * WCPattern::parseBehind(const bool pos, NFAUNode ** end) -{ - bkstring t = L""; - while (curInd < (int)pattern.size() && pattern[curInd] != (wchar_t)')') - { - wchar_t ch = pattern[curInd++]; - t += L" "; - if (ch == (wchar_t)'\\') - { - if (curInd + 1 >= (int)pattern.size()) - { - raiseError(); - return *end = registerNode(new NFACharUNode((wchar_t)' ')); - } - ch = pattern[curInd++]; - } - t[t.size() - 1] = ch; - } - if (curInd >= (int)pattern.size() || pattern[curInd] != (wchar_t)')') raiseError(); - else ++curInd; - return *end = registerNode(new NFALookBehindUNode(t, pos)); -} -NFAUNode * WCPattern::parseQuote() -{ - bool done = 0; - bkstring s = L""; - - while (!done) - { - if (curInd >= (int)pattern.size()) - { - raiseError(); - done = 1; - } - else if (pattern.substr(curInd, 2) == L"\\E") - { - curInd += 2; - done = 1; - } - else if (pattern[curInd] == (wchar_t)'\\') - { - s += L" "; - s[s.size() - 1] = pattern[++curInd]; - ++curInd; - } - else - { - s += L" "; - s[s.size() - 1] = pattern[curInd++]; - } - } - if ((flags & WCPattern::CASE_INSENSITIVE) != 0) return registerNode(new NFACIQuoteUNode(s)); - return registerNode(new NFAQuoteUNode(s)); -} -NFAUNode * WCPattern::parse(const bool inParen, const bool inOr, NFAUNode ** end) -{ - NFAUNode * start, * cur, * next = NULL; - bkstring t; - int grc = groupCount++; - bool inv, quo; - bool ahead = 0, pos = 0, noncap = 0, indep = 0; - unsigned long oldFlags = flags; - - if (inParen) - { - if (pattern[curInd] == (wchar_t)'?') - { - ++curInd; - --groupCount; - if (pattern[curInd] == (wchar_t)':') { noncap = 1; ++curInd; grc = --nonCapGroupCount; } - else if (pattern[curInd] == (wchar_t)'=') { ++curInd; ahead = 1; pos = 1; } - else if (pattern[curInd] == (wchar_t)'!') { ++curInd; ahead = 1; pos = 0; } - else if (pattern.substr(curInd, 2) == L"<=") { curInd += 2; return parseBehind(1, end); } - else if (pattern.substr(curInd, 2) == L"') { ++curInd; indep = 1; } - else - { - bool negate = false, done = false; - while (!done) - { - if (curInd >= (int)pattern.size()) - { - raiseError(); - return NULL; - } - else if (negate) - { - switch (pattern[curInd]) - { - case (wchar_t)'i': flags &= ~WCPattern::CASE_INSENSITIVE; break; - case (wchar_t)'d': flags &= ~WCPattern::UNIX_LINE_MODE; break; - case (wchar_t)'m': flags &= ~WCPattern::MULTILINE_MATCHING; break; - case (wchar_t)'s': flags &= ~WCPattern::DOT_MATCHES_ALL; break; - case (wchar_t)':': done = true; break; - case (wchar_t)')': - ++curInd; - *end = registerNode(new NFALookBehindUNode(L"", true)); - return *end; - case (wchar_t)'-': - default: raiseError(); return NULL; - } - } - else - { - switch (pattern[curInd]) - { - case (wchar_t)'i': flags |= WCPattern::CASE_INSENSITIVE; break; - case (wchar_t)'d': flags |= WCPattern::UNIX_LINE_MODE; break; - case (wchar_t)'m': flags |= WCPattern::MULTILINE_MATCHING; break; - case (wchar_t)'s': flags |= WCPattern::DOT_MATCHES_ALL; break; - case (wchar_t)':': done = true; break; - case (wchar_t)'-': negate = true; break; - case (wchar_t)')': - ++curInd; - *end = registerNode(new NFALookBehindUNode(L"", true)); - return *end; - default: raiseError(); return NULL; - } - } - ++curInd; - } - noncap = 1; - grc = --nonCapGroupCount; - } - - if (noncap) cur = start = registerNode(new NFAGroupHeadUNode(grc)); - else cur = start = registerNode(new NFASubStartUNode); - } - else cur = start = registerNode(new NFAGroupHeadUNode(grc)); - } - else cur = start = registerNode(new NFASubStartUNode); - while (curInd < (int)pattern.size()) - { - wchar_t ch = pattern[curInd++]; - - next = NULL; - if (error) return NULL; - switch (ch) - { - case (wchar_t)'^': - if ((flags & WCPattern::MULTILINE_MATCHING) != 0) next = registerNode(new NFAStartOfLineUNode); - else next = registerNode(new NFAStartOfInputUNode); - break; - case (wchar_t)'$': - if ((flags & WCPattern::MULTILINE_MATCHING) != 0) next = registerNode(new NFAEndOfLineUNode); - else next = registerNode(new NFAEndOfInputUNode(0)); - break; - case (wchar_t)'|': - --groupCount; - cur->next = registerNode(new NFAAcceptUNode); - cur = start = registerNode(new NFAOrUNode(start, parse(inParen, 1))); - break; - case (wchar_t)'\\': - if (curInd < (int)pattern.size()) - { - bool eoi = 0; - switch (pattern[curInd]) - { - case (wchar_t)'1': - case (wchar_t)'2': - case (wchar_t)'3': - case (wchar_t)'4': - case (wchar_t)'5': - case (wchar_t)'6': - case (wchar_t)'7': - case (wchar_t)'8': - case (wchar_t)'9': next = parseBackref(); break; - case (wchar_t)'A': ++curInd; next = registerNode(new NFAStartOfInputUNode); break; - case (wchar_t)'B': ++curInd; next = registerNode(new NFAWordBoundaryUNode(0)); break; - case (wchar_t)'b': ++curInd; next = registerNode(new NFAWordBoundaryUNode(1)); break; - case (wchar_t)'G': ++curInd; next = registerNode(new NFAEndOfMatchUNode); break; - case (wchar_t)'Z': eoi = 1; - case (wchar_t)'z': ++curInd; next = registerNode(new NFAEndOfInputUNode(eoi)); break; - default: - t = parseEscape(inv, quo); - //printf("inv quo classes { %c %c %s }\n", inv ? (wchar_t)'t' : (wchar_t)'f', quo ? (wchar_t)'t' : (wchar_t)'f', t.c_str()); - if (!quo) - { - if (t.size() > 1 || inv) - { - if ((flags & WCPattern::CASE_INSENSITIVE) != 0) next = registerNode(new NFACIClassUNode(t, inv)); - else next = registerNode(new NFAClassUNode(t, inv)); - } - else - { - next = registerNode(new NFACharUNode(t[0])); - } - } - else - { - next = parseQuote(); - } - } - } - else raiseError(); - break; - case (wchar_t)'[': - if ((flags & WCPattern::CASE_INSENSITIVE) == 0) - { - NFAClassUNode * clazz = new NFAClassUNode(); - bkstring s = parseClass(); - for (int i = 0; i < (int)s.size(); ++i) clazz->vals[s[i]] = 1; - next = registerNode(clazz); - } - else - { - NFACIClassUNode * clazz = new NFACIClassUNode(); - bkstring s = parseClass(); - for (int i = 0; i < (int)s.size(); ++i) clazz->vals[to_lower(s[i])] = 1; - next = registerNode(clazz); - } - break; - case (wchar_t)'.': - { - bool useN = 1, useR = 1; - NFAClassUNode * clazz = new NFAClassUNode(1); - if ((flags & WCPattern::UNIX_LINE_MODE) != 0) useR = 0; - if ((flags & WCPattern::DOT_MATCHES_ALL) != 0) useN = useR = 0; - if (useN) clazz->vals[(wchar_t)'\n'] = 1; - if (useR) clazz->vals[(wchar_t)'\r'] = 1; - next = registerNode(clazz); - } - break; - case (wchar_t)'(': - { - NFAUNode * end, * t1, * t2; - t1 = parse(1, 0, &end); - if (!t1) raiseError(); - else if (t1->isGroupHeadNode() && (t2 = quantifyGroup(t1, end, grc)) != NULL) - { - cur->next = t2; - cur = t2->next; - } - else - { - cur->next = t1; - cur = end; - } - } - break; - case (wchar_t)')': - if (!inParen) raiseError(); - else if (inOr) - { - --curInd; - cur = cur->next = registerNode(new NFAAcceptUNode); - flags = oldFlags; - return start; - } - else - { - if (ahead) - { - cur = cur->next = registerNode(new NFAAcceptUNode); - flags = oldFlags; - return *end = registerNode(new NFALookAheadUNode(start, pos)); - } - else if (indep) - { - cur = cur->next = registerNode(new NFAAcceptUNode); - flags = oldFlags; - return *end = registerNode(new NFAPossessiveQuantifierUNode(this, start, 1, 1)); - } - else // capping or noncapping, it doesnt matter - { - *end = cur = cur->next = registerNode(new NFAGroupTailUNode(grc)); - next = quantifyGroup(start, *end, grc); - if (next) - { - start = next; - *end = next->next; - } - flags = oldFlags; - return start; - } - } - break; - case (wchar_t)'{': // registered pattern - cur->next = parseRegisteredWCPattern(&next); - if (cur->next) cur = next; - break; - case (wchar_t)'*': - case (wchar_t)'+': - case (wchar_t)'?': -// case (wchar_t)'}': -// case (wchar_t)']': - raiseError(); - break; - default: - if ((flags & WCPattern::CASE_INSENSITIVE) != 0) next = registerNode(new NFACICharUNode(ch)); - else next = registerNode(new NFACharUNode(ch)); - break; - } - if (next) cur = cur->next = quantify(next); - } - if (inParen) raiseError(); - else - { - if (inOr) cur = cur->next = registerNode(new NFAAcceptUNode); - if (end) *end = cur; - } - - flags = oldFlags; - if (error) return NULL; - - return start; -} - -WCPattern * WCPattern::compile(const bkstring & pattern, const unsigned long mode) -{ - WCPattern * p = new WCPattern(pattern); - NFAUNode * end; - - p->flags = mode; - if ((mode & WCPattern::LITERAL) != 0) - { - p->head = p->registerNode(new NFAStartUNode); - if ((mode & WCPattern::CASE_INSENSITIVE) != 0) p->head->next = p->registerNode(new NFACIQuoteUNode(pattern)); - else p->head->next = p->registerNode(new NFAQuoteUNode(pattern)); - p->head->next->next = p->registerNode(new NFAEndUNode); - } - else - { - p->head = p->parse(0, 0, &end); - if (!p->head) - { - delete p; - p = NULL; - } - else - { - if (!(p->head && p->head->isStartOfInputNode())) - { - NFAUNode * n = p->registerNode(new NFAStartUNode); - n->next = p->head; - p->head = n; - } - end->next = p->registerNode(new NFAEndUNode); - } - } - if (p != NULL) - { - p->matcher = new WCMatcher(p, L""); - } - - return p; -} - -WCPattern * WCPattern::compileAndKeep(const bkstring & pattern, const unsigned long mode) -{ - WCPattern * ret = NULL; - std::map::iterator it = compiledWCPatterns.find(pattern); - - if (it != compiledWCPatterns.end()) - { - ret = it->second; - } - else - { - ret = compile(pattern, mode); - compiledWCPatterns[pattern] = ret; - } - - return ret; -} -bkstring WCPattern::replace(const bkstring & pattern, const bkstring & str, - const bkstring & replacementText, const unsigned long mode) -{ - bkstring ret; - WCPattern * p = WCPattern::compile(pattern, mode); - if (p) - { - ret = p->replace(str, replacementText); - delete p; - } - return ret; -} - -std::vector WCPattern::split(const bkstring & pattern, const bkstring & str, const bool keepEmptys, - const unsigned long limit, const unsigned long mode) -{ - std::vector ret; - WCPattern * p = WCPattern::compile(pattern, mode); - if (p) - { - ret = p->split(str, keepEmptys, limit); - delete p; - } - return ret; -} - -std::vector WCPattern::findAll(const bkstring & pattern, const bkstring & str, const unsigned long mode) -{ - std::vector ret; - WCPattern * p = WCPattern::compile(pattern, mode); - if (p) - { - ret = p->findAll(str); - delete p; - } - return ret; -} - -bool WCPattern::matches(const bkstring & pattern, const bkstring & str, const unsigned long mode) -{ - bool ret = 0; - WCPattern * p = compile(pattern, mode); - - if (p) - { - ret = p->matches(str); - delete p; - } - - return ret; -} - -bool WCPattern::registerWCPattern(const bkstring & name, const bkstring & pattern, const unsigned long mode) -{ - WCPattern * p = WCPattern::compile(pattern, mode); - if (!p) return 0; - WCPattern::registeredWCPatterns[name] = std::make_pair(pattern, mode); - delete p; - return 1; -} - -void WCPattern::unregisterWCPatterns() -{ - registeredWCPatterns.clear(); -} -void WCPattern::clearWCPatternCache() -{ - std::map::iterator it; - for (it = compiledWCPatterns.begin(); it != compiledWCPatterns.end(); ++it) - { - delete it->second; - } - compiledWCPatterns.clear(); -} - -std::pair WCPattern::findNthMatch(const bkstring & pattern, const bkstring & str, - const int matchNum, const unsigned long mode) -{ - std::pair ret; - WCPattern * p = WCPattern::compile(pattern, mode); - - ret.second = -1; - if (p) - { - int i = -1; - p->matcher->setString(str); - while (i < matchNum && p->matcher->findNextMatch()) { ++i; } - if (i == matchNum && p->matcher->getStartingIndex() >= 0) - { - ret.first = p->matcher->getGroup(0); - ret.second = p->matcher->getStartingIndex(); - } - delete p; - } - - return ret; -} - -WCPattern::~WCPattern() -{ - /* - nodes.clear(); - if (head) head->findAllNodes(nodes); - */ - if (matcher) delete matcher; - for (std::map::iterator it = nodes.begin(); it != nodes.end(); ++it) delete it->first; -} -bkstring WCPattern::replace(const bkstring & str, const bkstring & replacementText) -{ - int li = 0; - bkstring ret = L""; - - matcher->setString(str); - while (matcher->findNextMatch()) - { - ret += str.substr(li, matcher->getStartingIndex() - li); - ret += matcher->replaceWithGroups(replacementText); - li = matcher->getEndingIndex(); - } - ret += str.substr(li); - - return ret; -} -std::vector WCPattern::split(const bkstring & str, const bool keepEmptys, const unsigned long limit) -{ - unsigned long lim = (limit == 0 ? MAX_QMATCH : limit); - int li = 0; - std::vector ret; - - matcher->setString(str); - - while (matcher->findNextMatch() && ret.size() < lim) - { - if (matcher->getStartingIndex() == 0 && keepEmptys) ret.push_back(L""); - if ((matcher->getStartingIndex() != matcher->getEndingIndex()) || keepEmptys) - { - if (li != matcher->getStartingIndex() || keepEmptys) - { - ret.push_back(str.substr(li, matcher->getStartingIndex() - li)); - } - li = matcher->getEndingIndex(); - } - } - if (li < (int)str.size()) ret.push_back(str.substr(li)); - - return ret; -} -std::vector WCPattern::findAll(const bkstring & str) -{ - matcher->setString(str); - return matcher->findAll(); -} -bool WCPattern::matches(const bkstring & str) -{ - matcher->setString(str); - return matcher->matches(); -} -unsigned long WCPattern::getFlags() const -{ - return flags; -} -bkstring WCPattern::getWCPattern() const -{ - return pattern; -} -WCMatcher * WCPattern::createWCMatcher(const bkstring & str) -{ - return new WCMatcher(this, str); -} - -// NFAUNode - -NFAUNode::NFAUNode() { next = NULL; } -NFAUNode::~NFAUNode() { } -void NFAUNode::findAllNodes(std::map & soFar) -{ - if (soFar.find(this) == soFar.end()) return; - soFar[this] = 1; - if (next) next->findAllNodes(soFar); -} - -// NFACharUNode - -NFACharUNode::NFACharUNode(const wchar_t c) { ch = c; } -int NFACharUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd < (int)str.size() && str[curInd] == ch) return next->match(str, matcher, curInd + 1); - return -1; -} - -// NFACICharUNode - -NFACICharUNode::NFACICharUNode(const wchar_t c) { ch = to_lower(c); } -int NFACICharUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd < (int)str.size() && to_lower(str[curInd]) == ch) return next->match(str, matcher, curInd + 1); - return -1; -} - -// NFAStartUNode - -NFAStartUNode::NFAStartUNode() { } -int NFAStartUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int ret = -1, ci = curInd; - - matcher->starts[0] = curInd; - if ((matcher->getFlags() & WCMatcher::MATCH_ENTIRE_STRING) == (unsigned int)WCMatcher::MATCH_ENTIRE_STRING) - { - if (curInd != 0) - { - matcher->starts[0] = -1; - return -1; - } - return next->match(str, matcher, 0); - } - while ((ret = next->match(str, matcher, ci)) == -1 && ci < (int)str.size()) - { - matcher->clearGroups(); - matcher->starts[0] = ++ci; - } - if (ret < 0) matcher->starts[0] = -1; - return ret; -} - -// NFAEndUNode - -NFAEndUNode::NFAEndUNode() { } -int NFAEndUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - matcher->ends[0] = curInd; - if ((matcher->getFlags() & WCMatcher::MATCH_ENTIRE_STRING) != 0) - { - if (curInd == (int)str.size()) return curInd; - matcher->ends[0] = -1; - return -1; - } - return curInd; -} - -// NFAQuantifierUNode - -void NFAQuantifierUNode::findAllNodes(std::map & soFar) -{ - inner->findAllNodes(soFar); - NFAUNode::findAllNodes(soFar); -} -NFAQuantifierUNode::NFAQuantifierUNode(WCPattern * pat, NFAUNode * internal, const int minMatch, const int maxMatch) -{ - inner = internal; - inner->next = pat->registerNode(new NFAAcceptUNode); - min = (minMatch < WCPattern::MIN_QMATCH) ? WCPattern::MIN_QMATCH : minMatch; - max = (maxMatch > WCPattern::MAX_QMATCH) ? WCPattern::MAX_QMATCH : maxMatch; -} - -int NFAQuantifierUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int i0, i1, i2 = 0; - - i0 = i1 = curInd; - while (i2 < min) - { - - ++i2; - i1 = inner->match(str, matcher, i0); - if (i1 <= i0) return i1; // i1 < i0 means i1 is -1 - i0 = i1; - } - - return i1; -} -// NFAGreedyQuantifierUNode - -NFAGreedyQuantifierUNode::NFAGreedyQuantifierUNode(WCPattern * pat, NFAUNode * internal, const int minMatch, const int maxMatch) - : NFAQuantifierUNode(pat, internal, minMatch, maxMatch) { } -int NFAGreedyQuantifierUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int t = NFAQuantifierUNode::match(str, matcher, curInd); - if (t != -1) return matchInternal(str, matcher, t, min); - return t; -} -int NFAGreedyQuantifierUNode::matchInternal(const bkstring & str, WCMatcher * matcher, const int curInd, const int soFar) const -{ - if (soFar >= max) return next->match(str, matcher, curInd); - - int i, j; - - i = inner->match(str, matcher, curInd); - if (i != -1) - { - j = matchInternal(str, matcher, i, soFar + 1); - if (j != -1) return j; - } - return next->match(str, matcher, curInd); -} - -// NFALazyQuantifierUNode - -NFALazyQuantifierUNode::NFALazyQuantifierUNode(WCPattern * pat, NFAUNode * internal, const int minMatch, const int maxMatch) - : NFAQuantifierUNode(pat, internal, minMatch, maxMatch) { } -int NFALazyQuantifierUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int i, j, m = NFAQuantifierUNode::match(str, matcher, curInd); - - if (m == -1) return -1; - - for (i = min; i < max; ++i) - { - j = next->match(str, matcher, m); - if (j == -1) - { - j = inner->match(str, matcher, m); - // if j < m, then j is -1, so we bail. - // if j == m, then we would just go and call next->match on the same index, - // but it already failed trying to match right there, so we know we can - // just bail - if (j <= m) return -1; - m = j; - } - else return j; - } - return next->match(str, matcher, m); -} - -// NFAPossessiveQuantifierUNode - -NFAPossessiveQuantifierUNode::NFAPossessiveQuantifierUNode(WCPattern * pat, NFAUNode * internal, const int minMatch, const int maxMatch) - : NFAQuantifierUNode(pat, internal, minMatch, maxMatch) { } -int NFAPossessiveQuantifierUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int i, j, m = NFAQuantifierUNode::match(str, matcher, curInd); - - if (m == -1) return -1; - for (i = min; i < max; ++i) - { - j = inner->match(str, matcher, m); - if (j <= m) return next->match(str, matcher, m); - m = j; - } - return next->match(str, matcher, m); -} - -// NFAAcceptUNode - -NFAAcceptUNode::NFAAcceptUNode() { } -int NFAAcceptUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (!next) return curInd; - else return next->match(str, matcher, curInd); -} - -// NFAClassUNode - -NFAClassUNode::NFAClassUNode(const bool invert) -{ - inv = invert; -} -NFAClassUNode::NFAClassUNode(const bkstring & clazz, const bool invert) -{ - inv = invert; - for (int i = 0; i < (int)clazz.size(); ++i) vals[clazz[i]] = 1; -} -int NFAClassUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd < (int)str.size() && ((vals.find(str[curInd]) != vals.end()) ^ inv)) - { - return next->match(str, matcher, curInd + 1); - } - return -1; -} - -// NFACIClassUNode - -NFACIClassUNode::NFACIClassUNode(const bool invert) -{ - inv = invert; -} -NFACIClassUNode::NFACIClassUNode(const bkstring & clazz, const bool invert) -{ - inv = invert; - for (int i = 0; i < (int)clazz.size(); ++i) vals[to_lower(clazz[i])] = 1; -} -int NFACIClassUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd < (int)str.size() && ((vals.find(to_lower(str[curInd])) != vals.end()) ^ inv)) - { - return next->match(str, matcher, curInd + 1); - } - return -1; -} - -// NFASubStartUNode - -NFASubStartUNode::NFASubStartUNode() { } -int NFASubStartUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - return next->match(str, matcher, curInd); -} - -// NFAOrUNode - -NFAOrUNode::NFAOrUNode(NFAUNode * first, NFAUNode * second) : one(first), two(second) { } -void NFAOrUNode::findAllNodes(std::map & soFar) -{ - if (one) one->findAllNodes(soFar); - if (two) two->findAllNodes(soFar); - NFAUNode::findAllNodes(soFar); -} -int NFAOrUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int ci = one->match(str, matcher, curInd); - - if (ci != -1) ci = next->match(str, matcher, ci); - if (ci != -1) return ci; - if (ci == -1) ci = two->match(str, matcher, curInd); - if (ci != -1) ci = next->match(str, matcher, ci); - return ci; -} - -// NFAQuoteUNode - -NFAQuoteUNode::NFAQuoteUNode(const bkstring & quoted) : qStr(quoted) { } -int NFAQuoteUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd + qStr.size() > str.size()) return -1; - if (str.substr(curInd, qStr.size()) != qStr) return -1; - return next->match(str, matcher, curInd + (int)qStr.size()); -} - -// NFACIQuoteUNode - -NFACIQuoteUNode::NFACIQuoteUNode(const bkstring & quoted) : qStr(quoted) { } -int NFACIQuoteUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd + qStr.size() > str.size()) return -1; - if (str_icmp(str.substr(curInd, qStr.size()).c_str(), qStr.c_str())) return -1; - return next->match(str, matcher, (int)qStr.size()); -} - -// NFALookAheadUNode - -NFALookAheadUNode::NFALookAheadUNode(NFAUNode * internal, const bool positive) : NFAUNode(), pos(positive), inner(internal) { } -void NFALookAheadUNode::findAllNodes(std::map & soFar) -{ - if (inner) inner->findAllNodes(soFar); - NFAUNode::findAllNodes(soFar); -} -int NFALookAheadUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - return ((inner->match(str, matcher, curInd) == -1) ^ pos) ? next->match(str, matcher, curInd) : -1; -} - -// NFALookBehindUNode - -NFALookBehindUNode::NFALookBehindUNode(const bkstring & str, const bool positive) : pos(positive), mStr(str) { } -int NFALookBehindUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (pos) - { - if (curInd < (int)mStr.size()) return -1; - if (str.substr(curInd - mStr.size(), mStr.size()) == mStr) return next->match(str, matcher, curInd); - } - else - { - if (curInd < (int)mStr.size()) return next->match(str, matcher, curInd); - if (str.substr(curInd - mStr.size(), mStr.size()) == mStr) return -1; - return next->match(str, matcher, curInd); - } - return -1; -} - -// NFAStartOfLineUNode - -NFAStartOfLineUNode::NFAStartOfLineUNode() { } -int NFAStartOfLineUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd == 0 || str[curInd - 1] == (wchar_t)'\n' || str[curInd - 1] == (wchar_t)'\r') - { - return next->match(str, matcher, curInd); - } - return -1; -} - -// NFAEndOfLineUNode - -NFAEndOfLineUNode::NFAEndOfLineUNode() { } -int NFAEndOfLineUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd >= (int)str.size() || str[curInd] == (wchar_t)'\n' || str[curInd] == (wchar_t)'\r') - { - return next->match(str, matcher, curInd); - } - return -1; -} - -// NFAReferenceUNode - -NFAReferenceUNode::NFAReferenceUNode(const int groupIndex) : gi(groupIndex) { } -int NFAReferenceUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int len = matcher->ends[gi] - matcher->starts[gi]; - int ni = -1; - if (gi < 1 || matcher->ends[gi] < matcher->starts[gi] || len == 0) ni = curInd; - else if (curInd + len > (int)str.size()) return -1; - else if (str.substr(curInd, len) != str.substr(matcher->starts[gi], len)) return -1; - else ni = curInd + len; - - return next->match(str, matcher, ni); -} - -// NFAStartOfInputUNode - -NFAStartOfInputUNode::NFAStartOfInputUNode() { } -int NFAStartOfInputUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd == 0) return next->match(str, matcher, curInd); - return -1; -} - -// NFAEndOfInputUNode - -NFAEndOfInputUNode::NFAEndOfInputUNode(const bool lookForTerm) : term(lookForTerm) { } -int NFAEndOfInputUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int len = (int)str.size(); - if (curInd == len) return next->match(str, matcher, curInd); - else if (term) - { - if (curInd == len - 1 && (str[curInd] == (wchar_t)'\r' || str[curInd] == (wchar_t)'\n')) - { - return next->match(str, matcher, curInd); - } - else if (curInd == len - 2 && str.substr(curInd, 2) == L"\r\n") - { - return next->match(str, matcher, curInd); - } - } - return -1; -} - -// NFAWordBoundaryUNode - -NFAWordBoundaryUNode::NFAWordBoundaryUNode(const bool positive) : pos(positive) { } -int NFAWordBoundaryUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int len = (int)str.size(); - - wchar_t c1 = (curInd - 1 < len && curInd > 0) ? str[curInd - 1] : '\n'; - wchar_t c2 = (curInd < len) ? str[curInd ] : '\n'; - - if (curInd == len) return next->match(str, matcher, curInd); - bool ok = is_alpha(c1) != is_alpha(c2); - if (ok && pos) return next->match(str, matcher, curInd); - return -1; -} - -// NFAEndOfMatchUNode - -NFAEndOfMatchUNode::NFAEndOfMatchUNode() { } -int NFAEndOfMatchUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - if (curInd == matcher->lm) return next->match(str, matcher, curInd); - return -1; -} - -// NFAGroupHeadUNode - -NFAGroupHeadUNode::NFAGroupHeadUNode(const int groupIndex) : gi(groupIndex) { } -int NFAGroupHeadUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int ret, o = matcher->starts[gi]; - - matcher->starts[gi] = curInd; - ret = next->match(str, matcher, curInd); - if (ret < 0) matcher->starts[gi] = o; - - return ret; -} - -// NFAGroupTailUNode - -NFAGroupTailUNode::NFAGroupTailUNode(const int groupIndex) : gi(groupIndex) { } -int NFAGroupTailUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int ret, o = matcher->ends[gi]; - - matcher->ends[gi] = curInd; - ret = next->match(str, matcher, curInd); - if (ret < 0) matcher->ends[gi] = o; - - return ret; -} - -// NFAGroupLoopPrologueUNode - -NFAGroupLoopPrologueUNode::NFAGroupLoopPrologueUNode(const int groupIndex) : gi(groupIndex) { } -int NFAGroupLoopPrologueUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int ret, o1 = matcher->groups[gi], o2 = matcher->groupPos[gi], o3 = matcher->groupIndeces[gi]; - - matcher->groups[gi] = 0; - matcher->groupPos[gi] = 0; - matcher->groupIndeces[gi] = -1; - ret = next->match(str, matcher, curInd); - if (ret < 0) - { - matcher->groups[gi] = o1; - matcher->groupPos[gi] = o2; - matcher->groupIndeces[gi] = o3; - } - - return ret; -} - -// NFAGroupLoopUNode - -NFAGroupLoopUNode::NFAGroupLoopUNode(NFAUNode * internal, const int minMatch, const int maxMatch, - const int groupIndex, const int matchType) -{ - inner = internal; - min = minMatch; - max = maxMatch; - gi = groupIndex; - type = matchType; -} -void NFAGroupLoopUNode::findAllNodes(std::map & soFar) -{ - if (inner) inner->findAllNodes(soFar); - NFAUNode::findAllNodes(soFar); -} -int NFAGroupLoopUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - bool b = (curInd > matcher->groupIndeces[gi]); - - if (b && matcher->groups[gi] < min) - { - ++matcher->groups[gi]; - int o = matcher->groupIndeces[gi]; - matcher->groupIndeces[gi] = curInd; - int ret = inner->match(str, matcher, curInd); - if (ret < 0) - { - matcher->groupIndeces[gi] = o; - --matcher->groups[gi]; - } - return ret; - } - else if (!b || matcher->groups[gi] >= max) - { - return next->match(str, matcher, curInd); - } - else - { - switch (type) - { - case 0: return matchGreedy(str, matcher, curInd); - case 1: return matchLazy(str, matcher, curInd); - case 2: return matchPossessive(str, matcher, curInd); - } - } - return -1; -} -int NFAGroupLoopUNode::matchGreedy(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int o = matcher->groupIndeces[gi]; // save our info for backtracking - matcher->groupIndeces[gi] = curInd; // move along - ++matcher->groups[gi]; - int ret = inner->match(str, matcher, curInd); // match internally - if (ret < 0) - { // if we failed, then restore info and match next - --matcher->groups[gi]; - matcher->groupIndeces[gi] = o; - ret = next->match(str, matcher, curInd); - } - return ret; -} -int NFAGroupLoopUNode::matchLazy(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int ret = next->match(str, matcher, curInd); // be lazy, just go on - if (ret < 0) - { - int o = matcher->groupIndeces[gi]; // save info for backtracking - matcher->groupIndeces[gi] = curInd; // advance our position - ++matcher->groups[gi]; - ret = inner->match(str, matcher, curInd); // match our internal stuff - if (ret < 0) // if we failed, then restore the info - { - --matcher->groups[gi]; - matcher->groupIndeces[gi] = o; - } - } - return ret; -} -int NFAGroupLoopUNode::matchPossessive(const bkstring & str, WCMatcher * matcher, const int curInd) const -{ - int o = matcher->groupIndeces[gi]; // save info for backtracking - matcher->groupPos[gi] = matcher->groups[gi]; // set a flag stating we have matcher at least this much - matcher->groupIndeces[gi] = curInd; // move along - ++matcher->groups[gi]; - int ret = inner->match(str, matcher, curInd); // try and match again - if (ret < 0) - { // if we fail, back off, but to an extent - --matcher->groups[gi]; - matcher->groupIndeces[gi] = o; - if (matcher->groups[gi] == matcher->groupPos[gi]) ret = next->match(str, matcher, curInd); - } - return ret; -} - -#ifdef _WIN32 - #pragma warning(pop) -#endif diff --git a/plugins/SmileyAdd/regexp/WCPattern.h b/plugins/SmileyAdd/regexp/WCPattern.h deleted file mode 100644 index 3d52a7fd2e..0000000000 --- a/plugins/SmileyAdd/regexp/WCPattern.h +++ /dev/null @@ -1,1663 +0,0 @@ -#ifndef __WCPATTERN_H__ -#define __WCPATTERN_H__ - -#ifdef _WIN32 - #pragma warning(disable:4786) -#endif - -#include "bkstring.h" - -#include -#include - -class WCMatcher; -class NFAUNode; -class NFAQuantifierUNode; - -/** - This pattern class is very similar in functionality to Java's - java.util.regex.WCPattern class. The pattern class represents an immutable - regular expression object. Instead of having a single object contain both the - regular expression object and the matching object, instead the two objects are - split apart. The {@link WCMatcher WCMatcher} class represents the maching - object. - - The WCPattern class works primarily off of "compiled" patterns. A typical - instantiation of a regular expression looks like: - -

-  WCPattern * p = WCPattern::compile(L"a*b");
-  WCMatcher * m = p->createWCMatcher(L"aaaaaab");
-  if (m->matches()) ...
-  
- - However, if you do not need to use a pattern more than once, it is often times - okay to use the WCPattern's static methods insteads. An example looks like this: - -
-  if (WCPattern::matches(L"a*b", L"aaaab")) { ... }
-  
- - This class does not currently support unicode. The unicode update for this - class is coming soon. - - This class is partially immutable. It is completely safe to call createWCMatcher - concurrently in different threads, but the other functions (e.g. split) should - not be called concurrently on the same WCPattern. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Construct - - Matches - -
-   -
- Characters -
- x - - The character x -
- \\ - - The character \ -
- \0nn - - The character with octal ASCII value nn -
- \0nnn - - The character with octal ASCII value nnn -
- \xhh - - The character with hexadecimal ASCII value hh -
- \t - - A tab character -
- \r - - A carriage return character -
- \n - - A new-line character -
-   -
- Character Classes -
- [abc] - - Either a, b, or c -
- [^abc] - - Any character but a, b, or c -
- [a-zA-Z] - - Any character ranging from a thru z, or - A thru Z -
- [^a-zA-Z] - - Any character except those ranging from a thru - z, or A thru Z -
- [a\-z] - - Either a, -, or z -
- [a-z[A-Z]] - - Same as [a-zA-Z] -
- [a-z&&[g-i]] - - Any character in the intersection of a-z and - g-i -
- [a-z&&[^g-i]] - - Any character in a-z and not in g-i -
-   -
- Prefefined character classes -
- . - - Any character. Multiline matching must be compiled into the pattern for - . to match a \r or a \n. - Even if multiline matching is enabled, . will not - match a \r\n, only a \r or a \n. -
- \d - - [0-9] -
- \D - - [^\d] -
- \s - - [ \t\r\n\x0B] -
- \S - - [^\s] -
- \w - - [a-zA-Z0-9_] -
- \W - - [^\w] -
-   -
- POSIX character classes -
- \p{Lower} - - [a-z] -
- \p{Upper} - - [A-Z] -
- \p{ASCII} - - [\x00-\x7F] -
- \p{Alpha} - - [a-zA-Z] -
- \p{Digit} - - [0-9] -
- \p{Alnum} - - [\w&&[^_]] -
- \p{Punct} - - [!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~] -
- \p{XDigit} - - [a-fA-F0-9] -
-   -
- Boundary Matches -
- ^ - - The beginning of a line. Also matches the beginning of input. -
- $ - - The end of a line. Also matches the end of input. -
- \b - - A word boundary -
- \B - - A non word boundary -
- \A - - The beginning of input -
- \G - - The end of the previous match. Ensures that a "next" match will only - happen if it begins with the character immediately following the end of - the "current" match. -
- \Z - - The end of input. Will also match if there is a single trailing - \r\n, a single trailing \r, or a single - trailing \n. -
- \z - - The end of input -
-   -
- Greedy Quantifiers -
- x? - - x, either zero times or one time -
- x* - - x, zero or more times -
- x+ - - x, one or more times -
- x{n} - - x, exactly n times -
- x{n,} - - x, at least n times -
- x{,m} - - x, at most m times -
- x{n,m} - - x, at least n times and at most - m times -
-   -
- Possessive Quantifiers -
- x?+ - - x, either zero times or one time -
- x*+ - - x, zero or more times -
- x++ - - x, one or more times -
- x{n}+ - - x, exactly n times -
- x{n,}+ - - x, at least n times -
- x{,m}+ - - x, at most m times -
- x{n,m}+ - - x, at least n times and at most - m times -
-   -
- Reluctant Quantifiers -
- x?? - - x, either zero times or one time -
- x*? - - x, zero or more times -
- x+? - - x, one or more times -
- x{n}? - - x, exactly n times -
- x{n,}? - - x, at least n times -
- x{,m}? - - x, at most m times -
- x{n,m}? - - x, at least n times and at most - m times -
-   -
- Operators -
- xy - - x then y -
- x|y - - x or y -
- (x) - - x as a capturing group -
-   -
- Quoting -
- \Q - - Nothing, but treat every character (including \s) literally until a - matching \E -
- \E - - Nothing, but ends its matching \Q -
-   -
- Special Constructs -
- (?:x) - - x, but not as a capturing group -
- (?=x) - - x, via positive lookahead. This means that the - expression will match only if it is trailed by x. - It will not "eat" any of the characters matched by - x. -
- (?!x) - - x, via negative lookahead. This means that the - expression will match only if it is not trailed by - x. It will not "eat" any of the characters - matched by x. -
- (?<=x) - - x, via positive lookbehind. x - cannot contain any quantifiers. -
- (?x) - - x, via negative lookbehind. x - cannot contain any quantifiers. -
- (?>x) - - x{1}+ -
-   -
- Registered Expression Matching -
- {x} - - The registered pattern x -
- -
- - Begin Text Extracted And Modified From java.util.regex.WCPattern documentation - -

Backslashes, escapes, and quoting

- -

The backslash character ((wchar_t)'\') serves to introduce escaped - constructs, as defined in the table above, as well as to quote characters - that otherwise would be interpreted as unescaped constructs. Thus the - expression \\ matches a single backslash and \{ matches a - left brace. - -

It is an error to use a backslash prior to any alphabetic character that - does not denote an escaped construct; these are reserved for future - extensions to the regular-expression language. A backslash may be used - prior to a non-alphabetic character regardless of whether that character is - part of an unescaped construct. - -

It is necessary to double backslashes in string literals that represent - regular expressions to protect them from interpretation by a compiler. The - string literal "\b", for example, matches a single backspace - character when interpreted as a regular expression, while - "\\b" matches a word boundary. The string litera - "\(hello\)" is illegal and leads to a compile-time error; - in order to match the string (hello) the string literal - "\\(hello\\)" must be used. - -

Character Classes

- -

Character classes may appear within other character classes, and - may be composed by the union operator (implicit) and the intersection - operator (&&). - The union operator denotes a class that contains every character that is - in at least one of its operand classes. The intersection operator - denotes a class that contains every character that is in both of its - operand classes. - -

The precedence of character-class operators is as follows, from - highest to lowest: - -

- - - - - - - - - - - - - - - - -
1    Literal escape    \x
2    Rangea-z
3    Grouping[...]
4    Intersection[a-z&&[aeiou]]
5    Union[a-e][i-u]
- -

Note that a different set of metacharacters are in effect inside - a character class than outside a character class. For instance, the - regular expression . loses its special meaning inside a - character class, while the expression - becomes a range - forming metacharacter. - - - - -

Groups and capturing

- -

Capturing groups are numbered by counting their opening parentheses from - left to right. In the expression ((A)(B(C))), for example, there - are four such groups:

- -
- - - - - - - - - - -
1    ((A)(B(C)))
2    (A)
3    (B(C))
4    (C)
- -

Group zero always stands for the entire expression. - -

Capturing groups are so named because, during a match, each subsequence - of the input sequence that matches such a group is saved. The captured - subsequence may be used later in the expression, via a back reference, and - may also be retrieved from the matcher once the match operation is complete. - -

The captured input associated with a group is always the subsequence - that the group most recently matched. If a group is evaluated a second time - because of quantification then its previously-captured value, if any, will - be retained if the second evaluation fails. Matching the string - L"aba" against the expression (a(b)?)+, for example, leaves - group two set to L"b". All captured input is discarded at the - beginning of each match. - -

Groups beginning with (? are pure, non-capturing groups - that do not capture text and do not count towards the group total. - - -

WC support

- -

Coming Soon. - -

Comparison to Perl 5

- -

The WCPattern engine performs traditional NFA-based matching - with ordered alternation as occurs in Perl 5. - -

Perl constructs not supported by this class:

- -
    - -
  • The conditional constructs (?{X}) and - (?(condition)X|Y), -

  • - -
  • The embedded code constructs (?{code}) - and (??{code}),

  • - -
  • The embedded comment syntax (?#comment), and

  • - -
  • The preprocessing operations \l \u, - \L, and \U.

  • - -
  • Embedded flags

  • - -
- -

Constructs supported by this class but not by Perl:

- -
    - -
  • Possessive quantifiers, which greedily match as much as they can - and do not back off, even when doing so would allow the overall match to - succeed.

  • - -
  • Character-class union and intersection as described - above.

  • - -
- -

Notable differences from Perl:

- -
    - -
  • In Perl, \1 through \9 are always interpreted - as back references; a backslash-escaped number greater than 9 is - treated as a back reference if at least that many subexpressions exist, - otherwise it is interpreted, if possible, as an octal escape. In this - class octal escapes must always begin with a zero. In this class, - \1 through \9 are always interpreted as back - references, and a larger number is accepted as a back reference if at - least that many subexpressions exist at that point in the regular - expression, otherwise the parser will drop digits until the number is - smaller or equal to the existing number of groups or it is one digit. -

  • - -
  • Perl uses the g flag to request a match that resumes - where the last match left off. This functionality is provided implicitly - by the WCMatcher class: Repeated invocations of the - find method will resume where the last match left off, - unless the matcher is reset.

  • - -
  • Perl is forgiving about malformed matching constructs, as in the - expression *a, as well as dangling brackets, as in the - expression abc], and treats them as literals. This - class also strict and will not compile a pattern when dangling characters - are encountered.

  • - -
- - -

For a more precise description of the behavior of regular expression - constructs, please see - Mastering Regular Expressions, 2nd Edition, Jeffrey E. F. Friedl, - O'Reilly and Associates, 2002. -

-

- - End Text Extracted And Modified From java.util.regex.WCPattern documentation - -


- - @author Jeffery Stuart - @since March 2003, Stable Since November 2004 - @version 1.07.00 - @memo A class used to represent "PERL 5"-ish regular expressions - */ -class WCPattern -{ - friend class WCMatcher; - friend class NFAUNode; - friend class NFAQuantifierUNode; - private: - /** - This constructor should not be called directly. Those wishing to use the - WCPattern class should instead use the {@link compile compile} method. - - @param rhs The pattern to compile - @memo Creates a new pattern from the regular expression in rhs. - */ - WCPattern(const bkstring & rhs); - protected: - /** - This currently is not used, so don't try to do anything with it. - @memo Holds all the compiled patterns for quick access. - */ - static std::map compiledWCPatterns; - /** - Holds all of the registered patterns as strings. Due to certain problems - with compilation of patterns, especially with capturing groups, this seemed - to be the best way to do it. - */ - static std::map > registeredWCPatterns; - protected: - /** - Holds all the NFA nodes used. This makes deletion of a pattern, as well as - clean-up from an unsuccessful compile much easier and faster. - */ - std::map nodes; - /** - Used when methods like split are called. The matcher class uses a lot of - dynamic memeory, so having an instance increases speedup of certain - operations. - */ - WCMatcher * matcher; - /** - The front node of the NFA. - */ - NFAUNode * head; - /** - The actual regular expression we rerpesent - */ - bkstring pattern; - /** - Flag used during compilation. Once the pattern is successfully compiled, - error is no longer used. - */ - bool error; - /** - Used during compilation to keep track of the current index into - {@link pattern pattern}. Once the pattern is successfully - compiled, error is no longer used. - */ - int curInd; - /** - The number of capture groups this contains. - */ - int groupCount; - /** - The number of non-capture groups this contains. - */ - int nonCapGroupCount; - /** - The flags specified when this was compiled. - */ - unsigned long flags; - protected: - /** - Raises an error during compilation. Compilation will cease at that point - and compile will return NULL. - */ - void raiseError(); - /** - Convenience function for registering a node in nodes. - @param node The node to register - @return The registered node - */ - NFAUNode * registerNode(NFAUNode * node); - - /** - Calculates the union of two strings. This function will first sort the - strings and then use a simple selection algorithm to find the union. - @param s1 The first "class" to union - @param s2 The second "class" to union - @return A new string containing all unique characters. Each character - must have appeared in one or both of s1 and - s2. - */ - bkstring classUnion (bkstring s1, bkstring s2) const; - /** - Calculates the intersection of two strings. This function will first sort - the strings and then use a simple selection algorithm to find the - intersection. - @param s1 The first "class" to intersect - @param s2 The second "class" to intersect - @return A new string containing all unique characters. Each character - must have appeared both s1 and s2. - */ - bkstring classIntersect (bkstring s1, bkstring s2) const; - /** - Calculates the negation of a string. The negation is the set of all - characters between \x00 and \xFF not - contained in s1. - @param s1 The "class" to be negated. - @param s2 The second "class" to intersect - @return A new string containing all unique characters. Each character - must have appeared both s1 and s2. - */ - bkstring classNegate (bkstring s1) const; - /** - Creates a new "class" representing the range from low thru - hi. This function will wrap if low > - hi. This is a feature, not a buf. Sometimes it is useful - to be able to say [\x70-\x10] instead of [\x70-\x7F\x00-\x10]. - @param low The beginning character - @param hi The ending character - @return A new string containing all the characters from low thru hi. - */ - bkstring classCreateRange(wchar_t low, wchar_t hi) const; - - /** - Extracts a decimal number from the substring of member-variable - {@link pattern pattern} starting at start and - ending at end. - @param start The starting index in {@link pattern pattern} - @param end The last index in {@link pattern pattern} - @return The decimal number in {@link pattern pattern} - */ - int getInt(int start, int end); - /** - Parses a {n,m} string out of the member-variable - {@link pattern pattern} stores the result in sNum - and eNum. - @param sNum Output parameter. The minimum number of matches required - by the curly quantifier are stored here. - @param eNum Output parameter. The maximum number of matches allowed - by the curly quantifier are stored here. - @return Success/Failure. Fails when the curly does not have the proper - syntax - */ - bool quantifyCurly(int & sNum, int & eNum); - /** - Tries to quantify the currently parsed group. If the group being parsed - is indeed quantified in the member-variable - {@link pattern pattern}, then the NFA is modified accordingly. - @param start The starting node of the current group being parsed - @param stop The ending node of the current group being parsed - @param gn The group number of the current group being parsed - @return The node representing the starting node of the group. If the - group becomes quantified, then this node is not necessarily - a GroupHead node. - */ - NFAUNode * quantifyGroup(NFAUNode * start, NFAUNode * stop, const int gn); - - /** - Tries to quantify the last parsed expression. If the character was indeed - quantified, then the NFA is modified accordingly. - @param newNode The recently created expression node - @return The node representing the last parsed expression. If the - expression was quantified, return value != newNode - */ - NFAUNode * quantify(NFAUNode * newNode); - /** - Parses the current class being examined in - {@link pattern pattern}. - @return A string of unique characters contained in the current class being - parsed - */ - bkstring parseClass(); - /** - Parses the current POSIX class being examined in - {@link pattern pattern}. - @return A string of unique characters representing the POSIX class being - parsed - */ - bkstring parsePosix(); - /** - Returns a string containing the octal character being parsed - @return The string contained the octal value being parsed - */ - bkstring parseOctal(); - /** - Returns a string containing the hex character being parsed - @return The string contained the hex value being parsed - */ - bkstring parseHex(); - /** - Returns a new node representing the back reference being parsed - @return The new node representing the back reference being parsed - */ - NFAUNode * parseBackref(); - /** - Parses the escape sequence currently being examined. Determines if the - escape sequence is a class, a single character, or the beginning of a - quotation sequence. - @param inv Output parameter. Whether or not to invert the returned class - @param quo Output parameter. Whether or not this sequence starts a - quotation. - @return The characters represented by the class - */ - bkstring parseEscape(bool & inv, bool & quo); - /** - Parses a supposed registered pattern currently under compilation. If the - sequence of characters does point to a registered pattern, then the - registered pattern is appended to *end. The registered pattern - is parsed with the current compilation flags. - @param end The ending node of the thus-far compiled pattern - @return The new end node of the current pattern - */ - NFAUNode * parseRegisteredWCPattern(NFAUNode ** end); - /** - Parses a lookbehind expression. Appends the necessary nodes - *end. - @param pos Positive or negative look behind - @param end The ending node of the current pattern - @return The new end node of the current pattern - */ - NFAUNode * parseBehind(const bool pos, NFAUNode ** end); - /** - Parses the current expression and tacks on nodes until a \E is found. - @return The end of the current pattern - */ - NFAUNode * parseQuote(); - /** - Parses {@link pattern pattern}. This function is called - recursively when an or (|) or a group is encountered. - @param inParen Are we currently parsing inside a group - @param inOr Are we currently parsing one side of an or (|) - @param end The end of the current expression - @return The starting node of the NFA constructed from this parse - */ - NFAUNode * parse(const bool inParen = 0, const bool inOr = 0, NFAUNode ** end = NULL); - public: - /// We should match regardless of case - const static unsigned long CASE_INSENSITIVE; - /// We are implicitly quoted - const static unsigned long LITERAL; - /// @memo We should treat a . as [\x00-\x7F] - const static unsigned long DOT_MATCHES_ALL; - /** ^ and $ should anchor to the beginning and - ending of lines, not all input - */ - const static unsigned long MULTILINE_MATCHING; - /** When enabled, only instances of \n are recognized as - line terminators - */ - const static unsigned long UNIX_LINE_MODE; - /// The absolute minimum number of matches a quantifier can match (0) - const static int MIN_QMATCH; - /// The absolute maximum number of matches a quantifier can match (0x7FFFFFFF) - const static int MAX_QMATCH; - public: - /** - Call this function to compile a regular expression into a - WCPattern object. Special values can be assigned to - mode when certain non-standard behaviors are expected from - the WCPattern object. - @param pattern The regular expression to compile - @param mode A bitwise or of flags signalling what special behaviors are - wanted from this WCPattern object - @return If successful, compile returns a WCPattern - pointer. Upon failure, compile returns - NULL - */ - static WCPattern * compile (const bkstring & pattern, - const unsigned long mode = 0); - /** - Dont use this function. This function will compile a pattern, and cache - the result. This will eventually be used as an optimization when people - just want to call static methods using the same pattern over and over - instead of first compiling the pattern and then using the compiled - instance for matching. - @param pattern The regular expression to compile - @param mode A bitwise or of flags signalling what special behaviors are - wanted from this WCPattern object - @return If successful, compileAndKeep returns a - WCPattern pointer. Upon failure, compile - returns NULL. - */ - static WCPattern * compileAndKeep (const bkstring & pattern, - const unsigned long mode = 0); - - /** - Searches through replace and replaces all substrings matched - by pattern with str. str may - contain backreferences (e.g. \1) to capture groups. A typical - invocation looks like: -

- - WCPattern::replace(L"(a+)b(c+)", L"abcccbbabcbabc", L"\\2b\\1"); - -

- which would replace abcccbbabcbabc with - cccbabbcbabcba. - @param pattern The regular expression - @param str The replacement text - @param replacementText The string in which to perform replacements - @param mode The special mode requested of the WCPattern - during the replacement process - @return The text with the replacement string substituted where necessary - */ - static bkstring replace (const bkstring & pattern, - const bkstring & str, - const bkstring & replacementText, - const unsigned long mode = 0); - - /** - Splits the specified string over occurrences of the specified pattern. - Empty strings can be optionally ignored. The number of strings returned is - configurable. A typical invocation looks like: -

- - bkstring str(strSize, 0);
- FILE * fp = fopen(fileName, "r");
- fread((char*)str.data(), strSize * 2, 1, fp);
- fclose(fp);
-
- std::vector<bkstring> lines = WCPattern::split(L"[\r\n]+", str, true);
-
-
- - @param pattern The regular expression - @param replace The string to split - @param keepEmptys Whether or not to keep empty strings - @param limit The maximum number of splits to make - @param mode The special mode requested of the WCPattern - during the split process - @return All substrings of str split across pattern. - */ - static std::vector split (const bkstring & pattern, - const bkstring & str, - const bool keepEmptys = 0, - const unsigned long limit = 0, - const unsigned long mode = 0); - - /** - Finds all the instances of the specified pattern within the string. You - should be careful to only pass patterns with a minimum length of one. For - example, the pattern a* can be matched by an empty string, so - instead you should pass a+ since at least one character must - be matched. A typical invocation of findAll looks like: -

- - std::vector<td::string> numbers = WCPattern::findAll(L"\\d+", string); - -

- - @param pattern The pattern for which to search - @param str The string to search - @param mode The special mode requested of the WCPattern - during the find process - @return All instances of pattern in str - */ - static std::vector findAll (const bkstring & pattern, - const bkstring & str, - const unsigned long mode = 0); - - /** - Determines if an entire string matches the specified pattern - - @param pattern The pattern for to match - @param str The string to match - @param mode The special mode requested of the WCPattern - during the replacement process - @return True if str is recognized by pattern - */ - static bool matches (const bkstring & pattern, - const bkstring & str, - const unsigned long mode = 0); - - /** - Registers a pattern under a specific name for use in later compilations. - A typical invocation and later use looks like: -

- - WCPattern::registerWCPattern(L"ip", L"(?:\\d{1,3}\\.){3}\\d{1,3}");
- WCPattern * p1 = WCPattern::compile(L"{ip}:\\d+");
- WCPattern * p2 = WCPattern::compile(L"Connection from ({ip}) on port \\d+");
-
-

- Multiple calls to registerWCPattern with the same - name will result in the pattern getting overwritten. - - @param name The name to give to the pattern - @param pattern The pattern to register - @param mode Any special flags to use when compiling pattern - @return Success/Failure. Fails only if pattern has invalid - syntax - */ - static bool registerWCPattern(const bkstring & name, - const bkstring & pattern, - const unsigned long mode = 0); - - /** - Clears the pattern registry - */ - static void unregisterWCPatterns(); - /** - Don't use - */ - static void clearWCPatternCache(); - - /** - Searches through a string for the nth match of the - given pattern in the string. Match indeces start at zero, not one. - A typical invocation looks like this: -

- - std::pair<bkstring, int> match = WCPattern::findNthMatch(L"\\d{1,3}", L"192.168.1.101:22", 1);
- wprintf(L"%s %i\n", match.first.c_str(), match.second);
-
- Output: 168 4
-
- - @param pattern The pattern for which to search - @param str The string to search - @param matchNum Which match to find - @param mode Any special flags to use during the matching process - @return A string and an integer. The string is the string matched. The - integer is the starting location of the matched string in - str. You can check for success/failure by making sure - that the integer returned is greater than or equal to zero. - */ - static std::pair findNthMatch (const bkstring & pattern, - const bkstring & str, - const int matchNum, - const unsigned long mode = 0); - public: - /** - Deletes all NFA nodes allocated during compilation - */ - ~WCPattern(); - - bkstring replace (const bkstring & str, - const bkstring & replacementText); - std::vector split (const bkstring & str, const bool keepEmptys = 0, - const unsigned long limit = 0); - std::vector findAll (const bkstring & str); - bool matches (const bkstring & str); - /** - Returns the flags used during compilation of this pattern - @return The flags used during compilation of this pattern - */ - unsigned long getFlags () const; - /** - Returns the regular expression this pattern represents - @return The regular expression this pattern represents - */ - bkstring getWCPattern () const; - /** - Creates a matcher object using the specified string and this pattern. - @param str The string to match against - @return A new matcher using object using this pattern and the specified - string - */ - WCMatcher * createWCMatcher (const bkstring & str); -}; - -class NFAUNode -{ - friend class WCMatcher; - public: - NFAUNode * next; - NFAUNode(); - virtual ~NFAUNode(); - virtual void findAllNodes(std::map & soFar); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const = 0; - inline virtual bool isGroupHeadNode() const { return false; } - inline virtual bool isStartOfInputNode() const { return false; } -}; -class NFACharUNode : public NFAUNode -{ - protected: - wchar_t ch; - public: - NFACharUNode(const wchar_t c); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFACICharUNode : public NFAUNode -{ - protected: - wchar_t ch; - public: - NFACICharUNode(const wchar_t c); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAStartUNode : public NFAUNode -{ - public: - NFAStartUNode(); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAEndUNode : public NFAUNode -{ - public: - NFAEndUNode(); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAQuantifierUNode : public NFAUNode -{ - public: - int min, max; - NFAUNode * inner; - virtual void findAllNodes(std::map & soFar); - NFAQuantifierUNode(WCPattern * pat, NFAUNode * internal, - const int minMatch = WCPattern::MIN_QMATCH, - const int maxMatch = WCPattern::MAX_QMATCH); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAGreedyQuantifierUNode : public NFAQuantifierUNode -{ - public: - NFAGreedyQuantifierUNode(WCPattern * pat, NFAUNode * internal, - const int minMatch = WCPattern::MIN_QMATCH, - const int maxMatch = WCPattern::MAX_QMATCH); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; - virtual int matchInternal(const bkstring & str, WCMatcher * matcher, const int curInd, const int soFar) const; -}; -class NFALazyQuantifierUNode : public NFAQuantifierUNode -{ - public: - NFALazyQuantifierUNode(WCPattern * pat, NFAUNode * internal, - const int minMatch = WCPattern::MIN_QMATCH, - const int maxMatch = WCPattern::MAX_QMATCH); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAPossessiveQuantifierUNode : public NFAQuantifierUNode -{ - public: - NFAPossessiveQuantifierUNode(WCPattern * pat, NFAUNode * internal, - const int minMatch = WCPattern::MIN_QMATCH, - const int maxMatch = WCPattern::MAX_QMATCH); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAAcceptUNode : public NFAUNode -{ - public: - NFAAcceptUNode(); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAClassUNode : public NFAUNode -{ - public: - bool inv; - std::map vals; - NFAClassUNode(const bool invert = 0); - NFAClassUNode(const bkstring & clazz, const bool invert); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFACIClassUNode : public NFAUNode -{ - public: - bool inv; - std::map vals; - NFACIClassUNode(const bool invert = 0); - NFACIClassUNode(const bkstring & clazz, const bool invert); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFASubStartUNode : public NFAUNode -{ - public: - NFASubStartUNode(); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAOrUNode : public NFAUNode -{ - public: - NFAUNode * one; - NFAUNode * two; - NFAOrUNode(NFAUNode * first, NFAUNode * second); - virtual void findAllNodes(std::map & soFar); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAQuoteUNode : public NFAUNode -{ - public: - bkstring qStr; - NFAQuoteUNode(const bkstring & quoted); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFACIQuoteUNode : public NFAUNode -{ - public: - bkstring qStr; - NFACIQuoteUNode(const bkstring & quoted); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFALookAheadUNode : public NFAUNode -{ - public: - bool pos; - NFAUNode * inner; - NFALookAheadUNode(NFAUNode * internal, const bool positive); - virtual void findAllNodes(std::map & soFar); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFALookBehindUNode : public NFAUNode -{ - public: - bool pos; - bkstring mStr; - NFALookBehindUNode(const bkstring & str, const bool positive); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAStartOfLineUNode : public NFAUNode -{ - public: - NFAStartOfLineUNode(); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAEndOfLineUNode : public NFAUNode -{ - public: - NFAEndOfLineUNode(); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAReferenceUNode : public NFAUNode -{ - public: - int gi; - NFAReferenceUNode(const int groupIndex); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAStartOfInputUNode : public NFAUNode -{ - public: - NFAStartOfInputUNode(); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; - inline virtual bool isStartOfInputNode() const { return false; } -}; -class NFAEndOfInputUNode : public NFAUNode -{ - public: - bool term; - NFAEndOfInputUNode(const bool lookForTerm); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAWordBoundaryUNode : public NFAUNode -{ - public: - bool pos; - NFAWordBoundaryUNode(const bool positive); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAEndOfMatchUNode : public NFAUNode -{ - public: - NFAEndOfMatchUNode(); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAGroupHeadUNode : public NFAUNode -{ - public: - int gi; - NFAGroupHeadUNode(const int groupIndex); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; - inline virtual bool isGroupHeadNode() const { return false; } -}; -class NFAGroupTailUNode : public NFAUNode -{ - public: - int gi; - NFAGroupTailUNode(const int groupIndex); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAGroupLoopPrologueUNode : public NFAUNode -{ - public: - int gi; - NFAGroupLoopPrologueUNode(const int groupIndex); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; -class NFAGroupLoopUNode : public NFAUNode -{ - public: - int gi, min, max, type; - NFAUNode * inner; - NFAGroupLoopUNode(NFAUNode * internal, const int minMatch, - const int maxMatch, const int groupIndex, const int matchType); - virtual void findAllNodes(std::map & soFar); - virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; - int matchGreedy(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; - int matchLazy(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; - int matchPossessive(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; -}; - -#endif - diff --git a/plugins/SmileyAdd/regexp/test.cpp b/plugins/SmileyAdd/regexp/test.cpp deleted file mode 100644 index bb41566f96..0000000000 --- a/plugins/SmileyAdd/regexp/test.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include - -int main() -{ - { - Pattern * p = Pattern::compile("^([^:]*)://([^/:]*)((?::[0-9]+)?)/?(([^?]*)((?:\\?.*)?))$"); - Matcher * m0 = p->createMatcher("http://www.example.com:80/test.php?a=1&a=1&a=1"); - - if (m0->matches()) - { - std::vector groups = m0->getGroups(true); - for (int i = 0; i < (int)groups.size(); ++i) - { - printf("m->group(%d): %s\n", i, groups[i].c_str()); - } - } - } - { - std::wstring pat = L"^([^:]*)://([^/:]*)((?::[0-9]+)?)/?(([^?]*)((?:\\?.*)?))$"; - std::wstring mat = L"http://www.example.com:80/test.php?a=1&a=1&a=1"; - UnicodePattern * p = UnicodePattern::compile(pat); - UnicodeMatcher * m0 = p->createUnicodeMatcher(mat); - - if (m0->matches()) - { - std::vector groups = m0->getGroups(true); - for (int i = 0; i < (int)groups.size(); ++i) - { - wprintf(L"m->group(%d): %s\n", i, groups[i].c_str()); - } - } - } - - return 0; -} diff --git a/plugins/SmileyAdd/resource.h b/plugins/SmileyAdd/resource.h deleted file mode 100644 index bdf799fe2c..0000000000 --- a/plugins/SmileyAdd/resource.h +++ /dev/null @@ -1,49 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by resource.rc -// -#define IDI_SMILINGICON 124 -#define IDD_OPT_SMILEYS 245 -#define IDC_CATEGORYLIST 1017 -#define IDC_PLUGENABLED 1019 -#define IDC_INPUTSMILEYS 1020 -#define IDC_DCURSORSMILEY 1021 -#define IDC_LIBNAME 1023 -#define IDC_SPACES 1024 -#define IDC_LIBAUTHOR 1026 -#define IDC_LIBVERSION 1027 -#define IDC_SCALETOTEXTHEIGHT 1037 -#define IDC_APPENDSPACES 1040 -#define IDC_SMLOPTBUTTON 1045 -#define IDC_SCALEALLSMILEYS 1046 -#define IDC_IEVIEWSTYLE 1047 -#define IDC_ANIMATESEL 1048 -#define IDC_USESTDPACK 1049 -#define IDC_ANIMATEDLG 1051 -#define IDC_DISABLECUSTOM 1052 -#define IDC_DISABLECUSTOM2 1053 -#define IDC_HQSCALING 1053 -#define IDC_SELCLR 1055 -#define IDC_NEWCATEGORY 1058 -#define IDC_ADDCATEGORY 1059 -#define IDC_DELETECATEGORY 1060 -#define IDC_SMLBUT 1061 -#define IDC_MAXCUSTSMSZ 1062 -#define IDC_MAXCUSTSPIN 1063 -#define IDC_MINSMSZ 1064 -#define IDC_MINSPIN 1065 -#define IDC_BROWSE 1184 -#define IDC_FILENAME 1271 -#define IDC_STATIC -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 127 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1064 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/plugins/SmileyAdd/resource.rc b/plugins/SmileyAdd/resource.rc deleted file mode 100644 index 8c53c504bf..0000000000 --- a/plugins/SmileyAdd/resource.rc +++ /dev/null @@ -1,214 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include -#include "version.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Neutral resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) -#ifdef _WIN32 -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OPT_SMILEYS DIALOGEX 0, 0, 320, 256 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Smiley Categories",IDC_STATIC,6,3,310,102 - CONTROL "",IDC_CATEGORYLIST,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_CHECKBOXES | WS_BORDER | WS_HSCROLL | WS_TABSTOP,14,13,104,83 - CONTROL "Specify Smiley Pack for each category",IDC_USESTDPACK, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,124,11,165,11 - EDITTEXT IDC_FILENAME,124,25,185,12,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES - PUSHBUTTON "...",IDC_BROWSE,296,15,13,11 - LTEXT "Name:",IDC_STATIC,125,42,30,8 - LTEXT "",IDC_LIBNAME,159,41,150,11,SS_SUNKEN | SS_PATHELLIPSIS - LTEXT "Author:",IDC_STATIC,125,56,30,8 - LTEXT "",IDC_LIBAUTHOR,159,55,104,11,SS_SUNKEN | SS_PATHELLIPSIS - LTEXT "Version:",IDC_STATIC,125,70,30,8 - LTEXT "",IDC_LIBVERSION,159,70,104,11,SS_SUNKEN | SS_PATHELLIPSIS - PUSHBUTTON "Preview",IDC_SMLOPTBUTTON,270,55,37,25 - EDITTEXT IDC_NEWCATEGORY,126,85,129,13,ES_AUTOHSCROLL - PUSHBUTTON "+",IDC_ADDCATEGORY,263,84,17,15 - PUSHBUTTON "-",IDC_DELETECATEGORY,290,84,16,14 - GROUPBOX "Display",IDC_STATIC,6,106,310,54 - CONTROL "Replace only smileys surrounded by spaces",IDC_SPACES, - "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,16,115,198,12,WS_EX_RTLREADING - CONTROL "Scale smiley to textheight",IDC_SCALETOTEXTHEIGHT, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,128,147,10 - CONTROL "Animate",IDC_ANIMATEDLG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,218,116,98,10 - CONTROL "Disable custom smileys",IDC_DISABLECUSTOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,138,147,10 - GROUPBOX "Smiley Selector",IDC_STATIC,6,160,310,46 - CONTROL "Surround inserted smiley with spaces",IDC_APPENDSPACES, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,171,235,10 - CONTROL "Use first smiley for selection size",IDC_SCALEALLSMILEYS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,182,209,10 - CONTROL "IEView style window",IDC_IEVIEWSTYLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,193,198,10 - CONTROL "",IDC_SELCLR,"ColourPicker",WS_TABSTOP,260,170,50,11 - CONTROL "Animate",IDC_ANIMATESEL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,218,193,98,10 - GROUPBOX "Input Area",IDC_STATIC,6,208,145,42 - CONTROL "Enable Smileys",IDC_INPUTSMILEYS,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,15,219,130,12 - CONTROL "Don't replace at cursor",IDC_DCURSORSMILEY,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,15,231,130,12 - GROUPBOX "Built-In Message Dialog Support",IDC_STATIC,154,208,162,42 - CONTROL "Disable",IDC_PLUGENABLED,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,240,217,69,12 - COMBOBOX IDC_SMLBUT,159,230,55,35,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Smiley Button",IDC_STATIC,161,219,72,8 - EDITTEXT IDC_MAXCUSTSMSZ,165,128,30,15,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE - CONTROL "",IDC_MAXCUSTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,182,129,11,12 - LTEXT "Max ""Custom Smiley"" height",IDC_STATIC,198,132,118,8 - CONTROL "High Quality smiley scaling",IDC_HQSCALING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,148,148,10 - EDITTEXT IDC_MINSMSZ,165,144,30,15,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE - CONTROL "",IDC_MINSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,182,145,11,12 - LTEXT "Min smiley height",IDC_STATIC,198,148,118,8 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OPT_SMILEYS, DIALOG - BEGIN - LEFTMARGIN, 6 - RIGHTMARGIN, 316 - TOPMARGIN, 3 - BOTTOMMARGIN, 250 - END -END -#endif // APSTUDIO_INVOKED - -#endif // Neutral resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION __FILEVERSION_STRING - PRODUCTVERSION __FILEVERSION_STRING - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Boris Krasnovskiy" - VALUE "FileDescription", "SmileyAdd Miranda Plugin" - VALUE "FileVersion", __VERSION_STRING - VALUE "InternalName", "SmileyAdd" - VALUE "LegalCopyright", "Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved" - VALUE "OriginalFilename", "SmileyAdd.dll" - VALUE "ProductName", " SmileyAdd Miranda Plugin" - VALUE "ProductVersion", __VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_SMILINGICON ICON "RES\\smiley.ICO" -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (U.K.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include \r\n" - "#include ""version.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (U.K.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/plugins/SmileyAdd/richcall.cpp b/plugins/SmileyAdd/richcall.cpp deleted file mode 100644 index d9b9123c48..0000000000 --- a/plugins/SmileyAdd/richcall.cpp +++ /dev/null @@ -1,554 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "smileys.h" -#include "smileyroutines.h" -#include "services.h" -#include "options.h" -#include "SmileyBase.h" - -#include -#include - -typedef struct -{ - HWND hwnd; - HANDLE hContact; - WNDPROC wpOrigWndProc; - HWND hToolTip; - int tipActive; - bool inputarea; - bool dontReplace; -} RichEditData; - -typedef struct -{ - HWND hwnd; - WNDPROC wpOrigWndProc; - HWND hwndInput; - HWND hwndLog; -} RichEditOwnerData; - -static int CompareRichEditData(const RichEditData* p1, const RichEditData* p2) -{ - return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); -} -static LIST g_RichEditList(10, CompareRichEditData); - - -static int CompareRichEditData(const RichEditOwnerData* p1, const RichEditOwnerData* p2) -{ - return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); -} -static LIST g_RichEditOwnerList(5, CompareRichEditData); - - -static void SetPosition(HWND hwnd) -{ - IRichEditOle* RichEditOle; - if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) - return; - - ITextDocument* TextDocument; - if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) - { - RichEditOle->Release(); - return; - } - - // retrieve text range - ITextRange* TextRange; - if (TextDocument->Range(0, 0, &TextRange) != S_OK) - { - TextDocument->Release(); - RichEditOle->Release(); - return; - } - TextDocument->Release(); - - int objectCount = RichEditOle->GetObjectCount(); - for (int i = objectCount - 1; i >= 0; i--) - { - REOBJECT reObj = {0}; - reObj.cbStruct = sizeof(REOBJECT); - - HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ); - if (FAILED(hr)) continue; - - ISmileyBase *igsc = NULL; - if (reObj.clsid == CLSID_NULL) - reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc); - - reObj.poleobj->Release(); - if (igsc == NULL) continue; - - TextRange->SetRange(reObj.cp, reObj.cp); - - BOOL res; - POINT pt; - RECT rect; - hr = TextRange->GetPoint(tomStart | TA_BOTTOM | TA_LEFT, &pt.x, &pt.y); - if (hr == S_OK) - { - res = ScreenToClient(hwnd, &pt); - rect.bottom = pt.y; - rect.left = pt.x; - } - else - rect.bottom = -1; - - hr = TextRange->GetPoint(tomStart | TA_TOP | TA_LEFT, &pt.x, &pt.y); - if (hr == S_OK) - { - res = ScreenToClient(hwnd, &pt); - rect.top = pt.y; - rect.left = pt.x; - } - else - rect.top = -1; - - igsc->SetPosition(hwnd, &rect); - igsc->Release(); - } - TextRange->Release(); - RichEditOle->Release(); -} - -static void SetTooltip(long x, long y, HWND hwnd, RichEditData* rdt) -{ - TCHAR* smltxt; - int needtip = CheckForTip(x, y, hwnd, &smltxt); - if (needtip != rdt->tipActive) - { - TOOLINFO ti = {0}; - ti.cbSize = sizeof(ti); - ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; - ti.hwnd = hwnd; - ti.uId = (UINT_PTR)ti.hwnd; - - if (needtip != -1) - { - if (rdt->tipActive == -1) - { - rdt->hToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), - TTS_NOPREFIX | WS_POPUP, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - hwnd, NULL, g_hInst, NULL); - - SendMessage(rdt->hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti); - } - - ti.lpszText = smltxt; - SendMessage(rdt->hToolTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); - SendMessage(rdt->hToolTip, TTM_ACTIVATE, TRUE, 0); - } - else - { - if (rdt->tipActive != -1) - { - SendMessage(rdt->hToolTip, TTM_ACTIVATE, FALSE, 0); - DestroyWindow(rdt->hToolTip); - rdt->hToolTip = NULL; - } - } - rdt->tipActive = needtip; - } -} - -static const CHARRANGE allsel = { 0, LONG_MAX }; - - -static void ReplaceContactSmileys(RichEditData *rdt, const CHARRANGE &sel, bool ignoreLast, bool unFreeze) -{ - if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; - SmileyPackCType *smcp = NULL; - SmileyPackType* SmileyPack = GetSmileyPack(NULL, rdt->hContact, rdt->inputarea ? NULL : &smcp); - ReplaceSmileys(rdt->hwnd, SmileyPack, smcp, sel, false, ignoreLast, unFreeze); -} - -static void ReplaceContactSmileysWithText(RichEditData *rdt, CHARRANGE &sel, bool freeze) -{ - if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; - ReplaceSmileysWithText(rdt->hwnd, sel, freeze); -} - -static void SmileyToTextCutPrep(RichEditData* rdt) -{ - if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; - - SendMessage(rdt->hwnd, WM_SETREDRAW, FALSE, 0); - CHARRANGE sel; - SendMessage(rdt->hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - ReplaceContactSmileysWithText(rdt, sel, true); -} - -static void SmileyToTextCutRest(RichEditData* rdt) -{ - if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; - - CHARRANGE sel; - SendMessage(rdt->hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - ReplaceContactSmileys(rdt, sel, false, true); - SendMessage(rdt->hwnd, WM_SETREDRAW, TRUE, 0); - RedrawWindow(rdt->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); -} - - -static LRESULT CALLBACK RichEditSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - RichEditData* rdt = g_RichEditList.find((RichEditData*)&hwnd); - if (rdt == NULL) return 0; - - CHARRANGE sel; - - WNDPROC wpOrigWndProc = rdt->wpOrigWndProc; - - switch(uMsg) - { - case WM_DESTROY: - CloseRichCallback(hwnd, false); - break; - - case WM_COPY: - case WM_CUT: - SmileyToTextCutPrep(rdt); - break; - - case WM_PAINT: - SetPosition(hwnd); - break; - - case EM_STREAMOUT: - if (wParam & SFF_SELECTION) - SmileyToTextCutPrep(rdt); - else - { - sel = allsel; - ReplaceContactSmileysWithText(rdt, sel, true); - } - break; - - case WM_KEYDOWN: - if ((wParam == 'C' || wParam == VK_INSERT) && (GetKeyState(VK_CONTROL) & 0x8000)) - { - SmileyToTextCutPrep(rdt); - } - else if ((wParam == 'X' && (GetKeyState(VK_CONTROL) & 0x8000)) || - (wParam == VK_DELETE && (GetKeyState(VK_SHIFT) & 0x8000))) - { - SmileyToTextCutPrep(rdt); - } - else if (wParam == VK_TAB && ((GetKeyState(VK_CONTROL) | GetKeyState(VK_SHIFT)) & 0x8000) == 0) - { - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - sel.cpMin = max(sel.cpMin - 20, 0); - - ReplaceContactSmileysWithText(rdt, sel, true); - } - break; - } - - LRESULT result = CallWindowProc(wpOrigWndProc, hwnd, uMsg, wParam, lParam); - - switch(uMsg) - { - case WM_DESTROY: - CloseRichCallback(hwnd, true); - break; - - case WM_MOUSEMOVE: - SetTooltip(LOWORD(lParam), HIWORD(lParam), hwnd, rdt); - break; - - case WM_PAINT: - case WM_HSCROLL: - case WM_VSCROLL: - SetPosition(hwnd); - break; - - case WM_COPY: - case WM_CUT: - SmileyToTextCutRest(rdt); - break; - - case EM_STREAMOUT: - if (wParam & SFF_SELECTION) - SmileyToTextCutRest(rdt); - else - ReplaceContactSmileys(rdt, allsel, false, true); - break; - - case WM_KEYDOWN: - if ((wParam == 'C' || wParam == VK_INSERT) && (GetKeyState(VK_CONTROL) & 0x8000)) - { - SmileyToTextCutRest(rdt); - } - else if ((wParam == 'X' && (GetKeyState(VK_CONTROL) & 0x8000)) || - (wParam == VK_DELETE && (GetKeyState(VK_SHIFT) & 0x8000))) - { - SmileyToTextCutRest(rdt); - } - else if (wParam == VK_TAB && ((GetKeyState(VK_CONTROL) | GetKeyState(VK_SHIFT)) & 0x8000) == 0) - { - sel.cpMax = LONG_MAX; - bool hascont = rdt->hContact != NULL; - ReplaceContactSmileys(rdt, sel, false, hascont); - } - break; - - case WM_CHAR: - if (!rdt->inputarea || (rdt->inputarea && !opt.InputSmileys)) - break; - - if (lParam & (1 << 28)) // ALT key - break; - - if ((lParam & 0xFF) > 2) // Repeat rate - break; - - if (wParam > ' ' && opt.EnforceSpaces) - break; - - if (wParam == 0x16) - { - ReplaceContactSmileys(rdt, allsel, false, false); - break; - } - - if (opt.DCursorSmiley) - { - ReplaceContactSmileys(rdt, allsel, true, true); - } - else - { - if (wParam >= ' ' || wParam == '\n' || wParam == '\r') - { - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - sel.cpMin = max(sel.cpMin - 20, 0); - sel.cpMax += 20; - - ReplaceContactSmileysWithText(rdt, sel, true); - ReplaceContactSmileys(rdt, sel, false, true); - } - } - break; - - case EM_PASTESPECIAL: - case WM_PASTE: - case EM_REPLACESEL: - case WM_SETTEXT: - case EM_SETTEXTEX: - if (rdt->inputarea) - ReplaceContactSmileys(rdt, allsel, false, false); - break; - - case WM_REMAKERICH: - ReplaceContactSmileys(rdt, allsel, false, false); - break; - } - - return result; -} - -void CloseRichCallback(HWND hwnd, bool force) -{ - int ind = g_RichEditList.getIndex((RichEditData*)&hwnd); - if ( ind != -1 ) - { - RichEditData* rdt = g_RichEditList[ind]; - bool richsub = GetWindowLongPtr(hwnd, GWLP_WNDPROC) == (LONG_PTR)RichEditSubclass; - if (richsub) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)rdt->wpOrigWndProc); - if (richsub || force) - { - if (rdt->hToolTip) DestroyWindow(rdt->hToolTip); - delete rdt; - g_RichEditList.remove(ind); - } - } -} - -bool SetRichCallback(HWND hwnd, HANDLE hContact, bool subany, bool subnew) -{ - RichEditData* rdt = g_RichEditList.find((RichEditData*)&hwnd); - if (rdt == NULL) - { - IRichEditOle* RichEditOle; - if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) - return false; - RichEditOle->Release(); - - rdt = new RichEditData; - - rdt->hwnd = hwnd; - rdt->hContact = hContact; - rdt->inputarea = (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) == 0; - rdt->dontReplace = false; - rdt->tipActive = -1; - rdt->wpOrigWndProc = NULL; - rdt->hToolTip = NULL; - g_RichEditList.insert(rdt); - - if (subnew) - rdt->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditSubclass); - } - else - { - if (hContact && !rdt->hContact) rdt->hContact = hContact; - if (subany && rdt->wpOrigWndProc == NULL) - rdt->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditSubclass); - } - return true; -} - -static LRESULT CALLBACK RichEditOwnerSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - RichEditOwnerData* rdto = g_RichEditOwnerList.find((RichEditOwnerData*)&hwnd); - if (rdto == NULL) return 0; - - WNDPROC wpOrigWndProc = rdto->wpOrigWndProc; - - switch(uMsg) - { - case WM_DESTROY: - { - RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); - if (rdt && (!rdt->inputarea || opt.InputSmileys)) - { - CHARRANGE sel = allsel; - rdt->dontReplace = true; - ReplaceSmileysWithText(rdt->hwnd, sel, false); - } - } - CloseRichOwnerCallback(hwnd, false); - break; - - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK || LOWORD(wParam) == 1624) - { - RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); - if (rdt && (!rdt->inputarea || opt.InputSmileys)) - { - rdt->dontReplace = true; - CHARRANGE sel = allsel; - ReplaceSmileysWithText(rdt->hwnd, sel, false); - } - } - break; - } - - LRESULT result = CallWindowProc(wpOrigWndProc, hwnd, uMsg, wParam, lParam); - - switch(uMsg) - { - case WM_DESTROY: - CloseRichOwnerCallback(hwnd, true); - break; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK || LOWORD(wParam) == 1624) // && lParam == 0) - { - RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); - if (rdt) - { - CHARRANGE sel = allsel; - if (!result) ReplaceContactSmileys(rdt, sel, false, false); - rdt->dontReplace = false; - } - } - break; - } - return result; -} - -void CloseRichOwnerCallback(HWND hwnd, bool force) -{ - int ind = g_RichEditOwnerList.getIndex((RichEditOwnerData*)&hwnd); - if ( ind != -1 ) - { - RichEditOwnerData* rdto = g_RichEditOwnerList[ind]; - bool richsub = GetWindowLongPtr(hwnd, GWLP_WNDPROC) == (LONG_PTR)RichEditOwnerSubclass; - if (richsub) - { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)rdto->wpOrigWndProc); - rdto->wpOrigWndProc = NULL; - } - if (force) - { - CloseRichCallback(rdto->hwndInput, true); - CloseRichCallback(rdto->hwndLog, true); - - delete rdto; - g_RichEditOwnerList.remove(ind); - } - } -} - -void SetRichOwnerCallback(HWND hwnd, HWND hwndInput, HWND hwndLog) -{ - RichEditOwnerData* rdto = g_RichEditOwnerList.find((RichEditOwnerData*)&hwnd); - if (rdto == NULL) - { - rdto = new RichEditOwnerData; - - rdto->hwnd = hwnd; - rdto->hwndInput = hwndInput; - rdto->hwndLog = hwndLog; - rdto->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditOwnerSubclass); - g_RichEditOwnerList.insert(rdto); - } - else - { - if (rdto->hwndInput == NULL) rdto->hwndInput = hwndInput; - if (rdto->hwndLog == NULL) rdto->hwndLog = hwndLog; - } -} - -void ProcessAllInputAreas(bool restoreText) -{ - for (int i=g_RichEditList.getCount(); i--; ) - { - RichEditData* rdt = g_RichEditList[i]; - if (rdt->inputarea) - { - if (restoreText) - { - CHARRANGE sel = allsel; - ReplaceContactSmileysWithText(rdt, sel, false); - } - else - { - ReplaceContactSmileys(rdt, allsel, false, false); - } - } - } -} - - -void RichEditData_Destroy(void) -{ - int i; - for (i=g_RichEditList.getCount(); i--; ) - CloseRichCallback(g_RichEditList[i]->hwnd, true); - g_RichEditList.destroy(); - - for (i=g_RichEditOwnerList.getCount(); i--; ) - CloseRichOwnerCallback(g_RichEditOwnerList[i]->hwnd, true); - g_RichEditOwnerList.destroy(); -} diff --git a/plugins/SmileyAdd/services.cpp b/plugins/SmileyAdd/services.cpp deleted file mode 100644 index fed1b4c7ad..0000000000 --- a/plugins/SmileyAdd/services.cpp +++ /dev/null @@ -1,590 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "smltool.h" -#include "smileyroutines.h" -#include "services.h" -#include "options.h" - - -//globals, defined int main.cpp -extern HANDLE hEvent1, hContactMenuItem; - -LIST menuHandleArray(5); - -//implementation of service functions - -SmileyPackType* GetSmileyPack(const char* proto, HANDLE hContact, SmileyPackCType** smlc) -{ - bkstring categoryName; - - hContact = DecodeMetaContact(hContact); - if (smlc) *smlc = opt.DisableCustom ? NULL : g_SmileyPackCStore.GetSmileyPack(hContact); - - if (proto != NULL && IsBadStringPtrA(proto, 10)) return NULL; - - if (hContact != NULL) - { - opt.ReadContactCategory(hContact, categoryName); - if (categoryName == _T("")) return NULL; - if (!categoryName.empty() && - g_SmileyCategories.GetSmileyCategory(categoryName) == NULL) - { - categoryName.clear(); - opt.WriteContactCategory(hContact, categoryName); - } - - if (categoryName.empty() && !opt.UseOneForAll) - { - char *protonam = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - if (protonam != NULL) - { - DBVARIANT dbv; - if (DBGetContactSettingTString(hContact, protonam, "Transport", &dbv) == 0) - { - categoryName = dbv.ptszVal; - DBFreeVariant(&dbv); - } - else - categoryName = A2T_SM(protonam); - } - } - } - - if (categoryName.empty()) - { - if (proto == NULL || proto[0] == 0) - { - categoryName = _T("Standard"); - } - else - { - categoryName = A2T_SM(proto); - if (opt.UseOneForAll) - { - SmileyCategoryType *smc = g_SmileyCategories.GetSmileyCategory(categoryName); - if (smc == NULL || smc->IsProto()) categoryName = _T("Standard"); - } - } - } - - return g_SmileyCategories.GetSmileyPack(categoryName); -} - - -INT_PTR ReplaceSmileysCommand(WPARAM, LPARAM lParam) -{ - SMADD_RICHEDIT3* smre = (SMADD_RICHEDIT3*) lParam; - if (smre == NULL || smre->cbSize < SMADD_RICHEDIT_SIZE_V1) return FALSE; - - SMADD_RICHEDIT3 smrec = {0}; - memcpy(&smrec, smre, min(smre->cbSize, sizeof(smrec))); - - static const CHARRANGE selection = { 0, LONG_MAX }; - if (smre->rangeToReplace == NULL) smrec.rangeToReplace = (CHARRANGE*)&selection; - else if (smrec.rangeToReplace->cpMax < 0) smrec.rangeToReplace->cpMax = LONG_MAX; - - SmileyPackCType* smcp = NULL; - SmileyPackType* SmileyPack = GetSmileyPack(smrec.Protocolname, smrec.hContact, - (smrec.flags & (SAFLRE_OUTGOING | SAFLRE_NOCUSTOM)) ? NULL : &smcp); - - ReplaceSmileys(smre->hwndRichEditControl, SmileyPack, smcp, *smrec.rangeToReplace, - smrec.hContact == NULL, false, false); - - return TRUE; -} - - -INT_PTR ShowSmileySelectionCommand(WPARAM, LPARAM lParam) -{ - SMADD_SHOWSEL3* smaddInfo = (SMADD_SHOWSEL3*) lParam; - - if (smaddInfo == NULL || smaddInfo->cbSize < SMADD_SHOWSEL_SIZE_V1) return FALSE; - HWND parent = smaddInfo->cbSize > SMADD_SHOWSEL_SIZE_V1 ? smaddInfo->hwndParent : NULL; - HANDLE hContact = smaddInfo->cbSize > SMADD_SHOWSEL_SIZE_V2 ? smaddInfo->hContact : NULL; - - SmileyToolWindowParam *stwp = new SmileyToolWindowParam; - stwp->pSmileyPack = GetSmileyPack(smaddInfo->Protocolname, hContact); - stwp->hContact = hContact; - - stwp->hWndParent = parent; - stwp->hWndTarget = smaddInfo->hwndTarget; - stwp->targetMessage = smaddInfo->targetMessage; - stwp->targetWParam = smaddInfo->targetWParam; - stwp->xPosition = smaddInfo->xPosition; - stwp->yPosition = smaddInfo->yPosition; - stwp->direction = smaddInfo->Direction; - - mir_forkthread(SmileyToolThread, stwp); - - return TRUE; -} - -INT_PTR GetSmileyIconCommand(WPARAM, LPARAM lParam) -{ - SMADD_GETICON* smre = (SMADD_GETICON*) lParam; - - if (smre == NULL || smre->cbSize < sizeof(SMADD_GETICON)) return FALSE; - - SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname); - - if (SmileyPack == NULL || IsBadStringPtrA(smre->SmileySequence, MAX_SMILEY_LENGTH)) - { - smre->SmileyIcon = NULL; - smre->Smileylength = 0; - return FALSE; - } - - unsigned start, size; - SmileyType* sml; - FindSmileyInText(SmileyPack, A2T_SM(smre->SmileySequence), start, size, &sml); - - if (size == 0 || start != 0) - { - smre->SmileyIcon = NULL; - smre->Smileylength = 0; - } - else - { - smre->SmileyIcon = sml->GetIcon(); - smre->Smileylength = size; - } - - return TRUE; -} - - -static int GetInfoCommandE(SMADD_INFO2* smre, bool retDup) -{ - if (smre == NULL || smre->cbSize < SMADD_INFO_SIZE_V1) return FALSE; - HANDLE hContact = smre->cbSize > SMADD_INFO_SIZE_V1 ? smre->hContact : NULL; - - SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname, hContact); - - if (SmileyPack == NULL || SmileyPack->SmileyCount() == 0) - { - smre->ButtonIcon = NULL; - smre->NumberOfSmileys = 0; - smre->NumberOfVisibleSmileys = 0; - return FALSE; - } - - SmileyType* sml = FindButtonSmiley(SmileyPack); - - if (sml != NULL) - smre->ButtonIcon = retDup ? sml->GetIconDup() : sml->GetIcon(); - else - smre->ButtonIcon = GetDefaultIcon(retDup); - - smre->NumberOfSmileys = SmileyPack->SmileyCount(); - smre->NumberOfVisibleSmileys = SmileyPack->VisibleSmileyCount(); - - return TRUE; -} - - -INT_PTR GetInfoCommand(WPARAM, LPARAM lParam) -{ - return GetInfoCommandE((SMADD_INFO2*) lParam, false); -} - - -INT_PTR GetInfoCommand2(WPARAM, LPARAM lParam) -{ - return GetInfoCommandE((SMADD_INFO2*) lParam, true); -} - - -INT_PTR ParseText(WPARAM, LPARAM lParam) -{ - SMADD_PARSE* smre = (SMADD_PARSE*) lParam; - - if (smre == NULL || smre->cbSize < sizeof(SMADD_PARSE)) return FALSE; - - SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname); - - if (SmileyPack == NULL) - { - smre->SmileyIcon = NULL; - smre->size = 0; - return FALSE; - } - - unsigned strtChrOff = smre->startChar + smre->size; - char* workstr = smre->str + strtChrOff; - - if (strtChrOff > 1024 || IsBadStringPtrA(workstr, 10)) - { - smre->SmileyIcon = NULL; - smre->size = 0; - return FALSE; - } - - SmileyType* sml; - FindSmileyInText(SmileyPack, A2T_SM(workstr), smre->startChar, smre->size, &sml); - - if (smre->size == 0) - { - smre->SmileyIcon = NULL; - } - else - { - smre->SmileyIcon = sml->GetIconDup(); - smre->startChar += strtChrOff; - } - - return TRUE; -} - - -INT_PTR ParseTextW(WPARAM, LPARAM lParam) -{ - SMADD_PARSEW* smre = (SMADD_PARSEW*) lParam; - - if (smre == NULL || smre->cbSize < sizeof(SMADD_PARSEW)) return FALSE; - - SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname); - - if (SmileyPack == NULL) - { - smre->SmileyIcon = NULL; - smre->size = 0; - return FALSE; - } - - unsigned strtChrOff = smre->startChar + smre->size; - wchar_t* workstr = smre->str + strtChrOff; - - if (strtChrOff > 1024 || IsBadStringPtrW(workstr, 10)) - { - smre->SmileyIcon = NULL; - smre->size = 0; - return FALSE; - } - - SmileyType* sml; - FindSmileyInText(SmileyPack, workstr, smre->startChar, smre->size, &sml); - - if (smre->size == 0) - { - smre->SmileyIcon = NULL; - } - else - { - smre->SmileyIcon = sml->GetIconDup(); - smre->startChar += strtChrOff; - } - - return TRUE; -} - - -INT_PTR ParseTextBatch(WPARAM, LPARAM lParam) -{ - SMADD_BATCHPARSE2* smre = (SMADD_BATCHPARSE2*) lParam; - - if (smre == NULL || smre->cbSize < SMADD_BATCHPARSE_SIZE_V1) return FALSE; - HANDLE hContact = smre->cbSize > SMADD_BATCHPARSE_SIZE_V1 ? smre->hContact : NULL; - - SmileyPackCType* smcp = NULL; - SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname, hContact, - (smre->flag & (SAFL_OUTGOING | SAFL_NOCUSTOM)) ? NULL : &smcp); - - SmileysQueueType smllist; - - if (smre->flag & SAFL_UNICODE) - LookupAllSmileys(SmileyPack, smcp, W2T_SM(smre->wstr), smllist, false); - else - LookupAllSmileys(SmileyPack, smcp, A2T_SM(smre->astr), smllist, false); - - if (smllist.getCount() == 0) return 0; - - SMADD_BATCHPARSERES *res = new SMADD_BATCHPARSERES[smllist.getCount()]; - SMADD_BATCHPARSERES* cres = res; - for (int j = 0; j < smllist.getCount(); j++) - { - cres->startChar = smllist[j].loc.cpMin; - cres->size = smllist[j].loc.cpMax - smllist[j].loc.cpMin; - if (smllist[j].sml) - { - if (smre->flag & SAFL_PATH) - cres->filepath = smllist[j].sml->GetFilePath().c_str(); - else - cres->hIcon = smllist[j].sml->GetIconDup(); - } - else - { - if (smre->flag & SAFL_PATH) - cres->filepath = smllist[j].smlc->GetFilePath().c_str(); - else - cres->hIcon = smllist[j].smlc->GetIcon(); - } - - cres++; - } - - smre->numSmileys = smllist.getCount(); - - smre->oflag = smre->flag | SAFL_UNICODE; - - return (INT_PTR)res; -} - -INT_PTR FreeTextBatch(WPARAM, LPARAM lParam) -{ - delete[] (SMADD_BATCHPARSERES*)lParam; - return TRUE; -} - -INT_PTR RegisterPack(WPARAM, LPARAM lParam) -{ - SMADD_REGCAT* smre = (SMADD_REGCAT*) lParam; - - if (smre == NULL || smre->cbSize < sizeof(SMADD_REGCAT)) return FALSE; - if (IsBadStringPtrA(smre->name, 50) || IsBadStringPtrA(smre->dispname, 50)) return FALSE; - - - unsigned lpcp = (unsigned)CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); - if (lpcp == CALLSERVICE_NOTFOUND) lpcp = CP_ACP; - - - - bkstring nmd(A2W_SM(smre->dispname, lpcp)); - - - bkstring nm(A2T_SM(smre->name)); - g_SmileyCategories.AddAndLoad(nm, nmd); - - return TRUE; -} - -INT_PTR CustomCatMenu(WPARAM wParam, LPARAM lParam) -{ - const HANDLE hContact = (HANDLE)wParam; - if (lParam != 0) - { - SmileyCategoryType* smct = g_SmileyCategories.GetSmileyCategory((unsigned)lParam - 3); - if (smct != NULL) - opt.WriteContactCategory(hContact, smct->GetName()); - else - { - bkstring empty; - if (lParam == 1) empty = _T(""); - opt.WriteContactCategory(hContact, empty); - } - NotifyEventHooks(hEvent1, (WPARAM)hContact, 0); - } - - for (int i = 0; i < menuHandleArray.getCount(); i++) - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)menuHandleArray[i], 0); - menuHandleArray.destroy(); - - return TRUE; -} - - -int RebuildContactMenu(WPARAM wParam, LPARAM) -{ - int i; - CLISTMENUITEM mi = {0}; - - mi.cbSize = sizeof(mi); - mi.flags = CMIM_FLAGS | CMIF_ROOTPOPUP | CMIF_ICONFROMICOLIB; - - SmileyCategoryListType::SmileyCategoryVectorType& smc = *g_SmileyCategories.GetSmileyCategoryList(); - - char* protnam = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); - bool haveMenu = IsSmileyProto(protnam); - if (haveMenu && opt.UseOneForAll) - { - unsigned cnt = 0; - for (i = 0; i < smc.getCount(); ++i) - cnt += smc[i].IsCustom(); - haveMenu = cnt != 0; - } - - if (!haveMenu) mi.flags |= CMIF_HIDDEN; - - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuItem, (LPARAM)&mi); - - for (i = 0; i < menuHandleArray.getCount(); ++i) - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)menuHandleArray[i], 0); - menuHandleArray.destroy(); - - if (haveMenu) - { - bkstring cat; - opt.ReadContactCategory((HANDLE)wParam, cat); - - mi.pszPopupName = (char*)hContactMenuItem; - mi.flags = CMIF_CHILDPOPUP | CMIM_FLAGS | CMIF_TCHAR; - mi.pszService = MS_SMILEYADD_CUSTOMCATMENU; - - bool nonecheck = true; - HGENMENU hMenu; - - for (i = 0; i < smc.getCount(); i++) - { - if (smc[i].IsExt() || (smc[i].IsProto() && opt.UseOneForAll)) continue; - - const int ind = i + 3; - - mi.position = ind; - mi.popupPosition = ind; - mi.ptszName = (TCHAR*)smc[i].GetDisplayName().c_str(); - - if (cat == smc[i].GetName()) - { - mi.flags |= CMIF_CHECKED; - nonecheck = false; - } - - hMenu = Menu_AddContactMenuItem(&mi); - menuHandleArray.insert(hMenu); - mi.flags &= ~CMIF_CHECKED; - } - - mi.position = 1; - mi.popupPosition = 1; - mi.ptszName = _T(""); - if (cat == _T("")) { - mi.flags |= CMIF_CHECKED; - nonecheck = false; - } - - hMenu = Menu_AddContactMenuItem(&mi); - menuHandleArray.insert(hMenu); - - mi.position = 2; - mi.popupPosition = 2; - mi.ptszName = _T("Protocol specific"); - if (nonecheck) mi.flags |= CMIF_CHECKED; else mi.flags &= ~CMIF_CHECKED; - - hMenu = Menu_AddContactMenuItem(&mi); - menuHandleArray.insert(hMenu); - } - - return 0; -} - -INT_PTR ReloadPack(WPARAM, LPARAM lParam) -{ - if (lParam) - { - bkstring categoryName = A2T_SM((char*)lParam); - SmileyCategoryType *smc = g_SmileyCategories.GetSmileyCategory(categoryName); - if (smc != NULL) smc->Load(); - } - else - g_SmileyCategories.ClearAndLoadAll(); - - NotifyEventHooks(hEvent1, 0, 0); - return 0; -} - -INT_PTR LoadContactSmileys(WPARAM, LPARAM lParam) -{ - if (opt.DisableCustom) return 0; - - SMADD_CONT* cont = (SMADD_CONT*)lParam; - - switch (cont->type) - { - case 0: - g_SmileyPackCStore.AddSmileyPack(cont->hContact, cont->path); - NotifyEventHooks(hEvent1, (WPARAM)cont->hContact, 0); - break; - - case 1: - g_SmileyPackCStore.AddSmiley(cont->hContact, cont->path); - NotifyEventHooks(hEvent1, (WPARAM)cont->hContact, 0); - break; - } - return 0; -} - -int AccountListChanged(WPARAM wParam, LPARAM lParam) -{ - PROTOACCOUNT* acc = (PROTOACCOUNT*)lParam; - - switch (wParam) - { - case PRAC_ADDED: - if (acc != NULL) - { - bkstring catname(_T("Standard")); - const bkstring& defaultFile = g_SmileyCategories.GetSmileyCategory(catname)->GetFilename(); - g_SmileyCategories.AddAccountAsCategory(acc, defaultFile); - } - break; - - case PRAC_CHANGED: - if (acc != NULL && acc->szModuleName != NULL) - { - bkstring name(A2T_SM(acc->szModuleName)); - SmileyCategoryType* smc = g_SmileyCategories.GetSmileyCategory(name); - if (smc != NULL) - { - if (acc->tszAccountName) name = acc->tszAccountName; - smc->SetDisplayName(name); - } - } - break; - - case PRAC_REMOVED: - g_SmileyCategories.DeleteAccountAsCategory(acc); - break; - - case PRAC_CHECKED: - if (acc != NULL) - { - if (acc->bIsEnabled) - { - bkstring catname(_T("Standard")); - const bkstring& defaultFile = g_SmileyCategories.GetSmileyCategory(catname)->GetFilename(); - g_SmileyCategories.AddAccountAsCategory(acc, defaultFile); - } - else - { - g_SmileyCategories.DeleteAccountAsCategory(acc); - } - } - break; - } - return 0; -} - -int DbSettingChanged(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = (HANDLE)wParam; - DBCONTACTWRITESETTING* cws = (DBCONTACTWRITESETTING*)lParam; - - if (hContact == NULL) return 0; - if (cws->value.type == DBVT_DELETED) return 0; - - if (strcmp(cws->szSetting, "Transport") == 0) - { - bkstring catname(_T("Standard")); - SmileyCategoryType *smc = g_SmileyCategories.GetSmileyCategory(catname); - if (smc != NULL) - g_SmileyCategories.AddContactTransportAsCategory(hContact, smc->GetFilename()); - } - return 0; -} diff --git a/plugins/SmileyAdd/services.h b/plugins/SmileyAdd/services.h deleted file mode 100644 index 9311e3637d..0000000000 --- a/plugins/SmileyAdd/services.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef SMILEYADD_SERVICES_H_ -#define SMILEYADD_SERVICES_H_ - -#include "m_smileyadd.h" -#include "m_smileyadd_deprecated.h" - -// service commands -INT_PTR ReplaceSmileysCommand(WPARAM wParam, LPARAM lParam); -INT_PTR GetSmileyIconCommand(WPARAM wParam, LPARAM lParam); -INT_PTR ShowSmileySelectionCommand(WPARAM wParam, LPARAM lParam); -INT_PTR GetInfoCommand(WPARAM wParam, LPARAM); -INT_PTR GetInfoCommand2(WPARAM wParam, LPARAM); -INT_PTR ParseText(WPARAM wParam, LPARAM lParam); -INT_PTR ParseTextW(WPARAM wParam, LPARAM lParam); -INT_PTR RegisterPack(WPARAM wParam, LPARAM lParam); -INT_PTR ParseTextBatch(WPARAM wParam, LPARAM lParam); -INT_PTR FreeTextBatch(WPARAM wParam, LPARAM lParam); -INT_PTR CustomCatMenu(WPARAM, LPARAM lParam); -int RebuildContactMenu(WPARAM wParam, LPARAM); -INT_PTR ReloadPack(WPARAM, LPARAM lParam); -INT_PTR LoadContactSmileys(WPARAM, LPARAM lParam); -int AccountListChanged(WPARAM wParam, LPARAM lParam); -int DbSettingChanged(WPARAM wParam, LPARAM lParam); - -SmileyPackType* GetSmileyPack(const char* proto, HANDLE hContact = NULL, SmileyPackCType** smlc = NULL); - - -#endif // SMILEYADD_SERVICES_H_ - diff --git a/plugins/SmileyAdd/smileyadd-translation.txt b/plugins/SmileyAdd/smileyadd-translation.txt deleted file mode 100644 index d6120c560e..0000000000 --- a/plugins/SmileyAdd/smileyadd-translation.txt +++ /dev/null @@ -1,54 +0,0 @@ -; Common strings that belong to many files -;[] - -; ../../plugins/SmileyAdd/dlgboxsubclass.cpp -;[Show Smiley Selection Window] - -; ../../plugins/SmileyAdd/download.cpp -;[SmileyAdd HTTP connections] - -; ../../plugins/SmileyAdd/main.cpp -;[Button Smiley] -;[Please update SmileyAdd to ANSI Version] - -; ../../plugins/SmileyAdd/options.cpp -;[All Files] -;[Bottom] -;[Customize] -;[Off] -;[Smiley Packs] -;[Smileys] -;[Top] - -; ../../plugins/SmileyAdd/resource.rc -;[Animate] -;[Author:] -;[Built-In Message Dialog Support] -;[Disable] -;[Disable custom smileys] -;[Display] -;[Don't replace at cursor] -;[Enable Smileys] -;[High Quality smiley scaling] -;[IEView style window] -;[Input Area] -;[Max \"Custom Smiley\" height] -;[Min smiley height] -;[Name:] -;[Preview] -;[Replace only smileys surrounded by spaces] -;[Scale smiley to textheight] -;[Smiley Button] -;[Smiley Categories] -;[Smiley Selector] -;[Specify Smiley Pack for each category] -;[Surround inserted smiley with spaces] -;[Use first smiley for selection size] -;[Version:] - -; ../../plugins/SmileyAdd/smileys.cpp -;[Standard] -;[There were problems loading smiley pack (it should be corrected).\nSee Network Log for details.] - -; ../../plugins/SmileyAdd/smltool.cpp -;[d'Oh!] diff --git a/plugins/SmileyAdd/smileyroutines.cpp b/plugins/SmileyAdd/smileyroutines.cpp deleted file mode 100644 index ba136d7ed5..0000000000 --- a/plugins/SmileyAdd/smileyroutines.cpp +++ /dev/null @@ -1,610 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "smileyroutines.h" -#include "SmileyBase.h" -#include "options.h" - -#include -#include - -ISmileyBase* CreateSmileyObject(SmileyType* sml); -ISmileyBase* CreateAniSmileyObject(SmileyType* sml, COLORREF clr, bool ishpp); - - - -bool g_HiddenTextSupported = true; - - -// {8CC497C0-A1DF-11CE-8098-00AA0047BE5D} -const GUID IID_ITextDocument = -{ 0x8CC497C0, 0xA1DF, 0x11CE, { 0x80,0x98,0x00,0xAA,0x00,0x47,0xBE,0x5D } }; - -void LookupAllSmileys(SmileyPackType* smileyPack, SmileyPackCType* smileyCPack, const TCHAR* lpstrText, - SmileysQueueType& smllist, const bool firstOnly) -{ - if (lpstrText == NULL || *lpstrText == 0) return; - - SmileyPackType::SmileyLookupType* sml = smileyPack ? smileyPack->GetSmileyLookup() : NULL; - SmileyPackCType::SmileyLookupType* smlc = smileyCPack ? &smileyCPack->GetSmileyLookup() : NULL; - - // Precompute number of smileys - int smlszo = sml ? sml->getCount() : 0; - int smlszc = smlc ? smlc->getCount() : 0; - int smlsz = smlszo + smlszc; - - if (smlsz == 0) return; - - // All possible smileys - SmileyLookup::SmileyLocVecType* smileys = new SmileyLookup::SmileyLocVecType [smlsz]; - - // Find all possible smileys - bkstring tmpstr(lpstrText); - int i = 0; - - if (sml) - { - for (int j=0; jgetCount(); j++) - { - (*sml)[j].find(tmpstr, smileys[i], false); - i++; - } - } - - if (smlc) - { - for (int j=0; jgetCount(); j++) - { - (*smlc)[j].find(tmpstr, smileys[i], false); - i++; - } - } - - int* csmlit = (int*)alloca(smlsz * sizeof(int)); - if (csmlit == NULL) return; - memset(csmlit, 0, smlsz * sizeof(int)); - - long numCharsSoFar = 0; - bkstring::size_type smloff = 0; - - for (;;) - { - int firstSml = -1; - int firstSmlRef = -1; - SmileyLookup::SmileyLocVecType* smlf = NULL; - - for (int csml=0; csml= smloff) - { - if (firstSmlRef == -1 || smlv[tsml].pos < (*smlf)[firstSmlRef].pos || - (smlv[tsml].pos == (*smlf)[firstSmlRef].pos && smlv[tsml].len > (*smlf)[firstSmlRef].len)) - { - firstSmlRef = tsml; - firstSml = csml; - smlf = &smileys[csml]; - } - break; - } - } - csmlit[csml] = tsml; - } - - // Check if smiley found - if (firstSml != -1) - { - ReplaceSmileyType *dat = new ReplaceSmileyType; - - const TCHAR* textToSearch = lpstrText + smloff; - const TCHAR* textSmlStart = lpstrText + (*smlf)[firstSmlRef].pos; - const TCHAR* textSmlEnd = textSmlStart + (*smlf)[firstSmlRef].len; - - // check if leading space exist - const TCHAR* prech = _tcsdec(textToSearch, textSmlStart); - dat->ldspace = prech != NULL ? _istspace(*prech) != 0 : smloff == 0; - - // check if trailing space exist - dat->trspace = *textSmlEnd == 0 || _istspace(*textSmlEnd); - - // compute text location in RichEdit - dat->loc.cpMin = (long)_tcsnccnt(textToSearch, (*smlf)[firstSmlRef].pos - smloff) + numCharsSoFar; - dat->loc.cpMax = numCharsSoFar = (long)_tcsnccnt(textSmlStart, (*smlf)[firstSmlRef].len) + dat->loc.cpMin; - - if (!opt.EnforceSpaces || (dat->ldspace && dat->trspace)) - { - dat->ldspace |= !opt.SurroundSmileyWithSpaces; - dat->trspace |= !opt.SurroundSmileyWithSpaces; - - if (firstSml < smlszo) - { - dat->sml = smileyPack->GetSmiley((*sml)[firstSml].GetIndex()); - dat->smlc = NULL; - } - else - { - dat->smlc = smileyCPack->GetSmiley((*smlc)[firstSml-smlszo].GetIndex()); - dat->sml = NULL; - } - - if (dat->sml != NULL || dat->smlc != NULL) - { - // First smiley found record it - smllist.insert(dat); - if (firstOnly) break; - } - else - delete dat; - } - else - delete dat; - - // Advance string pointer to search for the next smiley - smloff = (*smlf)[firstSmlRef].pos + (*smlf)[firstSmlRef].len; - csmlit[firstSml]++; - } - else - // Nothing to parse exit - break; - } - delete[] smileys; -} - - -void FindSmileyInText(SmileyPackType* smp, const TCHAR* str, - unsigned& first, unsigned& size, SmileyType** sml) -{ - SmileysQueueType smllist; - LookupAllSmileys(smp, NULL, str, smllist, true); - if (smllist.getCount() == 0) - { - size = 0; - *sml = NULL; - } - else - { - first = smllist[0].loc.cpMin; - size = smllist[0].loc.cpMax - smllist[0].loc.cpMin; - *sml = smllist[0].sml; - } -} - - -SmileyType* FindButtonSmiley(SmileyPackType* smp) -{ - unsigned start, size; - SmileyType* sml; - - FindSmileyInText(smp, smp->GetButtonSmiley(), start, size, &sml); - - return sml; -} - -void UpdateSelection(CHARRANGE& sel, int pos, int dif) -{ - if (sel.cpMax == sel.cpMin) - { - if (sel.cpMax < LONG_MAX && sel.cpMax > pos) - { - sel.cpMax += dif; - sel.cpMin += dif; - } - } - else - { - if (sel.cpMax >= pos && sel.cpMax < LONG_MAX) sel.cpMax += dif; - if (sel.cpMin > pos) sel.cpMin += dif; - } -} - -void ReplaceSmileys(HWND hwnd, SmileyPackType* smp, SmileyPackCType* smcp, const CHARRANGE& sel, - bool useHidden, bool ignoreLast, bool unFreeze) -{ -/* - LARGE_INTEGER freq, strt, end; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&strt); -*/ - IRichEditOle* RichEditOle; - if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) - return; - - ITextDocument* TextDocument; - if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) - { - RichEditOle->Release(); - return; - } - - long cnt; - if (smp == NULL && smcp == NULL) - { - if (unFreeze) TextDocument->Unfreeze(&cnt); - TextDocument->Release(); - RichEditOle->Release(); - return; - } - - // retrieve text range - ITextRange* TextRange; - if (TextDocument->Range(sel.cpMin, sel.cpMax, &TextRange) != S_OK) - { - TextDocument->Release(); - RichEditOle->Release(); - return; - } - - // retrieve text to parse for smileys - BSTR btxt = 0; - if (TextRange->GetText(&btxt) != S_OK) - { - TextRange->Release(); - TextDocument->Release(); - RichEditOle->Release(); - return; - } - - TextRange->Release(); - - SmileysQueueType smllist; - - - LookupAllSmileys(smp, smcp, W2T_SM(btxt), smllist, false); - - SysFreeString(btxt); - - if (smllist.getCount() != 0) - { - // disable screen updates - TextDocument->Freeze(&cnt); - - TCHAR classname[20]; - GetClassName(hwnd, classname, SIZEOF(classname)); - bool ishpp = (_tcsncmp(classname, _T("THppRichEdit"), 12) == 0); - - SetRichCallback(hwnd, NULL, false, true); - - bool rdo = (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) != 0; - if (rdo) SendMessage(hwnd, EM_SETREADONLY, FALSE, 0); - - ITextSelection* TextSelection; - TextDocument->GetSelection(&TextSelection); - - ITextFont *TextFont; - TextSelection->GetFont(&TextFont); - - //save selection - CHARRANGE oldSel; - TextSelection->GetStart(&oldSel.cpMin); - TextSelection->GetEnd(&oldSel.cpMax); - - CHARFORMAT2 chf; - - chf.cbSize = sizeof(chf); - chf.dwMask = CFM_ALL2; - - // Determine background color - // This logic trying to minimize number of background color changes - static COLORREF bkgColor = GetSysColor(COLOR_WINDOW); -// if (!insemf) -// { - COLORREF bkgColorPv = (COLORREF)SendMessage(hwnd, EM_SETBKGNDCOLOR, 0, bkgColor); - if (bkgColorPv != bkgColor) - { - bkgColor = bkgColorPv; - SendMessage(hwnd, EM_SETBKGNDCOLOR, 0, bkgColor); - } -// } - - HDC hdc = GetDC(hwnd); - int sclX = GetDeviceCaps(hdc, LOGPIXELSX); - int sclY = GetDeviceCaps(hdc, LOGPIXELSY); - - unsigned numBTBSm = 0; - - BSTR spaceb = SysAllocString(L" "); - - // Replace smileys specified in the list in RichEdit - for (int j = smllist.getCount(); j--; ) - { - CHARRANGE& smlpos = smllist[j].loc; - if (ignoreLast && oldSel.cpMax == smlpos.cpMax) continue; - - smlpos.cpMin += sel.cpMin; - smlpos.cpMax += sel.cpMin; - - // Find all back to back smileys and for propper hidden text detection - if ( numBTBSm == 0 ) - { - CHARRANGE lastPos = smlpos; - for (int jn = j; jn--; ) - { - if (jn != j && smllist[jn].loc.cpMax != lastPos.cpMin) - break; - - ++numBTBSm; - lastPos.cpMin = smllist[jn].loc.cpMin; - } - TextSelection->SetRange(lastPos.cpMin, lastPos.cpMax); - long hid; - TextFont->GetHidden(&hid); - if (hid == tomFalse) numBTBSm = 0; - } - if ( numBTBSm != 0 ) - { - --numBTBSm; - continue; - } - - SmileyType* sml = smllist[j].sml; - SmileyCType* smlc = smllist[j].smlc; - if (sml == NULL && smlc == NULL) continue; - - // Select text analyze - TextSelection->SetRange(smlpos.cpMin, smlpos.cpMax); - - BSTR btxt = NULL; - - if (smlc == NULL && sml->IsText()) - { - btxt = SysAllocString(T2W_SM(sml->GetToolText().c_str())); - TextSelection->SetText(btxt); - } - else - { - TextSelection->GetText(&btxt); - - // Get font properties - SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&chf); - - //do not look for smileys in hyperlinks - if ((chf.dwEffects & (CFE_LINK | CFE_HIDDEN)) != 0) continue; - - SIZE osize; - if (sml) - sml->GetSize(osize); - else - smlc->GetSize(osize); - - if (osize.cx == 0 || osize.cy == 0) continue; - - int sizeX, sizeY; - if (opt.ScaleToTextheight) - { - sizeY = CalculateTextHeight(hdc, &chf); - sizeX = osize.cx * sizeY / osize.cy; - - int dx = osize.cx - sizeX; - sizeX += dx & 1; - - int dy = osize.cy - sizeY; - sizeY += dy & 1; - } - else - { - sizeX = osize.cx; - sizeY = osize.cy; - } - - if (smlc != NULL && opt.MaxCustomSmileySize && (unsigned)sizeY > opt.MaxCustomSmileySize) - { - sizeY = opt.MaxCustomSmileySize; - sizeX = osize.cx * sizeY / osize.cy; - - int dx = osize.cx - sizeX; - sizeX += dx & 1; - - int dy = osize.cy - opt.MaxCustomSmileySize; - sizeY += dy & 1; - } - - if (opt.MinSmileySize && (unsigned)sizeY < opt.MinSmileySize) - { - sizeY = opt.MinSmileySize; - sizeX = osize.cx * sizeY / osize.cy; - - int dx = osize.cx - sizeX; - sizeX += dx & 1; - - int dy = osize.cy - opt.MinSmileySize; - sizeY += dy & 1; - } - - // Convert pixel to HIMETRIC - SIZEL sizehm; - sizehm.cx = (2540 * (sizeX+1) + (sclX >> 1)) / sclX; - sizehm.cy = (2540 * (sizeY+1) + (sclY >> 1)) / sclY; - - // If font does not have designated background use control background - if (chf.dwEffects & CFE_AUTOBACKCOLOR) chf.crBackColor = bkgColor; - - // insert space after - if (!smllist[j].trspace && useHidden) - { - TextSelection->SetStart(smlpos.cpMax); - TextSelection->TypeText(spaceb); - UpdateSelection(oldSel, smlpos.cpMax , 1); - - // Restore selection - TextSelection->SetRange(smlpos.cpMin, smlpos.cpMax); - } - - if (g_HiddenTextSupported && useHidden) - { - TextFont->SetHidden(tomTrue); - TextSelection->SetEnd(smlpos.cpMin); - UpdateSelection(oldSel, smlpos.cpMin , 1); - } - else - { - UpdateSelection(oldSel, smlpos.cpMin, -(int)SysStringLen(btxt)+1); - } - - ISmileyBase* smileyBase = CreateAniSmileyObject(smlc ? smlc : sml, chf.crBackColor, ishpp); - if (smileyBase == NULL) continue; - - smileyBase->SetExtent(DVASPECT_CONTENT, &sizehm); - smileyBase->SetHint(W2T_SM(btxt)); - - smileyBase->SetPosition(hwnd, NULL); - - // Get the RichEdit container site - IOleClientSite *pOleClientSite; - RichEditOle->GetClientSite(&pOleClientSite); - - // Now Add the object to the RichEdit - REOBJECT reobject = { 0 }; - - reobject.cbStruct = sizeof(REOBJECT); - reobject.cp = REO_CP_SELECTION; - reobject.dvaspect = DVASPECT_CONTENT; - reobject.poleobj = smileyBase; - reobject.polesite = pOleClientSite; - reobject.dwFlags = REO_BELOWBASELINE | REO_BLANK; - reobject.dwUser = (DWORD)smileyBase; - - // Insert the bitmap at the current location in the richedit control - RichEditOle->InsertObject(&reobject); - - smileyBase->Release(); - - // insert space before - if (!smllist[j].ldspace && useHidden) - { - TextSelection->SetRange(smlpos.cpMin, smlpos.cpMin); - TextSelection->TypeText(spaceb); - UpdateSelection(oldSel, smlpos.cpMin , 1); - } - } - SysFreeString(btxt); - } - SysFreeString(spaceb); - - TextSelection->SetRange(oldSel.cpMin, oldSel.cpMax); - if (rdo) SendMessage(hwnd, EM_SETREADONLY, TRUE, 0); - - TextFont->Release(); - TextSelection->Release(); - - ReleaseDC(hwnd, hdc); - - TextDocument->Unfreeze(&cnt); - if (cnt == 0) UpdateWindow(hwnd); - } - - if (unFreeze) - { - TextDocument->Unfreeze(&cnt); - if (cnt == 0) UpdateWindow(hwnd); - } - - TextDocument->Release(); - RichEditOle->Release(); - -/* - QueryPerformanceCounter(&end); - unsigned dif = (end.QuadPart - strt.QuadPart)/(freq.QuadPart/1000); - TCHAR mess[300]; - wsprintf(mess, _T("Time elapsed: %u"), dif); - MessageBox(NULL, mess, _T(""), MB_OK); -*/ -} - - -void ReplaceSmileysWithText(HWND hwnd, CHARRANGE& sel, bool keepFrozen) -{ - IRichEditOle* RichEditOle; - if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) - return; - - ITextDocument* TextDocument; - if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) - { - RichEditOle->Release(); - return; - } - - // retrieve text range - ITextRange* TextRange; - if (TextDocument->Range(0, 0, &TextRange) != S_OK) - { - TextDocument->Release(); - RichEditOle->Release(); - return; - } - - long cnt; - TextDocument->Freeze(&cnt); - - bool rdo = (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) != 0; - if (rdo) SendMessage(hwnd, EM_SETREADONLY, FALSE, 0); - - CHARRANGE oldSel; - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&oldSel); - - int objectCount = RichEditOle->GetObjectCount(); - for (int i = objectCount - 1; i >= 0; i--) - { - REOBJECT reObj = {0}; - reObj.cbStruct = sizeof(REOBJECT); - - HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ); - if (FAILED(hr)) continue; - - if (reObj.cp < sel.cpMin) - { - reObj.poleobj->Release(); - break; - } - - ISmileyBase *igsc = NULL; - if (reObj.cp < sel.cpMax && reObj.clsid == CLSID_NULL) - reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc); - - reObj.poleobj->Release(); - if (igsc == NULL) continue; - - TextRange->SetRange(reObj.cp, reObj.cp + 1); - - BSTR bstr = NULL; - igsc->GetTooltip(&bstr); - TextRange->SetText(bstr); - - unsigned int len = SysStringLen(bstr); - UpdateSelection(oldSel, reObj.cp, len-1); - UpdateSelection(sel, reObj.cp, len-1); - - SysFreeString(bstr); - - igsc->Release(); - } - - SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&oldSel); - if (rdo) SendMessage(hwnd, EM_SETREADONLY, TRUE, 0); - if (!keepFrozen) TextDocument->Unfreeze(&cnt); - - TextRange->Release(); - TextDocument->Release(); - RichEditOle->Release(); -} diff --git a/plugins/SmileyAdd/smileyroutines.h b/plugins/SmileyAdd/smileyroutines.h deleted file mode 100644 index 6b12ee6ead..0000000000 --- a/plugins/SmileyAdd/smileyroutines.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef _SMILEYROUTINES_ -#define _SMILEYROUTINES_ - -#include "smileys.h" -#include "customsmiley.h" - -typedef struct ReplaceSmileyType_tag -{ - CHARRANGE loc; - SmileyType* sml; - SmileyCType* smlc; - bool ldspace; - bool trspace; -} ReplaceSmileyType; - -// Queue to store smileys found -typedef SMOBJLIST SmileysQueueType; - - - -void LookupAllSmileys(SmileyPackType* smileyPack, SmileyPackCType* smileyCPack, const TCHAR* lpstrText, - SmileysQueueType& smllist, const bool firstOnly); -void ReplaceSmileys(HWND hwnd, SmileyPackType* smp, SmileyPackCType* smcp, const CHARRANGE& sel, - bool useHidden, bool ignoreLast, bool unFreeze); -void ReplaceSmileysWithText(HWND hwnd, CHARRANGE& sel, bool keepFrozen); -void FindSmileyInText(SmileyPackType* smp, const TCHAR* str, - unsigned& first, unsigned& size, SmileyType** index); -SmileyType* FindButtonSmiley(SmileyPackType* smp); - -#endif diff --git a/plugins/SmileyAdd/smileys.cpp b/plugins/SmileyAdd/smileys.cpp deleted file mode 100644 index 2f16cee51e..0000000000 --- a/plugins/SmileyAdd/smileys.cpp +++ /dev/null @@ -1,1146 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - - -#include "smileys.h" -#include "smileyroutines.h" -#include "options.h" -#include "download.h" - -SmileyPackListType g_SmileyPacks; -SmileyCategoryListType g_SmileyCategories; - -extern HANDLE hNetlibUser; - -// -// SmileyType -// - - -SmileyType::SmileyType(void) -{ - m_SmileyIcon = NULL; - m_xepimg = NULL; - m_flags = 0; - m_index = 0; - m_size.cx = 0; - m_size.cy = 0; -} - -SmileyType::~SmileyType() -{ - if (m_xepimg) m_xepimg->Release(); - m_xepimg = NULL; - - if (m_SmileyIcon != NULL) DestroyIcon(m_SmileyIcon); - m_SmileyIcon = NULL; -} - - -HICON SmileyType::GetIcon(void) -{ - if (m_SmileyIcon == NULL) - { - ImageBase* img = CreateCachedImage(); - if (!img) return NULL; - img->SelectFrame(m_index); - m_SmileyIcon = img->GetIcon(); - img->Release(); - } - return m_SmileyIcon; -} - - -HICON SmileyType::GetIconDup(void) -{ - ImageBase* img = CreateCachedImage(); - img->SelectFrame(m_index); - HICON hIcon = img->GetIcon(); - img->Release(); - return hIcon; -} - - -bool SmileyType::LoadFromImage(IStream* pStream) -{ - if (m_xepimg) m_xepimg->Release(); - - bkstring name; - m_xepimg = new ImageType(0, name, pStream); - - return true; -} - - -bool SmileyType::LoadFromResource(const bkstring& file, const int index) -{ - m_index = index; - m_filepath = file; - - return true; -} - - -void SmileyType::GetSize(SIZE& size) -{ - if (m_size.cy == 0) - { - ImageBase* img = CreateCachedImage(); - if (img) - { - img->GetSize(m_size); - img->Release(); - } - } - size = m_size; -} - - -ImageBase* SmileyType::CreateCachedImage(void) -{ - if (m_xepimg) - { - m_xepimg->AddRef(); - return m_xepimg; - } - return AddCacheImage(m_filepath, m_index); -} - - -void SmileyType::SetImList(HIMAGELIST hImLst, long i) -{ - if (m_xepimg) m_xepimg->Release(); - m_xepimg = new ImageListItemType(0, hImLst, i); -} - - -HBITMAP SmileyType::GetBitmap(COLORREF bkgClr, int sizeX, int sizeY) -{ - ImageBase* img = CreateCachedImage(); - if (!img) return NULL; - img->SelectFrame(m_index); - HBITMAP hBmp = img->GetBitmap(bkgClr, sizeX, sizeY); - img->Release(); - - return hBmp; -} - - -// -// SmileyPackType -// - -SmileyPackType::SmileyPackType() -{ - m_hSmList = NULL; - errorFound = false; -} - -SmileyType* SmileyPackType::GetSmiley(unsigned index) -{ - return (index < (unsigned)m_SmileyList.getCount()) ? &m_SmileyList[index] : NULL; -} - - -static DWORD_PTR ConvertServiceParam(HANDLE hContact, const TCHAR *param) -{ - DWORD_PTR ret; - if (param == NULL) - ret = 0; - else if (_tcsicmp(_T("hContact"), param) == 0) - ret = (DWORD_PTR)hContact; - else if (_istdigit(*param)) - ret = _ttoi(param); - else - ret = (DWORD_PTR)param; - - return ret; -} - - -void SmileyType::CallSmileyService(HANDLE hContact) -{ - _TPattern * srvsplit = _TPattern::compile(_T("(.*)\\|(.*)\\|(.*)")); - _TMatcher * m0 = srvsplit->createTMatcher(GetTriggerText()); - m0->findFirstMatch(); - - bkstring name = m0->getGroup(1); - bkstring par1 = m0->getGroup(2); - bkstring par2 = m0->getGroup(3); - - delete m0; - delete srvsplit; - - char str[MAXMODULELABELLENGTH]; - const char *proto = ""; - - if (name[0] == '/') - { - proto = (const char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - if (proto == NULL) return; - } - mir_snprintf(str, sizeof(str), "%s%s", proto, T2A_SM(name.c_str())); - CallService(str, - ConvertServiceParam(hContact, par1.c_str()), - ConvertServiceParam(hContact, par2.c_str())); -} - - - -SmileyPackType::~SmileyPackType() -{ - if (m_hSmList != NULL) ImageList_Destroy(m_hSmList); -} - -static const TCHAR urlRegEx[] = - _T("(?:ftp|https|http|file|aim|webcal|irc|msnim|xmpp|gopher|mailto|news|nntp|telnet|wais|prospero)://?[\\w.?%:/$+;]*"); -static const TCHAR pathRegEx[] = _T("[\\s\"][a-zA-Z]:[\\\\/][\\w.\\-\\\\/]*"); -static const TCHAR timeRegEx[] = _T("\\d{1,2}:\\d{2}:\\d{2}|\\d{1,2}:\\d{2}"); - -void SmileyPackType::AddTriggersToSmileyLookup(void) -{ - _TPattern * p = _TPattern::compile(_T("\\s+")); - - { - bkstring emptystr; - m_SmileyLookup.insert(new SmileyLookup(urlRegEx, true, -1, emptystr)); - m_SmileyLookup.insert(new SmileyLookup(pathRegEx, true, -1, emptystr)); - m_SmileyLookup.insert(new SmileyLookup(timeRegEx, true, -1, emptystr)); - } - - for (int dist = 0; dist < m_SmileyList.getCount(); dist++) - { - if (m_SmileyList[dist].IsRegEx()) - { - SmileyLookup* dats = new SmileyLookup(m_SmileyList[dist].GetTriggerText(), true, dist, GetFilename()); - if (dats->IsValid()) - m_SmileyLookup.insert(dats); - else - errorFound = true; - if (m_SmileyList[dist].m_InsertText.empty()) m_SmileyList[dist].m_InsertText = m_SmileyList[dist].m_ToolText; - } - else if (!m_SmileyList[dist].IsService()) - { - bool first = true; - int li = 0; - _TMatcher * m0 = p->createTMatcher(m_SmileyList[dist].GetTriggerText()); - while (m0->findNextMatch()) - { - int stind = m0->getStartingIndex(); - if (li != stind) - { - bkstring out; - ReplaceAllSpecials(m0->getString().substr(li, stind - li), out); - SmileyLookup *dats = new SmileyLookup(out, false, dist, GetFilename()); - if (dats->IsValid()) - { - m_SmileyLookup.insert(dats); - if (first) - { - m_SmileyList[dist].m_InsertText = out; - first = false; - } - } - } - li = m0->getEndingIndex(); - } - - int stind = (int)m0->getString().size(); - if (li < stind) - { - bkstring out; - ReplaceAllSpecials(m0->getString().substr(li, stind - li), out); - SmileyLookup *dats = new SmileyLookup(out, false, dist, GetFilename()); - if (dats->IsValid()) - { - m_SmileyLookup.insert(dats); - if (first) - { - m_SmileyList[dist].m_InsertText = out; - first = false; - } - } - } - delete m0; - } - } - delete p; -} - - -void SmileyPackType::ReplaceAllSpecials(const bkstring& Input, bkstring& Output) -{ - Output = _TPattern::replace(_T("%%_{1,2}%%"), Input, _T(" ")); - Output = _TPattern::replace(_T("%%''%%"), Output, _T("\"")); -} - - -void SmileyPackType::Clear(void) -{ - m_SmileyList.destroy(); - m_SmileyLookup.destroy(); - if (m_hSmList != NULL) { ImageList_Destroy(m_hSmList); m_hSmList = NULL; } - m_Filename.clear(); - m_Name.clear(); - m_Date.clear(); - m_Version.clear(); - m_Author.clear(); - m_VisibleCount = 0; - m_ButtonSmiley.clear(); - errorFound = false; -} - -bool SmileyPackType::LoadSmileyFile(const bkstring& filename, bool onlyInfo, bool noerr) -{ - Clear(); - - if (filename.empty()) - { - m_Name = _T("Nothing loaded"); - return false; - } - - bkstring modpath; - pathToAbsolute(filename, modpath); - - // Load xep file - int fh = _topen(modpath.c_str(), _O_BINARY | _O_RDONLY); - if (fh == -1) - { - if (!noerr) - { - static const TCHAR errmsg[] = _T("Smiley Pack %s not found.\n") - _T("Select correct Smiley Pack in the Miranda Options | Customize | Smileys."); - TCHAR msgtxt[1024]; - mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), modpath.c_str()); - ReportError(msgtxt); - } - - m_Name = _T("Nothing loaded"); - return false; - } - - m_Filename = filename; - - // Find file size - const long flen = _filelength(fh); - - // Allocate file buffer - char* buf = new char[flen + sizeof(wchar_t)]; - - // Read xep file in - int len = _read(fh, buf, flen); - *(wchar_t*)(buf+len) = 0; - - // Close file - _close(fh); - - bkstring tbuf; - - if (len>2 && *(wchar_t*)buf == 0xfeff) - { - tbuf = W2T_SM((wchar_t*)buf+1); - } - else if (len>3 && buf[0]=='\xef' && buf[1]=='\xbb' && buf[2]=='\xbf') - { - tbuf = W2T_SM(A2W_SM(buf+3, CP_UTF8)); - } - else - { - tbuf = A2T_SM(buf); - } - - delete[] buf; - - bool res; - if (filename.find(_T(".xep")) == filename.npos) - res = LoadSmileyFileMSL(tbuf, onlyInfo, modpath); - else - res = LoadSmileyFileXEP(tbuf, onlyInfo, modpath); - - if (errorFound) ReportError(TranslateT("There were problems loading smiley pack (it should be corrected).\nSee Network Log for details.")); - - return res; -} - -bool SmileyPackType::LoadSmileyFileMSL(bkstring& tbuf, bool onlyInfo, bkstring& modpath) -{ - _TPattern * pathsplit = _TPattern::compile(_T("(.*\\\\)(.*)\\.|$")); - _TMatcher * m0 = pathsplit->createTMatcher(modpath); - - m0->findFirstMatch(); - const bkstring pathstr = m0->getGroup(1); - const bkstring packstr = m0->getGroup(2); - - delete m0; - delete pathsplit; - - _TPattern * otherf = _TPattern::compile( - _T("^\\s*(Name|Author|Date|Version|ButtonSmiley)\\s*=\\s*\"(.*)\""), - _TPattern::MULTILINE_MATCHING); - - m0 = otherf->createTMatcher(tbuf); - - while (m0->findNextMatch()) - { - if (m0->getGroup(1) == _T("Name")) m_Name = m0->getGroup(2); - if (m0->getGroup(1) == _T("Author")) m_Author = m0->getGroup(2); - if (m0->getGroup(1) == _T("Date")) m_Date = m0->getGroup(2); - if (m0->getGroup(1) == _T("Version")) m_Version = m0->getGroup(2); - if (m0->getGroup(1) == _T("ButtonSmiley")) m_ButtonSmiley = m0->getGroup(2); - } - delete m0; - delete otherf; - - if (!onlyInfo) - { - selec.x = 0; - selec.y = 0; - win.x = 0; - win.y = 0; - { - _TPattern * pat = _TPattern::compile( - _T("^\\s*(Selection|Window)Size\\s*=\\s*(\\d+)\\s*,\\s*(\\d+)"), - _TPattern::MULTILINE_MATCHING); - _TMatcher * m0 = pat->createTMatcher(tbuf); - while (m0->findNextMatch()) - { - POINT tpt; - tpt.x = _ttol(m0->getGroup(2).c_str()); - tpt.y = _ttol(m0->getGroup(3).c_str()); - - if (m0->getGroup(1) == _T("Selection")) - selec = tpt; - else if (m0->getGroup(1) == _T("Window")) - win = tpt; - } - delete m0; - delete pat; - } - - _TPattern * smiley = _TPattern::compile( - _T("^\\s*Smiley(\\*)?\\s*=") // Is Hidden - _T("(?:\\s*\"(.*)\")") // Smiley file name - _T("(?:[\\s,]+(\\-?\\d+))") // Icon resource id - _T("(?:[\\s,]+(R|S)?\"(.*?)\")") // Trigger text - _T("(?:[\\s,]+\"(.*?)\")?") // Tooltip or insert text - _T("(?:[\\s,]+\"(.*?)\")?"), // Tooltip text - _TPattern::MULTILINE_MATCHING); - - _TMatcher * m0 = smiley->createTMatcher(tbuf); - - SmileyVectorType hiddenSmileys; - - unsigned smnum = 0; - while (m0->findNextMatch()) - { - bkstring resname = m0->getGroup(2); - if (resname.find(_T("http://")) != resname.npos) - { - if (GetSmileyFile(resname, packstr)) continue; - } - else - { - if (!resname.empty()) resname.insert(0, pathstr); - } - - SmileyType *dat = new SmileyType; - - const int iconIndex = _ttol(m0->getGroup(3).c_str()); - - dat->SetHidden(m0->getStartingIndex(1) >= 0); - if (m0->getStartingIndex(4) >= 0) - { - dat->SetRegEx(m0->getGroup(4) == _T("R")); - dat->SetService(m0->getGroup(4) == _T("S")); - } - dat->m_TriggerText = m0->getGroup(5); - if (dat->IsRegEx()) - { - if (m0->getStartingIndex(6) >= 0) - ReplaceAllSpecials(m0->getGroup(6), dat->m_InsertText); - - if (m0->getStartingIndex(7) >= 0) - ReplaceAllSpecials(m0->getGroup(7), dat->m_ToolText); - else - dat->m_ToolText = dat->m_InsertText; - } - else - { - if (m0->getStartingIndex(6) >= 0) - ReplaceAllSpecials(m0->getGroup(6), dat->m_ToolText); - else - ReplaceAllSpecials(dat->m_TriggerText, dat->m_ToolText); - } - - bool noerr; - if (resname.empty()) - { - dat->SetHidden(true); - dat->SetText(true); - noerr = true; - } - else - noerr = dat->LoadFromResource(resname, iconIndex); - - if (dat->IsHidden()) - hiddenSmileys.insert(dat); - else - m_SmileyList.insert(dat); - - if (!noerr) - { - static const TCHAR errmsg[] = _T("Smiley #%u in file %s for Smiley Pack %s not found."); - TCHAR msgtxt[1024]; - mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), smnum, resname.c_str(), modpath.c_str()); - CallService(MS_NETLIB_LOG,(WPARAM) hNetlibUser, (LPARAM)(char*)T2A_SM(msgtxt)); - errorFound = true; - } - smnum++; - } - delete m0; - delete smiley; - - m_VisibleCount = m_SmileyList.getCount(); - - m_SmileyList.splice(hiddenSmileys); - - AddTriggersToSmileyLookup(); - } - - return true; -} - - -static void DecodeHTML(bkstring& str) -{ - if (str.find('&') != str.npos) - { - str = _TPattern::replace(bkstring(_T("<")), str, bkstring(_T("<"))); - str = _TPattern::replace(bkstring(_T(">")), str, bkstring(_T(">"))); - } -} - - -static IStream* DecodeBase64Data(const char* data) -{ - NETLIBBASE64 nlb64; - nlb64.pszEncoded = (char*)data; - nlb64.cchEncoded = (int)strlen(data); - nlb64.cbDecoded = Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded); - - IStream* pStream = NULL; - - // Read image list - HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, nlb64.cbDecoded); - if (hBuffer) - { - nlb64.pbDecoded = (PBYTE)GlobalLock(hBuffer); - CallService(MS_NETLIB_BASE64DECODE, 0, (LPARAM)&nlb64); - GlobalUnlock(hBuffer); - - CreateStreamOnHGlobal(hBuffer, TRUE, &pStream); - } - - return pStream; -} - - -bool SmileyPackType::LoadSmileyFileXEP(bkstring& tbuf, bool onlyInfo, bkstring& ) -{ - _TMatcher *m0, *m1, *m2; - - _TPattern * dbname_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"), - _TPattern::MULTILINE_MATCHING); - _TPattern * author_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"), - _TPattern::MULTILINE_MATCHING); - _TPattern * settings_re = _TPattern::compile(_T("(.*?)"), - _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL); - - m0 = settings_re->createTMatcher(tbuf); - if (m0->findFirstMatch()) - { - bkstring settings = m0->getGroup(1); - - m1 = author_re->createTMatcher(settings); - if (m1->findFirstMatch()) - { - m_Author = m1->getGroup(1); - DecodeHTML(m_Author); - } - delete m1; - - m1 = dbname_re->createTMatcher(settings); - if (m1->findFirstMatch()) - { - m_Name = m1->getGroup(1); - DecodeHTML(m_Name); - } - delete m1; - } - delete m0; - - delete dbname_re; - delete author_re; - delete settings_re; - - if (!onlyInfo) - { - _TPattern * record_re = _TPattern::compile(_T("(?:\\s*\"(.*?)\")?(.*?)"), - _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL); - _TPattern * expression_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"), - _TPattern::MULTILINE_MATCHING); - _TPattern * pastetext_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"), - _TPattern::MULTILINE_MATCHING); - _TPattern * images_re = _TPattern::compile(_T("(.*?)"), - _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL); - _TPattern * image_re = _TPattern::compile(_T("(.*?)"), - _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL); - _TPattern * imagedt_re = _TPattern::compile(_T(""), - _TPattern::MULTILINE_MATCHING ); - - m0 = images_re->createTMatcher(tbuf); - if (m0->findFirstMatch()) - { - bkstring images = m0->getGroup(1); - - m1 = imagedt_re->createTMatcher(images); - if (m1->findFirstMatch()) - { - IStream* pStream = DecodeBase64Data(T2A_SM(m1->getGroup(1).c_str())); - if (pStream != NULL) - { - if (m_hSmList != NULL) ImageList_Destroy(m_hSmList); - m_hSmList = ImageList_Read(pStream); - pStream->Release(); - } - } - delete m1; - } - delete m0; - - m0 = record_re->createTMatcher(tbuf); - while (m0->findNextMatch()) - { - SmileyType *dat = new SmileyType; - - dat->SetRegEx(true); - dat->SetImList(m_hSmList, _ttol(m0->getGroup(1).c_str())); - dat->m_ToolText = m0->getGroup(2); - DecodeHTML(dat->m_ToolText); - - bkstring rec = m0->getGroup(3); - - m1 = expression_re->createTMatcher(rec); - if (m1->findFirstMatch()) - { - dat->m_TriggerText = m1->getGroup(1); - DecodeHTML(dat->m_TriggerText); - } - delete m1; - - m1 = pastetext_re->createTMatcher(rec); - if (m1->findFirstMatch()) - { - dat->m_InsertText = m1->getGroup(1); - DecodeHTML(dat->m_InsertText); - } - delete m1; - dat->SetHidden(dat->m_InsertText.empty()); - - m1 = image_re->createTMatcher(rec); - if (m1->findFirstMatch()) - { - bkstring images = m1->getGroup(1); - - m2 = imagedt_re->createTMatcher(images); - if (m2->findFirstMatch()) - { - IStream* pStream = DecodeBase64Data(T2A_SM(m2->getGroup(1).c_str())); - if (pStream != NULL) - { - dat->LoadFromImage(pStream); - pStream->Release(); - } - } - delete m2; - } - delete m1; - - m_SmileyList.insert(dat); - } - delete m0; - - delete record_re; - delete expression_re; - delete pastetext_re; - delete images_re; - delete image_re; - delete imagedt_re; - } - - m_VisibleCount = m_SmileyList.getCount(); - - AddTriggersToSmileyLookup(); - - selec.x = 0; - selec.y = 0; - win.x = 0; - win.y = 0; - - return true; -} - - -// -// SmileyPackListType -// - - -bool SmileyPackListType::AddSmileyPack(bkstring& filename) -{ - bool res = true; - if (GetSmileyPack(filename) == NULL) - { //not exist yet, so add - SmileyPackType *smileyPack = new SmileyPackType; - - res = smileyPack->LoadSmileyFile(filename, FALSE); - if (res) - m_SmileyPacks.insert(smileyPack); - else - delete smileyPack; - } - return res; -} - - -SmileyPackType* SmileyPackListType::GetSmileyPack(bkstring& filename) -{ - bkstring modpath; - pathToAbsolute(filename, modpath); - - for (int i = 0; i < m_SmileyPacks.getCount(); i++) - { - bkstring modpath1; - pathToAbsolute(m_SmileyPacks[i].GetFilename(), modpath1); - if (lstrcmpi(modpath.c_str(), modpath1.c_str()) == 0) return &m_SmileyPacks[i]; - } - return NULL; -} - -void SmileyPackListType::ClearAndFreeAll() -{ - m_SmileyPacks.destroy(); -} - - -// -// SmileyCategoryType -// - - -SmileyCategoryType::SmileyCategoryType(SmileyPackListType* pSPS, const bkstring& name, - const bkstring& displayName, - const bkstring& defaultFilename, SmcType typ) -{ - m_pSmileyPackStore = pSPS; - type = typ; - m_Name = name; - m_DisplayName = displayName; - - opt.ReadPackFileName(m_Filename, m_Name, defaultFilename); -} - - -void SmileyCategoryType::Load(void) -{ - if (!opt.UseOneForAll || type != smcProto) - m_pSmileyPackStore->AddSmileyPack(m_Filename); -} - - -SmileyPackType* SmileyCategoryType::GetSmileyPack(void) -{ - return m_pSmileyPackStore->GetSmileyPack(m_Filename); -} - - -void SmileyCategoryType::SaveSettings(void) -{ - opt.WritePackFileName(m_Filename, m_Name); -} - -// -// SmileyCategoryListType -// - -void SmileyCategoryListType::ClearAndLoadAll(void) -{ - m_pSmileyPackStore->ClearAndFreeAll(); - - for (int i = 0; i < m_SmileyCategories.getCount(); i++) - m_SmileyCategories[i].Load(); -} - - -SmileyCategoryType* SmileyCategoryListType::GetSmileyCategory(const bkstring& name) -{ - for (int i = 0; i < m_SmileyCategories.getCount(); i++) - { - if (name.comparei(m_SmileyCategories[i].GetName()) == 0) return &m_SmileyCategories[i]; - } - return NULL; -} - - -SmileyCategoryType* SmileyCategoryListType::GetSmileyCategory(unsigned index) -{ - return index < (unsigned)m_SmileyCategories.getCount() ? &m_SmileyCategories[index] : NULL; -} - - -SmileyPackType* SmileyCategoryListType::GetSmileyPack(bkstring& categoryname) -{ - SmileyCategoryType* smc = GetSmileyCategory(categoryname); - return smc != NULL ? smc->GetSmileyPack() : NULL; -} - - -void SmileyCategoryListType::SaveSettings(void) -{ - bkstring catstr; - for (int i = 0; i < m_SmileyCategories.getCount(); i++) - { - m_SmileyCategories[i].SaveSettings(); - if (m_SmileyCategories[i].IsCustom()) - { - if (!catstr.empty()) catstr += '#'; - catstr += m_SmileyCategories[i].GetName(); - } - } - opt.WriteCustomCategories(catstr); -} - - -void SmileyCategoryListType::AddAndLoad(const bkstring& name, const bkstring& displayName) -{ - if (GetSmileyCategory(name) != NULL) return; - - AddCategory(name, displayName, smcExt); - // Load only if other smileys have been loaded already - if (m_SmileyCategories.getCount() > 1) - m_SmileyCategories[m_SmileyCategories.getCount()-1].Load(); -} - - -void SmileyCategoryListType::AddCategory(const bkstring& name, const bkstring& displayName, - SmcType typ, const bkstring& defaultFilename) -{ - if (GetSmileyCategory(name) == NULL) - m_SmileyCategories.insert(new SmileyCategoryType(m_pSmileyPackStore, name, - displayName, defaultFilename, typ)); -} - - -bool SmileyCategoryListType::DeleteCustomCategory(int index) -{ - if (index < m_SmileyCategories.getCount()) - { - if (m_SmileyCategories[index].IsCustom()) - { - m_SmileyCategories.remove(index); - return true; - } - - } - return false; -} - -void SmileyCategoryListType::AddAccountAsCategory(PROTOACCOUNT *acc, const bkstring& defaultFile) -{ - if (IsAccountEnabled(acc) && acc->szProtoName && IsSmileyProto(acc->szModuleName)) - { - bkstring displayName(acc->tszAccountName ? acc->tszAccountName : A2T_SM(acc->szModuleName)); - - const char* packnam = acc->szProtoName; - if (strcmp(packnam, "JABBER") == 0) - packnam = "JGMail"; - else if (strstr(packnam, "SIP") != NULL) - packnam = "MSN"; - - char path[MAX_PATH]; - mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packnam); - - bkstring paths = A2T_SM(path), patha; - pathToAbsolute(paths, patha); - - if (_taccess(patha.c_str(), 0) != 0) - paths = defaultFile; - - bkstring tname(A2T_SM(acc->szModuleName)); - AddCategory(tname, displayName, smcProto, paths); - } -} - -void SmileyCategoryListType::DeleteAccountAsCategory(PROTOACCOUNT *acc) -{ - bkstring tname(A2T_SM(acc->szModuleName)); - - HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0); - while (hContact != NULL) - { - char* proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - if (proto) - { - DBVARIANT dbv; - if (DBGetContactSettingTString(hContact, proto, "Transport", &dbv) == 0) - { - bool found = (tname.comparei(dbv.ptszVal) == 0); - DBFreeVariant(&dbv); - if (found) return; - } - } - hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); - } - - for (int i = 0; i < m_SmileyCategories.getCount(); i++) - { - if (tname.comparei(m_SmileyCategories[i].GetName()) == 0) - { - m_SmileyCategories.remove(i); - break; - } - } -} - -void SmileyCategoryListType::AddContactTransportAsCategory(HANDLE hContact, const bkstring& defaultFile) -{ - char* proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - if (proto == NULL) return; - - DBVARIANT dbv; - if (DBGetContactSettingTString(hContact, proto, "Transport", &dbv) == 0) - { - if (dbv.ptszVal[0] == '\0') - { - DBFreeVariant(&dbv); - return; - } - char* trsp = mir_strdup(T2A_SM(dbv.ptszVal)); - _strlwr(trsp); - - const char *packname = NULL; - if (strstr(trsp, "msn") != NULL) - packname = "msn"; - else if (strstr(trsp, "icq") != NULL) - packname = "icq"; - else if (strstr(trsp, "yahoo") != NULL) - packname = "yahoo"; - else if (strstr(trsp, "aim") != NULL) - packname = "aim"; - else if (strstr(trsp, "lcs") != NULL) - packname = "msn"; - - mir_free(trsp); - - bkstring displayName = dbv.ptszVal; - if (packname != NULL) - { - char path[MAX_PATH]; - mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packname); - - bkstring paths = A2T_SM(path), patha; - pathToAbsolute(paths, patha); - - if (_taccess(patha.c_str(), 0) != 0) - paths = defaultFile; - - AddCategory(displayName, displayName, smcProto, paths); - } - else - AddCategory(displayName, displayName, smcProto, defaultFile); - - DBFreeVariant(&dbv); - } -} - - -void SmileyCategoryListType::AddAllProtocolsAsCategory(void) -{ - bkstring displayName = TranslateT("Standard"); - bkstring tname = _T("Standard"); - AddCategory(tname, displayName, smcStd); - - const bkstring& defaultFile = GetSmileyCategory(tname)->GetFilename(); - - - unsigned lpcp = (unsigned)CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); - if (lpcp == CALLSERVICE_NOTFOUND) lpcp = CP_ACP; - - - PROTOCOLDESCRIPTOR **protoList; - PROTOACCOUNT **accList; - int protoCount; - - if (ProtoEnumAccounts(&protoCount, &accList) == CALLSERVICE_NOTFOUND || (protoCount > 0 && accList[0]->cbSize == 0)) - { - CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&protoCount, (LPARAM)&protoList); - for (int i = 0; i < protoCount; i++) - { - if (protoList[i]->type != PROTOTYPE_PROTOCOL) continue; - - if (IsSmileyProto(protoList[i]->szName)) - { - const char* packnam = protoList[i]->szName; - if (strcmp(packnam, "JABBER") == 0) - packnam = "JGMail"; - else if (strstr(packnam, "SIP") != NULL) - packnam = "MSN"; - - char path[MAX_PATH]; - mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packnam); - - bkstring paths = A2T_SM(path), patha; - pathToAbsolute(paths, patha); - - if (_taccess(patha.c_str(), 0) != 0) - paths = defaultFile; - - char protoName[128]; - CallProtoService(protoList[i]->szName, PS_GETNAME, sizeof(protoName), (LPARAM)protoName); - - - displayName = A2W_SM(protoName, lpcp); - - tname = A2T_SM(protoList[i]->szName); - AddCategory(tname, displayName, smcProto, paths); - } - } - } - else - { - for (int i = 0; i < protoCount; i++) - AddAccountAsCategory(accList[i], defaultFile); - } - - HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0); - while (hContact != NULL) - { - AddContactTransportAsCategory(hContact, defaultFile); - hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); - } - - bkstring cats; - opt.ReadCustomCategories(cats); - - bkstring::size_type cppv = 0; - for (;;) - { - bkstring::size_type cp = cats.find('#', cppv); - if (cp != cats.npos) - { - displayName = cats.substr(cppv, cp - cppv); - AddCategory(displayName, displayName, smcCustom, defaultFile); - cppv = cp + 1; - } - else break; - } - if (cppv != cats.size()) - { - displayName = cats.substr(cppv, cats.size() - cppv); - AddCategory(displayName, displayName, smcCustom, defaultFile); - } -} - - -SmileyLookup::SmileyLookup(const bkstring& str, const bool regexs, const int ind, const bkstring& smpt) -{ - TCHAR msgtxt[1024]; - - m_ind = ind; - if (regexs) - { - static const bkstring testString(_T("Test String")); - m_pattern = _TPattern::compile(str); - m_valid = m_pattern != NULL; - if (m_valid) - { - _TMatcher* matcher = m_pattern->createTMatcher(testString); - m_valid &= (!matcher->findFirstMatch() || - matcher->getStartingIndex() != matcher->getEndingIndex()); - if (!m_valid) - { - static const TCHAR errmsg[] = _T("Regular Expression \"%s\" in smiley pack \"%s\" could produce \"empty matches\"."); - mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), str.c_str(), smpt.c_str()); - } - delete matcher; - } - else - { - static const TCHAR errmsg[] = _T("Regular Expression \"%s\" in smiley pack \"%s\" malformed.") ; - mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), str.c_str(), smpt.c_str()); - } - - if (!m_valid) CallService(MS_NETLIB_LOG, (WPARAM) hNetlibUser, (LPARAM)(char*)T2A_SM(msgtxt)); - } - else - { - m_text = str; - m_pattern = NULL; - m_valid = !str.empty(); - } -} - - -SmileyLookup::~SmileyLookup() -{ - if (m_pattern) delete m_pattern; -} - - -void SmileyLookup::find(const bkstring& str, SmileyLocVecType& smlcur, bool firstOnly) const -{ - if (!m_valid) return; - - if (m_text.empty()) - { - _TMatcher* matcher = m_pattern->createTMatcher(str); - while( matcher->findNextMatch()) - { - bkstring::size_type st = matcher->getStartingIndex(); - bkstring::size_type sz = matcher->getEndingIndex() - st; - if (sz != 0) - { - smlcur.insert(new SmileyLocType(st, sz)); - if (firstOnly && m_ind != -1) return; - } - } - delete matcher; - } - else - { - const TCHAR* pos = str.c_str(); - while( (pos = _tcsstr(pos, m_text.c_str())) != NULL ) - { - smlcur.insert(new SmileyLocType(pos - str.c_str(), m_text.size())); - pos += m_text.size(); - if (firstOnly && m_ind != -1) return; - } - } -} diff --git a/plugins/SmileyAdd/smileys.h b/plugins/SmileyAdd/smileys.h deleted file mode 100644 index 2b127eb225..0000000000 --- a/plugins/SmileyAdd/smileys.h +++ /dev/null @@ -1,287 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef SMILEYADD_SMILEYS_H_ -#define SMILEYADD_SMILEYS_H_ - -#include "general.h" -#include "smltool.h" -#include "imagecache.h" - -#define MS_SMILEYADD_CUSTOMCATMENU "SmileyAdd/CustomCatMenu" - -const unsigned HiddenSmiley = 1; -const unsigned RegExSmiley = 2; -const unsigned ServiceSmiley = 4; -const unsigned TextSmiley = 8; -const unsigned SoundSmiley = 16; - -class SmileyType -{ -protected: - unsigned m_flags; - int m_index; - - SIZE m_size; - - HICON m_SmileyIcon; - ImageBase* m_xepimg; - - bkstring m_filepath; - - void SetFlagsBit(unsigned flag, bool set) - { if (set) m_flags |= flag; else m_flags &= ~flag; } - -public: - - bkstring m_TriggerText; - bkstring m_ToolText; - bkstring m_InsertText; - - SmileyType(void); - ~SmileyType(); - - const bkstring& GetTriggerText(void) const { return m_TriggerText; } - const bkstring& GetToolText(void) const { return m_ToolText; } - const bkstring& GetInsertText(void) const { return m_InsertText; } - const bkstring& GetFilePath(void) const { return m_filepath; } - - bool IsHidden(void) const { return (m_flags & HiddenSmiley) != 0; } - bool IsRegEx(void) const { return (m_flags & RegExSmiley) != 0; } - bool IsService(void) const { return (m_flags & ServiceSmiley) != 0; } - bool IsSound(void) const { return (m_flags & SoundSmiley) != 0; } - bool IsText(void) const { return (m_flags & TextSmiley) != 0; } - - bool IsFileFound(void) { return _taccess(m_filepath.c_str(), 0) == 0; } - bool IsValid(void) { return m_size.cx != 0; } - - ImageBase* CreateCachedImage(void); - - void GetSize(SIZE& size); - int GetStaticFrame(void) const { return m_index; } - - HICON GetIcon(void); - HICON GetIconDup(void); - HBITMAP GetBitmap(COLORREF bkgClr, int sizeX, int sizeY); - - void CallSmileyService(HANDLE hContact); - - void SetHidden(bool hid) { SetFlagsBit(HiddenSmiley, hid); } - void SetRegEx(bool regex) { SetFlagsBit(RegExSmiley, regex); } - void SetService(bool service) { SetFlagsBit(ServiceSmiley, service); } - void SetSound(bool sound) { SetFlagsBit(SoundSmiley, sound); } - void SetText(bool text) { SetFlagsBit(TextSmiley, text); } - - void SetImList(HIMAGELIST hImLst, long i); - - bool LoadFromResource(const bkstring& file, const int index); - bool LoadFromImage(IStream* pStream); -}; - - -class SmileyLookup -{ -private: - _TPattern* m_pattern; - - int m_ind; - bkstring m_text; - bool m_valid; - -public: - struct SmileyLocType - { - size_t pos, len; - SmileyLocType(size_t p, size_t l) : pos(p), len(l) {} - SmileyLocType() {} - }; - typedef SMOBJLIST SmileyLocVecType; - - SmileyLookup() { m_ind = 0; m_valid = false; m_pattern = NULL; }; - SmileyLookup(const bkstring& str, const bool regexs, const int ind, const bkstring& smpt); - ~SmileyLookup(); - - void find(const bkstring& str, SmileyLocVecType& smlcur, bool firstOnly) const; - int GetIndex(void) const { return m_ind; } - bool IsValid(void) const { return m_valid; } -}; - - -class SmileyPackType -{ -public: - typedef SMOBJLIST SmileyVectorType; - typedef SMOBJLIST SmileyLookupType; - - POINT selec, win; - -private: - bkstring m_Filename; //used as identification - bkstring m_Name; - bkstring m_Author; - bkstring m_Date; - bkstring m_Version; - bkstring m_ButtonSmiley; - - HIMAGELIST m_hSmList; - - int m_VisibleCount; - - SmileyVectorType m_SmileyList; - SmileyLookupType m_SmileyLookup; - - bool errorFound; - - void InsertLookup(SmileyType& sml, bkstring& lk, bool first); - void AddTriggersToSmileyLookup(void); - void ReplaceAllSpecials(const bkstring& Input, bkstring& Output); - bool LoadSmileyFileMSL(bkstring& tbuf, bool onlyInfo, bkstring& modpath); - bool LoadSmileyFileXEP(bkstring& tbuf, bool onlyInfo, bkstring& modpath); - -public: - SmileyPackType(); - ~SmileyPackType(); - - SmileyVectorType& GetSmileyList(void) { return m_SmileyList; } - SmileyLookupType* GetSmileyLookup(void) { return &m_SmileyLookup; } - - const bkstring& GetFilename(void) const { return m_Filename; } - const bkstring& GetName(void) const { return m_Name; } - const bkstring& GetAuthor(void) const { return m_Author; } - const bkstring& GetDate(void) const { return m_Date; } - const bkstring& GetVersion(void) const { return m_Version; } - - int SmileyCount(void) const { return m_SmileyList.getCount(); } - int VisibleSmileyCount(void) const { return m_VisibleCount; } - - SmileyType* GetSmiley(unsigned index); - - const TCHAR* GetButtonSmiley(void) const { return m_ButtonSmiley.c_str(); } - - bool LoadSmileyFile(const bkstring& filename, bool onlyInfo, bool noerr = false); - - void Clear(void); -}; - - -class SmileyPackListType -{ -public: - typedef SMOBJLIST SmileyPackVectorType; - -private: - SmileyPackVectorType m_SmileyPacks; - -public: - int NumberOfSmileyPacks(void) { return m_SmileyPacks.getCount(); } - - bool AddSmileyPack(bkstring& filename); - void ClearAndFreeAll(void); - SmileyPackType* GetSmileyPack(bkstring& filename); -}; - - -typedef enum -{ - smcNone, - smcStd, - smcProto, - smcCustom, - smcExt -} SmcType; - - -class SmileyCategoryType -{ -private: - bkstring m_Name; - bkstring m_DisplayName; - bkstring m_Filename; //functions as identification - - SmcType type; - - SmileyPackListType* m_pSmileyPackStore; - -public: - SmileyCategoryType() { type = smcNone; m_pSmileyPackStore = NULL; }; - SmileyCategoryType(SmileyPackListType* pSPS, const bkstring& name, - const bkstring& displayName, const bkstring& defaultFilename, SmcType typ); - - const bkstring& GetDisplayName(void) const { return m_DisplayName; } - const bkstring& GetName(void) const { return m_Name; } - const bkstring& GetFilename(void) const { return m_Filename; } - - bool IsCustom(void) { return type == smcCustom; } - bool IsProto(void) { return type == smcProto; } - bool IsExt(void) { return type == smcExt; } - - SmcType GetType(void) { return type; } - - SmileyPackType* GetSmileyPack(void); - - void SetFilename(bkstring& name) { m_Filename = name; } - void SetDisplayName(bkstring& name) { m_DisplayName = name; } - - void ClearFilename(void) { m_Filename.clear(); } - void SaveSettings(void); - - void Load(void); -}; - - -class SmileyCategoryListType -{ -public: - typedef SMOBJLIST SmileyCategoryVectorType; - -private: - SmileyCategoryVectorType m_SmileyCategories; - SmileyPackListType* m_pSmileyPackStore; - -public: - void SetSmileyPackStore(SmileyPackListType* pSPS) { m_pSmileyPackStore = pSPS; } - - SmileyCategoryType* GetSmileyCategory(const bkstring& name); - SmileyCategoryType* GetSmileyCategory(unsigned index); - SmileyPackType* GetSmileyPack(bkstring& name); - SmileyCategoryVectorType* GetSmileyCategoryList(void) { return &m_SmileyCategories; }; - - int NumberOfSmileyCategories(void) { return m_SmileyCategories.getCount(); } - - void AddCategory(const bkstring& name, const bkstring& displayName, SmcType typ, - const bkstring& defaultFilename = bkstring(_T("Smileys\\nova\\default.msl"))); - void AddAndLoad(const bkstring& name, const bkstring& displayName); - void AddAllProtocolsAsCategory(void); - void AddAccountAsCategory(PROTOACCOUNT *acc, const bkstring& defaultFile); - void AddContactTransportAsCategory(HANDLE hContact, const bkstring& defaultFile); - - void ClearAndLoadAll(void); - void ClearAll(void) - { m_pSmileyPackStore->ClearAndFreeAll(); m_SmileyCategories.destroy(); } - - bool DeleteCustomCategory(int index); - void DeleteAccountAsCategory(PROTOACCOUNT *acc); - - void SaveSettings(void); -}; - -extern SmileyPackListType g_SmileyPacks; -extern SmileyCategoryListType g_SmileyCategories; - -#endif //SMILEYADD_SMILEYS_H_ diff --git a/plugins/SmileyAdd/smltool.cpp b/plugins/SmileyAdd/smltool.cpp deleted file mode 100644 index 31695a516a..0000000000 --- a/plugins/SmileyAdd/smltool.cpp +++ /dev/null @@ -1,785 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "general.h" -#include "options.h" -#include "smileys.h" -#include "smltool.h" -#include "anim.h" - -#define SB_MYMOVE 20 - -// -// SmileyToolwindowType -// -class SmileyToolWindowType -{ -private: - unsigned m_NumberOfVerticalButtons; - unsigned m_NumberOfHorizontalButtons; - SIZE m_BitmapWidth; - SIZE m_ButtonSize; - unsigned m_ButtonSpace; - unsigned m_NumberOfButtons; - int m_WindowSizeY; - - HWND m_hwndDialog; - HWND m_hToolTip; - HWND m_hWndTarget; - SmileyPackType* m_pSmileyPack; - int m_CurrentHotTrack; - int m_XPosition; - int m_YPosition; - int m_Direction; - UINT m_TargetMessage; - WPARAM m_TargetWParam; - HANDLE m_hContact; - int rowSel; - bool m_Choosing; - - AnimatedPack* m_AniPack; - - void InitDialog(LPARAM lParam); - void PaintWindow(void); - void InsertSmiley(void); - void MouseMove(int x, int y); - void KeyUp(WPARAM wParam, LPARAM lParam); - void SmileySel(int but); - void ScrollV(int action, int dist = 0); - - int GetRowSize(void) const { return m_ButtonSize.cy + m_ButtonSpace; } - - void CreateSmileyBitmap(HDC hdc); - void CreateSmileyWinDim(void); - RECT CalculateButtonToCoordinates(int buttonPosition, int scroll); - int CalculateCoordinatesToButton(POINT pt, int scroll); - -public: - SmileyToolWindowType(HWND hWnd); - LRESULT DialogProcedure(UINT msg, WPARAM wParam, LPARAM lParam); -}; - - -LRESULT CALLBACK DlgProcSmileyToolWindow(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - SmileyToolWindowType* pOD; - LRESULT Result; - - pOD = (SmileyToolWindowType*) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - if (pOD == NULL) { - pOD = new SmileyToolWindowType(hwndDlg); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pOD); - } - - Result = pOD->DialogProcedure(msg, wParam, lParam); - // SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result); - - if (msg == WM_NCDESTROY) - { - delete pOD; - Result = FALSE; - } - - return Result; -} - - -SmileyToolWindowType::SmileyToolWindowType(HWND hWnd) -{ - m_hwndDialog = hWnd; - rowSel = -1; - m_AniPack = NULL; - - m_NumberOfVerticalButtons = 0; - m_NumberOfHorizontalButtons = 0; - m_BitmapWidth.cx = 0; - m_BitmapWidth.cy = 0; - m_ButtonSize.cx = 0; - m_ButtonSize.cy = 0; - m_ButtonSpace = 1; - m_NumberOfButtons = 0; -} - - -LRESULT SmileyToolWindowType::DialogProcedure(UINT msg, WPARAM wParam, LPARAM lParam) -{ - LRESULT Result = FALSE; - - switch (msg) - { - case WM_ACTIVATE: - if (wParam == WA_INACTIVE) - DestroyWindow(m_hwndDialog); - break; - - case WM_PAINT: - PaintWindow(); - break; - - case WM_TIMER: - if (m_AniPack) m_AniPack->ProcessTimerTick(m_hwndDialog); - break; - - case WM_DESTROY: - KillTimer(m_hwndDialog, 1); - if (m_AniPack) delete m_AniPack; - m_AniPack = NULL; - DestroyWindow(m_hToolTip); - PostQuitMessage(0); - if (m_Choosing) - SetFocus(m_hWndTarget); - break; - - case WM_KEYUP: - KeyUp(wParam, lParam); - break; - - case WM_CREATE: - InitDialog(lParam); - break; - - case WM_VSCROLL: - ScrollV(LOWORD(wParam)); - break; - - case WM_MOUSEMOVE: - MouseMove(LOWORD(lParam), HIWORD(lParam)); - break; - - case WM_LBUTTONUP: - InsertSmiley(); - break; - - case WM_MOUSEWHEEL: - ScrollV(SB_MYMOVE, ((short)HIWORD(wParam))/-120); - MouseMove(LOWORD(lParam), HIWORD(lParam)); - break; - - default: - Result = DefWindowProc(m_hwndDialog, msg, wParam, lParam); - break; - } - - return Result; -} - -struct smlsrvstruct -{ - smlsrvstruct(SmileyType *tsml, HANDLE thContact) - : sml(tsml), hContact(thContact) {} - SmileyType *sml; - HANDLE hContact; -}; - -void CALLBACK smileyServiceCallback(void* arg) -{ - smlsrvstruct* p = (smlsrvstruct*)arg; - p->sml->CallSmileyService(p->hContact); - delete p; -} - -void SmileyToolWindowType::InsertSmiley(void) -{ - if (m_CurrentHotTrack >= 0 && m_hWndTarget != NULL) - { - SmileyType *sml = m_pSmileyPack->GetSmiley(m_CurrentHotTrack); - - if (sml->IsService()) - { - smlsrvstruct* p = new smlsrvstruct(sml, m_hContact); - CallFunctionAsync(smileyServiceCallback, p); - } - else - { - bkstring insertText; - - if (opt.SurroundSmileyWithSpaces) insertText = ' '; - insertText += sml->GetInsertText(); - if (opt.SurroundSmileyWithSpaces) insertText += ' '; - - SendMessage(m_hWndTarget, m_TargetMessage, m_TargetWParam, (LPARAM) insertText.c_str()); - } - m_Choosing = true; - DestroyWindow(m_hwndDialog); - } - else if (m_hWndTarget == NULL) - DestroyWindow(m_hwndDialog); -} - -void SmileyToolWindowType::SmileySel(int but) -{ - if (but != m_CurrentHotTrack) - { - SCROLLINFO si; - si.cbSize = sizeof (si); - si.fMask = SIF_POS; - si.nPos = 0; - GetScrollInfo (m_hwndDialog, SB_VERT, &si); - - HDC hdc = GetDC(m_hwndDialog); - if (m_CurrentHotTrack >= 0) - { - RECT rect = CalculateButtonToCoordinates(m_CurrentHotTrack, si.nPos); - DrawFocusRect(hdc, &rect); - m_CurrentHotTrack = -1; - SendMessage(m_hToolTip, TTM_ACTIVATE, FALSE, 0); - } - m_CurrentHotTrack = but; - if (m_CurrentHotTrack >= 0) - { - TOOLINFO ti = {0}; - ti.cbSize = sizeof(ti); - ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; - ti.hwnd = m_hwndDialog; - ti.uId = (UINT_PTR)m_hwndDialog; - - const bkstring& toolText = m_pSmileyPack->GetSmiley(m_CurrentHotTrack)->GetToolText(); - ti.lpszText = const_cast(toolText.c_str()); - SendMessage(m_hToolTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); - SendMessage(m_hToolTip, TTM_ACTIVATE, TRUE, 0); - - RECT rect = CalculateButtonToCoordinates(m_CurrentHotTrack, si.nPos); - DrawFocusRect(hdc, &rect); - if (m_AniPack) m_AniPack->SetSel(rect); - } - ReleaseDC(m_hwndDialog, hdc); - } -} - - -void SmileyToolWindowType::ScrollV(int action, int dist) -{ - SCROLLINFO si; - si.cbSize = sizeof (si); - si.fMask = SIF_ALL; - GetScrollInfo (m_hwndDialog, SB_VERT, &si); - - // Save the position for comparison later on - int yPos = si.nPos; - switch (action) - { - // user clicked the HOME keyboard key - case SB_TOP: - si.nPos = si.nMin; - break; - - // user clicked the END keyboard key - case SB_BOTTOM: - si.nPos = si.nMax; - break; - - // user clicked the top arrow - case SB_LINEUP: - si.nPos -= 1; - break; - - // user clicked the bottom arrow - case SB_LINEDOWN: - si.nPos += 1; - break; - - // user clicked the scroll bar shaft above the scroll box - case SB_PAGEUP: - si.nPos -= si.nPage; - break; - - // user clicked the scroll bar shaft below the scroll box - case SB_PAGEDOWN: - si.nPos += si.nPage; - break; - - // user dragged the scroll box - case SB_THUMBTRACK: - si.nPos = si.nTrackPos; - break; - - // user dragged the scroll box - case SB_MYMOVE: - si.nPos += dist; - break; - } - // Set the position and then retrieve it. Due to adjustments - // by Windows it may not be the same as the value set. - si.fMask = SIF_POS; - SetScrollInfo (m_hwndDialog, SB_VERT, &si, TRUE); - GetScrollInfo (m_hwndDialog, SB_VERT, &si); - // If the position has changed, scroll window and update it - if (si.nPos != yPos) - { - if (m_AniPack) m_AniPack->SetOffset(si.nPos*GetRowSize()); - - ScrollWindowEx(m_hwndDialog, 0, (yPos - si.nPos) * GetRowSize(), - NULL, NULL, NULL, NULL, SW_INVALIDATE); - - UpdateWindow (m_hwndDialog); - } -} - - -void SmileyToolWindowType::MouseMove(int xposition, int yposition) -{ - if (m_CurrentHotTrack == -2) return; //prevent focussing when not drawn yet! - // SetFocus(m_hwndDialog); - - - SCROLLINFO si; - si.cbSize = sizeof (si); - si.fMask = SIF_POS; - si.nPos = 0; - GetScrollInfo (m_hwndDialog, SB_VERT, &si); - - POINT pt = { xposition, yposition }; - int but = CalculateCoordinatesToButton(pt, si.nPos); - SmileySel(but); -} - - - -void SmileyToolWindowType::KeyUp(WPARAM wParam, LPARAM lParam) -{ - int colSel = -1, numKey = -1; - int but = m_CurrentHotTrack; - - switch(wParam) - { - case VK_END: - but = m_NumberOfButtons-1; - break; - - case VK_HOME: - but = 0; - break; - - case VK_LEFT: - but -= (opt.IEViewStyle ? 1 : m_NumberOfVerticalButtons) * LOWORD(lParam); - break; - - case VK_UP: - but -= (opt.IEViewStyle ? m_NumberOfHorizontalButtons : 1) * LOWORD(lParam); - break; - - case VK_RIGHT: - but += (opt.IEViewStyle ? 1 : m_NumberOfVerticalButtons) * LOWORD(lParam); - break; - - case VK_DOWN: - but += (opt.IEViewStyle ? m_NumberOfHorizontalButtons : 1) * LOWORD(lParam); - break; - - case VK_SPACE: - case VK_RETURN: - if (but != -1) InsertSmiley(); - return; - - case VK_ESCAPE: - DestroyWindow(m_hwndDialog); - return; - - case VK_NUMPAD1: - case VK_NUMPAD2: - case VK_NUMPAD3: - case VK_NUMPAD4: - case VK_NUMPAD5: - case VK_NUMPAD6: - case VK_NUMPAD7: - case VK_NUMPAD8: - case VK_NUMPAD9: - if ((GetKeyState(VK_NUMLOCK) & 1) != 0) - numKey = (int)wParam - VK_NUMPAD1; - else - { - rowSel = -1; - return; - } - break; - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - numKey = (int)wParam - '1'; - break; - - default: - rowSel = -1; - return; - } - - if (numKey != -1) - { - if (rowSel == -1) - { - rowSel = numKey; - but = (opt.IEViewStyle ? m_NumberOfHorizontalButtons : 1) * rowSel; - } - else - { - colSel = numKey; - if (opt.IEViewStyle) - but = colSel + m_NumberOfHorizontalButtons * rowSel; - else - but = rowSel + m_NumberOfVerticalButtons * colSel; - } - } - - if (but < 0) but = 0; - if (but >= (int)m_NumberOfButtons) but = m_NumberOfButtons-1; - - SmileySel(but); - if (colSel != -1) InsertSmiley(); -} - - -void SmileyToolWindowType::InitDialog(LPARAM lParam) -{ - LPCREATESTRUCT createStruct = (LPCREATESTRUCT)lParam; - SmileyToolWindowParam* stwp = (SmileyToolWindowParam*) createStruct->lpCreateParams; - - m_pSmileyPack = stwp->pSmileyPack; - m_XPosition = stwp->xPosition; - m_YPosition = stwp->yPosition; - m_hWndTarget = stwp->hWndTarget; - m_TargetMessage = stwp->targetMessage; - m_TargetWParam = stwp->targetWParam; - m_Direction = stwp->direction; - m_hContact = stwp->hContact; - - m_CurrentHotTrack = -2; - m_Choosing = false; - - CreateSmileyWinDim(); - - int width = m_BitmapWidth.cx; - int height = m_BitmapWidth.cy; - - const int colsz = GetRowSize(); - const int heightn = m_WindowSizeY; - - SCROLLINFO si; - - si.cbSize = sizeof(si); - si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; - si.nMin = 0; - si.nMax = height / colsz - 1; - si.nPage = heightn / colsz; - si.nPos = 0; - SetScrollInfo(m_hwndDialog, SB_VERT, &si, TRUE); - - if (GetWindowLongPtr(m_hwndDialog, GWL_STYLE) & WS_VSCROLL) - width += GetSystemMetrics(SM_CXVSCROLL); - - RECT rc = { 0, 0, width, heightn }; - AdjustWindowRectEx(&rc, GetWindowLongPtr(m_hwndDialog, GWL_STYLE), - FALSE, GetWindowLongPtr(m_hwndDialog, GWL_EXSTYLE)); - - width = rc.right - rc.left; - height = rc.bottom - rc.top; - - switch (m_Direction) - { - case 1: - m_XPosition-=width; - break; - case 2: - m_XPosition-=width; - m_YPosition-=height; - break; - case 3: - m_YPosition-=height; - break; - } - - // Get screen dimentions - int xoScreen = GetSystemMetrics(SM_XVIRTUALSCREEN); - int yoScreen = GetSystemMetrics(SM_YVIRTUALSCREEN); - - int xScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN); - int yScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN); - - if (xScreen == 0) xScreen = GetSystemMetrics(SM_CXSCREEN); - if (yScreen == 0) yScreen = GetSystemMetrics(SM_CYSCREEN); - - xScreen += xoScreen; - yScreen += yoScreen; - - // Prevent window from opening off-screen - if (m_YPosition + height > yScreen) m_YPosition = yScreen - height; - if (m_XPosition + width > xScreen) m_XPosition = xScreen - width; - if (m_YPosition < yoScreen) m_YPosition = yoScreen; - if (m_XPosition < xoScreen) m_XPosition = xoScreen; - - // Move window to desired location - SetWindowPos(m_hwndDialog, NULL, m_XPosition, m_YPosition, - width, height, SWP_NOZORDER); - - m_AniPack = new AnimatedPack(m_hwndDialog, height, m_ButtonSize, opt.SelWndBkgClr); - - SmileyPackType::SmileyVectorType &sml = m_pSmileyPack->GetSmileyList(); - for (unsigned i=0; iAdd(&sml[i], CalculateButtonToCoordinates(i, 0), opt.IEViewStyle); - } - } - m_AniPack->SetOffset(0); - - if (opt.AnimateSel) SetTimer(m_hwndDialog, 1, 100, NULL); - - //add tooltips - m_hToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), - TTS_NOPREFIX | WS_POPUP, 0, 0, 0, 0, m_hwndDialog, NULL, g_hInst, NULL); - TOOLINFO ti = {0}; - ti.cbSize = sizeof(ti); - ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; - ti.hwnd = m_hwndDialog; - ti.uId = (UINT_PTR)m_hwndDialog; - ti.lpszText = TranslateT("d'Oh!"); - SendMessage(m_hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti); -} - - -void SmileyToolWindowType::PaintWindow(void) -{ - SCROLLINFO si; - si.cbSize = sizeof(si); - si.fMask = SIF_POS; - si.nPos = 0; - GetScrollInfo(m_hwndDialog, SB_VERT, &si); - - PAINTSTRUCT ps; - HDC hdc = BeginPaint(m_hwndDialog, &ps); - - HBITMAP hBmp = CreateCompatibleBitmap(hdc, m_BitmapWidth.cx, m_BitmapWidth.cy); - HDC hdcMem = CreateCompatibleDC(hdc); - HANDLE hOld = SelectObject(hdcMem, hBmp); - - CreateSmileyBitmap(hdcMem); - - if (m_AniPack) m_AniPack->Draw(hdcMem); - - BitBlt(hdc, 0, 0, m_BitmapWidth.cx, m_WindowSizeY, hdcMem, 0, 0, SRCCOPY); - - SelectObject(hdcMem, hOld); - DeleteObject(hBmp); - DeleteDC(hdcMem); - - if (m_CurrentHotTrack == -2) m_CurrentHotTrack = -1; - - EndPaint(m_hwndDialog, &ps); -} - - -void SmileyToolWindowType::CreateSmileyWinDim(void) -{ - m_NumberOfButtons = m_pSmileyPack->VisibleSmileyCount(); - - if (m_NumberOfButtons == 0) return; - - // Find largest smiley - if (m_pSmileyPack->selec.x == 0 || m_pSmileyPack->selec.y == 0) - { - if (opt.ScaleAllSmileys) - { - m_pSmileyPack->GetSmiley(0)->GetSize(m_ButtonSize); - ++m_ButtonSize.cx; ++m_ButtonSize.cy; - } - else - { - m_ButtonSize.cx = 0; - m_ButtonSize.cy = 0; - SmileyPackType::SmileyVectorType &sml = m_pSmileyPack->GetSmileyList(); - for (unsigned i=0; iselec; - } - - if (m_pSmileyPack->win.x == 0 || m_pSmileyPack->win.y == 0) - { - if (opt.IEViewStyle) - { - // All integer square root - unsigned i; - for (i=1; i*iwin.x; - m_NumberOfVerticalButtons = m_NumberOfButtons / m_NumberOfHorizontalButtons + - (m_NumberOfButtons % m_NumberOfHorizontalButtons != 0); - } - - m_BitmapWidth.cx = m_NumberOfHorizontalButtons * (m_ButtonSize.cx + m_ButtonSpace) + m_ButtonSpace; - m_BitmapWidth.cy = m_NumberOfVerticalButtons * (m_ButtonSize.cy + m_ButtonSpace) + m_ButtonSpace; - - const int colsz = m_ButtonSize.cy + m_ButtonSpace; - int wndsz = min((int)m_BitmapWidth.cy, GetSystemMetrics(SM_CYSCREEN) / 2); - if (opt.IEViewStyle) wndsz = min(wndsz, 250); - - if (m_pSmileyPack->win.x != 0 && m_pSmileyPack->win.y != 0) - wndsz = min(wndsz, m_pSmileyPack->win.y * (m_ButtonSize.cy + (int)m_ButtonSpace) + (int)m_ButtonSpace); - - m_WindowSizeY = wndsz - (wndsz % colsz) + m_ButtonSpace; -} - - -void SmileyToolWindowType::CreateSmileyBitmap(HDC hdc) -{ - const RECT rc = { 0, 0, m_BitmapWidth.cx, m_WindowSizeY }; - - SetBkColor(hdc, opt.SelWndBkgClr); - const HBRUSH hBkgBrush = CreateSolidBrush(opt.SelWndBkgClr); - FillRect(hdc, &rc, hBkgBrush); - DeleteObject(hBkgBrush); - - if (opt.IEViewStyle) - { - HPEN hpen = CreatePen(PS_DOT, 1, 0); - HGDIOBJ hOldPen = SelectObject(hdc, hpen); - - POINT pts[2] = { {0, 0}, {m_BitmapWidth.cx, 0} }; - - for (unsigned i=0; i<=m_NumberOfVerticalButtons; i++) - { - pts[0].y = pts[1].y = i * (m_ButtonSize.cy + m_ButtonSpace); - if (pts[0].y > m_WindowSizeY) break; - Polyline(hdc, pts, 2); - } - - pts[0].y = 0; pts[1].y = m_BitmapWidth.cy; - for (unsigned j=0; j<=m_NumberOfHorizontalButtons; j++) - { - pts[0].x = pts[1].x = j * (m_ButtonSize.cx + m_ButtonSpace); - Polyline(hdc, pts, 2); - } - - SelectObject(hdc, hOldPen); - DeleteObject(hpen); - } -} - - -RECT SmileyToolWindowType::CalculateButtonToCoordinates(int buttonPosition, int scroll) -{ - int row, rowpos; - - if (opt.IEViewStyle) - { - row = buttonPosition / m_NumberOfHorizontalButtons; - rowpos = buttonPosition % m_NumberOfHorizontalButtons; - } - else - { - row = buttonPosition % m_NumberOfVerticalButtons; - rowpos = buttonPosition / m_NumberOfVerticalButtons; - } - - RECT pt; - pt.left = rowpos * (m_ButtonSize.cx + m_ButtonSpace) + m_ButtonSpace; - pt.top = (row - scroll) * (m_ButtonSize.cy + m_ButtonSpace) + m_ButtonSpace; - pt.right = pt.left + m_ButtonSize.cx; - pt.bottom = pt.top + m_ButtonSize.cy; - - return pt; -} - - -int SmileyToolWindowType::CalculateCoordinatesToButton(POINT pt, int scroll) -{ - const int rowpos = (pt.x - m_ButtonSpace) / (m_ButtonSize.cx + m_ButtonSpace); - const int row = (pt.y - m_ButtonSpace) / (m_ButtonSize.cy + m_ButtonSpace) + scroll; - - int pos; - if (opt.IEViewStyle) - pos = m_NumberOfHorizontalButtons * row + rowpos; - else - pos = m_NumberOfVerticalButtons * rowpos + row; - - if (pos >= (int)m_NumberOfButtons) pos = -1; - - return pos; -} - -void __cdecl SmileyToolThread(void *arg) -{ - SmileyToolWindowParam* stwp = (SmileyToolWindowParam*)arg; - if (stwp->pSmileyPack && stwp->pSmileyPack->VisibleSmileyCount()) - { - WNDCLASSEX wndclass; - wndclass.cbSize = sizeof(wndclass); - wndclass.style = CS_SAVEBITS; - wndclass.lpfnWndProc = DlgProcSmileyToolWindow; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 4; - wndclass.hInstance = g_hInst; - wndclass.hIcon = NULL; - wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); - wndclass.hbrBackground = CreateSolidBrush(opt.SelWndBkgClr); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = _T("SmileyTool"); - wndclass.hIconSm = NULL; - RegisterClassEx(&wndclass); - - CreateWindowEx(WS_EX_TOPMOST | WS_EX_NOPARENTNOTIFY, _T("SmileyTool"), NULL, - WS_BORDER | WS_POPUP | WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - ((SmileyToolWindowParam*)arg)->hWndParent, NULL, g_hInst, arg); - - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); - - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - UnregisterClass(_T("SmileyTool"), g_hInst); - } - delete stwp; -} diff --git a/plugins/SmileyAdd/smltool.h b/plugins/SmileyAdd/smltool.h deleted file mode 100644 index 89fb786862..0000000000 --- a/plugins/SmileyAdd/smltool.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -Miranda SmileyAdd Plugin -Copyright (C) 2005 - 2011 Boris Krasnovskiy -Copyright (C) 2003 - 2004 Rein-Peter de Boer - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef SMILEYADD_SMLTOOL_H_ -#define SMILEYADD_SMLTOOL_H_ - -class SmileyPackType; - -struct SmileyToolWindowParam -{ - SmileyPackType* pSmileyPack; - int xPosition; - int yPosition; - int direction; - HWND hWndTarget; - HWND hWndParent; - UINT targetMessage; - WPARAM targetWParam; - HANDLE hContact; -}; - - -void __cdecl SmileyToolThread(void *arg); - -#ifndef min -#define min(A, B) ((A) < (B) ? (A) : (B)) -#endif - -#endif // SMILEYADD_SMLTOOL_H_ diff --git a/plugins/SmileyAdd/src/AniSmileyObject.cpp b/plugins/SmileyAdd/src/AniSmileyObject.cpp new file mode 100644 index 0000000000..42a63d3549 --- /dev/null +++ b/plugins/SmileyAdd/src/AniSmileyObject.cpp @@ -0,0 +1,450 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "SmileyBase.h" +#include "m_smileyadd.h" +#include "smileys.h" +#include "options.h" + +#include + + +class CAniSmileyObject; + +static int CompareAniSmiley(const CAniSmileyObject* p1, const CAniSmileyObject* p2) +{ + return (int)((char*)p2 - (char*)p1); +} + +static LIST regAniSmileys(10, CompareAniSmiley); + +static UINT_PTR timerId; +static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD); + +static void CALLBACK sttMainThreadCallback( PVOID ) +{ + if (timerId == 0xffffffff) + timerId = SetTimer(NULL, 0, 100, (TIMERPROC)timerProc); +} + + +class CAniSmileyObject : public ISmileyBase +{ +private: + typedef enum { animStdOle, animDrctRichEd, animHpp } AnimType; + + POINTL m_rectOrig; + SIZEL m_rectExt; + + COLORREF m_bkg; + + SmileyType* m_sml; + ImageBase* m_img; + unsigned m_nFramePosition; + + long m_counter; + unsigned m_richFlags; + long m_lastObjNum; + + AnimType m_animtype; + bool m_allowAni; + +public: + CAniSmileyObject(SmileyType* sml, COLORREF clr, bool ishpp) + { + m_allowAni = false; + m_animtype = ishpp ? animHpp : animStdOle; + m_bkg = clr; + + m_rectOrig.x = 0; + m_rectOrig.y = 0; + m_rectExt.cx = 0; + m_rectExt.cy = 0; + + m_richFlags = 0; + m_lastObjNum = 0; + + m_sml = sml; + m_img = NULL; + m_nFramePosition = 0; + m_counter = 0; + } + + ~CAniSmileyObject(void) + { + UnloadSmiley(); + } + + void LoadSmiley(void) + { + if (m_img != NULL) return; + + m_img = m_sml->CreateCachedImage(); + if (m_img && m_img->IsAnimated() && opt.AnimateDlg) + { + m_nFramePosition = 0; + m_img->SelectFrame(m_nFramePosition); + long frtm = m_img->GetFrameDelay(); + m_counter = frtm / 10 + ((frtm % 10) >= 5); + + regAniSmileys.insert(this); + if (timerId == 0) + { + timerId = 0xffffffff; + CallFunctionAsync(sttMainThreadCallback, NULL); + } + } + else + m_nFramePosition = m_sml->GetStaticFrame(); + } + + void UnloadSmiley(void) + { + regAniSmileys.remove(this); + + if (timerId && (timerId+1) && regAniSmileys.getCount() == 0) + { + KillTimer(NULL, timerId); + timerId = 0; + } + if (m_img) m_img->Release(); + m_img = NULL; + } + + void GetDrawingProp(void) + { + if (m_hwnd == NULL) return; + + IRichEditOle* RichEditOle; + if (SendMessage(m_hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return; + + REOBJECT reObj = {0}; + reObj.cbStruct = sizeof(REOBJECT); + + HRESULT hr = RichEditOle->GetObject(m_lastObjNum, &reObj, REO_GETOBJ_NO_INTERFACES); + if (hr == S_OK && reObj.dwUser == (DWORD)(ISmileyBase*)this && reObj.clsid == CLSID_NULL) + { + m_richFlags = reObj.dwFlags; + } + else + { + long objectCount = RichEditOle->GetObjectCount(); + for (long i = objectCount; i--; ) + { + HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_NO_INTERFACES); + if (FAILED(hr)) continue; + + if (reObj.dwUser == (DWORD)(ISmileyBase*)this && reObj.clsid == CLSID_NULL) + { + m_lastObjNum = i; + m_richFlags = reObj.dwFlags; + break; + } + } + } + RichEditOle->Release(); + + if ((m_richFlags & REO_SELECTED) == 0) + { + CHARRANGE sel; + SendMessage(m_hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + if (reObj.cp >= sel.cpMin && reObj.cp < sel.cpMax) + m_richFlags |= REO_INVERTEDSELECT; + else + m_richFlags &= ~REO_INVERTEDSELECT; + } + } + + + void DoDirectDraw(HDC hdc) + { + HBITMAP hBmp = CreateCompatibleBitmap(hdc, m_rectExt.cx, m_rectExt.cy); + HDC hdcMem = CreateCompatibleDC(hdc); + HANDLE hOld = SelectObject(hdcMem, hBmp); + + RECT rc; + rc.left = m_rectExt.cx - m_sizeExtent.cx; + rc.top = m_rectExt.cy - m_sizeExtent.cy; + rc.right = rc.left + m_sizeExtent.cx; + rc.bottom = rc.top + m_sizeExtent.cy; + + HBRUSH hbr = CreateSolidBrush(m_bkg); + RECT frc = { 0, 0, m_rectExt.cx, m_rectExt.cy }; + FillRect(hdcMem, &frc, hbr); + DeleteObject(hbr); + + m_img->DrawInternal(hdcMem, rc.left, rc.top, m_sizeExtent.cx - 1, m_sizeExtent.cy - 1); + + if (m_richFlags & REO_SELECTED) + { + HBRUSH hbr = CreateSolidBrush(m_bkg ^ 0xFFFFFF); + FrameRect(hdcMem, &rc, hbr); + DeleteObject(hbr); + } + + if (m_richFlags & REO_INVERTEDSELECT) + InvertRect(hdcMem, &rc); + + BitBlt(hdc, m_rectOrig.x, m_rectOrig.y, m_rectExt.cx, m_rectExt.cy, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, hOld); + DeleteObject(hBmp); + DeleteDC(hdcMem); + } + + void DrawOnRichEdit(void) + { + HDC hdc = GetDC(m_hwnd); + if (RectVisible(hdc, &m_orect)) + { + RECT crct; + GetClientRect(m_hwnd, &crct); + + HRGN hrgnOld = CreateRectRgnIndirect(&crct); + int res = GetClipRgn(hdc, hrgnOld); + + HRGN hrgn = CreateRectRgnIndirect(&crct); + SelectClipRgn(hdc, hrgn); + DeleteObject(hrgn); + + DoDirectDraw(hdc); + + SelectClipRgn(hdc, res < 1 ? NULL : hrgnOld); + DeleteObject(hrgnOld); + } + else + { + m_visible = false; + m_allowAni = false; + UnloadSmiley(); + } + ReleaseDC(m_hwnd, hdc); + } + + void DrawOnHPP(void) + { + FVCNDATA_NMHDR nmh = {0}; + nmh.code = NM_FIREVIEWCHANGE; + nmh.hwndFrom = m_hwnd; + + nmh.cbSize = sizeof(nmh); + nmh.bEvent = FVCN_PREFIRE; + nmh.bAction = FVCA_DRAW; + nmh.rcRect = m_orect; + SendMessage(GetParent(m_hwnd), WM_NOTIFY, (WPARAM)m_hwnd, (LPARAM)&nmh); + + switch (nmh.bAction) + { + case FVCA_DRAW: + // support for pseudo-edit mode and event details + m_animtype = m_dirAniAllow ? animDrctRichEd : animStdOle; + GetDrawingProp(); + DrawOnRichEdit(); + break; + + case FVCA_CUSTOMDRAW: + m_rectExt.cy = nmh.rcRect.bottom - nmh.rcRect.top; + m_rectExt.cx = nmh.rcRect.right - nmh.rcRect.left; + m_rectOrig.x = nmh.rcRect.left; + m_rectOrig.y = nmh.rcRect.top; + + m_bkg = nmh.clrBackground; + + DoDirectDraw(nmh.hDC); + + nmh.bEvent = FVCN_POSTFIRE; + SendMessage(GetParent(m_hwnd), WM_NOTIFY, (WPARAM)m_hwnd, (LPARAM)&nmh); + break; + + case FVCA_SKIPDRAW: + break; + + case FVCA_NONE: + m_visible = false; + break; + + default: + break; + } + } + + void ProcessTimerTick(void) + { + if (m_visible && m_img && --m_counter <= 0) + { + m_nFramePosition = m_img->SelectNextFrame(m_nFramePosition); + long frtm = m_img->GetFrameDelay(); + m_counter = frtm / 10 + ((frtm % 10) >= 5); + + switch (m_animtype) + { + case animStdOle: + if (m_allowAni) SendOnViewChange(); + else + { + m_visible = false; + UnloadSmiley(); + } + m_allowAni = false; + break; + + case animDrctRichEd: + DrawOnRichEdit(); + break; + + case animHpp: + DrawOnHPP(); + break; + } + } + } + + void SetPosition(HWND hwnd, LPCRECT lpRect) + { + ISmileyBase::SetPosition(hwnd, lpRect); + + m_allowAni = m_visible; + + if (m_visible) LoadSmiley(); + else UnloadSmiley(); + + if (lpRect == NULL) return; + if (m_animtype == animStdOle) + { + m_animtype = animDrctRichEd; + GetDrawingProp(); + } + + if (lpRect->top == -1) + { + m_rectOrig.x = lpRect->left; + m_rectOrig.y = lpRect->bottom - m_sizeExtent.cy; + m_rectExt.cy = m_sizeExtent.cy; + } + else if (lpRect->bottom == -1) + { + m_rectOrig.x = lpRect->left; + m_rectOrig.y = lpRect->top; + } + else + { + m_rectOrig.x = lpRect->left; + m_rectOrig.y = lpRect->top; + m_rectExt.cy = lpRect->bottom - lpRect->top; + } + } + + STDMETHOD(Close)(DWORD dwSaveOption) + { + m_visible = false; + UnloadSmiley(); + + return ISmileyBase::Close(dwSaveOption); + } + + STDMETHOD(Draw)(DWORD dwAspect, LONG, void*, DVTARGETDEVICE*, HDC, + HDC hdc, LPCRECTL pRectBounds, LPCRECTL /* pRectWBounds */, + BOOL (__stdcall *)(ULONG_PTR), ULONG_PTR) + { + if (dwAspect != DVASPECT_CONTENT) return DV_E_DVASPECT; + if (pRectBounds == NULL) return E_INVALIDARG; + + LoadSmiley(); + + if (m_img == NULL) return E_FAIL; + + m_sizeExtent.cx = pRectBounds->right - pRectBounds->left; + m_sizeExtent.cy = pRectBounds->bottom - pRectBounds->top; + + m_rectExt = m_sizeExtent; + + switch (m_animtype) + { + case animDrctRichEd: + { + m_rectExt.cy = pRectBounds->bottom - m_rectOrig.y; + RECT frc = { 0, 0, m_sizeExtent.cx - 1, m_sizeExtent.cy - 1 }; + + HBITMAP hBmp = CreateCompatibleBitmap(hdc, frc.right, frc.bottom); + HDC hdcMem = CreateCompatibleDC(hdc); + HANDLE hOld = SelectObject(hdcMem, hBmp); + + HBRUSH hbr = CreateSolidBrush(m_bkg); + FillRect(hdcMem, &frc, hbr); + DeleteObject(hbr); + + m_img->DrawInternal(hdcMem, 0, 0, frc.right, frc.bottom); + + BitBlt(hdc, pRectBounds->left, pRectBounds->top, frc.right, frc.bottom, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, hOld); + DeleteObject(hBmp); + DeleteDC(hdcMem); + } + GetDrawingProp(); + break; + + case animHpp: + m_orect = *(LPRECT)pRectBounds; + + default: + m_img->DrawInternal(hdc, pRectBounds->left, pRectBounds->top, + m_sizeExtent.cx - 1, m_sizeExtent.cy - 1); + break; + } + + m_allowAni = true; + m_visible = true; + + return S_OK; + } + + STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL* psizel) + { + HRESULT hr = ISmileyBase::SetExtent(dwDrawAspect, psizel); + if (hr == S_OK) m_rectExt = m_sizeExtent; + return hr; + } +}; + +ISmileyBase* CreateAniSmileyObject(SmileyType* sml, COLORREF clr, bool ishpp) +{ + if (!sml->IsValid()) return NULL; + + CAniSmileyObject *obj = new CAniSmileyObject(sml, clr, ishpp); + return obj; +} + +static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD) +{ + for (int i=0; iProcessTimerTick(); +} + +void DestroyAniSmileys(void) +{ + if (timerId && (timerId+1)) + { + KillTimer(NULL, timerId); + timerId = 0; + } + regAniSmileys.destroy(); +} + diff --git a/plugins/SmileyAdd/src/SmileyBase.cpp b/plugins/SmileyAdd/src/SmileyBase.cpp new file mode 100644 index 0000000000..28bd767153 --- /dev/null +++ b/plugins/SmileyAdd/src/SmileyBase.cpp @@ -0,0 +1,391 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "SmileyBase.h" + +#include + +static void HiMetricToPixel(const SIZEL * lpSizeInHiMetric, LPSIZEL lpSizeInPix) +{ + HDC hDCScreen = GetDC(NULL); + const int nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX); + const int nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY); + ReleaseDC(NULL, hDCScreen); + + lpSizeInPix->cx = (lpSizeInHiMetric->cx * nPixelsPerInchX + (2540/2)) / 2540; + lpSizeInPix->cy = (lpSizeInHiMetric->cy * nPixelsPerInchY + (2540/2)) / 2540; +} + +static int CompareISmileyBase(const ISmileyBase* p1, const ISmileyBase* p2) +{ + return (int)((char*)p2 - (char*)p1); +} + +static LIST regSmileys(10, CompareISmileyBase); + +// {105C56DF-6455-4705-A501-51F1CCFCF688} +const GUID IID_ISmileyAddSmiley = +{ 0x105c56df, 0x6455, 0x4705, { 0xa5, 0x1, 0x51, 0xf1, 0xcc, 0xfc, 0xf6, 0x88 } }; + +// {58B32D03-1BD2-4840-992E-9AE799FD4ADE} +const GUID IID_ITooltipData = +{ 0x58b32d03, 0x1bd2, 0x4840, { 0x99, 0x2e, 0x9a, 0xe7, 0x99, 0xfd, 0x4a, 0xde } }; + +ISmileyBase::ISmileyBase(void) +{ + m_spAdviseSink = NULL; + m_spClientSite = NULL; + m_spAdviseHolder = NULL; + m_lRefCount = 1; + m_advf = 0; + m_smltxt = NULL; + m_hwnd = NULL; + m_visible = false; + m_dirAniAllow = false; + + memset(&m_sizeExtent, 0, sizeof(m_sizeExtent)); + memset(&m_sizeExtentHiM, 0, sizeof(m_sizeExtentHiM)); + memset(&m_orect, 0, sizeof(m_orect)); + + regSmileys.insert(this); +} + +ISmileyBase::~ISmileyBase(void) +{ + free(m_smltxt); + + Close(OLECLOSE_NOSAVE); + + if (m_spClientSite) + { + m_spClientSite->Release(); + m_spClientSite = NULL; + } + if (m_spAdviseHolder) + { + m_spAdviseHolder->Release(); + m_spAdviseHolder = NULL; + } +} + +void ISmileyBase::OnClose(void) +{ + if (m_spAdviseHolder) m_spAdviseHolder->SendOnClose(); +} + +void ISmileyBase::SendOnViewChange(void) +{ + if (m_spAdviseSink) m_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1); + if (m_advf & ADVF_ONLYONCE) + { + m_spAdviseSink->Release(); + m_spAdviseSink = NULL; + m_advf = 0; + } +} + +bool ISmileyBase::QueryHitPointSpecial(int x, int y, HWND hwnd, TCHAR** smltxt) +{ + bool result = m_visible && m_hwnd == hwnd; + if (result) + { + result = x >= m_orect.left && x <= m_orect.right && + y >= m_orect.top && y <= m_orect.bottom; + } + if (result) *smltxt = m_smltxt; + return result; +} + +void ISmileyBase::SetHint(TCHAR* smltxt) +{ + m_smltxt = _tcsdup(smltxt); +} + + +void ISmileyBase::SetPosition(HWND hwnd, LPCRECT lpRect) +{ + m_hwnd = hwnd; + if (lpRect == NULL || (lpRect->top == -1 && lpRect->bottom == -1)) + { + m_visible = false; + } + else + { + m_visible = true; + m_dirAniAllow = true; + m_orect.left = lpRect->left; + m_orect.right = lpRect->left + m_sizeExtent.cx; + if (lpRect->top == -1) + { + m_orect.top = lpRect->bottom - m_sizeExtent.cy; + m_orect.bottom = lpRect->bottom; + } + else if (lpRect->bottom == -1) + { + m_orect.top = lpRect->top; + m_orect.bottom = lpRect->top + m_sizeExtent.cy;; + } + else + { + m_orect.top = lpRect->bottom - m_sizeExtent.cy; + m_orect.bottom = lpRect->bottom; + } + } +} + + +// +// IUnknown members +// +ULONG ISmileyBase::AddRef(void) +{ return InterlockedIncrement(&m_lRefCount); } + +ULONG ISmileyBase::Release(void) +{ + LONG count = InterlockedDecrement(&m_lRefCount); + if(count == 0) + delete this; + return count; +} + + +HRESULT ISmileyBase::QueryInterface(REFIID iid, void ** ppvObject) +{ + // check to see what interface has been requested + if (ppvObject == NULL) return E_POINTER; + if (iid == IID_ISmileyAddSmiley) + *ppvObject = this; + else if (iid == IID_ITooltipData) + *ppvObject = static_cast(this); + else if (iid == IID_IViewObject) + *ppvObject = static_cast(this); + else if (iid == IID_IOleObject) + *ppvObject = static_cast(this); + else if (iid == IID_IUnknown) + *ppvObject = this; + else if (iid == IID_IViewObject2) + *ppvObject = static_cast(this); + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + AddRef(); + return S_OK; +} + +// +// IOleObject members +// +HRESULT ISmileyBase::SetClientSite(IOleClientSite *pClientSite) +{ + if (m_spClientSite != NULL) m_spClientSite->Release(); + m_spClientSite = pClientSite; + if (m_spClientSite != NULL) m_spClientSite->AddRef(); + return S_OK; +} + +HRESULT ISmileyBase::GetClientSite(IOleClientSite **ppClientSite) +{ + if (ppClientSite == NULL) return E_POINTER; + *ppClientSite = m_spClientSite; + if (m_spClientSite != NULL) m_spClientSite->AddRef(); + return S_OK; +} + +HRESULT ISmileyBase::SetHostNames(LPCOLESTR /* szContainerApp */, LPCOLESTR /* szContainerObj */) +{ return S_OK; } + +HRESULT ISmileyBase::Close(DWORD /* dwSaveOption */) +{ + regSmileys.remove(this); + + if (m_spAdviseSink) m_spAdviseSink->Release(); + m_spAdviseSink = NULL; + + return S_OK; +} + +HRESULT ISmileyBase::SetMoniker(DWORD /* dwWhichMoniker */, IMoniker* /* pmk */) +{ return E_NOTIMPL; } + +HRESULT ISmileyBase::GetMoniker(DWORD /* dwAssign */, DWORD /* dwWhichMoniker */, IMoniker** /* ppmk */) +{ return E_NOTIMPL; } + +HRESULT ISmileyBase::InitFromData(IDataObject* /* pDataObject */, BOOL /* fCreation */, DWORD /* dwReserved */) +{ return E_NOTIMPL; } + +HRESULT ISmileyBase::GetClipboardData(DWORD /* dwReserved */, IDataObject** /* ppDataObject */) +{ return E_NOTIMPL; } + +HRESULT ISmileyBase::DoVerb(LONG /* iVerb */, LPMSG /* pMsg */, IOleClientSite* /* pActiveSite */, LONG /* lindex */, + HWND /* hwndParent */, LPCRECT /* lprcPosRect */) +{ + return E_NOTIMPL; +} + +HRESULT ISmileyBase::EnumVerbs(IEnumOLEVERB** /*ppEnumOleVerb*/) { return E_NOTIMPL; } +HRESULT ISmileyBase::Update(void) { return S_OK; } +HRESULT ISmileyBase::IsUpToDate(void) { return S_OK; } + +HRESULT ISmileyBase::GetUserClassID(CLSID *pClsid) +{ + if (!pClsid) return E_POINTER; + *pClsid = CLSID_NULL; + return S_OK; +} + +HRESULT ISmileyBase::GetUserType(DWORD /*dwFormOfType*/, LPOLESTR* /*pszUserType*/) +{ return E_NOTIMPL; } + +HRESULT ISmileyBase::SetExtent(DWORD dwDrawAspect, SIZEL* psizel) +{ + if (dwDrawAspect != DVASPECT_CONTENT) return E_FAIL; + if (psizel == NULL) return E_POINTER; + + HiMetricToPixel(psizel, &m_sizeExtent); + m_sizeExtentHiM = *psizel; + return S_OK; +} + +HRESULT ISmileyBase::GetExtent(DWORD dwDrawAspect, SIZEL *psizel) +{ + if (dwDrawAspect != DVASPECT_CONTENT) return E_FAIL; + if (psizel == NULL) return E_POINTER; + + *psizel = m_sizeExtentHiM; + return S_OK; +} + +HRESULT ISmileyBase::Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection) +{ + HRESULT hr = S_OK; + if (m_spAdviseHolder == NULL) + hr = CreateOleAdviseHolder(&m_spAdviseHolder); + if (SUCCEEDED(hr)) + hr = m_spAdviseHolder->Advise(pAdvSink, pdwConnection); + else + m_spAdviseHolder = NULL; + return hr; +} + +HRESULT ISmileyBase::Unadvise(DWORD dwConnection) +{ + return m_spAdviseHolder ? m_spAdviseHolder->Unadvise(dwConnection) : E_FAIL; +} + +HRESULT ISmileyBase::EnumAdvise(IEnumSTATDATA **ppEnumAdvise) +{ + if (ppEnumAdvise == NULL) return E_POINTER; + return m_spAdviseHolder ? m_spAdviseHolder->EnumAdvise(ppEnumAdvise) : E_FAIL; +} + +HRESULT ISmileyBase::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus) +{ + if (pdwStatus == NULL) return E_POINTER; + if (dwAspect == DVASPECT_CONTENT) + { + *pdwStatus = OLEMISC_STATIC | OLEMISC_INVISIBLEATRUNTIME | + OLEMISC_CANTLINKINSIDE | OLEMISC_NOUIACTIVATE; + return S_OK; + } + else + { + *pdwStatus = 0; + return E_FAIL; + } +} + +HRESULT ISmileyBase::SetColorScheme(LOGPALETTE* /* pLogpal */) +{ return E_NOTIMPL; } + +// +// IViewObject members +// +HRESULT ISmileyBase::SetAdvise(DWORD aspect, DWORD advf, IAdviseSink* pAdvSink) +{ + if (aspect != DVASPECT_CONTENT) return DV_E_DVASPECT; + m_advf = advf; + if (m_spAdviseSink) m_spAdviseSink->Release(); + m_spAdviseSink = pAdvSink; + if (advf & ADVF_PRIMEFIRST) SendOnViewChange(); + return S_OK; +} +HRESULT ISmileyBase::GetAdvise(DWORD* /*pAspects*/, DWORD* /*pAdvf*/, IAdviseSink** ppAdvSink) +{ + if (!ppAdvSink) return E_POINTER; + *ppAdvSink = m_spAdviseSink; + if (m_spAdviseSink) m_spAdviseSink->AddRef(); + return S_OK; +} +HRESULT ISmileyBase::Freeze(DWORD, long, void*, DWORD*) { return E_NOTIMPL; } +HRESULT ISmileyBase::Unfreeze(DWORD) { return E_NOTIMPL; } +HRESULT ISmileyBase::GetColorSet(DWORD, long, void*, DVTARGETDEVICE*, HDC, + LOGPALETTE**) { return E_NOTIMPL; } + +// +// IViewObject2 members +// +HRESULT ISmileyBase::GetExtent(DWORD aspect, long, DVTARGETDEVICE*, SIZEL* pSize) +{ + if (pSize == NULL) return E_POINTER; + if (aspect != DVASPECT_CONTENT) return DV_E_DVASPECT; + *pSize = m_sizeExtent; + return S_OK; +} + + +// +// ITooltipData members +// +HRESULT ISmileyBase::SetTooltip(BSTR /* bstrHint */) +{ + return S_OK; +} + +HRESULT ISmileyBase::GetTooltip(BSTR *bstrHint) +{ + if (bstrHint == NULL) return E_POINTER; + *bstrHint = SysAllocString(T2W_SM(m_smltxt)); + return S_OK; +} + + +void CloseSmileys(void) +{ + for (int i=regSmileys.getCount(); i--;) + { + regSmileys[i]->OnClose(); + regSmileys[i]->Close(OLECLOSE_NOSAVE); + } +} + +int CheckForTip(int x, int y, HWND hwnd, TCHAR** smltxt) +{ + for (int i=0; iQueryHitPointSpecial(x, y, hwnd, smltxt)) return i; + + return -1; +} + +void DestroySmileyBase(void) +{ + regSmileys.destroy(); +} + diff --git a/plugins/SmileyAdd/src/SmileyBase.h b/plugins/SmileyAdd/src/SmileyBase.h new file mode 100644 index 0000000000..3cdf244007 --- /dev/null +++ b/plugins/SmileyAdd/src/SmileyBase.h @@ -0,0 +1,127 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#pragma once +#include +#include + +#define OLEIVERB_SETOWNER (-24) + +EXTERN_C const IID IID_ITooltipData; + +class ITooltipData : public IUnknown +{ +public: + STDMETHOD(SetTooltip) (BSTR bstrHint) PURE; + STDMETHOD(GetTooltip) (BSTR * bstrHint) PURE; +}; + + +EXTERN_C const IID IID_ISmileyAddSmiley; + +class ISmileyBase : + public IOleObject, public IViewObject2, public ITooltipData +{ +protected: + IOleAdviseHolder* m_spAdviseHolder; + IAdviseSink* m_spAdviseSink; + IOleClientSite* m_spClientSite; + DWORD m_advf; + LONG m_lRefCount; + + SIZEL m_sizeExtent; + SIZEL m_sizeExtentHiM; + RECT m_orect; + + TCHAR* m_smltxt; + HWND m_hwnd; + + bool m_visible; + bool m_dirAniAllow; + +public: + ISmileyBase(void); + virtual ~ISmileyBase(void); + + void OnClose(void); + void SendOnViewChange(void); + + bool QueryHitPointSpecial(int x, int y, HWND hwnd, TCHAR** smltxt); + void SetHint(TCHAR* smltxt); + + virtual void SetPosition(HWND hwnd, LPCRECT lpRect); + + // + // IUnknown members + // + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + + // + // IOleObject members + // + STDMETHOD(SetClientSite)(IOleClientSite *pClientSite); + STDMETHOD(GetClientSite)(IOleClientSite **ppClientSite); + STDMETHOD(SetHostNames)(LPCOLESTR /* szContainerApp */, LPCOLESTR /* szContainerObj */); + STDMETHOD(Close)(DWORD /* dwSaveOption */); + STDMETHOD(SetMoniker)(DWORD /* dwWhichMoniker */, IMoniker* /* pmk */); + STDMETHOD(GetMoniker)(DWORD /* dwAssign */, DWORD /* dwWhichMoniker */, IMoniker** /* ppmk */); + STDMETHOD(InitFromData)(IDataObject* /* pDataObject */, BOOL /* fCreation */, DWORD /* dwReserved */); + STDMETHOD(GetClipboardData)(DWORD /* dwReserved */, IDataObject** /* ppDataObject */); + STDMETHOD(DoVerb)(LONG /*iVerb*/, LPMSG /* pMsg */, IOleClientSite* /* pActiveSite */, LONG /* lindex */, + HWND /*hwndParent*/, LPCRECT /*lprcPosRect*/); + STDMETHOD(EnumVerbs)(IEnumOLEVERB** /*ppEnumOleVerb*/); + STDMETHOD(Update)(void); + STDMETHOD(IsUpToDate)(void); + STDMETHOD(GetUserClassID)(CLSID *pClsid); + STDMETHOD(GetUserType)(DWORD /*dwFormOfType*/, LPOLESTR* /*pszUserType*/); + STDMETHOD(SetExtent)(DWORD /*dwDrawAspect*/, SIZEL* /*psizel*/); + STDMETHOD(GetExtent)(DWORD dwDrawAspect, SIZEL *psizel); + STDMETHOD(Advise)(IAdviseSink *pAdvSink, DWORD *pdwConnection); + STDMETHOD(Unadvise)(DWORD dwConnection); + STDMETHOD(EnumAdvise)(IEnumSTATDATA **ppEnumAdvise); + STDMETHOD(GetMiscStatus)(DWORD dwAspect, DWORD *pdwStatus); + STDMETHOD(SetColorScheme)(LOGPALETTE* /* pLogpal */); + + // + // IViewObject members + // + STDMETHOD(SetAdvise)(DWORD aspect, DWORD advf, IAdviseSink* pAdvSink); + STDMETHOD(GetAdvise)(DWORD* /*pAspects*/, DWORD* /*pAdvf*/, IAdviseSink** ppAdvSink); + STDMETHOD(Freeze)(DWORD, long, void*, DWORD*); + STDMETHOD(Unfreeze)(DWORD); + STDMETHOD(GetColorSet)(DWORD, long, void*, DVTARGETDEVICE*, HDC, + LOGPALETTE**); + + // + // IViewObject2 members + // + STDMETHOD(GetExtent)(DWORD aspect, long, DVTARGETDEVICE*, SIZEL* pSize); + + // + // ITooltipData members + // + STDMETHOD(SetTooltip)(BSTR bstrHint); + STDMETHOD(GetTooltip)(BSTR * bstrHint); + +}; + +int CheckForTip(int x, int y, HWND hwnd, TCHAR** smltxt); +void CloseSmileys(void); + diff --git a/plugins/SmileyAdd/src/anim.cpp b/plugins/SmileyAdd/src/anim.cpp new file mode 100644 index 0000000000..5352383821 --- /dev/null +++ b/plugins/SmileyAdd/src/anim.cpp @@ -0,0 +1,184 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2006 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "anim.h" + +#include + +Animate::Animate(SmileyType *sml, RECT& rect, HDC hdcMem, HBRUSH hbr, bool clip) + : m_sml(sml), m_img(NULL), + m_nFramePosition(0), m_sel(false), m_clip(clip), + m_offset(0), m_running(false), + m_hdcMem(hdcMem), m_hbr(hbr) +{ + m_cliprect = rect; +} + + +Animate::~Animate() +{ + if (m_img) m_img->Release(); +} + + +void Animate::StartAnimation(void) +{ + m_img = m_sml->CreateCachedImage(); + + if (m_img && m_img->IsAnimated()) + { + m_img->SelectFrame(m_nFramePosition); + long frtm = m_img->GetFrameDelay(); + m_counter = frtm / 10 + ((frtm % 10) >= 5); + } +} + + +void Animate::ProcessTimerTick(HWND hwnd) +{ + if (m_running && m_img->IsAnimated() && --m_counter <= 0) + { + m_nFramePosition = m_img->SelectNextFrame(m_nFramePosition); + + long frtm = m_img->GetFrameDelay(); + m_counter = frtm / 10 + ((frtm % 10) >= 5); + + HDC hdc = GetDC(hwnd); + DrawFrame(hdc); + ReleaseDC(hwnd, hdc); + } +} + + +void Animate::DrawFrame(HDC hdc) +{ + long width = m_cliprect.right - m_cliprect.left; + long height = m_cliprect.bottom - m_cliprect.top; + + RECT frc = { 0, 0, width, height }; + FillRect(m_hdcMem, &frc, m_hbr); + + m_img->Draw(m_hdcMem, frc, m_clip); + + BitBlt(hdc, m_cliprect.left, m_cliprect.top, width, height, m_hdcMem, 0, 0, SRCCOPY); + + if (m_sel) + DrawFocusRect(hdc, &m_cliprect); +} + + +void Animate::Draw(HDC hdc) +{ + if (m_running) + { + m_img->Draw(hdc, m_cliprect, m_clip); + + if (m_sel) + DrawFocusRect(hdc, &m_cliprect); + } +} + + +void Animate::SetOffset(int off, int wsize) +{ + const int dy = m_offset - off; + + m_cliprect.top += dy; + m_cliprect.bottom += dy; + + m_offset = off; + + m_running = m_cliprect.top >= 0 && m_cliprect.top < wsize; + if (m_running) + { + if (m_img == NULL) + { + StartAnimation(); + if (m_img == NULL) m_running = false; + } + } + else + { + if (m_img) m_img->Release(); + m_img = NULL; + } +} + + +void Animate::SetSel(int x, int y) +{ + m_sel = x >= m_cliprect.left && x < m_cliprect.right && + y >= m_cliprect.top && y < m_cliprect.bottom; +} + + +AnimatedPack::AnimatedPack(HWND hwnd, int wsize, SIZE& sel, COLORREF bkg) + : m_AniList(40), m_hwnd(hwnd), m_wsize(wsize) +{ + HDC hdc = GetDC(hwnd); + + m_hBmp = CreateCompatibleBitmap(hdc, sel.cx, sel.cy); + m_hdcMem = CreateCompatibleDC(hdc); + m_hOld = (HBITMAP)SelectObject(m_hdcMem, m_hBmp); + m_hbr = CreateSolidBrush(bkg); + + ReleaseDC(hwnd, hdc); +} + + +AnimatedPack::~AnimatedPack() +{ + DeleteObject(m_hbr); + SelectObject(m_hdcMem, m_hOld); + DeleteObject(m_hBmp); + DeleteDC(m_hdcMem); +} + + +void AnimatedPack::Add(SmileyType *sml, RECT rect, bool clip) +{ + m_AniList.insert(new Animate(sml, rect, m_hdcMem, m_hbr, clip)); +} + + +void AnimatedPack::Draw(HDC hdc) +{ + for (int i=0; i. +*/ + +#ifndef anim_h +#define anim_h + +#include "smileys.h" + +class Animate +{ +private: + + ImageBase *m_img; + SmileyType *m_sml; + + HDC m_hdcMem; + HBRUSH m_hbr; + + RECT m_cliprect; + + unsigned m_nFramePosition; + int m_offset; + int m_counter; + bool m_running; + bool m_sel; + bool m_clip; + + void DrawFrame(HDC hdc); + +public: + + Animate(SmileyType *sml, RECT &rect, HDC hdcMem, HBRUSH hbr, bool clip); + Animate(const Animate& an); + ~Animate(); + + void Draw(HDC hdc); + + void StartAnimation(void); + void SetOffset(int off, int wsize); + void SetSel(int x, int y); + + void ProcessTimerTick(HWND hwnd); +}; + +class AnimatedPack +{ +private: + OBJLIST m_AniList; + + HWND m_hwnd; + int m_wsize; + + HBRUSH m_hbr; + HBITMAP m_hBmp; + HDC m_hdcMem; + HBITMAP m_hOld; + + static unsigned CALLBACK AnimateThreadFunc ( void* arg ); + +public: + AnimatedPack(HWND hwnd, int wsize, SIZE& sel, COLORREF bkg); + ~AnimatedPack(); + + void Add(SmileyType *sml, RECT rect, bool clip); + void Draw(HDC hdc); + void SetOffset(int off); + void SetSel(RECT& rect); + + void ProcessTimerTick(HWND hwnd); +}; + +#endif diff --git a/plugins/SmileyAdd/src/bkstring.cpp b/plugins/SmileyAdd/src/bkstring.cpp new file mode 100644 index 0000000000..2973783abc --- /dev/null +++ b/plugins/SmileyAdd/src/bkstring.cpp @@ -0,0 +1,215 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef __GNUC__ +# ifdef _DEBUG +# define _CRTDBG_MAP_ALLOC +# include +# include +# else +# include +# endif +#endif + +#include +#include + +#include "bkstring.h" + + +bkstring::~bkstring() { if (sizeAlloced) free(buf); } + +void bkstring::reserve(size_type len) +{ + if (len >= sizeAlloced || sizeAlloced == 0) + { + if (sizeAlloced == 0) buf = NULL; + buf = (value_type*)realloc(buf, (len+1) * sizeof(value_type)); + if (sizeAlloced == 0) buf[0] = 0; + sizeAlloced = len+1; + } +} + +void bkstring::appendfmt(const value_type *fmt, ...) +{ + areserve(_tcslen(fmt)*2); + + va_list vararg; + va_start(vararg, fmt); + for (;;) + { + int len = _vsntprintf(buf + lenBuf, sizeAlloced - lenBuf - 1, fmt, vararg); + if (len < 0) + reserve(sizeAlloced + 256); + else + { + lenBuf += len; + buf[lenBuf] = 0; + break; + } + } + va_end(vararg); +} + +bkstring& bkstring::append(const value_type* _Ptr) +{ + size_type len = _tcslen(_Ptr); + areserve(len); + memcpy(buf+lenBuf, _Ptr, (len+1)*sizeof(value_type)); + lenBuf += len; + return *this; +} + +bkstring& bkstring::append(const value_type* _Ptr, size_type _Count) +{ + size_type len = min(_tcslen(_Ptr), _Count); + areserve(len); + memcpy(buf+lenBuf, _Ptr, len*sizeof(value_type)); + lenBuf += len; + buf[lenBuf] = 0; + return *this; +} + +bkstring& bkstring::append(const bkstring& _Str, size_type _Off, size_type _Count) +{ + size_type len = min(_Count, _Str.size() - _Off); + areserve(len); + memcpy(buf+lenBuf, _Str.c_str()+_Off, len*sizeof(value_type)); + lenBuf += len; + buf[lenBuf] = 0; + return *this; +} + +bkstring& bkstring::append(const bkstring& _Str) +{ + size_type len = _Str.size(); + areserve(len); + memcpy(buf+lenBuf, _Str.c_str(), len*sizeof(value_type)); + lenBuf += len; + buf[lenBuf] = 0; + return *this; +} + +bkstring& bkstring::append(size_type _Count, value_type _Ch) +{ + areserve(_Count); + for(size_type i=0; i<_Count; ++i) buf[lenBuf+i] = _Ch; + lenBuf += _Count; + buf[lenBuf] = 0; + return *this; +} + + +bkstring& bkstring::assign(const value_type* _Ptr, size_type _Count) +{ + if (_Count == 0 && sizeAlloced == 0) + { + buf = (TCHAR*)_T(""); + } + else + { + reserve(_Count); + memcpy(buf, _Ptr, _Count*sizeof(value_type)); + buf[_Count] = 0; + lenBuf = _Count; + } + return *this; +} + +bkstring& bkstring::assign(const bkstring& _Str, size_type _Off, size_type _Count) +{ + size_type len = min(_Count, _Str.size() - _Off); + if (len == 0 && sizeAlloced == 0) + { + buf = (TCHAR*)_T(""); + } + else + { + reserve(len); + memcpy(buf, _Str.c_str() + _Off, len*sizeof(value_type)); + lenBuf = len; + buf[len] = 0; + } + return *this; +} + +bkstring& bkstring::assign(size_type _Count, value_type _Ch) +{ + reserve(_Count); + for(size_type i=0; i<_Count; ++i) buf[i] = _Ch; + buf[_Count] = 0; + lenBuf = _Count; + return *this; +} + +bkstring::size_type bkstring::find(value_type _Ch, size_type _Off) const +{ + for (size_type i=_Off; i<=lenBuf; ++i) + if (buf[i] == _Ch) return i; + return (size_type)npos; +} + +bkstring::size_type bkstring::find(const value_type* _Ptr, size_type _Off) const +{ + if (_Off > lenBuf) return (size_type)npos; + + value_type* pstr = _tcsstr(buf+_Off, _Ptr); + return pstr ? pstr - buf : npos; +} + +bkstring::size_type bkstring::find_last_of(value_type _Ch, size_type _Off) const +{ + for (size_type i=(_Off == npos ? lenBuf : _Off); i--;) + if (buf[i] == _Ch) return i; + return (size_type)npos; +} + +bkstring& bkstring::insert(size_type _P0, const value_type* _Ptr, size_type _Count) +{ + size_type len = _tcslen(_Ptr); + if (_Count < len) len = _Count; + areserve(len); + value_type *p = buf + _P0; + memmove(p+len, p, (lenBuf-_P0+1)*sizeof(value_type)); + memcpy(p, _Ptr, _Count*sizeof(value_type)); + lenBuf += len; + return *this; +} + +bkstring& bkstring::insert(size_type _P0, size_type _Count, value_type _Ch) +{ + areserve(_Count); + value_type *p = buf + _P0; + memmove(p+_Count, p, (lenBuf-_P0+1)*sizeof(value_type)); + for(size_type i=0; i<_Count; ++i) p[i] = _Ch; + lenBuf += _Count; + return *this; +} + +bkstring& bkstring::erase(size_type _Pos, size_type _Count) +{ + if (_Pos < lenBuf) + { + const size_type len = min(lenBuf - _Pos, _Count); + value_type *p = buf + _Pos; + lenBuf -= len; + memmove(p, p+len, (lenBuf - _Pos)*sizeof(value_type)); + buf[lenBuf] = 0; + } + return *this; +} diff --git a/plugins/SmileyAdd/src/bkstring.h b/plugins/SmileyAdd/src/bkstring.h new file mode 100644 index 0000000000..eb164f74e2 --- /dev/null +++ b/plugins/SmileyAdd/src/bkstring.h @@ -0,0 +1,270 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#pragma once + +#include +#include + +#ifndef min +#define min(A, B) ((A) < (B) ? (A) : (B)) +#endif + +class bkstring +{ +public: + typedef size_t size_type; + typedef TCHAR value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + +#if defined(_MSC_VER) && (_MSC_VER <= 1200) + enum { npos = -1 }; +#else + static const size_type npos = size_type(-1); +#endif + +private: + value_type* buf; + size_type sizeAlloced; + size_type lenBuf; + + void areserve(size_type len) { reserve(lenBuf + len); } + +public: + + explicit bkstring() : buf((TCHAR*)_T("")), sizeAlloced(0), lenBuf(0) + {} + + bkstring(const value_type* _Ptr, size_type _Count) : sizeAlloced(0), lenBuf(0) + { assign(_Ptr, _Count); } + + bkstring(const value_type* _Ptr) : sizeAlloced(0), lenBuf(0) + { assign(_Ptr); } + + bkstring(size_type _Count, value_type _Ch) : sizeAlloced(0), lenBuf(0) + { assign(_Count, _Ch); } + + bkstring(const bkstring& _Str) : sizeAlloced(0), lenBuf(0) + { assign(_Str); } + + bkstring(const bkstring& _Str, size_type _Off, size_type _Count) : sizeAlloced(0), lenBuf(0) + { assign(_Str, _Off, _Count); } + + ~bkstring(); + + size_type size(void) const { return lenBuf; } + const value_type* c_str(void) const { return buf; } + + void clear(void) { if (lenBuf) { lenBuf = 0; buf[0] = 0; } } + void insert(const value_type *txt); + void reserve(size_type len); + + bkstring& assign(const value_type* _Ptr) + { return assign(_Ptr, _tcslen(_Ptr)); } + + bkstring& assign(const bkstring& _Str) + { return assign(_Str, 0, (size_type)npos); } + + bkstring& assign(const value_type* _Ptr, size_type _Count); + bkstring& assign(const bkstring& _Str, size_type off, size_type _Count); + bkstring& assign(size_type _Count, value_type _Ch); + + bkstring& append(const value_type* _Ptr); + bkstring& append(const value_type* _Ptr, size_type _Count); + bkstring& append(const bkstring& _Str, size_type _Off, size_type _Count); + bkstring& append(const bkstring& _Str); + bkstring& append(size_type _Count, value_type _Ch); + + int compare(const bkstring& _Str) const + { return _tcscmp(buf, _Str.c_str()); } + + int compare(size_type _Pos1, size_type _Num1, const bkstring& _Str) const + { return _tcsncmp(&buf[_Pos1], _Str.c_str(), _Num1); } + + int compare(size_type _Pos1, size_type _Num1, const bkstring& _Str, size_type _Off, size_type _Count) const + { return _tcsncmp(&buf[_Pos1], _Str.c_str()+_Off, min(_Num1, _Count)); } + + int compare(const value_type* _Ptr) const + { return _tcscmp(buf, _Ptr); } + + int compare(size_type _Pos1, size_type _Num1, const value_type* _Ptr) const + { return _tcsncmp(&buf[_Pos1], _Ptr, _Num1); } + + int compare(size_type _Pos1, size_type _Num1, const value_type* _Ptr, size_type _Num2) const + { return _tcsncmp(&buf[_Pos1], _Ptr, min(_Num1, _Num2)); } + + int comparei(const bkstring& _Str) const + { return _tcsicmp(buf, _Str.c_str()); } + + int comparei(size_type _Pos1, size_type _Num1, const bkstring& _Str) const + { return _tcsnicmp(&buf[_Pos1], _Str.c_str(), _Num1); } + + int comparei(size_type _Pos1, size_type _Num1, const bkstring& _Str, size_type _Off, size_type _Count) const + { return _tcsnicmp(&buf[_Pos1], _Str.c_str()+_Off, min(_Num1, _Count)); } + + int comparei(const value_type* _Ptr) const + { return _tcsicmp(buf, _Ptr); } + + int comparei(size_type _Pos1, size_type _Num1, const value_type* _Ptr) const + { return _tcsnicmp(&buf[_Pos1], _Ptr, _Num1); } + + int comparei(size_type _Pos1, size_type _Num1, const value_type* _Ptr, size_type _Num2) const + { return _tcsnicmp(&buf[_Pos1], _Ptr, min(_Num1, _Num2)); } + + bool empty(void) const { return lenBuf == 0; }; + bkstring& erase(size_type _Pos = 0, size_type _Count = npos); + + size_type find(value_type _Ch, size_type _Off = 0) const; + size_type find(const value_type* _Ptr, size_type _Off = 0) const; + size_type find(bkstring& _Str, size_type _Off = 0) const + { return find(_Str.c_str(), _Off); } + + size_type find_last_of(value_type _Ch, size_type _Off = npos) const; + + bkstring& insert(size_type _P0, const value_type* _Ptr) + { return insert(_P0, _Ptr, _tcslen(_Ptr)); } + + bkstring& insert(size_type _P0, const bkstring& _Str) + { return insert(_P0, _Str.c_str(), _Str.size()); }; + + bkstring& insert(size_type _P0, const value_type* _Ptr, size_type _Count); + bkstring& insert(size_type _P0, size_type _Count, value_type _Ch); + + bkstring substr(size_type _Off = 0, size_type _Count = npos) const + { return bkstring(*this, _Off, _Count); } + + bkstring& operator = (const bkstring& _Str) + { return assign(_Str); } + + bkstring& operator =(const value_type* _Ptr) + { return assign(_Ptr); } + + bkstring& operator = (const value_type _Ch) + { return assign(1, _Ch); } + + bkstring& operator +=(const bkstring& _Str) + { return append(_Str); } + + bkstring& operator += (const value_type* _Ptr) + { return append(_Ptr); } + + bkstring& operator += (const value_type _Ch) + { return append(1, _Ch); } + + value_type& operator[] (int ind) const + { return buf[ind]; } + + friend bkstring operator+ (const bkstring& _Str1, const bkstring& _Str2) + { bkstring s(_Str1); return s.append(_Str2); } + + friend bkstring operator+ (const bkstring& _Str1, const value_type* _Ptr2) + { bkstring s(_Str1); return s.append(_Ptr2); } + + friend bkstring operator+(const value_type* _Ptr1, const bkstring& _Str2) + { bkstring s(_Ptr1); return s.append(_Str2); } + + friend bkstring operator+ (const bkstring& _Str1, const value_type _Ch) + { bkstring s(_Str1); return s.append(1, _Ch); } + + friend bool operator==(const bkstring& _Str1, const bkstring& _Str2) + { return _Str1.compare(_Str2) == 0; } + + friend bool operator==(const bkstring& _Str1, const value_type* _Ptr2) + { return _Str1.compare(_Ptr2) == 0; } + + friend bool operator==(const value_type* _Ptr1, const bkstring& _Str2) + { return _Str2.compare(_Ptr1) == 0; } + + friend bool operator!=(const bkstring& _Str1, const bkstring& _Str2) + { return _Str1.compare(_Str2) != 0; } + + friend bool operator!=(const bkstring& _Str1, const value_type* _Ptr2) + { return _Str1.compare(_Ptr2) != 0; } + + friend bool operator!=(const value_type* _Ptr1, const bkstring& _Str2) + { return _Str2.compare(_Ptr1) != 0; } + + friend bool operator<(const bkstring& _Str1, const bkstring& _Str2) + { return _Str1.compare(_Str2) < 0; } + + friend bool operator<(const bkstring& _Str1, const value_type* _Ptr2) + { return _Str1.compare(_Ptr2) < 0; } + + friend bool operator<(const value_type* _Ptr1, const bkstring& _Str2) + { return _Str2.compare(_Ptr1) > 0; } + + friend bool operator>(const bkstring& _Str1, const bkstring& _Str2) + { return _Str1.compare(_Str2) > 0; } + + friend bool operator>(const bkstring& _Str1, const value_type* _Ptr2) + { return _Str1.compare(_Ptr2) > 0; } + + friend bool operator>(const value_type* _Ptr1, const bkstring& _Str2) + { return _Str2.compare(_Ptr1) < 0; } + + friend bool operator<=(const bkstring& _Str1, const bkstring& _Str2) + { return _Str1.compare(_Str2) <= 0; } + + friend bool operator<=(const bkstring& _Str1, const value_type* _Ptr2) + { return _Str1.compare(_Ptr2) <= 0; } + + friend bool operator<=(const value_type* _Ptr1, const bkstring& _Str2) + { return _Str2.compare(_Ptr1) >= 0; } + + friend bool operator>=(const bkstring& _Str1, const bkstring& _Str2) + { return _Str1.compare(_Str2) >= 0; } + + friend bool operator>=(const bkstring& _Str1, const value_type* _Ptr2) + { return _Str1.compare(_Ptr2) >= 0; } + + friend bool operator>=(const value_type* _Ptr1, const bkstring& _Str2) + { return _Str2.compare(_Ptr1) <= 0; } + + friend bool operator==(const value_type _Ch1, const bkstring& _Str2) + { return (_Str2.size() == 1) && (_Str2[0] == _Ch1); } + + friend bool operator==(const bkstring& _Str1, const value_type _Ch2) + { return (_Str1.size() == 1) && (_Str1[0] == _Ch2); } + + friend bool operator!=(const value_type _Ch1, const bkstring& _Str2) + { return (_Str2.size() != 1) || (_Str2[0] != _Ch1); } + + friend bool operator!=(const bkstring& _Str1, const value_type _Ch2) + { return (_Str1.size() != 1) || (_Str1[0] != _Ch2); } + + iterator begin(void) + { return buf; } + + const_iterator begin(void) const + { return buf; } + + iterator end(void) + { return buf + lenBuf; } + + const_iterator end(void) const + { return buf + lenBuf; } + + // Custom extentions + + void appendfmt(const value_type *fmt, ...); + + size_type sizebytes(void) const { return lenBuf * sizeof(value_type); } +}; + +//const bkstring::size_type bkstring::npos = -1; diff --git a/plugins/SmileyAdd/src/customsmiley.cpp b/plugins/SmileyAdd/src/customsmiley.cpp new file mode 100644 index 0000000000..f125f015db --- /dev/null +++ b/plugins/SmileyAdd/src/customsmiley.cpp @@ -0,0 +1,172 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "customsmiley.h" + +SmileyPackCListType g_SmileyPackCStore; + + +bool SmileyPackCListType::AddSmileyPack(HANDLE hContact, TCHAR* dir) +{ + bool res = true; + if (GetSmileyPack(hContact) == NULL) + { + SmileyPackCType *smileyPack = new SmileyPackCType; + + res = smileyPack->LoadSmileyDir(dir); + if (res) + { + smileyPack->SetId(hContact); + m_SmileyPacks.insert(smileyPack); + } + else + delete smileyPack; + } + return res; +} + + +bool SmileyPackCListType::AddSmiley(HANDLE hContact, TCHAR* path) +{ + SmileyPackCType* smpack = GetSmileyPack(hContact); + if (smpack == NULL) + { + smpack = new SmileyPackCType; + + smpack->SetId(hContact); + m_SmileyPacks.insert(smpack); + } + return smpack->LoadSmiley(path); +} + + +SmileyPackCType* SmileyPackCListType::GetSmileyPack(HANDLE id) +{ + for (int i = 0; i < m_SmileyPacks.getCount(); i++) + { + if (m_SmileyPacks[i].GetId() == id) return &m_SmileyPacks[i]; + } + return NULL; +} + + +SmileyCType::SmileyCType(const bkstring& fullpath, const TCHAR* filepath) +{ + LoadFromResource(fullpath, 0); + CreateTriggerText(T2A_SM(filepath)); +} + +bool SmileyCType::CreateTriggerText(char* text) +{ + UrlDecode(text); + + int len = (int)strlen(text); + if (len == 0) return false; + + int reslen = Netlib_GetBase64DecodedBufferSize(len)+1; + char* res = (char*)alloca(reslen); + + NETLIBBASE64 nlb = { text, len, ( PBYTE )res, reslen }; + if (!CallService(MS_NETLIB_BASE64DECODE, 0, LPARAM( &nlb ))) return false; + res[nlb.cbDecoded] = 0; + + TCHAR *txt = mir_utf8decodeT(res); + + if (txt == NULL) return false; + + m_TriggerText = txt; + mir_free(txt); + + return true; +} + + +// +// SmileyPackCType +// + +bool SmileyPackCType::LoadSmileyDir(TCHAR* dir) +{ + bkstring dirs = dir; + dirs += _T("\\*.*"); + + _tfinddata_t c_file; + INT_PTR hFile = _tfindfirst((TCHAR*)dirs.c_str(), &c_file); + if (hFile > -1L) + { + do { + if (c_file.name[0] != '.') + { + bkstring fullpath = dir; + fullpath = fullpath + _T("\\") + c_file.name; + TCHAR* div = _tcsrchr(c_file.name, '.'); + if (div) + { + *div = 0; + SmileyCType *smlc = new SmileyCType(fullpath, c_file.name); + if (smlc->GetTriggerText().empty()) + delete smlc; + else + m_SmileyList.insert(smlc); + } + } + } while( _tfindnext( hFile, &c_file ) == 0 ); + _findclose( hFile ); + AddTriggersToSmileyLookup(); + return true; + } + return false; +} + + +bool SmileyPackCType::LoadSmiley(TCHAR* path) +{ + bkstring dirs = path; + bkstring::size_type slash = dirs.find_last_of('\\'); + bkstring::size_type dot = dirs.find_last_of('.'); + + bkstring name = dirs.substr(slash+1, dot - slash - 1); + + for (int i=0; i < m_SmileyList.getCount(); i++) + { + if (m_SmileyList[i].GetTriggerText() == name) + { + m_SmileyList[i].LoadFromResource(dirs, 0); + return true; + } + } + + m_SmileyList.insert(new SmileyCType(dirs, (TCHAR*)name.c_str())); + + bkstring empty; + m_SmileyLookup.insert(new SmileyLookup( + m_SmileyList[m_SmileyList.getCount()-1].GetTriggerText(), false, m_SmileyList.getCount()-1, empty)); + + return true; +} + + +void SmileyPackCType::AddTriggersToSmileyLookup(void) +{ + bkstring empty; + for (int dist=0; dist. +*/ + +#include "general.h" +#include "smileys.h" + +#ifndef SMILEYADD_CUSTOMSMILEY_H_ +#define SMILEYADD_CUSTOMSMILEY_H_ + +class SmileyCType : public SmileyType +{ +public: + SmileyCType(const bkstring& fullpath, const TCHAR* filepath); + + bool CreateTriggerText(char* text); +}; + +class SmileyPackCType +{ +public: + typedef SMOBJLIST SmileyVectorType; + typedef SMOBJLIST SmileyLookupType; + +private: + SmileyVectorType m_SmileyList; + SmileyLookupType m_SmileyLookup; + + HANDLE m_id; + + void InsertLookup(SmileyCType& sml, bkstring& lk, bool first); + void AddTriggersToSmileyLookup(void); + +public: + SmileyVectorType& GetSmileyList(void) { return m_SmileyList; } + SmileyLookupType& GetSmileyLookup(void) { return m_SmileyLookup; } + + int SmileyCount(void) const { return m_SmileyList.getCount(); } + + SmileyCType* GetSmiley(unsigned index) { return &m_SmileyList[index]; } + + HANDLE GetId(void) { return m_id; } + void SetId(HANDLE id) { m_id = id; } + + bool LoadSmileyDir(TCHAR* dir); + bool LoadSmiley(TCHAR* path); +}; + + +class SmileyPackCListType +{ +public: + typedef SMOBJLIST SmileyPackVectorType; + +private: + SmileyPackVectorType m_SmileyPacks; + +public: + int NumberOfSmileyPacks(void) { return m_SmileyPacks.getCount(); } + + bool AddSmileyPack(HANDLE hContact, TCHAR* dir); + bool AddSmiley(HANDLE hContact, TCHAR* path); + + void ClearAndFreeAll(void) { m_SmileyPacks.destroy(); } + + SmileyPackCType* GetSmileyPack(HANDLE id); +}; + +extern SmileyPackCListType g_SmileyPackCStore; + +#endif diff --git a/plugins/SmileyAdd/src/dlgboxsubclass.cpp b/plugins/SmileyAdd/src/dlgboxsubclass.cpp new file mode 100644 index 0000000000..03a0a6e5fd --- /dev/null +++ b/plugins/SmileyAdd/src/dlgboxsubclass.cpp @@ -0,0 +1,568 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2012 Boris Krasnovskiy All Rights Reserved +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "smileyroutines.h" +#include "services.h" +#include "options.h" + +//***************************************************// +// DISCLAIMER!!! +// we are not supposed to use this object, so be aware +typedef struct NewMessageWindowLParam +{ + HANDLE hContact; + int isSend; + const char *szInitialText; +} +msgData; +// this is an undocumented object!!!!!!! +// subject to change in miranda versions...!!!!!! +// DISCLAIMER!!! +//***************************************************// + +extern HINSTANCE g_hInst; + +static HHOOK g_hMessageHookPre = NULL; +static HANDLE g_hMutex = NULL; +static HANDLE g_hHookMsgWnd = NULL; + +static LRESULT CALLBACK MessageDlgSubclas(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + +//type definitions +class MsgWndData +{ +public: + HWND hwnd; + char ProtocolName[52]; + HWND REdit; + HWND QuoteB; + HWND MEdit; + HWND MOK; + HWND LButton; + mutable HWND hSmlButton; + mutable HBITMAP hSmlBmp; + mutable HICON hSmlIco; + int idxLastChar; + WNDPROC wpOrigWndProc; + HANDLE hContact; + bool doSmileyReplace; + bool doSmileyButton; + bool OldButtonPlace; + bool isSplit; + bool isSend; + + MsgWndData() + { + ProtocolName[0] = 0; + REdit = NULL; + QuoteB = NULL; + MEdit = NULL; + MOK = NULL; + LButton = NULL; + hSmlButton = NULL; + hSmlBmp = NULL; + hSmlIco = NULL; + idxLastChar = 0; + hContact = NULL; + doSmileyReplace = false; + doSmileyButton = false; + OldButtonPlace = false; + isSplit = false; + isSend = false; + wpOrigWndProc = NULL; + } + + MsgWndData(const MsgWndData &dsb) + { + *this = dsb; + dsb.hSmlBmp = NULL; + dsb.hSmlIco = NULL; + dsb.hSmlButton = NULL; + } + + + ~MsgWndData() + { + clear(); + } + + void clear(void) + { + if (hSmlBmp != NULL) DeleteObject(hSmlBmp); + if (hSmlIco != NULL) DestroyIcon(hSmlIco); + if (hSmlButton != NULL) DestroyWindow(hSmlButton); + hSmlBmp = NULL; + hSmlIco = NULL; + hSmlButton = NULL; + } + + RECT CalcSmileyButtonPos(void) + { + RECT rect; + POINT pt; + + if (OldButtonPlace) + { + if (isSplit && DBGetContactSettingByte(NULL, "SRMsg", "ShowQuote", FALSE)) + { + GetWindowRect(QuoteB, &rect); + pt.x = rect.right + 12; + } + else + { + GetWindowRect(MEdit, &rect); + pt.x = rect.left; + } + GetWindowRect(MOK, &rect); + pt.y = rect.top; + } + else + { + GetWindowRect(LButton, &rect); + pt.y = rect.top; + + if ((GetWindowLongPtr(LButton, GWL_STYLE) & WS_VISIBLE) != 0) + pt.x = rect.left - 28; + else + pt.x = rect.left; + } + + ScreenToClient(GetParent(LButton), &pt); + rect.bottom += pt.y - rect.top; + rect.right += pt.x - rect.left; + rect.top = pt.y; + rect.left = pt.x; + + return rect; + } + + //helper function + //identifies the message dialog + bool IsMessageSendDialog(HWND hwnd) + { + TCHAR szClassName[32] = _T(""); + + GetClassName(hwnd, szClassName, SIZEOF(szClassName)); + if (_tcscmp(szClassName, _T("#32770"))) return false; + + if ((REdit = GetDlgItem(hwnd, MI_IDC_LOG)) != NULL) + { + GetClassName(REdit, szClassName, SIZEOF(szClassName)); + if (_tcscmp(szClassName, _T("RichEdit20A")) != 0 && + _tcscmp(szClassName, _T("RichEdit20W")) != 0 && + _tcscmp(szClassName, _T("RICHEDIT50W")) != 0) return false; + } + else return false; + + if ((MEdit = GetDlgItem(hwnd, MI_IDC_MESSAGE)) != NULL) + { + GetClassName(MEdit, szClassName, SIZEOF(szClassName)); + if (_tcscmp(szClassName, _T("Edit")) != 0 && + _tcscmp(szClassName, _T("RichEdit20A")) != 0 && + _tcscmp(szClassName, _T("RichEdit20W")) != 0 && + _tcscmp(szClassName, _T("RICHEDIT50W")) != 0) return false; + } + else return false; + + QuoteB = GetDlgItem(hwnd, MI_IDC_QUOTE); + + if ((LButton = GetDlgItem(hwnd, MI_IDC_ADD)) == NULL) + return false; + + if (GetDlgItem(hwnd, MI_IDC_NAME) == NULL) + return false; + if ((MOK = GetDlgItem(hwnd, IDOK)) == NULL) + return false; + + return true; + } + + void CreateSmileyButton(void) + { + doSmileyButton = opt.ButtonStatus != 0; + OldButtonPlace = opt.ButtonStatus == 2; + + SmileyPackType* SmileyPack = GetSmileyPack(ProtocolName, hContact); + doSmileyButton &= SmileyPack != NULL && SmileyPack->VisibleSmileyCount() != 0; + + bool showButtonLine; + if (IsOldSrmm()) + { + isSplit = DBGetContactSettingByte(NULL,"SRMsg","Split", TRUE) != 0; + + doSmileyReplace = (isSplit || !isSend); + doSmileyButton &= isSplit || isSend; + showButtonLine = DBGetContactSettingByte(NULL, "SRMsg", "ShowButtonLine", TRUE) != 0; + } + else + { + doSmileyReplace = true; + OldButtonPlace = false; + showButtonLine = DBGetContactSettingByte(NULL, "SRMM", "ShowButtonLine", TRUE) != 0; + } + + doSmileyButton &= OldButtonPlace || showButtonLine; + + if (ProtocolName[0] != 0) + { + INT_PTR cap = CallProtoService(ProtocolName, PS_GETCAPS, PFLAGNUM_1, 0); + doSmileyButton &= ((cap & (PF1_IMSEND | PF1_CHAT)) != 0); + doSmileyReplace &= ((cap & (PF1_IMRECV | PF1_CHAT)) != 0); + } + + if (doSmileyButton && opt.PluginSupportEnabled) + { + //create smiley button + RECT rect = CalcSmileyButtonPos(); + + hSmlButton = CreateWindowEx( + WS_EX_LEFT | WS_EX_NOPARENTNOTIFY | WS_EX_TOPMOST, + MIRANDABUTTONCLASS, + _T("S"), + WS_CHILD|WS_VISIBLE|WS_TABSTOP, // window style + rect.left, // horizontal position of window + rect.top, // vertical position of window + rect.bottom - rect.top + 1, // window width + rect.bottom - rect.top + 1, // window height + GetParent(LButton), // handle to parent or owner window + (HMENU) IDC_SMLBUTTON, // menu handle or child identifier + NULL, // handle to application instance + NULL); // window-creation data + + // Conversion to bitmap done to prevent Miranda from scaling the image + SmileyType* sml = FindButtonSmiley(SmileyPack); + if (sml != NULL) + { + hSmlBmp = sml->GetBitmap(GetSysColor(COLOR_BTNFACE), 0, 0); + SendMessage(hSmlButton, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hSmlBmp); + } + else + { + hSmlIco = GetDefaultIcon(); + SendMessage(hSmlButton, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hSmlIco); + } + + SendMessage(hSmlButton, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Show Smiley Selection Window"), 0); + SendMessage(hSmlButton, BUTTONSETASFLATBTN, TRUE, 0); + } + } +}; + +static int CompareMsgWndData(const MsgWndData* p1, const MsgWndData* p2) +{ + return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); +} +static LIST g_MsgWndList(10, CompareMsgWndData); + + +bool IsOldSrmm(void) +{ + return ServiceExists(MS_MSG_GETWINDOWCLASS) == 0; +} + + +int UpdateSrmmDlg(WPARAM wParam, LPARAM /* lParam */) +{ + WaitForSingleObject(g_hMutex, 2000); + for (int i=0; ihContact == (HANDLE)wParam) + { + SendMessage(g_MsgWndList[i]->hwnd, WM_SETREDRAW, FALSE, 0); + SendMessage(g_MsgWndList[i]->hwnd, DM_OPTIONSAPPLIED, 0, 0); + SendMessage(g_MsgWndList[i]->hwnd, WM_SETREDRAW, TRUE, 0); + } + } + ReleaseMutex(g_hMutex); + + return 0; +} + + +//find the dialog info in the stored list +static MsgWndData* IsMsgWnd(HWND hwnd) +{ + WaitForSingleObject(g_hMutex, 2000); + MsgWndData* res = g_MsgWndList.find((MsgWndData*)&hwnd); + ReleaseMutex(g_hMutex); + + return res; +} + + +static void MsgWndDetect(HWND hwndDlg, HANDLE hContact, msgData* datm) +{ + MsgWndData dat; + + if (dat.IsMessageSendDialog(hwndDlg)) + { + dat.hwnd = hwndDlg; + if (datm != NULL) + { + dat.isSend = datm->isSend != 0; + dat.hContact = datm->hContact; + } + else + dat.hContact = hContact; + + // Get the protocol for this contact to display correct smileys. + char *protonam = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, + (WPARAM)DecodeMetaContact(dat.hContact), 0); + + if (protonam) + { + strncpy(dat.ProtocolName, protonam, sizeof(dat.ProtocolName)); + dat.ProtocolName[sizeof(dat.ProtocolName)-1] = 0; + } + + WaitForSingleObject(g_hMutex, 2000); + + MsgWndData* msgwnd = g_MsgWndList.find((MsgWndData*)&hwndDlg); + if (msgwnd == NULL) + { + msgwnd = new MsgWndData(dat); + g_MsgWndList.insert(msgwnd); + } + else + msgwnd = NULL; + ReleaseMutex(g_hMutex); + + if (msgwnd != NULL) + { + msgwnd->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)MessageDlgSubclas); + msgwnd->CreateSmileyButton(); + if (hContact == NULL) SetRichCallback(msgwnd->REdit, msgwnd->hContact, true, true); + } + } +} + + +//global subclass function for all dialogs +static LRESULT CALLBACK MessageDlgSubclas(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + MsgWndData* dat = IsMsgWnd(hwnd); + if (dat == NULL) return 0; + + switch(uMsg) + { + case DM_OPTIONSAPPLIED: + dat->clear(); + dat->CreateSmileyButton(); + break; + + case DM_APPENDTOLOG: + if (opt.PluginSupportEnabled) + { + //get length of text now before things can get added... + GETTEXTLENGTHEX gtl; + gtl.codepage = 1200; + gtl.flags = GTL_PRECISE | GTL_NUMCHARS; + dat->idxLastChar = (int)SendMessage(dat->REdit, EM_GETTEXTLENGTHEX, (WPARAM) >l, 0); + } + break; + } + + LRESULT result = CallWindowProc(dat->wpOrigWndProc, hwnd, uMsg, wParam, lParam); + + if (!opt.PluginSupportEnabled) return result; + + switch(uMsg) + { + case WM_DESTROY: + WaitForSingleObject(g_hMutex, 2000); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)dat->wpOrigWndProc); + { + int ind = g_MsgWndList.getIndex((MsgWndData*)&hwnd); + if ( ind != -1 ) + { + delete g_MsgWndList[ind]; + g_MsgWndList.remove(ind); + } + } + ReleaseMutex(g_hMutex); + break; + + case WM_SIZE: + if (dat->doSmileyButton) + { + RECT rect = dat->CalcSmileyButtonPos(); + SetWindowPos(dat->hSmlButton, NULL, rect.left, rect.top, + 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + break; + + case DM_APPENDTOLOG: + if (dat->doSmileyReplace) + { + SmileyPackCType* smcp; + SmileyPackType* SmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact, &smcp); + if (SmileyPack != NULL) + { + const CHARRANGE sel = { dat->idxLastChar, LONG_MAX }; + ReplaceSmileys(dat->REdit, SmileyPack, smcp, sel, false, false, false); + } + } + break; + + case DM_REMAKELOG: + if (dat->doSmileyReplace) + { + SmileyPackCType* smcp; + SmileyPackType* SmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact, &smcp); + if (SmileyPack != NULL) + { + static const CHARRANGE sel = { 0, LONG_MAX }; + ReplaceSmileys(dat->REdit, SmileyPack, smcp, sel, false, false, false); + } + } + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDC_SMLBUTTON && + HIWORD(wParam) == BN_CLICKED) + { + SmileyToolWindowParam *stwp = new SmileyToolWindowParam; + stwp->pSmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact); + + stwp->hWndParent = hwnd; + stwp->hWndTarget = dat->MEdit; + stwp->targetMessage = EM_REPLACESEL; + stwp->targetWParam = TRUE; + + RECT rect; + GetWindowRect(dat->hSmlButton, &rect); + + if (dat->OldButtonPlace) + { + stwp->direction = 3; + stwp->xPosition = rect.left; + stwp->yPosition = rect.top + 4; + } + else + { + stwp->direction = 0; + stwp->xPosition = rect.left; + stwp->yPosition = rect.top + 24; + } + + mir_forkthread(SmileyToolThread, stwp); + } + + if (LOWORD(wParam) == MI_IDC_ADD && + HIWORD(wParam) == BN_CLICKED && + dat->doSmileyButton) + { + RECT rect = dat->CalcSmileyButtonPos(); + SetWindowPos(dat->hSmlButton, NULL, rect.left, rect.top, + 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + break; + } + + return result; +} + +static int MsgDlgHook(WPARAM, LPARAM lParam) +{ + const MessageWindowEventData *wndEvtData = (MessageWindowEventData*)lParam; + switch(wndEvtData->uType) + { + case MSG_WINDOW_EVT_OPENING: + MsgWndDetect(wndEvtData->hwndWindow, wndEvtData->hContact, NULL); + if (wndEvtData->cbSize >= sizeof(MessageWindowEventData)) + { + SetRichOwnerCallback(wndEvtData->hwndWindow, wndEvtData->hwndInput, wndEvtData->hwndLog); + + if (wndEvtData->hwndLog) + SetRichCallback(wndEvtData->hwndLog, wndEvtData->hContact, false, false); + if (wndEvtData->hwndInput) + SetRichCallback(wndEvtData->hwndInput, wndEvtData->hContact, false, false); + } + break; + + case MSG_WINDOW_EVT_OPEN: + if (wndEvtData->cbSize >= sizeof(MessageWindowEventData)) + { + SetRichOwnerCallback(wndEvtData->hwndWindow, wndEvtData->hwndInput, wndEvtData->hwndLog); + if (wndEvtData->hwndLog) + SetRichCallback(wndEvtData->hwndLog, wndEvtData->hContact, true, true); + if (wndEvtData->hwndInput) + { + SetRichCallback(wndEvtData->hwndInput, wndEvtData->hContact, true, true); + SendMessage(wndEvtData->hwndInput, WM_REMAKERICH, 0, 0); + } + } + break; + + case MSG_WINDOW_EVT_CLOSE: + if (wndEvtData->cbSize >= sizeof(MessageWindowEventData) && wndEvtData->hwndLog) + { + CloseRichCallback(wndEvtData->hwndLog, true); + CloseRichOwnerCallback(wndEvtData->hwndWindow, true); + } + break; + } + return 0; +} + + +//global subclass function for all dialogs +static LRESULT CALLBACK MsgDlgHookProcPre(int code, WPARAM wParam, LPARAM lParam) +{ + const CWPSTRUCT *msg = (CWPSTRUCT*)lParam; + + if (code == HC_ACTION && msg->message == WM_INITDIALOG) + MsgWndDetect(msg->hwnd, NULL, (msgData*)msg->lParam); + + return CallNextHookEx(g_hMessageHookPre, code, wParam, lParam); +} + + +void InstallDialogBoxHook(void) +{ + g_hMutex = CreateMutex(NULL, FALSE, NULL); + + g_hHookMsgWnd = HookEvent(ME_MSG_WINDOWEVENT, MsgDlgHook); + + // Hook message API + if (g_hHookMsgWnd == NULL) + g_hMessageHookPre = SetWindowsHookEx(WH_CALLWNDPROC, MsgDlgHookProcPre, + NULL, GetCurrentThreadId()); +} + + +void RemoveDialogBoxHook(void) +{ + if (g_hHookMsgWnd) UnhookEvent(g_hHookMsgWnd); + if (g_hMessageHookPre) UnhookWindowsHookEx(g_hMessageHookPre); + + WaitForSingleObject(g_hMutex, 2000); + for (int i=0; i. +*/ + +#include "general.h" +#include "m_smileyadd.h" +#include "m_folders.h" + +extern HANDLE hEvent1; +HANDLE hNetlibUser; +static HANDLE hFolder, hFolderHook; + +struct QueueElem +{ + bkstring url; + bkstring fname; + bool needext; + + QueueElem(bkstring& purl, bkstring& pfname, bool ne) + : url(purl), fname(pfname), needext(ne) {} +}; + +static HANDLE g_hDlMutex; +static OBJLIST dlQueue(10); + +static TCHAR cachepath[MAX_PATH]; +static bool threadRunning; + +bool InternetDownloadFile(const char *szUrl, char* szDest, HANDLE &hHttpDwnl) +{ + int result = 0xBADBAD; + char* szRedirUrl = NULL; + NETLIBHTTPREQUEST nlhr = {0}; + + // initialize the netlib request + nlhr.cbSize = sizeof(nlhr); + nlhr.requestType = REQUEST_GET; + nlhr.flags = NLHRF_NODUMP; + nlhr.szUrl = (char*)szUrl; + nlhr.nlc = hHttpDwnl; + + if (CallService(MS_SYSTEM_GETVERSION, 0, 0) >= PLUGIN_MAKE_VERSION(0,9,0,5)) + nlhr.flags |= NLHRF_HTTP11 | NLHRF_PERSISTENT | NLHRF_REDIRECT; + + // change the header so the plugin is pretended to be IE 6 + WinXP + nlhr.headersCount = 2; + nlhr.headers=(NETLIBHTTPHEADER*)alloca(sizeof(NETLIBHTTPHEADER)*nlhr.headersCount); + nlhr.headers[0].szName = "User-Agent"; + nlhr.headers[0].szValue = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; + nlhr.headers[1].szName = "Connection"; + nlhr.headers[1].szValue = "close"; + + while (result == 0xBADBAD) + { + // download the page + NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, + (WPARAM)hNetlibUser,(LPARAM)&nlhr); + + if (nlhrReply) + { + hHttpDwnl = nlhrReply->nlc; + // if the recieved code is 200 OK + if(nlhrReply->resultCode == 200) + { + char* delim = strrchr(szDest, '\\'); + if (delim) *delim = '\0'; + CallService(MS_UTILS_CREATEDIRTREE, 0, (LPARAM)szDest); + if (delim) *delim = '\\'; + int res = -1; + int fh = _open(szDest, _O_BINARY | _O_WRONLY | _O_CREAT, _S_IREAD | _S_IWRITE); + if (fh != -1) + { + res = _write(fh, nlhrReply->pData, nlhrReply->dataLength); + _close(fh); + } + if (res < 0) + remove(szDest); + else + result = 0; + } + // if the recieved code is 302 Moved, Found, etc + // workaround for url forwarding + else if(nlhrReply->resultCode == 302 || nlhrReply->resultCode == 301 || nlhrReply->resultCode == 307) // page moved + { + // get the url for the new location and save it to szInfo + // look for the reply header "Location" + for (int i=0; iheadersCount; i++) + { + if (!strcmp(nlhrReply->headers[i].szName, "Location")) + { + size_t rlen = 0; + if (nlhrReply->headers[i].szValue[0] == '/') + { + const char* szPath; + const char* szPref = strstr(szUrl, "://"); + szPref = szPref ? szPref + 3 : szUrl; + szPath = strchr(szPref, '/'); + rlen = szPath != NULL ? szPath - szUrl : strlen(szUrl); + } + + szRedirUrl = (char*)mir_realloc(szRedirUrl, + rlen + strlen(nlhrReply->headers[i].szValue)*3 + 1); + + strncpy(szRedirUrl, szUrl, rlen); + strcpy(szRedirUrl+rlen, nlhrReply->headers[i].szValue); + + nlhr.szUrl = szRedirUrl; + break; + } + } + } + else + result = 1; + } + else + { + hHttpDwnl = NULL; + result = 1; + } + + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)nlhrReply); + } + + mir_free(szRedirUrl); + + return result == 0; +} + + +void __cdecl SmileyDownloadThread(void*) +{ + bool needext = false; + HANDLE hHttpDwnl = NULL; + WaitForSingleObject(g_hDlMutex, 3000); + while (!Miranda_Terminated() && dlQueue.getCount()) + { + ReleaseMutex(g_hDlMutex); + if (_taccess(dlQueue[0].fname.c_str(), 0) != 0) + { + InternetDownloadFile(T2A_SM(dlQueue[0].url.c_str()), T2A_SM(dlQueue[0].fname.c_str()), hHttpDwnl); + WaitForSingleObject(g_hDlMutex, 3000); + + bkstring fname(dlQueue[0].fname); + if (dlQueue[0].needext) { fname += GetImageExt(fname); needext = true; } + _trename(dlQueue[0].fname.c_str(), fname.c_str()); + } + else + WaitForSingleObject(g_hDlMutex, 3000); + + dlQueue.remove(0); + } + dlQueue.destroy(); + if (hHttpDwnl) Netlib_CloseHandle(hHttpDwnl); + threadRunning = false; + ReleaseMutex(g_hDlMutex); + + if (!Miranda_Terminated()) + { + if (needext) + CallServiceSync(MS_SMILEYADD_RELOAD, 0, 0); + else + NotifyEventHooks(hEvent1, 0, 0); + } +} + + +bool GetSmileyFile(bkstring& url, const bkstring& packstr) +{ + _TPattern * urlsplit = _TPattern::compile(_T(".*/(.*)")); + _TMatcher * m0 = urlsplit->createTMatcher(url); + + m0->findFirstMatch(); + + bkstring filename; + filename.appendfmt(_T("%s\\%s\\"), cachepath, packstr.c_str()); + size_t pathpos = filename.size(); + filename += m0->getGroup(1); + + delete m0; + delete urlsplit; + + bool needext = filename.find('.') == filename.npos; + if (needext) filename += _T(".*"); + + _tfinddata_t c_file; + INT_PTR hFile = _tfindfirst((TCHAR*)filename.c_str(), &c_file); + if (hFile > -1) + { + _findclose(hFile); + filename.erase(pathpos); + filename += c_file.name; + url = filename; + return false; + } + if (needext) filename.erase(filename.size()-1); + + WaitForSingleObject(g_hDlMutex, 3000); + dlQueue.insert(new QueueElem(url, filename, needext)); + ReleaseMutex(g_hDlMutex); + + if (!threadRunning) + { + threadRunning = true; + mir_forkthread(SmileyDownloadThread, NULL); + } + + url = filename; + return false; +} + +void GetDefaultSmileyCacheFolder(TCHAR* szPath, size_t cbLen) +{ + TCHAR *tmpPath = Utils_ReplaceVarsT(_T("%miranda_userdata%\\SmileyCache")); + if ((INT_PTR)tmpPath != CALLSERVICE_NOTFOUND) + { + mir_sntprintf(szPath, cbLen, _T("%s"), tmpPath); + mir_free(tmpPath); + } + else + { + char dbPath[MAX_PATH]; + CallService(MS_DB_GETPROFILEPATH, SIZEOF(dbPath), (LPARAM)dbPath); + mir_sntprintf(szPath, cbLen, _T("%s\\SmileyCache"), A2T_SM(dbPath)); + } +} + +int FolderChanged(WPARAM, LPARAM) +{ + FOLDERSGETDATA fgd = {0}; + fgd.cbSize = sizeof(FOLDERSGETDATA); + fgd.nMaxPathSize = SIZEOF(cachepath); + fgd.szPathT = cachepath; + if (CallService(MS_FOLDERS_GET_PATH, (WPARAM) hFolder, (LPARAM) &fgd)) + { + GetDefaultSmileyCacheFolder(cachepath, SIZEOF(cachepath)); + } + + return 0; +} + +void GetSmileyCacheFolder(void) +{ + TCHAR defaultPath[MAX_PATH]; + + GetDefaultSmileyCacheFolder(defaultPath, SIZEOF(defaultPath)); + + FOLDERSDATA fd = {0}; + fd.cbSize = sizeof(FOLDERSDATA); + strcpy(fd.szSection, "SmileyAdd"); + strcpy(fd.szName,"Smiley Cache"); + fd.szFormatT = defaultPath; + fd.flags = FF_TCHAR; + hFolder = (HANDLE)CallService(MS_FOLDERS_REGISTER_PATH, 0, (LPARAM) &fd); + + FolderChanged(0, 0); + + hFolderHook = HookEvent(ME_FOLDERS_PATH_CHANGED, FolderChanged); +} + +void DownloadInit(void) +{ + NETLIBUSER nlu = {0}; + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING|NUF_HTTPCONNS|NUF_NOHTTPSOPTION; + nlu.szSettingsModule = "SmileyAdd"; + nlu.szDescriptiveName = Translate("SmileyAdd HTTP connections"); + hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + GetSmileyCacheFolder(); + g_hDlMutex = CreateMutex(NULL, FALSE, NULL); +} + +void DownloadClose(void) +{ + UnhookEvent(hFolderHook); + CloseHandle(g_hDlMutex); + Netlib_CloseHandle(hNetlibUser); +} diff --git a/plugins/SmileyAdd/src/download.h b/plugins/SmileyAdd/src/download.h new file mode 100644 index 0000000000..bb83926acc --- /dev/null +++ b/plugins/SmileyAdd/src/download.h @@ -0,0 +1,28 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef SMILEYADD_DOWNLOAD_H_ +#define SMILEYADD_DOWNLOAD_H_ + +#include "general.h" + +bool GetSmileyFile(bkstring& url, const bkstring& packstr); +void DownloadInit(void); +void DownloadClose(void); + +#endif diff --git a/plugins/SmileyAdd/src/general.cpp b/plugins/SmileyAdd/src/general.cpp new file mode 100644 index 0000000000..9e97737f8c --- /dev/null +++ b/plugins/SmileyAdd/src/general.cpp @@ -0,0 +1,299 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2012 Boris Krasnovskiy All Rights Reserved +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "m_metacontacts.h" + +#ifdef _MSC_VER +#include +#endif + +/* +#include "m_popup.h" +*/ +static ULONG_PTR g_gdiplusToken = 0; +static bool gdiPlusFail = false; + +// +// General functions +// +int CalculateTextHeight(HDC hdc, CHARFORMAT2* chf) +{ + HDC hcdc = CreateCompatibleDC(hdc); + + int logPixelsY = GetDeviceCaps(hdc, LOGPIXELSY); + HFONT hFont = CreateFont(-(chf->yHeight * logPixelsY / 1440), 0, 0, 0, + chf->wWeight, chf->dwEffects & CFE_ITALIC ? 1 : 0, 0, 0, + chf->bCharSet, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + chf->szFaceName); + SelectObject(hcdc, hFont); + + SIZE fontSize; + GetTextExtentPoint32(hcdc, _T(")"), 1, &fontSize); + + DeleteObject(hFont); + DeleteDC(hcdc); + + return fontSize.cy; +} + + +HICON GetDefaultIcon(bool copy) +{ + HICON resIco = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"SmileyAdd_ButtonSmiley"); + if ( resIco == NULL || resIco == (HICON)CALLSERVICE_NOTFOUND ) + { + resIco = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_SMILINGICON), + IMAGE_ICON, 0, 0, copy ? 0 : LR_SHARED); + } + else + { + if (copy) + { + resIco = (HICON)CopyImage(resIco, IMAGE_ICON, 0, 0, 0); + CallService(MS_SKIN2_RELEASEICON, 0, (LPARAM)"SmileyAdd_ButtonSmiley"); + } + } + + return resIco; +} + + +const TCHAR* GetImageExt(bkstring &fname) +{ + const TCHAR* ext = _T(""); + + int fileId = _topen(fname.c_str(), O_RDONLY | _O_BINARY); + if (fileId != -1) + { + BYTE buf[6]; + + int bytes = _read(fileId, buf, sizeof(buf)); + if (bytes > 4) + { + if ( *(unsigned short*)buf == 0xd8ff ) + ext = _T("jpg"); + else if ( *(unsigned short*)buf == 0x4d42 ) + ext = _T("bmp"); + else if ( *(unsigned*)buf == 0x474e5089 ) + ext = _T("png"); + else if ( *(unsigned*)buf == 0x38464947 ) + ext = _T("gif"); + } + _close(fileId); + } + return ext; +} + + + +HICON ImageList_GetIconFixed (HIMAGELIST himl, INT i, UINT fStyle) +{ + ICONINFO ii; + HICON hIcon; + HBITMAP hOldDstBitmap; + HDC hdcDst; + + int cx, cy; + ImageList_GetIconSize(himl, &cx, &cy); + + hdcDst = CreateCompatibleDC(NULL); + + ii.fIcon = TRUE; + ii.xHotspot = 0; + ii.yHotspot = 0; + + /* draw mask*/ + ii.hbmMask = CreateBitmap (cx, cy, 1, 1, NULL); + hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask); + PatBlt(hdcDst, 0, 0, cx, cy, WHITENESS); + ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK); + + /* draw image*/ + ii.hbmColor = CreateBitmap (cx, cy, 1, 32, NULL); + SelectObject (hdcDst, ii.hbmColor); + PatBlt (hdcDst, 0, 0, cx, cy, BLACKNESS); + ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT); + + /* + * CreateIconIndirect requires us to deselect the bitmaps from + * the DCs before calling + */ + SelectObject(hdcDst, hOldDstBitmap); + + hIcon = CreateIconIndirect (&ii); + + DeleteObject (ii.hbmMask); + DeleteObject (ii.hbmColor); + DeleteDC (hdcDst); + + return hIcon; +} + +void pathToRelative(const bkstring& pSrc, bkstring& pOut) +{ + TCHAR szOutPath[MAX_PATH]; + CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)pSrc.c_str(), (LPARAM)szOutPath); + pOut = szOutPath; +} + +void pathToAbsolute(const bkstring& pSrc, bkstring& pOut) +{ + TCHAR szOutPath[MAX_PATH]; + + TCHAR* szVarPath = Utils_ReplaceVarsT(pSrc.c_str()); + if (szVarPath == (TCHAR*)CALLSERVICE_NOTFOUND || szVarPath == NULL) + { + TCHAR szExpPath[MAX_PATH]; + ExpandEnvironmentStrings(pSrc.c_str(), szExpPath, SIZEOF(szExpPath)); + CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)szExpPath, (LPARAM)szOutPath); + } + else + { + CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)szVarPath, (LPARAM)szOutPath); + mir_free(szVarPath); + } + pOut = szOutPath; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// UrlDecode - converts URL chars like %20 into printable characters + +static int __fastcall SingleHexToDecimal(char c) +{ + if (c >= '0' && c <= '9') return c-'0'; + if (c >= 'a' && c <= 'f') return c-'a'+10; + if (c >= 'A' && c <= 'F') return c-'A'+10; + return -1; +} + +void UrlDecode(char* str) +{ + char* s = str, *d = str; + + while(*s) + { + if (*s == '%') + { + int digit1 = SingleHexToDecimal(s[1]); + if ( digit1 != -1 ) + { + int digit2 = SingleHexToDecimal(s[2]); + if ( digit2 != -1 ) + { + s += 3; + *d++ = (char)((digit1 << 4) | digit2); + continue; + } + } + } + *d++ = *s++; + } + + *d = 0; +} + + +bool InitGdiPlus(void) +{ + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + + static const TCHAR errmsg[] = _T("GDI+ not installed.\n") + _T("GDI+ can be downloaded here: http://www.microsoft.com/downloads"); + +#ifdef _MSC_VER + __try +#endif + { + if (g_gdiplusToken == 0 && !gdiPlusFail) + { + Gdiplus::GdiplusStartup(&g_gdiplusToken, &gdiplusStartupInput, NULL); + } + } +#ifdef _MSC_VER + __except ( EXCEPTION_EXECUTE_HANDLER ) + { + gdiPlusFail = true; + ReportError(errmsg); + } +#endif + + return !gdiPlusFail; +} + +void DestroyGdiPlus(void) +{ + if (g_gdiplusToken != 0) + { + Gdiplus::GdiplusShutdown(g_gdiplusToken); +#ifdef _MSC_VER +#if 1200 < _MSC_VER + __FUnloadDelayLoadedDLL2("gdiplus.dll"); +#else + __FUnloadDelayLoadedDLL("gdiplus.dll"); +#endif +#endif + g_gdiplusToken = 0; + } +} + +HANDLE DecodeMetaContact(HANDLE hContact) +{ + if (hContact == NULL) return NULL; + HANDLE hReal = (HANDLE) CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM) hContact, 0); + if (hReal == NULL || hReal == (HANDLE)CALLSERVICE_NOTFOUND) + hReal = hContact; + + return hReal; +} + +bool IsSmileyProto(char* proto) +{ + return proto && (!metaProtoName || strcmp(proto, metaProtoName)) && + (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & (PF1_IM | PF1_CHAT)); +} + +void ReportError(const TCHAR* errmsg) +{ + static const TCHAR title[] = _T("Miranda SmileyAdd"); +/* + + POPUPDATAW pd = {0}; + + + _tcscpy(pd.lpwzContactName, title); + _tcscpy(pd.lpwzText, errmsg); + + pd.iSeconds = -1; + + + bool popupFail = PUAddPopUpW(&pd) != CALLSERVICE_NOTFOUND; + + if (popupFail) +*/ + MessageBox(NULL, errmsg, title, MB_OK | MB_ICONWARNING | MB_TOPMOST); +} + +#pragma warning( disable : 4786 ) +#undef _MT + +#include +#include diff --git a/plugins/SmileyAdd/src/general.h b/plugins/SmileyAdd/src/general.h new file mode 100644 index 0000000000..8cc13c5619 --- /dev/null +++ b/plugins/SmileyAdd/src/general.h @@ -0,0 +1,232 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef _GENERAL_ +#define _GENERAL_ + +#define _HAS_EXCEPTIONS 0 +#define _SECURE_SCL 0 +#define _SECURE_SCL_THROWS 0 +#define __STDC_WANT_SECURE_LIB__ 0 +#define _STRALIGN_USE_SECURE_CRT 0 +#define _NO_EXCEPTIONS + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "bkstring.h" + +#undef _MT + +#pragma warning( push ) +#pragma warning( disable : 4530 ) +#pragma warning( disable : 4275 ) +#pragma warning( disable : 4390 ) + +#include +#include + +typedef WCPattern _TPattern; +typedef WCMatcher _TMatcher; +#define createTMatcher createWCMatcher + +#pragma warning( pop ) + +#define _MT + +#include "resource.h" + +#pragma warning( push ) +#pragma warning( disable : 4100 ) +#define MIRANDA_VER 0x0A00 +#define NETLIB_NOLOGGING +#define MIRANDA_CUSTOM_LP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning( pop ) + +//globals, defined int main.cpp +extern HINSTANCE g_hInst; +extern char* metaProtoName; + +//some system and NT stuff... +#ifndef OPENFILENAME_SIZE_VERSION_400 +#define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME) +#endif + + +#define IDC_SMLBUTTON (WM_USER + 33) + +/////////////////////////////////////////////////// +// +//defines from miranda im sources (undocumented!) +// +#define MI_IDC_LOG 1001 //rich edit +#define MI_IDC_MESSAGE 1002 //edit control +#define MI_IDC_QUOTE 1034 //button control +#define MI_IDC_NAME 1009 //text control +#define MI_IDC_ADD 1070 //Add button. + +#define DM_REMAKELOG (WM_USER + 11) +#define DM_OPTIONSAPPLIED (WM_USER + 14) +#define DM_APPENDTOLOG (WM_USER + 17) + +#define WM_REMAKERICH (WM_USER + 0x3457) + +///////////////////////////////////////////////////// + +#define MAX_SMILEY_LENGTH 96 + +class A2W_SM +{ +public: + wchar_t* m_psz; + + A2W_SM(const char* psz, unsigned nCodePage = CP_ACP) + { + const int nLength = MultiByteToWideChar(nCodePage, 0, psz, -1, NULL, 0); + m_psz = new wchar_t[nLength]; + MultiByteToWideChar(nCodePage, 0, psz, -1, m_psz, nLength); + } + ~A2W_SM() { delete [] m_psz; } + operator wchar_t*() const { return m_psz; } +}; + + +class W2A_SM +{ +public: + char* m_psz; + + W2A_SM(const wchar_t* psz, unsigned nCodePage = CP_ACP) + { + const int nLength = WideCharToMultiByte(nCodePage, 0, psz, -1, NULL, 0, NULL, NULL); + m_psz = new char[nLength]; + WideCharToMultiByte(nCodePage, 0, psz, -1, m_psz, nLength, NULL, NULL); + } + ~W2A_SM() { delete [] m_psz; } + operator char*() const { return m_psz; } +}; + +#define T2A_SM (char*)W2A_SM +#define T2W_SM(p1) (wchar_t*)p1 +#define A2T_SM (wchar_t*)A2W_SM +#define W2T_SM(p1) (TCHAR*)p1 + +template struct SMOBJLIST : public OBJLIST +{ + SMOBJLIST() : OBJLIST(5) {}; + + SMOBJLIST& operator = (const SMOBJLIST& lst) + { + OBJLIST::destroy(); + return operator += (lst); + } + + SMOBJLIST& operator += (const SMOBJLIST& lst) + { + for (int i=0; i& lst) + { + for (int i=0; i::destroy(); + } +}; + +inline unsigned short GetWinVer(void) +{ + unsigned short ver = LOWORD(GetVersion()); + ver = (ver & 0xFF) << 8 | (ver >> 8); + return ver; +} + + +// init functions +void InstallDialogBoxHook(void); +void RemoveDialogBoxHook(void); +int UpdateSrmmDlg(WPARAM wParam, LPARAM lParam); +bool IsOldSrmm(void); + +//functions for general use (defined in general.cpp) +int CalculateTextHeight(HDC hdc, CHARFORMAT2* chf); +const TCHAR* GetImageExt(bkstring &fname); + +HANDLE DecodeMetaContact(HANDLE hContact); +bool IsSmileyProto(char* proto); + +HICON ImageList_GetIconFixed (HIMAGELIST himl, INT i, UINT fStyle); + +void pathToRelative(const bkstring& pSrc, bkstring& pOut); +void pathToAbsolute(const bkstring& pSrc, bkstring& pOut); + +bool InitGdiPlus(void); +void DestroyGdiPlus(void); + +void ReportError(const TCHAR* errmsg); +HICON GetDefaultIcon(bool copy = true); + +void CloseRichCallback(HWND hwnd, bool force); +void CloseRichOwnerCallback(HWND hwnd, bool force); +bool SetRichCallback(HWND hwnd, HANDLE hContact, bool subany, bool subnew); +void SetRichOwnerCallback(HWND hwnd, HWND hwndInput, HWND hwndLog); +void ProcessAllInputAreas(bool restoreText); +void RichEditData_Destroy(void); + +void CloseSmileys(void); +void DestroySmileyBase(void); +void DestroyAniSmileys(void); + +void UrlDecode(char* str); + +#endif diff --git a/plugins/SmileyAdd/src/imagecache.cpp b/plugins/SmileyAdd/src/imagecache.cpp new file mode 100644 index 0000000000..8fdcea9003 --- /dev/null +++ b/plugins/SmileyAdd/src/imagecache.cpp @@ -0,0 +1,775 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "imagecache.h" +#include "options.h" + +typedef BOOL (WINAPI *tAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); +static tAlphaBlend pAlphaBlend; + +static FI_INTERFACE *fei; + +static HANDLE g_hMutexIm; +static OBJLIST g_imagecache(25, ImageType::CompareImg); + +static bkstring lastdllname; +static HMODULE lastmodule; +static time_t laststamp; +static UINT_PTR timerId; + +static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD) +{ + WaitForSingleObject(g_hMutexIm, 3000); + const time_t ts = time(NULL) - 10; + if ( lastmodule && ts > laststamp) + { + FreeLibrary(lastmodule); + lastmodule = NULL; + lastdllname.clear(); + } + + for (int i=g_imagecache.getCount(); i--; ) + g_imagecache[i].ProcessTimerTick(ts); + + if (g_imagecache.getCount() == 0) + { + g_imagecache.destroy(); + if (timerId && (timerId+1) && lastmodule == NULL) + { + KillTimer(NULL, timerId); + timerId = 0; + } + } + + ReleaseMutex(g_hMutexIm); +} + + +static void CALLBACK sttMainThreadCallback( PVOID ) +{ + if (timerId == 0xffffffff) + timerId = SetTimer(NULL, 0, 10000, (TIMERPROC)timerProc); +} + + +static HMODULE LoadDll(const bkstring& file) +{ + WaitForSingleObject(g_hMutexIm, 3000); + + if (lastdllname != file) + { + FreeLibrary(lastmodule); + lastdllname = file; + + lastmodule = LoadLibraryEx(file.c_str(), NULL, LOAD_LIBRARY_AS_DATAFILE); + + } + laststamp = time(NULL); + + ReleaseMutex(g_hMutexIm); + return lastmodule; +} + + + +ImageBase::ImageBase(unsigned id) +{ + m_id = id; + m_lRefCount = 1; + m_timestamp = 0; +} + +long ImageBase::AddRef(void) +{ + WaitForSingleObject(g_hMutexIm, 3000); + long cnt = ++m_lRefCount; + ReleaseMutex(g_hMutexIm); + return cnt; +} + +long ImageBase::Release(void) +{ + WaitForSingleObject(g_hMutexIm, 3000); + + long cnt = m_lRefCount; + if (cnt) m_lRefCount = --cnt; + if (cnt == 0) m_timestamp = time(NULL); + + ReleaseMutex(g_hMutexIm); + return cnt; +} + +void ImageBase::ProcessTimerTick(time_t ts) +{ + WaitForSingleObject(g_hMutexIm, 3000); + if (m_lRefCount == 0 && m_timestamp < ts ) + { + if (!g_imagecache.remove(this)) + delete this; + } + ReleaseMutex(g_hMutexIm); +} + +int ImageBase::CompareImg(const ImageBase* p1, const ImageBase* p2) +{ + unsigned id1 = p1->m_id; + unsigned id2 = p2->m_id; + + if (id1 == id2) return 0; + else return id1 < id2 ? -1 : 1; +} + +void ImageBase::Draw(HDC hdc, RECT& rc, bool clip) +{ + HRGN hrgn = NULL; + if (clip) + { + hrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); + SelectClipRgn(hdc, hrgn); + } + + SIZE iSize; + GetSize(iSize); + + const int sizeX = rc.right - rc.left; + const int sizeY = rc.bottom - rc.top; + + const int x = rc.left + (sizeX > iSize.cx || clip ? (sizeX - iSize.cx) / 2 : 0); + const int y = rc.top + (sizeY > iSize.cy || clip ? (sizeY - iSize.cy) / 2 : 0); + + const int scaleX = sizeX > iSize.cx || clip ? iSize.cx : sizeX; + const int scaleY = sizeY > iSize.cy || clip ? iSize.cy : sizeY; + + DrawInternal(hdc, x, y, scaleX, scaleY); + + if (clip) + { + SelectClipRgn(hdc, NULL); + DeleteObject(hrgn); + } +} + + +HBITMAP ImageBase::GetBitmap(COLORREF bkgClr, int sizeX, int sizeY) +{ + RECT rc = { 0, 0, sizeX, sizeY }; + + if (sizeX == 0 || sizeY == 0) + { + SIZE iSize; + GetSize(iSize); + + if (sizeX == 0) rc.right = iSize.cx; + if (sizeY == 0) rc.bottom = iSize.cy; + } + + HBRUSH hBkgBrush = CreateSolidBrush(bkgClr); + HDC hdc = GetDC(NULL); + HBITMAP hBmp = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); + HDC hdcMem = CreateCompatibleDC(hdc); + SelectObject(hdcMem, hBmp); + + FillRect(hdcMem, &rc, hBkgBrush); + + Draw(hdcMem, rc, false); + + DeleteDC(hdcMem); + ReleaseDC(NULL, hdc); + DeleteObject(hBkgBrush); + + return hBmp; +} + +int ImageBase::SelectNextFrame(const int frame) +{ + int res = (frame + 1) % GetFrameCount(); + SelectFrame(res); + return res; +} + + + +IconType::IconType(const unsigned id, const bkstring& file, const int index, const IcoTypeEnum type) + : ImageBase(id) +{ + m_SmileyIcon = NULL; + + switch (type) + { + case icoDll: + { + const HMODULE hModule = LoadDll(file); + if (hModule != NULL) + m_SmileyIcon = (HICON) LoadImage(hModule, MAKEINTRESOURCE(-index), IMAGE_ICON, 0, 0, 0); + } + break; + + case icoFile: + m_SmileyIcon = (HICON) LoadImage(NULL, file.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + break; + + default: + ExtractIconEx(file.c_str(), index, NULL, &m_SmileyIcon, 1); + break; + } +} + +IconType::~IconType() +{ + DestroyIcon(m_SmileyIcon); +} + +void IconType::DrawInternal(HDC hdc, int x, int y, int sizeX, int sizeY) +{ + if (m_SmileyIcon != NULL) + DrawIconEx(hdc, x, y, m_SmileyIcon, sizeX, sizeY, 0, NULL, DI_NORMAL); +} + +HICON IconType::GetIcon(void) +{ + return (HICON)CopyImage(m_SmileyIcon, IMAGE_ICON, 0, 0, 0); +} + +void IconType::GetSize(SIZE& size) +{ + if (m_SmileyIcon != NULL) + { + ICONINFO ii; + BITMAP bm; + GetIconInfo(m_SmileyIcon, &ii); + GetObject(ii.hbmColor, sizeof(bm), &bm); + size.cx = bm.bmWidth; + size.cy = bm.bmHeight; + DeleteObject(ii.hbmMask); + DeleteObject(ii.hbmColor); + } +} + + + +ImageListItemType::ImageListItemType(const unsigned id, HIMAGELIST hImList, int index) + : ImageBase(id) +{ + m_index = index; + m_hImList = hImList; +} + +void ImageListItemType::DrawInternal(HDC hdc, int x, int y, int sizeX, int sizeY) +{ + SIZE iSize; + GetSize(iSize); + + if (sizeX >= iSize.cx && sizeY >= iSize.cy) + ImageList_Draw(m_hImList, m_index, hdc, x, y, ILD_TRANSPARENT); + else + { + HICON hIcon = ImageList_GetIconFixed(m_hImList, m_index, ILD_TRANSPARENT); + DrawIconEx(hdc, x, y, hIcon, sizeX, sizeY, 0, NULL, DI_NORMAL); + DestroyIcon(hIcon); + } +} + +HICON ImageListItemType::GetIcon(void) +{ + return ImageList_GetIconFixed(m_hImList, m_index, ILD_TRANSPARENT); +} + +void ImageListItemType::GetSize(SIZE& size) +{ + ImageList_GetIconSize(m_hImList, (int*)&size.cx, (int*)&size.cy); +} + +ImageType::ImageType(const unsigned id, const bkstring& file, IStream* pStream) + : ImageBase(id) +{ + m_bmp = NULL; + m_pPropertyItem = NULL; + m_nCurrentFrame = 0; + m_nFrameCount = 0; + + if (!InitGdiPlus()) return; + + if (pStream) + m_bmp = new Gdiplus::Bitmap(pStream); + else + m_bmp = new Gdiplus::Bitmap(T2W_SM(file.c_str())); + + if (m_bmp->GetLastStatus() != Gdiplus::Ok) + { + delete m_bmp; + m_bmp = NULL; + return; + } + + GUID pageGuid = Gdiplus::FrameDimensionTime; + m_nFrameCount = m_bmp->GetFrameCount(&pageGuid); + + if (IsAnimated()) + { + int nSize = m_bmp->GetPropertyItemSize(PropertyTagFrameDelay); + m_pPropertyItem = (Gdiplus::PropertyItem*) new char[nSize]; + m_bmp->GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem); + } +} + +ImageType::ImageType(const unsigned id, const bkstring& file, const int index, const IcoTypeEnum type) + : ImageBase(id) +{ + m_bmp = NULL; + m_pPropertyItem = NULL; + m_nCurrentFrame = 0; + m_nFrameCount = 0; + + if (!InitGdiPlus()) return; + + switch (type) + { + case icoDll: + { + const HMODULE hModule = LoadDll(file); + if (hModule != NULL) + { + HICON hIcon = (HICON) LoadImage(hModule, MAKEINTRESOURCE(-index), IMAGE_ICON, 0, 0, 0); + m_bmp = new Gdiplus::Bitmap(hIcon); + DestroyIcon(hIcon); + } + } + break; + + case icoFile: + m_bmp = new Gdiplus::Bitmap(T2W_SM(file.c_str())); + break; + + default: + HICON hIcon = NULL; + ExtractIconEx(file.c_str(), index, NULL, &hIcon, 1); + m_bmp = new Gdiplus::Bitmap(hIcon); + DestroyIcon(hIcon); + break; + } + + if (m_bmp->GetLastStatus() != Gdiplus::Ok) + { + delete m_bmp; + m_bmp = NULL; + return; + } +} + + +ImageType::~ImageType(void) +{ + if (m_pPropertyItem) delete[] m_pPropertyItem; + if (m_bmp) delete m_bmp; +} + +void ImageType::SelectFrame(int frame) +{ + if ((unsigned)frame >= (unsigned)m_nFrameCount) frame = 0; + if (IsAnimated() && frame != m_nCurrentFrame) + { + m_nCurrentFrame = frame; + GUID pageGuid = Gdiplus::FrameDimensionTime; + m_bmp->SelectActiveFrame(&pageGuid, frame); + } +} + + +void ImageType::DrawInternal(HDC hdc, int x, int y, int sizeX, int sizeY) +{ + if (m_bmp == NULL) return; + + WaitForSingleObject(g_hMutexIm, 3000); + { + Gdiplus::Graphics grp(hdc); +// if (opt.HQScaling) grp.SetInterpolationMode(Gdiplus::InterpolationModeBicubic); + grp.DrawImage(m_bmp, x, y, sizeX, sizeY); + } + ReleaseMutex(g_hMutexIm); +} + +int ImageType::GetFrameDelay(void) const +{ + return ((long*) m_pPropertyItem->value)[m_nCurrentFrame]; +} + +HICON ImageType::GetIcon(void) +{ + if (m_bmp == NULL) return NULL; + + HICON hIcon = NULL; + WaitForSingleObject(g_hMutexIm, 3000); + + m_bmp->GetHICON(&hIcon); + + ReleaseMutex(g_hMutexIm); + return hIcon; +} + + +void ImageType::GetSize(SIZE& size) +{ + if (m_bmp) + { + size.cx = m_bmp->GetWidth(); + size.cy = m_bmp->GetHeight(); + } + else + { + size.cx = 0; + size.cy = 0; + } +} + + +ImageFType::ImageFType(const unsigned id) + : ImageBase(id) +{ + m_bmp = NULL; +} + +ImageFType::ImageFType(const unsigned id, const bkstring& file) + : ImageBase(id) +{ + m_bmp = NULL; + + FREE_IMAGE_FORMAT fif = fei->FI_GetFileTypeT(file.c_str(), 0); + if (fif == FIF_UNKNOWN) + fif = fei->FI_GetFIFFromFilenameT(file.c_str()); + if (fif == FIF_UNKNOWN) return; + + FIBITMAP *dib = fei->FI_LoadT(fif, file.c_str(), 0); + if (dib == NULL) return; + + bool transp = fei->FI_IsTransparent(dib) != 0; + FREE_IMAGE_TYPE imt = fei->FI_GetImageType(dib); + unsigned bpp = fei->FI_GetBPP(dib); + + if (transp && bpp != 32 || imt == FIT_RGBA16) + { + FIBITMAP *tdib = fei->FI_ConvertTo32Bits(dib); + fei->FI_Unload(dib); + dib = tdib; + } + else if (!transp && bpp > 24) + { + FIBITMAP *tdib = fei->FI_ConvertTo24Bits(dib); + fei->FI_Unload(dib); + dib = tdib; + } + + m_bmp = fei->FI_CreateHBITMAPFromDIB(dib); + fei->FI_Unload(dib); + + if (transp) + fei->FI_Premultiply(m_bmp); +} + +ImageFType::~ImageFType() +{ + DeleteObject(m_bmp); +} + +void ImageFType::DrawInternal(HDC hdc, int x, int y, int sizeX, int sizeY) +{ + if (m_bmp == NULL) return; + + HDC hdcImg = CreateCompatibleDC(hdc); + HBITMAP oldBmp = (HBITMAP) SelectObject(hdcImg, m_bmp); + + BITMAP bm; + GetObject(m_bmp, sizeof(bm), &bm); + + if (bm.bmBitsPixel == 32 && pAlphaBlend) + { + BLENDFUNCTION bf = {0}; + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = AC_SRC_ALPHA; + pAlphaBlend(hdc, x, y, sizeX, sizeY, hdcImg, 0, 0, bm.bmWidth, bm.bmHeight, bf); + } + else + { + BitBlt(hdc, x, y, sizeX, sizeY, hdcImg, 0, 0, SRCCOPY); + } + + SelectObject(hdcImg, oldBmp); + DeleteDC(hdcImg); +} + +HICON ImageFType::GetIcon(void) +{ + if (m_bmp == NULL) return NULL; + + HICON hIcon; + + BITMAP bm; + GetObject(m_bmp, sizeof(bm), &bm); + + ICONINFO ii; + ii.fIcon = TRUE; + ii.xHotspot = 0; + ii.yHotspot = 0; + + if (bm.bmBitsPixel == 32 && GetWinVer() < 0x0501) + { + int slen = bm.bmWidth * 4; + int len = bm.bmHeight * slen; + + BYTE* p = (BYTE*)mir_alloc(len); + BYTE* maskBits = (BYTE*)mir_calloc(len); + BYTE* colorBits = (BYTE*)mir_calloc(len); + + GetBitmapBits(m_bmp, len, p); + + for (int y = 0; y < bm.bmHeight; ++y) + { + int shift = y * slen; + BYTE *px = p + shift; + BYTE *color = colorBits + shift; + BYTE *mask = maskBits + shift; + + for (int x = 0; x < bm.bmWidth; ++x) + { + for(int i = 0; i < 4; i++) + { + mask[i] = px[3]; + color[i] = px[i]; + } + + px += 4; + mask += 4; + color += 4; + } + } + + ii.hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 32, maskBits); + ii.hbmColor = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 32, colorBits); + + hIcon = CreateIconIndirect(&ii); + + DeleteObject(ii.hbmMask); + DeleteObject(ii.hbmColor); + + mir_free(p); + mir_free(maskBits); + mir_free(colorBits); + } + else + { + ii.hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL); + ii.hbmColor = m_bmp; + hIcon = CreateIconIndirect(&ii); + DeleteObject(ii.hbmMask); + } + return hIcon; +} + +void ImageFType::GetSize(SIZE& size) +{ + if (m_bmp) + { + BITMAP bm; + GetObject(m_bmp, sizeof(bm), &bm); + size.cx = bm.bmWidth; + size.cy = bm.bmHeight; + } + else + { + size.cx = 0; + size.cy = 0; + } +} +/* +ImageFAniType::ImageFAniType(const unsigned id, const bkstring& file) +: ImageFType(id) +{ + m_fmbmp = NULL; + m_nCurrentFrame = -1; + m_FrameDelay = NULL; + + FREE_IMAGE_FORMAT fif = fei->FI_GetFileTypeT(file.c_str(), 0); + if (fif == FIF_UNKNOWN) + fif = fei->FI_GetFIFFromFilenameT(file.c_str()); + + m_fmbmp = fei->FI_OpenMultiBitmap(fif, T2A_SM(file.c_str()), FALSE, TRUE, TRUE, GIF_PLAYBACK); + if (m_fmbmp == NULL) return; + + m_nFrameCount = fei->FI_GetPageCount(m_fmbmp); + m_bmpl = (HBITMAP*)mir_calloc(m_nFrameCount*sizeof(HBITMAP)); + m_FrameDelay = (int*)mir_calloc(m_nFrameCount*sizeof(int)); + SelectFrame(0); +} + +ImageFAniType::~ImageFAniType() +{ + if (m_fmbmp) fei->FI_CloseMultiBitmap(m_fmbmp, 0); + for (int i=0; i= (unsigned)m_nFrameCount) frame = 0; + if (frame == m_nCurrentFrame) return; + m_nCurrentFrame = frame; + + if (m_bmpl[frame]) + { + m_bmp = m_bmpl[frame]; + return; + } + + FITAG *tag = NULL; + + FIBITMAP *dib = fei->FI_LockPage(m_fmbmp, frame); + if (dib == NULL) + return; + + if (fei->FI_GetMetadata(FIMD_ANIMATION, dib, "FrameTime", &tag)) + m_FrameDelay[frame] = *(LONG *)fei->FI_GetTagValue(tag) / 10; + + m_bmpl[frame] = m_bmp = fei->FI_CreateHBITMAPFromDIB(dib); + + if (fei->FI_IsTransparent(dib)) + fei->FI_Premultiply(m_bmp); + + fei->FI_UnlockPage(m_fmbmp, dib, FALSE); +} +*/ + +#pragma optimize("gt", on) + +// MurmurHash2, by Austin Appleby +unsigned int __fastcall hash( const void * key, unsigned int len ) +{ + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + const unsigned int m = 0x5bd1e995; + const int r = 24; + + // Initialize the hash to a 'random' value + unsigned int h = len; + + // Mix 4 bytes at a time into the hash + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + unsigned int k = *(unsigned int *)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + // Handle the last few bytes of the input array + switch(len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} +#pragma optimize("", on) + + +void InitImageCache(void) +{ + g_hMutexIm = CreateMutex(NULL, FALSE, NULL); + CallService(MS_IMG_GETINTERFACE, FI_IF_VERSION, (LPARAM) &fei); + + pAlphaBlend = (tAlphaBlend) GetProcAddress(GetModuleHandleA("gdi32"), "GdiAlphaBlend"); + if (pAlphaBlend == NULL) + pAlphaBlend = (tAlphaBlend) GetProcAddress(LoadLibraryA("msimg32"), "AlphaBlend"); +} + +void DestroyImageCache(void) +{ + WaitForSingleObject(g_hMutexIm, 3000); + + if (timerId) KillTimer(NULL, timerId); + if (lastmodule) FreeLibrary(lastmodule); + + g_imagecache.destroy(); + + ReleaseMutex(g_hMutexIm); + CloseHandle(g_hMutexIm); +} + + +ImageBase* AddCacheImage(const bkstring& file, int index) +{ + bkstring tmpfile(file); tmpfile.appendfmt(_T("#%d"), index); + unsigned id = hash(tmpfile.c_str(), (unsigned int)tmpfile.size() * sizeof(TCHAR)); + + WaitForSingleObject(g_hMutexIm, 3000); + + ImageBase srch(id); + ImageBase *img = g_imagecache.find(&srch); + if (img == NULL) + { + bkstring::size_type ind = file.find_last_of('.'); + if (ind == file.npos) return NULL; + bkstring ext = file.substr(ind+1); + + if (ext.comparei(_T("dll")) == 0 || ext.comparei(_T("exe")) == 0) + img = opt.HQScaling ? (ImageBase*)new ImageType(id, file, index, icoDll) : (ImageBase*)new IconType(id, file, index, icoDll); + else if (ext.comparei(_T("ico")) == 0) + img = opt.HQScaling ? (ImageBase*)new ImageType(id, file, 0, icoFile) : (ImageBase*)new IconType(id, file, 0, icoFile); + else if (ext.comparei(_T("icl")) == 0) + img = opt.HQScaling ? (ImageBase*)new ImageType(id, file, index, icoIcl) : (ImageBase*)new IconType(id, file, index, icoIcl); + else if (ext.comparei(_T("gif")) == 0) + img = new ImageType(id, file, NULL); + else if (fei == NULL || ext.comparei(_T("tif")) == 0 || ext.comparei(_T("tiff")) == 0) + img = new ImageType(id, file, NULL); + else + img = opt.HQScaling ? (ImageBase*)new ImageType(id, file, NULL) : (ImageBase*)new ImageFType(id, file); + + g_imagecache.insert(img); + + if (timerId == 0) + { + timerId = 0xffffffff; + CallFunctionAsync(sttMainThreadCallback, NULL); + } + } + else + img->AddRef(); + + ReleaseMutex(g_hMutexIm); + + return img; +} diff --git a/plugins/SmileyAdd/src/imagecache.h b/plugins/SmileyAdd/src/imagecache.h new file mode 100644 index 0000000000..aa13e4981c --- /dev/null +++ b/plugins/SmileyAdd/src/imagecache.h @@ -0,0 +1,166 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef SMILEYADD_IMAGECACHE_H_ +#define SMILEYADD_IMAGECACHE_H_ + +#include "general.h" + + +class ImageBase +{ +protected: + unsigned m_id; + long m_lRefCount; + time_t m_timestamp; + +public: + + ImageBase(unsigned id); + virtual ~ImageBase() {} + + long AddRef(void); + long Release(void); + + void ProcessTimerTick(time_t ts); + + virtual void GetSize(SIZE& /* size */) {}; + virtual int GetFrameCount(void) const { return 0; } + virtual int GetFrameDelay(void) const { return 0; } + virtual HICON GetIcon(void) { return NULL; }; + virtual void DrawInternal(HDC /* dc */, int /* x */, int /* y */, int /* sizeX */, int /* sizeY */) {}; + virtual void SelectFrame(int /* frame */) {} + + bool IsAnimated(void) const { return GetFrameCount() > 1; } + HBITMAP GetBitmap(COLORREF bkgClr, int sizeX, int sizeY); + void Draw(HDC dc, RECT &rc, bool clip); + int SelectNextFrame(const int frame); + + static int CompareImg(const ImageBase* p1, const ImageBase* p2); +}; + + +typedef enum +{ + icoDll, + icoFile, + icoIcl +} +IcoTypeEnum; + + +class IconType : public ImageBase +{ +private: + HICON m_SmileyIcon; + +public: + IconType(const unsigned id, const bkstring& file, const int index, const IcoTypeEnum type); + ~IconType(); + + void DrawInternal(HDC dc, int x, int y, int sizeX, int sizeY); + HICON GetIcon(void); + void GetSize(SIZE& size); +}; + + +class ImageListItemType : public ImageBase +{ +private: + int m_index; + HIMAGELIST m_hImList; + +public: + ImageListItemType(const unsigned id, HIMAGELIST hImList, int index); + + void DrawInternal(HDC dc, int x, int y, int sizeX, int sizeY); + HICON GetIcon(void); + void GetSize(SIZE& size); +}; + + +class ImageType : public ImageBase +{ +private: + int m_nCurrentFrame; + int m_nFrameCount; + + Gdiplus::Bitmap* m_bmp; + Gdiplus::PropertyItem* m_pPropertyItem; + +public: + + ImageType(const unsigned id, const bkstring& file, IStream* pStream); + ImageType(const unsigned id, const bkstring& file, const int index, const IcoTypeEnum type); + ~ImageType(); + + void SelectFrame(int frame); + + void DrawInternal(HDC dc, int x, int y, int sizeX, int sizeY); + HICON GetIcon(void); + void GetSize(SIZE& size); + + int GetFrameDelay(void) const; + int GetFrameCount(void) const { return m_nFrameCount; } +}; + +class ImageFType : public ImageBase +{ +protected: + HBITMAP m_bmp; + +public: + + ImageFType(const unsigned id); + ImageFType(const unsigned id, const bkstring& file); + ~ImageFType(); + + void DrawInternal(HDC dc, int x, int y, int sizeX, int sizeY); + HICON GetIcon(void); + void GetSize(SIZE& size); +}; +/* +class ImageFAniType : public ImageFType +{ +private: + int m_nCurrentFrame; + int m_nFrameCount; + int *m_FrameDelay; + + FIMULTIBITMAP *m_fmbmp; + HBITMAP* m_bmpl; + +public: + + ImageFAniType(const unsigned id, const bkstring& file); + ~ImageFAniType(); + + void SelectFrame(int frame); + + int GetFrameDelay(void) const { return m_FrameDelay[m_nCurrentFrame]; } + int GetFrameCount(void) const { return m_nFrameCount; } +}; +*/ + + +ImageBase* AddCacheImage(const bkstring& file, int index); + +void InitImageCache(void); +void DestroyImageCache(void); + +#endif + diff --git a/plugins/SmileyAdd/src/main.cpp b/plugins/SmileyAdd/src/main.cpp new file mode 100644 index 0000000000..a2deb4399a --- /dev/null +++ b/plugins/SmileyAdd/src/main.cpp @@ -0,0 +1,225 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "smileys.h" +#include "customsmiley.h" +#include "services.h" +#include "options.h" +#include "download.h" +#include "imagecache.h" +#include "version.h" +#include "m_metacontacts.h" + +//globals +HINSTANCE g_hInst; +HANDLE hEvent1, hContactMenuItem; +extern LIST menuHandleArray; + +char* metaProtoName; + + + +//static globals +static HANDLE hHooks[7]; +static HANDLE hService[13]; +int hLangpack; + + +static const PLUGININFOEX pluginInfoEx = +{ + sizeof(PLUGININFOEX), + "SmileyAdd", + __VERSION_DWORD, + "Smiley support for Miranda Instant Messanger", + "Peacow, nightwish, bid, borkra", + "borkra@miranda-im.org", + "Copyright© 2004 - 2012 Boris Krasnovskiy, portions by Rein-Peter de Boer", + "http://nightly.miranda.im/", + // "http://nightly.miranda.im/", + UNICODE_AWARE, + // {BD542BB4-5AE4-4d0e-A435-BA8DBE39607F} + { 0xbd542bb4, 0x5ae4, 0x4d0e, { 0xa4, 0x35, 0xba, 0x8d, 0xbe, 0x39, 0x60, 0x7f } } +}; + +static SKINICONDESC skinDesc = +{ + sizeof(SKINICONDESC), "SmileyAdd", NULL, + "SmileyAdd_ButtonSmiley", NULL, -IDI_SMILINGICON +}; + + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD /* mirandaVersion */) +{ + return (PLUGININFOEX*)&pluginInfoEx; +} + +// MirandaInterfaces - returns the protocol interface to the core +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_SMILEY, MIID_LAST}; + +static int ModulesLoaded(WPARAM, LPARAM) +{ + char path[MAX_PATH]; + GetModuleFileNameA(g_hInst, path, MAX_PATH); + + skinDesc.pszDefaultFile = path; + skinDesc.pszDescription = LPGEN("Button Smiley"); + HANDLE hSkinIcon = Skin_AddIcon(&skinDesc); + + INT_PTR temp = CallService(MS_MC_GETPROTOCOLNAME, 0, 0); + metaProtoName = mir_strdup(temp == CALLSERVICE_NOTFOUND ? NULL : (char*)temp); + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.flags = CMIF_ROOTPOPUP | CMIF_ICONFROMICOLIB; + mi.popupPosition = 2000070050; + mi.position = 2000070050; + mi.icolibItem = hSkinIcon; + mi.pszPopupName = (char*)-1; + mi.pszName = "Assign Smiley Category"; + hContactMenuItem = Menu_AddContactMenuItem(&mi); + + DownloadInit(); + + //install hooks if enabled + InstallDialogBoxHook(); + + g_SmileyCategories.AddAllProtocolsAsCategory(); + g_SmileyCategories.ClearAndLoadAll(); + + return 0; +} + +static int MirandaShutdown(WPARAM, LPARAM) +{ + CloseSmileys(); + return 0; +} + +extern "C" __declspec(dllexport) int Load(void) +{ + + mir_getLP(&pluginInfoEx); + + if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS)) + { + static const TCHAR errmsg[] = _T("Only one instance of SmileyAdd could be executed.\n") + _T("Remove duplicate instances from 'Plugins' directory"); + ReportError(TranslateTS(errmsg)); + + return 1; + } + + char temp[80]; + CallService(MS_SYSTEM_GETVERSIONTEXT, (WPARAM)SIZEOF(temp), (LPARAM)temp); + + + if (strstr(temp, "Unicode") == NULL) + { + ReportError(TranslateT("Please update SmileyAdd to ANSI Version")); + return 1; + } + + + InitImageCache(); + + g_SmileyCategories.SetSmileyPackStore(&g_SmileyPacks); + + opt.Load(); + + // create smiley events + hEvent1 = CreateHookableEvent(ME_SMILEYADD_OPTIONSCHANGED); + + hHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); + hHooks[1] = HookEvent(ME_SYSTEM_PRESHUTDOWN, MirandaShutdown); + hHooks[2] = HookEvent(ME_OPT_INITIALISE, SmileysOptionsInitialize); + hHooks[3] = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, RebuildContactMenu); + hHooks[4] = HookEvent(ME_SMILEYADD_OPTIONSCHANGED, UpdateSrmmDlg); + hHooks[5] = HookEvent(ME_PROTO_ACCLISTCHANGED, AccountListChanged); + hHooks[6] = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, DbSettingChanged); + + //create the smiley services + hService[0] = CreateServiceFunction(MS_SMILEYADD_REPLACESMILEYS, ReplaceSmileysCommand); + hService[1] = CreateServiceFunction(MS_SMILEYADD_GETSMILEYICON, GetSmileyIconCommand); + hService[2] = CreateServiceFunction(MS_SMILEYADD_SHOWSELECTION, ShowSmileySelectionCommand); + hService[3] = CreateServiceFunction(MS_SMILEYADD_GETINFO, GetInfoCommand); + hService[4] = CreateServiceFunction(MS_SMILEYADD_GETINFO2, GetInfoCommand2); + hService[5] = CreateServiceFunction(MS_SMILEYADD_PARSE, ParseText); + hService[6] = CreateServiceFunction(MS_SMILEYADD_REGISTERCATEGORY, RegisterPack); + hService[7] = CreateServiceFunction(MS_SMILEYADD_BATCHPARSE, ParseTextBatch); + hService[8] = CreateServiceFunction(MS_SMILEYADD_BATCHFREE, FreeTextBatch); + hService[9] = CreateServiceFunction(MS_SMILEYADD_CUSTOMCATMENU, CustomCatMenu); + hService[10] = CreateServiceFunction(MS_SMILEYADD_RELOAD, ReloadPack); + hService[11] = CreateServiceFunction(MS_SMILEYADD_LOADCONTACTSMILEYS, LoadContactSmileys); + + + hService[12] = CreateServiceFunction(MS_SMILEYADD_PARSEW, ParseTextW); + + + return 0; +} + + +extern "C" __declspec(dllexport) int Unload(void) +{ + int i; + + RemoveDialogBoxHook(); + + for (i=0; i. +*/ + +#include "general.h" +#include "options.h" +#include "smileys.h" +#include "customsmiley.h" +#include "services.h" + +//globals, defined int main.cpp +extern HINSTANCE g_hInst; +extern HANDLE hEvent1; +extern SmileyCategoryListType g_SmileyCategories; +extern SmileyPackListType g_SmileyPacks; + +OptionsType opt; + +#define UM_CHECKSTATECHANGE (WM_USER + 100) + +class OptionsDialogType +{ +private: + HWND m_hwndDialog; + SmileyCategoryListType tmpsmcat; + SmileyPackType smPack; + + void InitDialog(void); + void DestroyDialog(void); + void AddCategory(void); + void ApplyChanges(void); + void UpdateControls(bool force = false); + void SetChanged(void); + bool BrowseForSmileyPacks(int item); + void FilenameChanged(void); + void ShowSmileyPreview(void); + void PopulateSmPackList(void); + void UserAction(HTREEITEM hItem); + long GetSelProto(HTREEITEM hItem = NULL); + +public: + OptionsDialogType(HWND hWnd) { m_hwndDialog = hWnd; } + BOOL DialogProcedure(UINT msg, WPARAM wParam, LPARAM lParam); +}; + +static INT_PTR CALLBACK DlgProcSmileysOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +//Init and de-init functions, called from main +int SmileysOptionsInitialize(WPARAM addInfo, LPARAM) +{ + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.position = 910000000; + odp.hInstance = g_hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SMILEYS); + odp.pszTitle = LPGEN("Smileys"); + odp.pszGroup = LPGEN("Customize"); + odp.pfnDlgProc = DlgProcSmileysOptions; + odp.flags = ODPF_BOLDGROUPS; + Options_AddPage(addInfo, &odp); + + return 0; +} + + +// +// dialog procedure for the options dialog. creates or +// retrieves the options class and calls it +// +static INT_PTR CALLBACK DlgProcSmileysOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + OptionsDialogType* pOD; + INT_PTR Result; + + pOD = (OptionsDialogType*) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (pOD == NULL) + { + pOD = new OptionsDialogType(hwndDlg); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pOD); + } + + Result = pOD->DialogProcedure(msg, wParam, lParam); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result); + + if (msg == WM_NCDESTROY) + { + delete pOD; + } + + return Result; +} + + +//OptionsDialog class functions +BOOL OptionsDialogType::DialogProcedure(UINT msg, WPARAM wParam, LPARAM lParam) +{ + BOOL Result = FALSE; + + switch(msg) + { + case WM_INITDIALOG: + InitDialog(); + Result = TRUE; + break; + + case WM_DESTROY: + DestroyDialog(); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_FILENAME: + switch(HIWORD(wParam)) + { + case EN_KILLFOCUS: + FilenameChanged(); + break; + + case EN_CHANGE: + if (GetFocus() == (HWND)lParam) SetChanged(); + break; + } + break; + + case IDC_BROWSE: + if (HIWORD(wParam) == BN_CLICKED) + { + if (BrowseForSmileyPacks(GetSelProto())) + { + UpdateControls(true); + SetChanged(); + } + } + break; + + case IDC_SMLOPTBUTTON: + if (HIWORD(wParam) == BN_CLICKED) ShowSmileyPreview(); + break; + + case IDC_USESTDPACK: + if (HIWORD(wParam) == BN_CLICKED) + { + PopulateSmPackList(); + SetChanged(); + } + break; + + case IDC_PLUGENABLED: + if (HIWORD(wParam) == BN_CLICKED) + { + BOOL en = IsDlgButtonChecked(m_hwndDialog, IDC_PLUGENABLED) == BST_UNCHECKED; + EnableWindow(GetDlgItem(m_hwndDialog, IDC_SMLBUT), en); + SetChanged(); + } + break; + + case IDC_ADDCATEGORY: + if (HIWORD(wParam) == BN_CLICKED) + { + AddCategory(); + } + break; + + case IDC_DELETECATEGORY: + if (HIWORD(wParam) == BN_CLICKED) + { + if (tmpsmcat.DeleteCustomCategory(GetSelProto())) + { + PopulateSmPackList(); + SetChanged(); + } + } + break; + + case IDC_SPACES: + case IDC_SCALETOTEXTHEIGHT: + case IDC_APPENDSPACES: + case IDC_SMLBUT: + case IDC_SCALEALLSMILEYS: + case IDC_IEVIEWSTYLE: + case IDC_ANIMATESEL: + case IDC_ANIMATEDLG: + case IDC_INPUTSMILEYS: + case IDC_DCURSORSMILEY: + case IDC_DISABLECUSTOM: + case IDC_HQSCALING: + if (HIWORD(wParam) == BN_CLICKED) SetChanged(); + break; + + case IDC_SELCLR: + if (HIWORD(wParam) == CPN_COLOURCHANGED) SetChanged(); + break; + + case IDC_MAXCUSTSMSZ: + case IDC_MINSMSZ: + if (HIWORD(wParam) == EN_CHANGE && GetFocus() == (HWND)lParam) SetChanged(); + break; + } + break; + + case UM_CHECKSTATECHANGE: + UserAction((HTREEITEM)lParam); + break; + + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) + { + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + ApplyChanges(); + break; + } + break; + + case IDC_CATEGORYLIST: + switch (((LPNMHDR)lParam)->code) + { + case NM_CLICK: + { + TVHITTESTINFO ht = {0}; + + DWORD dwpos = GetMessagePos(); + POINTSTOPOINT(ht.pt, MAKEPOINTS(dwpos)); + MapWindowPoints(HWND_DESKTOP, ((LPNMHDR)lParam)->hwndFrom, &ht.pt, 1); + + TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &ht); + if (TVHT_ONITEM & ht.flags) + FilenameChanged(); + if (TVHT_ONITEMSTATEICON & ht.flags) + PostMessage(m_hwndDialog, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.hItem); + } + + case TVN_KEYDOWN: + if (((LPNMTVKEYDOWN) lParam)->wVKey == VK_SPACE) + PostMessage(m_hwndDialog, UM_CHECKSTATECHANGE, 0, + (LPARAM)TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom)); + break; + + case TVN_SELCHANGEDA: + case TVN_SELCHANGEDW: + { + LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam; + if (pnmtv->itemNew.state & TVIS_SELECTED) + UpdateControls(); + } + break; + } + break; + } + break; + } + + return Result; +} + + +void OptionsDialogType::AddCategory(void) +{ + TCHAR cat[30]; + + GetDlgItemText(m_hwndDialog, IDC_NEWCATEGORY, cat, SIZEOF(cat)); + bkstring catd = cat; + + if (!catd.empty()) + { + tmpsmcat.AddCategory(cat, catd, smcCustom); + + PopulateSmPackList(); + SetChanged(); + } +} + + +void OptionsDialogType::UserAction(HTREEITEM hItem) +{ + HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); + + if (TreeView_GetCheckState(hLstView, hItem)) + { + if (!BrowseForSmileyPacks(GetSelProto(hItem))) + { + TreeView_SetCheckState(hLstView, hItem, TRUE) + } + } + else + { + tmpsmcat.GetSmileyCategory(GetSelProto(hItem))->ClearFilename(); + } + + if (hItem == TreeView_GetSelection(hLstView)) + UpdateControls(); + else + TreeView_SelectItem(hLstView, hItem); + + SetChanged(); +} + + +void OptionsDialogType::SetChanged(void) +{ + SendMessage(GetParent(m_hwndDialog), PSM_CHANGED, 0, 0); +} + + +void OptionsDialogType::UpdateControls(bool force) +{ + const SmileyCategoryType* smc = tmpsmcat.GetSmileyCategory(GetSelProto()); + if (smc == NULL) return; + + const bkstring& smf = smc->GetFilename(); + + SetDlgItemText(m_hwndDialog, IDC_FILENAME, smf.c_str()); + + if (smPack.GetFilename() != smf || force) + { + smPack.LoadSmileyFile(smf, false, true); + } + + HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); + TreeView_SetCheckState(hLstView, TreeView_GetSelection(hLstView), smPack.SmileyCount() != 0); + + SetDlgItemText(m_hwndDialog, IDC_LIBAUTHOR, smPack.GetAuthor().c_str()); + SetDlgItemText(m_hwndDialog, IDC_LIBVERSION, smPack.GetVersion().c_str()); + SetDlgItemText(m_hwndDialog, IDC_LIBNAME, TranslateTS(smPack.GetName().c_str())); +} + + +long OptionsDialogType::GetSelProto(HTREEITEM hItem) +{ + HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); + TVITEM tvi = {0}; + + tvi.mask = TVIF_PARAM; + tvi.hItem = hItem == NULL ? TreeView_GetSelection(hLstView) : hItem; + + TreeView_GetItem(hLstView, &tvi); + + return (long)tvi.lParam; +} + + +void OptionsDialogType::PopulateSmPackList(void) +{ + bool useOne = IsDlgButtonChecked(m_hwndDialog, IDC_USESTDPACK) == BST_UNCHECKED; + + HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); + + TreeView_SelectItem(hLstView, NULL); + TreeView_DeleteAllItems(hLstView); + + TVINSERTSTRUCT tvi = {0}; + tvi.hParent = TVI_ROOT; + tvi.hInsertAfter = TVI_LAST; + tvi.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_STATE | TVIF_SELECTEDIMAGE | TVIF_PARAM; + tvi.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_SELECTED; + + SmileyCategoryListType::SmileyCategoryVectorType& smc = *tmpsmcat.GetSmileyCategoryList(); + for (int i = 0; i < smc.getCount(); i++) + { + if (!useOne || !smc[i].IsProto()) + { + tvi.item.pszText = (TCHAR*)smc[i].GetDisplayName().c_str(); + if (!smc[i].IsProto()) + { + tvi.item.iImage = 0; + tvi.item.iSelectedImage = 0; + } + else + { + tvi.item.iImage = i; + tvi.item.iSelectedImage = i; + } + tvi.item.lParam = i; + tvi.item.state = + INDEXTOSTATEIMAGEMASK(smPack.LoadSmileyFile(smc[i].GetFilename(), true, true) ? 2 : 1); + + TreeView_InsertItem(hLstView, &tvi); + + smPack.Clear(); + } + } + TreeView_SelectItem(hLstView, TreeView_GetRoot(hLstView)); +} + +void OptionsDialogType::InitDialog(void) +{ + TranslateDialogDefault(m_hwndDialog); + + CheckDlgButton(m_hwndDialog, IDC_PLUGENABLED, opt.PluginSupportEnabled ? BST_UNCHECKED : BST_CHECKED); + CheckDlgButton(m_hwndDialog, IDC_SPACES, opt.EnforceSpaces ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_SCALETOTEXTHEIGHT, opt.ScaleToTextheight ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_USESTDPACK, opt.UseOneForAll ? BST_UNCHECKED : BST_CHECKED); + CheckDlgButton(m_hwndDialog, IDC_APPENDSPACES, opt.SurroundSmileyWithSpaces ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_SCALEALLSMILEYS, opt.ScaleAllSmileys ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_IEVIEWSTYLE, opt.IEViewStyle ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_ANIMATESEL, opt.AnimateSel ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_ANIMATEDLG, opt.AnimateDlg ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_INPUTSMILEYS, opt.InputSmileys ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_DCURSORSMILEY, opt.DCursorSmiley ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_DISABLECUSTOM, opt.DisableCustom ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwndDialog, IDC_HQSCALING, opt.HQScaling ? BST_CHECKED : BST_UNCHECKED); + + SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_ADDSTRING, 0, (LPARAM) TranslateT("Off")); + SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_ADDSTRING, 0, (LPARAM) TranslateT("Top")); + + if (IsOldSrmm()) + SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_ADDSTRING, 0, (LPARAM) TranslateT("Bottom")); + + SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_SETCURSEL, opt.ButtonStatus, 0); + EnableWindow(GetDlgItem(m_hwndDialog, IDC_SMLBUT), opt.PluginSupportEnabled); + + SendDlgItemMessage(m_hwndDialog, IDC_MAXCUSTSPIN, UDM_SETRANGE32, 0, 99); + SendDlgItemMessage(m_hwndDialog, IDC_MAXCUSTSPIN, UDM_SETPOS, 0, opt.MaxCustomSmileySize); + SendDlgItemMessage(m_hwndDialog, IDC_MAXCUSTSMSZ, EM_LIMITTEXT, 2, 0); + + SendDlgItemMessage(m_hwndDialog, IDC_MINSPIN, UDM_SETRANGE32, 0, 99); + SendDlgItemMessage(m_hwndDialog, IDC_MINSPIN, UDM_SETPOS, 0, opt.MinSmileySize); + SendDlgItemMessage(m_hwndDialog, IDC_MINSMSZ, EM_LIMITTEXT, 2, 0); + + SendDlgItemMessage(m_hwndDialog, IDC_SELCLR, CPM_SETCOLOUR, 0, opt.SelWndBkgClr); + SendDlgItemMessage(m_hwndDialog, IDC_SELCLR, CPM_SETDEFAULTCOLOUR, 0, GetSysColor(COLOR_WINDOW)); + + // Create and populate image list + HIMAGELIST hImList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, g_SmileyCategories.NumberOfSmileyCategories(), 0); + + tmpsmcat = g_SmileyCategories; + + SmileyCategoryListType::SmileyCategoryVectorType& smc = *g_SmileyCategories.GetSmileyCategoryList(); + for (int i = 0; i < smc.getCount(); i++) + { + HICON hIcon = NULL; + if (smc[i].IsProto()) + { + hIcon=(HICON)CallProtoService(T2A_SM(smc[i].GetName().c_str()), PS_LOADICON, + PLI_PROTOCOL | PLIF_SMALL, 0); + if (hIcon == NULL || (INT_PTR)hIcon == CALLSERVICE_NOTFOUND) + { + hIcon=(HICON)CallProtoService(T2A_SM(smc[i].GetName().c_str()), PS_LOADICON, PLI_PROTOCOL, 0); + } + } + if (hIcon == NULL || hIcon == (HICON)CALLSERVICE_NOTFOUND) + hIcon = GetDefaultIcon(); + + ImageList_AddIcon(hImList, hIcon); + DestroyIcon(hIcon); + } + + HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); + TreeView_SetImageList(hLstView, hImList, TVSIL_NORMAL); + + PopulateSmPackList(); +} + +void OptionsDialogType::DestroyDialog(void) +{ + HWND hLstView = GetDlgItem(m_hwndDialog, IDC_CATEGORYLIST); + HIMAGELIST hImList = TreeView_SetImageList(hLstView, NULL, TVSIL_NORMAL); + ImageList_Destroy(hImList); +} + + +void OptionsDialogType::ApplyChanges(void) +{ + ProcessAllInputAreas(true); + CloseSmileys(); + + opt.PluginSupportEnabled = IsDlgButtonChecked(m_hwndDialog, IDC_PLUGENABLED) == BST_UNCHECKED; + opt.EnforceSpaces = IsDlgButtonChecked(m_hwndDialog, IDC_SPACES) == BST_CHECKED; + opt.ScaleToTextheight = IsDlgButtonChecked(m_hwndDialog, IDC_SCALETOTEXTHEIGHT) == BST_CHECKED; + opt.UseOneForAll = IsDlgButtonChecked(m_hwndDialog, IDC_USESTDPACK) == BST_UNCHECKED; + opt.SurroundSmileyWithSpaces = IsDlgButtonChecked(m_hwndDialog, IDC_APPENDSPACES) == BST_CHECKED; + opt.ScaleAllSmileys = IsDlgButtonChecked(m_hwndDialog, IDC_SCALEALLSMILEYS) == BST_CHECKED; + opt.IEViewStyle = IsDlgButtonChecked(m_hwndDialog, IDC_IEVIEWSTYLE) == BST_CHECKED; + opt.AnimateSel = IsDlgButtonChecked(m_hwndDialog, IDC_ANIMATESEL) == BST_CHECKED; + opt.AnimateDlg = IsDlgButtonChecked(m_hwndDialog, IDC_ANIMATEDLG) == BST_CHECKED; + opt.InputSmileys = IsDlgButtonChecked(m_hwndDialog, IDC_INPUTSMILEYS) == BST_CHECKED; + opt.DCursorSmiley = IsDlgButtonChecked(m_hwndDialog, IDC_DCURSORSMILEY) == BST_CHECKED; + opt.DisableCustom = IsDlgButtonChecked(m_hwndDialog, IDC_DISABLECUSTOM) == BST_CHECKED; + opt.HQScaling = IsDlgButtonChecked(m_hwndDialog, IDC_HQSCALING) == BST_CHECKED; + + opt.ButtonStatus = (unsigned)SendDlgItemMessage(m_hwndDialog, IDC_SMLBUT, CB_GETCURSEL, 0, 0); + opt.SelWndBkgClr = (unsigned)SendDlgItemMessage(m_hwndDialog, IDC_SELCLR, CPM_GETCOLOUR, 0, 0); + opt.MaxCustomSmileySize = GetDlgItemInt(m_hwndDialog, IDC_MAXCUSTSMSZ, NULL, FALSE); + opt.MinSmileySize = GetDlgItemInt(m_hwndDialog, IDC_MINSMSZ, NULL, FALSE); + + opt.Save(); + + // Cleanup database + SmileyCategoryListType::SmileyCategoryVectorType& smc = *g_SmileyCategories.GetSmileyCategoryList(); + for (int i = 0; i < smc.getCount(); i++) + { + if (tmpsmcat.GetSmileyCategory(smc[i].GetName()) == NULL) + { + bkstring empty; + opt.WritePackFileName(empty, smc[i].GetName()); + } + } + + g_SmileyCategories = tmpsmcat; + g_SmileyCategories.SaveSettings(); + g_SmileyCategories.ClearAndLoadAll(); + + smPack.LoadSmileyFile(tmpsmcat.GetSmileyCategory(GetSelProto())->GetFilename(), false); + + NotifyEventHooks(hEvent1, 0, 0); + ProcessAllInputAreas(false); +} + +bool OptionsDialogType::BrowseForSmileyPacks(int item) +{ + OPENFILENAME ofn = {0}; + + TCHAR filename[MAX_PATH] = _T(""); + ofn.lpstrFile = filename; + ofn.nMaxFile = SIZEOF(filename); + + bkstring inidir; + SmileyCategoryType* smc = tmpsmcat.GetSmileyCategory(item); + if (smc->GetFilename().empty()) + { + pathToAbsolute(_T("Smileys"), inidir); + } + else + { + pathToAbsolute(smc->GetFilename(), inidir); + inidir.erase(inidir.find_last_of('\\')); + } + + ofn.lpstrInitialDir = inidir.c_str(); + ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + ofn.hwndOwner = m_hwndDialog; + + TCHAR filter[512], *pfilter; + _tcscpy(filter, TranslateT("Smiley Packs")); + lstrcat(filter, _T(" (*.msl;*.asl;*.xep)")); + pfilter = filter + _tcslen(filter) + 1; + _tcscpy(pfilter, _T("*.msl;*.asl;*.xep")); + pfilter = pfilter + _tcslen(pfilter) + 1; + _tcscpy(pfilter, TranslateT("All Files")); + lstrcat(pfilter, _T(" (*.*)")); + pfilter = pfilter + _tcslen(pfilter) + 1; + _tcscpy(pfilter, _T("*.*")); + pfilter = pfilter + _tcslen(pfilter) + 1; + *pfilter = '\0'; + ofn.lpstrFilter = filter; + + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_READONLY | + OFN_EXPLORER | OFN_LONGNAMES | OFN_NOCHANGEDIR; + ofn.lpstrDefExt = _T("msl"); + + if (GetOpenFileName(&ofn)) + { + bkstring relpath; + pathToRelative(filename, relpath); + smc->SetFilename(relpath); + + return true; + } + + return false; +} + +void OptionsDialogType::FilenameChanged(void) +{ + TCHAR str[MAX_PATH]; + GetDlgItemText(m_hwndDialog, IDC_FILENAME, str, SIZEOF(str)); + + SmileyCategoryType* smc = tmpsmcat.GetSmileyCategory(GetSelProto()); + if (smc->GetFilename() != str) + { + bkstring temp(str); + smc->SetFilename(temp); + UpdateControls(); + } +} + +void OptionsDialogType::ShowSmileyPreview(void) +{ + RECT rect; + GetWindowRect(GetDlgItem(m_hwndDialog, IDC_SMLOPTBUTTON), &rect); + + SmileyToolWindowParam *stwp = new SmileyToolWindowParam; + stwp->pSmileyPack = &smPack; + stwp->hWndParent = m_hwndDialog; + stwp->hWndTarget = NULL; + stwp->targetMessage = 0; + stwp->targetWParam = 0; + stwp->xPosition = rect.left; + stwp->yPosition = rect.bottom + 4; + stwp->direction = 1; + stwp->hContact = NULL; + + mir_forkthread(SmileyToolThread, stwp); +} + + +void OptionsType::Save(void) +{ + DBWriteContactSettingByte(NULL, "SmileyAdd", "PluginSupportEnabled", PluginSupportEnabled); + DBWriteContactSettingByte(NULL, "SmileyAdd", "EnforceSpaces", EnforceSpaces); + DBWriteContactSettingByte(NULL, "SmileyAdd", "ScaleToTextheight", ScaleToTextheight); + DBWriteContactSettingByte(NULL, "SmileyAdd", "UseOneForAll", UseOneForAll); + DBWriteContactSettingByte(NULL, "SmileyAdd", "SurroundSmileyWithSpaces", SurroundSmileyWithSpaces); + DBWriteContactSettingByte(NULL, "SmileyAdd", "ScaleAllSmileys", ScaleAllSmileys); + DBWriteContactSettingByte(NULL, "SmileyAdd", "IEViewStyle", IEViewStyle); + DBWriteContactSettingByte(NULL, "SmileyAdd", "AnimateSel", AnimateSel); + DBWriteContactSettingByte(NULL, "SmileyAdd", "AnimateDlg", AnimateDlg); + DBWriteContactSettingByte(NULL, "SmileyAdd", "InputSmileys", InputSmileys); + DBWriteContactSettingByte(NULL, "SmileyAdd", "DCursorSmiley", DCursorSmiley); + DBWriteContactSettingByte(NULL, "SmileyAdd", "DisableCustom", DisableCustom); + DBWriteContactSettingByte(NULL, "SmileyAdd", "HQScaling", HQScaling); + DBWriteContactSettingByte(NULL, "SmileyAdd", "ButtonStatus", (BYTE)ButtonStatus); + DBWriteContactSettingDword(NULL, "SmileyAdd", "SelWndBkgClr", SelWndBkgClr); + DBWriteContactSettingDword(NULL, "SmileyAdd", "MaxCustomSmileySize", MaxCustomSmileySize); + DBWriteContactSettingDword(NULL, "SmileyAdd", "MinSmileySize", MinSmileySize); +} + + +void OptionsType::Load(void) +{ + PluginSupportEnabled = DBGetContactSettingByte(NULL, "SmileyAdd", "PluginSupportEnabled", TRUE) != 0; + EnforceSpaces = DBGetContactSettingByte(NULL, "SmileyAdd", "EnforceSpaces", FALSE) != 0; + ScaleToTextheight = DBGetContactSettingByte(NULL, "SmileyAdd", "ScaleToTextheight", FALSE) != 0; + UseOneForAll = DBGetContactSettingByte(NULL, "SmileyAdd", "UseOneForAll", TRUE) != 0; + SurroundSmileyWithSpaces = + DBGetContactSettingByte(NULL, "SmileyAdd", "SurroundSmileyWithSpaces", FALSE) != 0; + ScaleAllSmileys = DBGetContactSettingByte(NULL, "SmileyAdd", "ScaleAllSmileys", FALSE) != 0; + IEViewStyle = DBGetContactSettingByte(NULL, "SmileyAdd", "IEViewStyle", FALSE) != 0; + AnimateSel = DBGetContactSettingByte(NULL, "SmileyAdd", "AnimateSel", TRUE) != 0; + AnimateDlg = DBGetContactSettingByte(NULL, "SmileyAdd", "AnimateDlg", TRUE) != 0; + InputSmileys = DBGetContactSettingByte(NULL, "SmileyAdd", "InputSmileys", TRUE) != 0; + DCursorSmiley = DBGetContactSettingByte(NULL, "SmileyAdd", "DCursorSmiley", FALSE) != 0; + DisableCustom = DBGetContactSettingByte(NULL, "SmileyAdd", "DisableCustom", FALSE) != 0; + HQScaling = DBGetContactSettingByte(NULL, "SmileyAdd", "HQScaling", FALSE) != 0; + + ButtonStatus = DBGetContactSettingByte(NULL, "SmileyAdd", "ButtonStatus", 1); + SelWndBkgClr = DBGetContactSettingDword(NULL, "SmileyAdd", "SelWndBkgClr", GetSysColor(COLOR_WINDOW)); + MaxCustomSmileySize = DBGetContactSettingDword(NULL, "SmileyAdd", "MaxCustomSmileySize", 0); + MinSmileySize = DBGetContactSettingDword(NULL, "SmileyAdd", "MinSmileySize", 0); +} + + +void OptionsType::ReadPackFileName(bkstring& filename, const bkstring& name, + const bkstring& defaultFilename) +{ + DBVARIANT dbv; + bkstring settingKey = name + _T("-filename"); + + INT_PTR res = DBGetContactSettingTString(NULL, "SmileyAdd", T2A_SM(settingKey.c_str()), &dbv); + if (res == 0) + { + filename = dbv.ptszVal; + DBFreeVariant(&dbv); + } + else + filename = defaultFilename; +} + + +void OptionsType::WritePackFileName(const bkstring& filename, const bkstring& name) +{ + bkstring settingKey = name + _T("-filename"); + DBWriteContactSettingTString(NULL, "SmileyAdd", T2A_SM(settingKey.c_str()), + filename.c_str()); +} + + +void OptionsType::ReadCustomCategories(bkstring& cats) +{ + DBVARIANT dbv; + + INT_PTR res = DBGetContactSettingTString(NULL, "SmileyAdd", "CustomCategories", &dbv); + if (res == 0) + { + cats = dbv.ptszVal; + DBFreeVariant(&dbv); + } +} + + +void OptionsType::WriteCustomCategories(const bkstring& cats) +{ + if (cats.empty()) + DBDeleteContactSetting(NULL, "SmileyAdd", "CustomCategories"); + else + DBWriteContactSettingTString(NULL, "SmileyAdd", "CustomCategories", cats.c_str()); +} + + +void OptionsType::ReadContactCategory(HANDLE hContact, bkstring& cats) +{ + DBVARIANT dbv; + + INT_PTR res = DBGetContactSettingTString(hContact, "SmileyAdd", "CustomCategory", &dbv); + if (res == 0) + { + cats = dbv.ptszVal; + DBFreeVariant(&dbv); + } +} + + +void OptionsType::WriteContactCategory(HANDLE hContact, const bkstring& cats) +{ + if (cats.empty()) + DBDeleteContactSetting(hContact, "SmileyAdd", "CustomCategory"); + else + DBWriteContactSettingTString(hContact, "SmileyAdd", "CustomCategory", cats.c_str()); +} diff --git a/plugins/SmileyAdd/src/options.h b/plugins/SmileyAdd/src/options.h new file mode 100644 index 0000000000..3b83b0dc8f --- /dev/null +++ b/plugins/SmileyAdd/src/options.h @@ -0,0 +1,60 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef SMILEYADD_OPTIONS_H_ +#define SMILEYADD_OPTIONS_H_ + +int SmileysOptionsInitialize(WPARAM wParam, LPARAM lParam); + +class OptionsType +{ +public: + bool PluginSupportEnabled; + bool EnforceSpaces; + bool ScaleToTextheight; + bool UseOneForAll; + bool SurroundSmileyWithSpaces; + bool ScaleAllSmileys; + bool IEViewStyle; + bool AnimateSel; + bool AnimateDlg; + bool InputSmileys; + bool DCursorSmiley; + bool DisableCustom; + bool HQScaling; + unsigned ButtonStatus; + unsigned SelWndBkgClr; + unsigned MaxCustomSmileySize; + unsigned MinSmileySize; + + void Load(void); + void Save(void); + static void ReadPackFileName(bkstring& filename, const bkstring& name, + const bkstring& defaultFilename); + static void ReadCustomCategories(bkstring& cats); + static void ReadContactCategory(HANDLE hContact, bkstring& cats); + static void WritePackFileName(const bkstring& filename, const bkstring& name); + static void WriteCustomCategories(const bkstring& cats); + static void WriteContactCategory(HANDLE hContact, const bkstring& cats); +}; + +extern OptionsType opt; + +#endif // SMILEYADD_OPTIONS_H_ + diff --git a/plugins/SmileyAdd/src/regexp/Matcher.cpp b/plugins/SmileyAdd/src/regexp/Matcher.cpp new file mode 100644 index 0000000000..ebd1f57850 --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/Matcher.cpp @@ -0,0 +1,178 @@ +#include +#include + +const int Matcher::MATCH_ENTIRE_STRING = 0x01; + +/* + Detailed documentation is provided in this class' header file + + @author Jeffery Stuart + @since November 2004 + @version 1.07.00 +*/ + +Matcher::Matcher(Pattern * pattern, const bkstring & text) +{ + pat = pattern; + str = &text; + gc = pattern->groupCount; + ncgc = -pattern->nonCapGroupCount; + flags = 0; + matchedSomething = false; + starts = new int[gc + ncgc]; + ends = new int[gc + ncgc]; + groups = new int[gc + ncgc]; + groupPos = new int[gc + ncgc]; + groupIndeces = new int[gc + ncgc]; + starts = starts + ncgc; + ends = ends + ncgc; + groups = groups + ncgc; + groupPos = groupPos + ncgc; + groupIndeces = groupIndeces + ncgc; + for (int i = 0; i < gc; ++i) starts[i] = ends[i] = 0; +} +Matcher::~Matcher() +{ + delete [] (starts - ncgc); + delete [] (ends - ncgc); + delete [] (groups - ncgc); + delete [] (groupIndeces - ncgc); + delete [] (groupPos - ncgc); +} +void Matcher::clearGroups() +{ + int i; + lm = 0; + for (i = 0; i < gc; ++i) groups[i] = starts[i] = ends[i] = -1; + for (i = 1; i <= ncgc; ++i) groups[0 - i] = -1; +} +bkstring Matcher::replaceWithGroups(const bkstring & str) +{ + bkstring ret = ""; + + bkstring t = str; + while (t.size() > 0) + { + if (t[0] == '\\') + { + t.erase(0, 1); + if (t.size() == 0) + { + ret += "\\"; + } + else if (t[0] < '0' || t[0] > '9') + { + ret += t[0]; + t.erase(0, 1); + } + else + { + int gn = 0; + while (t.size() > 0 && t[0] >= '0' && t[0] <= '9') + { + gn = gn * 10 + (t[0] - '0'); + t.erase(0, 1); + } + ret += getGroup(gn); + } + } + else + { + ret += t[0]; + t.erase(0, 1); + } + } + + return ret; +} +unsigned long Matcher::getFlags() const +{ + return flags; +} +const bkstring& Matcher::getText() const +{ + return *str; +} + +bool Matcher::matches() +{ + flags = MATCH_ENTIRE_STRING; + matchedSomething = false; + clearGroups(); + lm = 0; + return pat->head->match(*str, this, 0) == (int)str->size(); +} +bool Matcher::findFirstMatch() +{ + starts[0] = 0; + flags = 0; + clearGroups(); + start = 0; + lm = 0; + ends[0] = pat->head->match(*str, this, 0); + if (ends[0] >= 0) + { + matchedSomething = true; + return 1; + } + return 0; +} +bool Matcher::findNextMatch() +{ + int s = starts[0], e = ends[0]; + + if (!matchedSomething) return findFirstMatch(); + if (s == e) ++e; + flags = 0; + clearGroups(); + + starts[0] = e; + if (e >= (int)str->size()) return 0; + start = e; + lm = e; + ends[0] = pat->head->match(*str, this, e); + return ends[0] >= 0; +} +std::vector Matcher::findAll() +{ + std::vector ret; + reset(); + while (findNextMatch()) + { + ret.push_back(getGroup()); + } + return ret; +} + +void Matcher::reset() +{ + lm = 0; + clearGroups(); + matchedSomething = false; +} + +int Matcher::getStartingIndex(const int groupNum) const +{ + if (groupNum < 0 || groupNum >= gc) return -1; + return starts[groupNum]; +} +int Matcher::getEndingIndex(const int groupNum) const +{ + if (groupNum < 0 || groupNum >= gc) return -1; + return ends[groupNum]; +} +bkstring Matcher::getGroup(const int groupNum) const +{ + if (groupNum < 0 || groupNum >= gc) return ""; + if (starts[groupNum] < 0 || ends[groupNum] < 0) return ""; + return str->substr(starts[groupNum], ends[groupNum] - starts[groupNum]); +} +std::vector Matcher::getGroups(const bool includeGroupZero) const +{ + int i, start = (includeGroupZero ? 0 : 1); + std::vector ret; + + for (i = start; i < gc; ++i) ret.push_back(getGroup(i)); + return ret; +} + diff --git a/plugins/SmileyAdd/src/regexp/Matcher.h b/plugins/SmileyAdd/src/regexp/Matcher.h new file mode 100644 index 0000000000..621184d8c2 --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/Matcher.h @@ -0,0 +1,248 @@ +#ifndef __MATCHER_H__ +#define __MATCHER_H__ + +#include "bkstring.h" +#include + +class Vector; +class NFANode; +class NFAStartNode; +class NFAEndNode; +class NFAGroupHeadNode; +class NFAGroupLoopNode; +class NFAGroupLoopPrologueNode; +class NFAGroupTailNode; +class NFALookBehindNode; +class NFAStartOfLineNode; +class NFAEndOfLineNode; +class NFAEndOfMatchNode; +class NFAReferenceNode; +class Pattern; + +/** + A matcher is a non thread-safe object used to scan strings using a given + {@link Pattern Pattern} object. Using a Matcher is the preferred + method for scanning strings. Matchers are not thread-safe. Matchers require + very little dynamic memory, hence one is encouraged to create several + instances of a matcher when necessary as opposed to sharing a single instance + of a matcher. +

+ The most common methods needed by the matcher are matches, + findNextMatch, and getGroup. matches + and findNextMatch both return success or failure, and further + details can be gathered from their documentation. +

+ Unlike Java's Matcher, this class allows you to change the string + you are matching against. This provides a small optimization, since you no + longer need multiple matchers for a single pattern in a single thread. +

+ This class also provides an extremely handy method for replacing text with + captured data via the replaceWithGroups method. A typical + invocation looks like: +

+  char buf[10000];
+  bkstring str = "\\5 (user name \\1) uses \\7 for his/her shell and \\6 is their home directory";
+  FILE * fp = fopen("/etc/passwd", "r");
+  Pattern::registerPattern("entry", "[^:]+");
+  Pattern * p = Pattern::compile("^({entry}):({entry}):({entry}):({entry}):({entry}):({entry}):({entry})$",
+                                 Pattern::MULTILINE_MATCHING | Pattern::UNIX_LINE_MODE);
+  Matcher * m = p->createMatcher("");
+  while (fgets(buf, 9999, fp))
+  {
+    m->setString(buf);
+    if (m->matches())
+    {
+      printf("%s\n", m->replaceWithGroups(str).c_str());
+    }
+  }
+  fclose(fp);
+
+  
+ Calling any of the following functions before first calling + matches, findFirstMatch, or + findNextMatch results in undefined behavior and may cause your + program to crash. + +
    +
  • replaceWithGroups +
  • getStartingIndex
  • +
  • getEndingIndex
  • +
  • getGroup
  • +
  • getGroups
  • +
+
+

+ The function findFirstMatch will attempt to find the first match + in the input string. The same results can be obtained by first calling + reset followed by findNextMatch. +

+ To eliminate the necessity of looping through a string to find all the + matching substrings, findAll was created. The function will find + all matching substrings and return them in a vector. If you need + to examine specific capture groups within the substrings, then this method + should not be used. + + @author Jeffery Stuart + @since March 2003, Stable Since November 2004 + @version 1.07.00 + @memo Mutable object used on instances of a Pattern class + */ +class Matcher +{ + friend class NFANode; + friend class NFAStartNode; + friend class NFAEndNode; + friend class NFAGroupHeadNode; + friend class NFAGroupLoopNode; + friend class NFAGroupLoopPrologueNode; + friend class NFAGroupTailNode; + friend class NFALookBehindNode; + friend class NFAStartOfLineNode; + friend class NFAEndOfLineNode; + friend class NFAEndOfMatchNode; + friend class NFAReferenceNode; + friend class Pattern; + private: + /** + Creates a new matcher object against text using + pattern. + + @param pattern The pattern with which to search + @param text The text in which to search + */ + Matcher(Pattern * pattern, const bkstring & text); + protected: + /// The pattern we use to match + Pattern * pat; + /// The string in which we are matching + const bkstring* str; + /// The starting point of our match + int start; + /// An array of the starting positions for each group + int * starts; + /// An array of the ending positions for each group + int * ends; + /// An array of private data used by NFANodes during matching + int * groups; + /// An array of private data used by NFANodes during matching + int * groupIndeces; + /// An array of private data used by NFANodes during matching + int * groupPos; + /// The ending index of the last match + int lm; + /// The number of capturing groups we have + int gc; + /// The number of non-capturing groups we havew + int ncgc; + /// Whether or not we have matched something (used only by findFirstMatch and findNextMatch) + int matchedSomething; + /// The flags with which we were made + unsigned long flags; + /// Called by reset to clear the group arrays + void clearGroups(); + public: + /// Used internally by match to signify we want the entire string matched + const static int MATCH_ENTIRE_STRING; + public: + /// Cleans up the dynamic memory used by this matcher + ~Matcher(); + /** + Replaces the contents of str with the appropriate captured + text. str should have at least one back reference, otherwise + this function does nothing. + @param str The string in which to replace text + @return A string with all backreferences appropriately replaced + */ + bkstring replaceWithGroups(const bkstring & str); + /** + The flags currently being used by the matcher. + @return Zero + */ + unsigned long getFlags() const; + /** + The text being searched by the matcher. + @return the text being searched by the matcher. + */ + const bkstring& getText() const; + + /** + Scans the string from start to finish for a match. The entire string must + match for this function to return success. Group variables are + appropriately set and can be queried after this function returns. + + @return Success if and only if the entire string matches the pattern + */ + bool matches(); + /** + Scans the string for the first substring matching the pattern. The entire + string does not necessarily have to match for this function to return + success. Group variables are appropriately set and can be queried after + this function returns. + + @return Success if any substring matches the specified pattern + */ + bool findFirstMatch(); + /** + Scans the string for the next substring matching the pattern. If no calls + have been made to findFirstMatch of findNextMatch since the last call to + reset, matches, or setString, then this function's behavior results to + that of findFirstMatch. + + @return Success if another substring can be found that matches the pattern + */ + bool findNextMatch(); + /** + Returns a vector of every substring in order which matches the given + pattern. + + @return Every substring in order which matches the given pattern + */ + std::vector findAll(); + /** + Resets the internal state of the matcher + */ + void reset(); + /** + Same as getText. Left n for backwards compatibilty with old source code + @return Returns the string that is currently being used for matching + */ + inline const bkstring& getString() const { return *str; } + /** + Sets the string to scan + @param newStr The string to scan for subsequent matches + */ + inline void setString(const bkstring & newStr) { str = &newStr; reset(); } + + /** + Returns the starting index of the specified group. + @param groupNum The group to query + @return The starting index of the group if it was matched, -1 for an + invalid group or if the group was not matched + */ + int getStartingIndex(const int groupNum = 0) const; + /** + Returns the ending index of the specified group. + @param groupNum The group to query + @return The ending index of the group if it was matched, -1 for an + invalid group or if the group was not matched + */ + int getEndingIndex(const int groupNum = 0) const; + /** + Returns the specified group. An empty string ("") does not necessarily + mean the group was not matched. A group such as (a*b?) could be matched by + a zero length. If an empty string is returned, getStartingIndex can be + called to determine if the group was actually matched. + @param groupNum The group to query + @return The text of the group + */ + bkstring getGroup(const int groupNum = 0) const; + /** + Returns every capture group in a vector + + @param includeGroupZero Whether or not include capture group zero + @return Every capture group + */ + std::vector getGroups(const bool includeGroupZero = 0) const; +}; + +#endif diff --git a/plugins/SmileyAdd/src/regexp/Pattern.cpp b/plugins/SmileyAdd/src/regexp/Pattern.cpp new file mode 100644 index 0000000000..4487dddd4b --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/Pattern.cpp @@ -0,0 +1,1709 @@ +/** + From the author (Jeff Stuart) + " + Let me start by saying this file is pretty big. If you feel up to it, you can + try making changes yourself, but you would be better off to just email me at + stuart@cs.ucdavis.edu if you think there is a bug, or have something useful you + would like added. This project is very "near and dear" to me, so I am fairly + quick to make bug fixes. The header files for Pattern and Matcher are fairly + well documented and the function names are pretty self-explanatory, but if you + are having any trouble, feel free to email me at stuart@cs.ucdavis.edu. + + If you email me, make sure you put something like C++RE in the subject because + I tend to delete email if I don't recognize the name and the subject is + something like "I Need Your Help" or "Got A Second" or "I Found It". + " + */ + +/* + Detailed documentation is provided in this class' header file + + @author Jeffery Stuart + @since November 2004 + @version 1.07.00 +*/ + +#define to_lower(a) (char)(unsigned)CharLowerA((LPSTR)static_cast(a)) +#define is_alpha IsCharAlphaA + +#ifdef _WIN32 + #pragma warning(push) + #pragma warning(disable:4996) + #define str_icmp lstrcmpiA +#else + #define str_icmp strcasecmp +#endif + +#include +#include +#include +#include + +std::map Pattern::compiledPatterns; +std::map > Pattern::registeredPatterns; + +const int Pattern::MIN_QMATCH = 0x00000000; +const int Pattern::MAX_QMATCH = 0x7FFFFFFF; + +const unsigned long Pattern::CASE_INSENSITIVE = 0x01; +const unsigned long Pattern::LITERAL = 0x02; +const unsigned long Pattern::DOT_MATCHES_ALL = 0x04; +const unsigned long Pattern::MULTILINE_MATCHING = 0x08; +const unsigned long Pattern::UNIX_LINE_MODE = 0x10; + +Pattern::Pattern(const bkstring & rhs) +{ + matcher = NULL; + pattern = rhs; + curInd = 0; + groupCount = 0; + nonCapGroupCount = 0; + error = 0; + head = NULL; +} +// convenience function in case we want to add any extra debugging output +void Pattern::raiseError() +{ +/* switch (pattern[curInd - 1]) + { + case '*': + case ')': + case '+': + case '?': + case ']': + case '}': + fprintf(stderr, "%s\n%*c^\n", pattern.c_str(), curInd - 1, ' '); + fprintf(stderr, "Syntax Error near here. Possible unescaped meta character.\n"); + break; + default: + fprintf(stderr, "%s\n%*c^\n", pattern.c_str(), curInd - 1, ' '); + fprintf(stderr, "Syntax Error near here. \n"); + break; + }*/ + error = 1; +} +NFANode * Pattern::registerNode(NFANode * node) +{ + nodes[node] = 1; + return node; +} + +bkstring Pattern::classUnion (bkstring s1, bkstring s2) const +{ + char out[300]; + std::sort(s1.begin(), s1.end()); + std::sort(s2.begin(), s2.end()); + *std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), out) = 0; + return out; +} +bkstring Pattern::classIntersect (bkstring s1, bkstring s2) const +{ + char out[300]; + std::sort(s1.begin(), s1.end()); + std::sort(s2.begin(), s2.end()); + *std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), out) = 0; + return out; +} +bkstring Pattern::classNegate (bkstring s1) const +{ + char out[300]; + int i, ind = 0; + std::map m; + + for (i = 0; i < (int)s1.size(); ++i) m[s1[i]] = 1; + for (i = 0xFF; i >= 0; --i) if (m.find((char)i) == m.end()) out[ind++] = (char)i; + out[ind] = 0; + return bkstring(out, ind); +} +bkstring Pattern::classCreateRange(char low, char hi) const +{ + char out[300]; + int ind = 0; + while (low != hi) out[ind++] = low++; + out[ind++] = low; + return bkstring(out, ind); +} + +int Pattern::getInt(int start, int end) +{ + int ret = 0; + for (; start <= end; ++start) ret = ret * 10 + (pattern[start] - '0'); + return ret; +} +bool Pattern::quantifyCurly(int & sNum, int & eNum) +{ + bool good = 1; + int i, ci = curInd + 1; + int commaInd = ci, endInd = ci, len = (int)pattern.size(); + sNum = eNum = 0; + + while (endInd < len && pattern[endInd ] != '}') ++endInd; + while (commaInd < endInd && pattern[commaInd] != ',') ++commaInd; + if (endInd >= len) { raiseError(); return 0; } + for (i = ci; good && i < endInd; ++i) if (i != commaInd && !isdigit(pattern[i])) good = 0; + if (!good && commaInd < endInd) { raiseError(); return 0; } + if (!good) return 0; + /* so now everything in here is either a comma (and there is at most one comma) or a digit */ + if (commaInd == ci) // {,*} + { + if (endInd == commaInd + 1) { sNum = MIN_QMATCH; eNum = MAX_QMATCH; } // {,} = * + else { sNum = MIN_QMATCH; eNum = getInt(commaInd + 1, endInd - 1); } // {,+} + } + else if (commaInd == endInd - 1) { sNum = getInt(ci, commaInd - 1); eNum = MAX_QMATCH; } // {+,} + else if (commaInd == endInd) { sNum = getInt(ci, endInd - 1); eNum = sNum; } // {+} + else { sNum = getInt(ci, commaInd - 1); eNum = getInt(commaInd + 1, endInd - 1); } // {+,+} + curInd = endInd + 1; + return 1; +} +NFANode * Pattern::quantifyGroup(NFANode * start, NFANode * stop, const int gn) +{ + NFANode * newNode = NULL; + int type = 0; + + if (curInd < (int)pattern.size()) + { + char ch = (curInd + 1 >= (int)pattern.size()) ? -1 : pattern[curInd + 1]; + switch (pattern[curInd]) + { + case '*': + ++curInd; + switch (ch) + { + case '?': ++curInd; type = 1; break; + case '+': ++curInd; type = 2; break; + } + newNode = registerNode(new NFAGroupLoopPrologueNode(gn)); + newNode->next = registerNode(new NFAGroupLoopNode(start, MIN_QMATCH, MAX_QMATCH, gn, type)); + stop->next = newNode->next; + return newNode; + case '?': + ++curInd; + switch (ch) + { + case '?': ++curInd; type = 1; break; + case '+': ++curInd; type = 2; break; + } + newNode = registerNode(new NFAGroupLoopPrologueNode(gn)); + newNode->next = registerNode(new NFAGroupLoopNode(start, MIN_QMATCH, 1, gn, type)); + stop->next = newNode->next; + return newNode; + case '+': + ++curInd; + switch (ch) + { + case '?': ++curInd; type = 1; break; + case '+': ++curInd; type = 2; break; + } + newNode = registerNode(new NFAGroupLoopPrologueNode(gn)); + newNode->next = registerNode(new NFAGroupLoopNode(start, 1, MAX_QMATCH, gn, type)); + stop->next = newNode->next; + return newNode; + case '{': + { + int s, e; + if (quantifyCurly(s, e)) + { + ch = (curInd < (int)pattern.size()) ? pattern[curInd] : -1; + switch (ch) + { + case '?': ++curInd; type = 1; break; + case '+': ++curInd; type = 2; break; + } + newNode = registerNode(new NFAGroupLoopPrologueNode(gn)); + newNode->next = registerNode(new NFAGroupLoopNode(start, s, e, gn, type)); + stop->next = newNode->next; + return newNode; + } + } + default: + break; + } + } + return NULL; +} + +NFANode * Pattern::quantify(NFANode * newNode) +{ + if (curInd < (int)pattern.size()) + { + char ch = (curInd + 1 >= (int)pattern.size()) ? -1 : pattern[curInd + 1]; + switch (pattern[curInd]) + { + case '*': + ++curInd; + switch (ch) + { + case '?': ++curInd; newNode = registerNode(new NFALazyQuantifierNode (this, newNode, MIN_QMATCH, MAX_QMATCH)); break; + case '+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierNode(this, newNode, MIN_QMATCH, MAX_QMATCH)); break; + default: newNode = registerNode(new NFAGreedyQuantifierNode (this, newNode, MIN_QMATCH, MAX_QMATCH)); break; + } + break; + case '?': + ++curInd; + switch (ch) + { + case '?': ++curInd; newNode = registerNode(new NFALazyQuantifierNode (this, newNode, MIN_QMATCH, 1)); break; + case '+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierNode(this, newNode, MIN_QMATCH, 1)); break; + default: newNode = registerNode(new NFAGreedyQuantifierNode (this, newNode, MIN_QMATCH, 1)); break; + } + break; + case '+': + ++curInd; + switch (ch) + { + case '?': ++curInd; newNode = registerNode(new NFALazyQuantifierNode (this, newNode, 1, MAX_QMATCH)); break; + case '+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierNode(this, newNode, 1, MAX_QMATCH)); break; + default: newNode = registerNode(new NFAGreedyQuantifierNode (this, newNode, 1, MAX_QMATCH)); break; + } + break; + case '{': + { + int s, e; + if (quantifyCurly(s, e)) + { + ch = (curInd < (int)pattern.size()) ? pattern[curInd] : -1; + switch (ch) + { + case '?': ++curInd; newNode = registerNode(new NFALazyQuantifierNode (this, newNode, s, e)); break; + case '+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierNode(this, newNode, s, e)); break; + default: newNode = registerNode(new NFAGreedyQuantifierNode (this, newNode, s, e)); break; + } + } + } + break; + default: + break; + } + } + return newNode; +} +bkstring Pattern::parseClass() +{ + bkstring t, ret = ""; + char ch, c1, c2; + bool inv = 0, neg = 0, quo = 0; + + if (curInd < (int)pattern.size() && pattern[curInd] == '^') + { + ++curInd; + neg = 1; + } + while (curInd < (int)pattern.size() && pattern[curInd] != ']') + { + ch = pattern[curInd++]; + if (ch == '[') + { + t = parseClass(); + ret = classUnion(ret, t); + } + /*else if (ch == '-') + { + raiseError(); + curInd = pattern.size(); + }*/ + else if (ch == '&' && curInd < (int)pattern.size() && pattern[curInd] == '&') + { + if (pattern[++curInd] != '[') + { + raiseError(); + curInd = (int)pattern.size(); + } + else + { + ++curInd; + t = parseClass(); + ret = classIntersect(ret, t); + } + } + else if (ch == '\\') + { + t = parseEscape(inv, quo); + if (quo) + { + raiseError(); + curInd = (int)pattern.size(); + } + else if (inv || t.size() > 1) // cant be part of a range (a-z) + { + if (inv) t = classNegate(t); + ret = classUnion(ret, t); + } + else if (curInd < (int)pattern.size() && pattern[curInd] == '-') // part of a range (a-z) + { + c1 = t[0]; + ++curInd; + if (curInd >= (int)pattern.size()) raiseError(); + else + { + c2 = pattern[curInd++]; + if (c2 == '\\') + { + t = parseEscape(inv, quo); + if (quo) + { + raiseError(); + curInd = (int)pattern.size(); + } + else if (inv || t.size() > 1) raiseError(); + else ret = classUnion(ret, classCreateRange(c1, c2)); + } + else if (c2 == '[' || c2 == ']' || c2 == '-' || c2 == '&') + { + raiseError(); + curInd = (int)pattern.size(); + } + else ret = classUnion(ret, classCreateRange(c1, c2)); + } + } + else + { + ret = classUnion(ret, t); + } + } + else if (curInd < (int)pattern.size() && pattern[curInd] == '-') + { + c1 = ch; + ++curInd; + if (curInd >= (int)pattern.size()) raiseError(); + else + { + c2 = pattern[curInd++]; + if (c2 == '\\') + { + t = parseEscape(inv, quo); + if (quo) + { + raiseError(); + curInd = (int)pattern.size(); + } + else if (inv || t.size() > 1) raiseError(); + else ret = classUnion(ret, classCreateRange(c1, c2)); + } + else if (c2 == '[' || c2 == ']' || c2 == '-' || c2 == '&') + { + raiseError(); + curInd = (int)pattern.size(); + } + else + { + ret = classUnion(ret, classCreateRange(c1, c2)); + } + } + } + else + { + ret += " "; + ret[ret.size() - 1] = ch; + } + } + if (curInd >= (int)pattern.size() || pattern[curInd] != ']') + { + raiseError(); + ret = ""; + } + else + { + ++curInd; + if (neg) ret = classNegate(ret); + } + return ret; +} +bkstring Pattern::parsePosix() +{ + bkstring s7 = pattern.substr(curInd, 7); + if (s7 == "{Lower}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyz"; } + if (s7 == "{Upper}") { curInd += 7; return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } + if (s7 == "{Alpha}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; } + if (s7 == "{Digit}") { curInd += 7; return "0123456789"; } + if (s7 == "{Alnum}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; } + if (s7 == "{Punct}") { curInd += 7; return "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } + if (s7 == "{Graph}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } + if (s7 == "{Print}") { curInd += 7; return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } + if (s7 == "{Blank}") { curInd += 7; return " \t"; } + if (s7 == "{Space}") { curInd += 7; return " \t\n\x0B\f\r"; } + if (s7 == "{Cntrl}") + { + bkstring::value_type i; + bkstring s = " "; + + for (i = 0; i < 5; ++i) s += s; + s += " "; + for (i = 0; i <= 0x1F; ++i) s[i] = i; + s[0x20] = 0x7F; + curInd += 7; + return s; + } + if (s7 == "{ASCII}") + { + bkstring s(0x80, ' '); + for (int i = 0; i <= 0x7f; ++i) s[i] = (bkstring::value_type)i; + curInd += 7; + return s; + } + if (pattern.substr(curInd, 8) == "{XDigit}") { curInd += 8; return "abcdefABCDEF0123456789"; } + raiseError(); + return ""; +} +NFANode * Pattern::parseBackref() +{ + #define is_dig(x) ((x) >= '0' && (x) <= '9') + #define to_int(x) ((x) - '0') + int ci = curInd; + int oldRef = 0, ref = 0; + + while (ci < (int)pattern.size() && is_dig(pattern[ci]) && (ref < 10 || ref < groupCount)) + { + oldRef = ref; + ref = ref * 10 + to_int(pattern[ci++]); + } + if (ci == (int)pattern.size()) + { + oldRef = ref; + ++ci; + } + if (oldRef < 0 || ci <= curInd) + { + raiseError(); + return registerNode(new NFAReferenceNode(-1)); + } + curInd = ci; + return registerNode(new NFAReferenceNode(ref)); + + #undef is_dig + #undef to_int +} +bkstring Pattern::parseOctal() +{ + #define islowoc(x) ((x) >= '0' && (x) <= '3') + #define isoc(x) ((x) >= '0' && (x) <= '7') + #define fromoc(x) ((x) - '0') + int ci = curInd; + char ch1 = (ci + 0 < (int)pattern.size()) ? pattern[ci + 0] : -1; + char ch2 = (ci + 1 < (int)pattern.size()) ? pattern[ci + 1] : -1; + char ch3 = (ci + 2 < (int)pattern.size()) ? pattern[ci + 2] : -1; + bkstring s = " "; + + if (islowoc(ch1) && isoc(ch2)) + { + curInd += 2; + s[0] = fromoc(ch1) * 8 + fromoc(ch2); + if (isoc(ch3)) + { + ++curInd; + s[0] = s[0] * 8 + fromoc(ch3); + } + } + else if (isoc(ch1) && isoc(ch2)) + { + curInd += 2; + s[0] = fromoc(ch1) * 8 + fromoc(ch2); + } + else raiseError(); + + return s; + #undef islowoc + #undef isoc + #undef fromoc +} +bkstring Pattern::parseHex() +{ + #define to_low(x) (((x) >= 'A' && (x) <= 'Z') ? ((x) - 'A' + 'a') : (x)) + #define is_dig(x) ((x) >= '0' && (x) <= '9') + #define is_hex(x) (is_dig(x) || (to_low(x) >= 'a' && to_low(x) <= 'f')) + #define to_int(x) ((is_dig(x)) ? ((x) - '0') : (to_low(x) - 'a' + 10)) + + int ci = curInd; + char ch1 = (ci + 0 < (int)pattern.size()) ? pattern[ci + 0] : -1; + char ch2 = (ci + 1 < (int)pattern.size()) ? pattern[ci + 1] : -1; + bkstring s = " "; + + if (is_hex(ch1) && is_hex(ch2)) + { + curInd += 2; + s[0] = (to_int(ch1) << 4 & 0xF0) | (to_int(ch2) & 0x0F); + } + + return s; + #undef to_low + #undef is_dig + #undef is_hex + #undef to_int +} +bkstring Pattern::parseEscape(bool & inv, bool & quo) +{ + char ch = pattern[curInd++]; + bkstring classes = ""; + + if (curInd > (int)pattern.size()) + { + raiseError(); + return NULL; + } + + quo = 0; + inv = 0; + switch (ch) + { + case 'p': classes = parsePosix(); break; + case 'P': classes = "!!"; classes += parsePosix(); break; + case 'd': classes = "0123456789"; break; + case 'D': classes = "!!0123456789"; break; + case 's': classes = " \t\r\n\f"; break; + case 'S': classes = "!! \t\r\n\f"; break; + case 'w': classes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; break; + case 'W': classes = "!!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; break; + case '0': classes = parseOctal(); break; + case 'x': classes = parseHex(); break; + + case 'Q': quo = 1; break; + case 't': classes = "\t"; break; + case 'r': classes = "\r"; break; + case 'n': classes = "\n"; break; + case 'f': classes = "\f"; break; + case 'a': classes = "\a"; break; + case 'e': classes = "\r"; break; + default: classes = " "; classes[0] = ch; break; + } + if (classes.substr(0, 2) == "!!") + { + classes = classes.substr(2); + inv = 1; + } + return classes; +} +NFANode * Pattern::parseRegisteredPattern(NFANode ** end) +{ + int i, j; + bkstring s; + NFANode * ret = NULL; + for (i = curInd; i < (int)pattern.size() && pattern[i] != '}'; ++i) { } + if (pattern[i] != '}') { raiseError(); return NULL; } + if (i == curInd + 1) { raiseError(); return NULL; } // {} + if ( + !( + (pattern[curInd] >= 'a' && pattern[curInd] <= 'z') || + (pattern[curInd] >= 'A' && pattern[curInd] <= 'Z') || + (pattern[curInd] == '_') + ) + ) + { + raiseError(); + return NULL; + } + for (j = curInd; !error && j < i; ++j) + { + if ( + !( + (pattern[j] >= 'a' && pattern[j] <= 'z') || + (pattern[j] >= 'A' && pattern[j] <= 'Z') || + (pattern[j] >= '0' && pattern[j] <= '9') || + (pattern[j] == '_') + ) + ) + { + raiseError(); + return NULL; + } + } + s = pattern.substr(curInd, i - curInd); + if (registeredPatterns.find(s) == registeredPatterns.end()) raiseError(); + else + { + unsigned long oflags = flags; + bkstring op = pattern; + int ci = i + 1; + + pattern = registeredPatterns[s].first; + curInd = 0; + flags = registeredPatterns[s].second; + + --groupCount; + ret = parse(0, 0, end); + + pattern = op; + curInd = ci; + flags = oflags; + } + if (error) { *end = ret = NULL; } + return ret; +} + +// look behind should interpret everything as a literal (except \\) since the +// pattern must have a concrete length +NFANode * Pattern::parseBehind(const bool pos, NFANode ** end) +{ + bkstring t = ""; + while (curInd < (int)pattern.size() && pattern[curInd] != ')') + { + char ch = pattern[curInd++]; + t += " "; + if (ch == '\\') + { + if (curInd + 1 >= (int)pattern.size()) + { + raiseError(); + return *end = registerNode(new NFACharNode(' ')); + } + ch = pattern[curInd++]; + } + t[t.size() - 1] = ch; + } + if (curInd >= (int)pattern.size() || pattern[curInd] != ')') raiseError(); + else ++curInd; + return *end = registerNode(new NFALookBehindNode(t, pos)); +} +NFANode * Pattern::parseQuote() +{ + bool done = 0; + bkstring s = ""; + + while (!done) + { + if (curInd >= (int)pattern.size()) + { + raiseError(); + done = 1; + } + else if (pattern.substr(curInd, 2) == "\\E") + { + curInd += 2; + done = 1; + } + else if (pattern[curInd] == '\\') + { + s += " "; + s[s.size() - 1] = pattern[++curInd]; + ++curInd; + } + else + { + s += " "; + s[s.size() - 1] = pattern[curInd++]; + } + } + if ((flags & Pattern::CASE_INSENSITIVE) != 0) return registerNode(new NFACIQuoteNode(s)); + return registerNode(new NFAQuoteNode(s)); +} +NFANode * Pattern::parse(const bool inParen, const bool inOr, NFANode ** end) +{ + NFANode * start, * cur, * next = NULL; + bkstring t; + int grc = groupCount++; + bool inv, quo; + bool ahead = 0, pos = 0, noncap = 0, indep = 0; + unsigned long oldFlags = flags; + + if (inParen) + { + if (pattern[curInd] == '?') + { + ++curInd; + --groupCount; + if (pattern[curInd] == ':') { noncap = 1; ++curInd; grc = --nonCapGroupCount; } + else if (pattern[curInd] == '=') { ++curInd; ahead = 1; pos = 1; } + else if (pattern[curInd] == '!') { ++curInd; ahead = 1; pos = 0; } + else if (pattern.substr(curInd, 2) == "<=") { curInd += 2; return parseBehind(1, end); } + else if (pattern.substr(curInd, 2) == "') { ++curInd; indep = 1; } + else + { + bool negate = false, done = false; + while (!done) + { + if (curInd >= (int)pattern.size()) + { + raiseError(); + return NULL; + } + else if (negate) + { + switch (pattern[curInd]) + { + case 'i': flags &= ~Pattern::CASE_INSENSITIVE; break; + case 'd': flags &= ~Pattern::UNIX_LINE_MODE; break; + case 'm': flags &= ~Pattern::MULTILINE_MATCHING; break; + case 's': flags &= ~Pattern::DOT_MATCHES_ALL; break; + case ':': done = true; break; + case ')': + ++curInd; + *end = registerNode(new NFALookBehindNode("", true)); + return *end; + case '-': + default: raiseError(); return NULL; + } + } + else + { + switch (pattern[curInd]) + { + case 'i': flags |= Pattern::CASE_INSENSITIVE; break; + case 'd': flags |= Pattern::UNIX_LINE_MODE; break; + case 'm': flags |= Pattern::MULTILINE_MATCHING; break; + case 's': flags |= Pattern::DOT_MATCHES_ALL; break; + case ':': done = true; break; + case '-': negate = true; break; + case ')': + ++curInd; + *end = registerNode(new NFALookBehindNode("", true)); + return *end; + default: raiseError(); return NULL; + } + } + ++curInd; + } + noncap = 1; + grc = --nonCapGroupCount; + } + if (noncap) cur = start = registerNode(new NFAGroupHeadNode(grc)); + else cur = start = registerNode(new NFASubStartNode); + } + else cur = start = registerNode(new NFAGroupHeadNode(grc)); + } + else cur = start = registerNode(new NFASubStartNode); + while (curInd < (int)pattern.size()) + { + char ch = pattern[curInd++]; + + next = NULL; + if (error) return NULL; + switch (ch) + { + case '^': + if ((flags & Pattern::MULTILINE_MATCHING) != 0) next = registerNode(new NFAStartOfLineNode); + else next = registerNode(new NFAStartOfInputNode); + break; + case '$': + if ((flags & Pattern::MULTILINE_MATCHING) != 0) next = registerNode(new NFAEndOfLineNode); + else next = registerNode(new NFAEndOfInputNode(0)); + break; + case '|': + --groupCount; + cur->next = registerNode(new NFAAcceptNode); + cur = start = registerNode(new NFAOrNode(start, parse(inParen, 1))); + break; + case '\\': + if (curInd < (int)pattern.size()) + { + bool eoi = 0; + switch (pattern[curInd]) + { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': next = parseBackref(); break; + case 'A': ++curInd; next = registerNode(new NFAStartOfInputNode); break; + case 'B': ++curInd; next = registerNode(new NFAWordBoundaryNode(0)); break; + case 'b': ++curInd; next = registerNode(new NFAWordBoundaryNode(1)); break; + case 'G': ++curInd; next = registerNode(new NFAEndOfMatchNode); break; + case 'Z': eoi = 1; + case 'z': ++curInd; next = registerNode(new NFAEndOfInputNode(eoi)); break; + default: + t = parseEscape(inv, quo); + if (!quo) + { + if (t.size() > 1 || inv) + { + if ((flags & Pattern::CASE_INSENSITIVE) != 0) next = registerNode(new NFACIClassNode(t, inv)); + else next = registerNode(new NFAClassNode(t, inv)); + } + else + { + next = registerNode(new NFACharNode(t[0])); + } + } + else + { + next = parseQuote(); + } + } + } + else raiseError(); + break; + case '[': + if ((flags & Pattern::CASE_INSENSITIVE) == 0) + { + NFAClassNode * clazz = new NFAClassNode(); + bkstring s = parseClass(); + for (int i = 0; i < (int)s.size(); ++i) clazz->vals[s[i]] = 1; + next = registerNode(clazz); + } + else + { + NFACIClassNode * clazz = new NFACIClassNode(); + bkstring s = parseClass(); + for (int i = 0; i < (int)s.size(); ++i) clazz->vals[to_lower(s[i])] = 1; + next = registerNode(clazz); + } + break; + case '.': + { + bool useN = 1, useR = 1; + NFAClassNode * clazz = new NFAClassNode(1); + if ((flags & Pattern::UNIX_LINE_MODE) != 0) useR = 0; + if ((flags & Pattern::DOT_MATCHES_ALL) != 0) useN = useR = 0; + if (useN) clazz->vals['\n'] = 1; + if (useR) clazz->vals['\r'] = 1; + next = registerNode(clazz); + } + break; + case '(': + { + NFANode * end, * t1, * t2; + t1 = parse(1, 0, &end); + if (!t1) raiseError(); + else if (t1->isGroupHeadNode() && (t2 = quantifyGroup(t1, end, grc)) != NULL) + { + cur->next = t2; + cur = t2->next; + } + else + { + cur->next = t1; + cur = end; + } + } + break; + case ')': + if (!inParen) raiseError(); + else if (inOr) + { + --curInd; + cur = cur->next = registerNode(new NFAAcceptNode); + flags = oldFlags; + return start; + } + else + { + if (ahead) + { + cur = cur->next = registerNode(new NFAAcceptNode); + flags = oldFlags; + return *end = registerNode(new NFALookAheadNode(start, pos)); + } + else if (indep) + { + cur = cur->next = registerNode(new NFAAcceptNode); + flags = oldFlags; + return *end = registerNode(new NFAPossessiveQuantifierNode(this, start, 1, 1)); + } + else // capping or noncapping, it doesnt matter + { + *end = cur = cur->next = registerNode(new NFAGroupTailNode(grc)); + next = quantifyGroup(start, *end, grc); + if (next) + { + start = next; + *end = next->next; + } + flags = oldFlags; + return start; + } + } + break; + case '{': // registered pattern + cur->next = parseRegisteredPattern(&next); + if (cur->next) cur = next; + break; + case '*': + case '+': + case '?': +// case '}': +// case ']': + raiseError(); + break; + default: + if ((flags & Pattern::CASE_INSENSITIVE) != 0) next = registerNode(new NFACICharNode(ch)); + else next = registerNode(new NFACharNode(ch)); + break; + } + if (next) + { + cur = cur->next = quantify(next); + } + } + if (inParen) raiseError(); + else + { + if (inOr) cur = cur->next = registerNode(new NFAAcceptNode); + if (end) *end = cur; + } + + flags = oldFlags; + if (error) return NULL; + + return start; +} + +Pattern * Pattern::compile(const bkstring & pattern, const unsigned long mode) +{ + Pattern * p = new Pattern(pattern); + NFANode * end; + + p->flags = mode; + if ((mode & Pattern::LITERAL) != 0) + { + p->head = p->registerNode(new NFAStartNode); + if ((mode & Pattern::CASE_INSENSITIVE) != 0) p->head->next = p->registerNode(new NFACIQuoteNode(pattern)); + else p->head->next = p->registerNode(new NFAQuoteNode(pattern)); + p->head->next->next = p->registerNode(new NFAEndNode); + } + else + { + p->head = p->parse(0, 0, &end); + if (!p->head) + { + delete p; + p = NULL; + } + else + { + if (!(p->head && p->head->isStartOfInputNode())) + { + NFANode * n = p->registerNode(new NFAStartNode); + n->next = p->head; + p->head = n; + } + end->next = p->registerNode(new NFAEndNode); + } + } + if (p != NULL) + { + p->matcher = new Matcher(p, ""); + } + + return p; +} + +Pattern * Pattern::compileAndKeep(const bkstring & pattern, const unsigned long mode) +{ + Pattern * ret = NULL; + std::map::iterator it = compiledPatterns.find(pattern); + + if (it != compiledPatterns.end()) + { + ret = it->second; + } + else + { + ret = compile(pattern, mode); + compiledPatterns[pattern] = ret; + } + + return ret; +} +bkstring Pattern::replace(const bkstring & pattern, const bkstring & str, + const bkstring & replacementText, const unsigned long mode) +{ + bkstring ret; + Pattern * p = Pattern::compile(pattern, mode); + if (p) + { + ret = p->replace(str, replacementText); + delete p; + } + return ret; +} + +std::vector Pattern::split(const bkstring & pattern, const bkstring & str, const bool keepEmptys, + const unsigned long limit, const unsigned long mode) +{ + std::vector ret; + Pattern * p = Pattern::compile(pattern, mode); + if (p) + { + ret = p->split(str, keepEmptys, limit); + delete p; + } + return ret; +} + +std::vector Pattern::findAll(const bkstring & pattern, const bkstring & str, const unsigned long mode) +{ + std::vector ret; + Pattern * p = Pattern::compile(pattern, mode); + if (p) + { + ret = p->findAll(str); + delete p; + } + return ret; +} + +bool Pattern::matches(const bkstring & pattern, const bkstring & str, const unsigned long mode) +{ + bool ret = 0; + Pattern * p = compile(pattern, mode); + + if (p) + { + ret = p->matches(str); + delete p; + } + + return ret; +} + +bool Pattern::registerPattern(const bkstring & name, const bkstring & pattern, const unsigned long mode) +{ + Pattern * p = Pattern::compile(pattern, mode); + if (!p) return 0; + Pattern::registeredPatterns[name] = std::make_pair(pattern, mode); + delete p; + return 1; +} + +void Pattern::unregisterPatterns() +{ + registeredPatterns.clear(); +} +void Pattern::clearPatternCache() +{ + std::map::iterator it; + for (it = compiledPatterns.begin(); it != compiledPatterns.end(); ++it) + { + delete it->second; + } + compiledPatterns.clear(); +} + +std::pair Pattern::findNthMatch(const bkstring & pattern, const bkstring & str, + const int matchNum, const unsigned long mode) +{ + std::pair ret; + Pattern * p = Pattern::compile(pattern, mode); + + ret.second = -1; + if (p) + { + int i = -1; + p->matcher->setString(str); + while (i < matchNum && p->matcher->findNextMatch()) { ++i; } + if (i == matchNum && p->matcher->getStartingIndex() >= 0) + { + ret.first = p->matcher->getGroup(0); + ret.second = p->matcher->getStartingIndex(); + } + delete p; + } + + return ret; +} + +Pattern::~Pattern() +{ + if (matcher) delete matcher; + for (std::map::iterator it = nodes.begin(); it != nodes.end(); ++it) + { + delete it->first; + } +} +bkstring Pattern::replace(const bkstring & str, const bkstring & replacementText) +{ + int li = 0; + bkstring ret = ""; + + matcher->setString(str); + while (matcher->findNextMatch()) + { + ret += str.substr(li, matcher->getStartingIndex() - li); + ret += matcher->replaceWithGroups(replacementText); + li = matcher->getEndingIndex(); + } + ret += str.substr(li); + + return ret; +} +std::vector Pattern::split(const bkstring & str, const bool keepEmptys, const unsigned long limit) +{ + unsigned long lim = (limit == 0 ? MAX_QMATCH : limit); + int li = 0; + std::vector ret; + + matcher->setString(str); + + while (matcher->findNextMatch() && ret.size() < lim) + { + if (matcher->getStartingIndex() == 0 && keepEmptys) ret.push_back(""); + if ((matcher->getStartingIndex() != matcher->getEndingIndex()) || keepEmptys) + { + if (li != matcher->getStartingIndex() || keepEmptys) + { + ret.push_back(str.substr(li, matcher->getStartingIndex() - li)); + } + li = matcher->getEndingIndex(); + } + } + if (li < (int)str.size()) ret.push_back(str.substr(li)); + + return ret; +} +std::vector Pattern::findAll(const bkstring & str) +{ + matcher->setString(str); + return matcher->findAll(); +} +bool Pattern::matches(const bkstring & str) +{ + matcher->setString(str); + return matcher->matches(); +} +unsigned long Pattern::getFlags() const +{ + return flags; +} +bkstring Pattern::getPattern() const +{ + return pattern; +} +Matcher * Pattern::createMatcher(const bkstring & str) +{ + return new Matcher(this, str); +} + +// NFANode + +NFANode::NFANode() { next = NULL; } +NFANode::~NFANode() { } +void NFANode::findAllNodes(std::map & soFar) +{ + if (soFar.find(this) == soFar.end()) return; + soFar[this] = 1; + if (next) next->findAllNodes(soFar); +} + +// NFACharNode + +NFACharNode::NFACharNode(const char c) { ch = c; } +int NFACharNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd < (int)str.size() && str[curInd] == ch) return next->match(str, matcher, curInd + 1); + return -1; +} + +// NFACICharNode + +NFACICharNode::NFACICharNode(const char c) { ch = to_lower(c); } +int NFACICharNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd < (int)str.size() && to_lower(str[curInd]) == ch) return next->match(str, matcher, curInd + 1); + return -1; +} + +// NFAStartNode + +NFAStartNode::NFAStartNode() { } +int NFAStartNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int ret = -1, ci = curInd; + + matcher->starts[0] = curInd; + if ((matcher->getFlags() & Matcher::MATCH_ENTIRE_STRING) == (unsigned int)Matcher::MATCH_ENTIRE_STRING) + { + if (curInd != 0) + { + matcher->starts[0] = -1; + return -1; + } + return next->match(str, matcher, 0); + } + while ((ret = next->match(str, matcher, ci)) == -1 && ci < (int)str.size()) + { + matcher->clearGroups(); + matcher->starts[0] = ++ci; + } + if (ret < 0) matcher->starts[0] = -1; + return ret; +} + +// NFAEndNode + +NFAEndNode::NFAEndNode() { } +int NFAEndNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + matcher->ends[0] = curInd; + if ((matcher->getFlags() & Matcher::MATCH_ENTIRE_STRING) != 0) + { + if (curInd == (int)str.size()) return curInd; + matcher->ends[0] = -1; + return -1; + } + return curInd; +} + +// NFAQuantifierNode + +void NFAQuantifierNode::findAllNodes(std::map & soFar) +{ + inner->findAllNodes(soFar); + NFANode::findAllNodes(soFar); +} +NFAQuantifierNode::NFAQuantifierNode(Pattern * pat, NFANode * internal, const int minMatch, const int maxMatch) +{ + inner = internal; + inner->next = pat->registerNode(new NFAAcceptNode); + min = (minMatch < Pattern::MIN_QMATCH) ? Pattern::MIN_QMATCH : minMatch; + max = (maxMatch > Pattern::MAX_QMATCH) ? Pattern::MAX_QMATCH : maxMatch; +} + +int NFAQuantifierNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int i0, i1, i2 = 0; + + i0 = i1 = curInd; + while (i2 < min) + { + + ++i2; + i1 = inner->match(str, matcher, i0); + if (i1 <= i0) return i1; // i1 < i0 means i1 is -1 + i0 = i1; + } + + return i1; +} +// NFAGreedyQuantifierNode + +NFAGreedyQuantifierNode::NFAGreedyQuantifierNode(Pattern * pat, NFANode * internal, const int minMatch, const int maxMatch) + : NFAQuantifierNode(pat, internal, minMatch, maxMatch) { } +int NFAGreedyQuantifierNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int t = NFAQuantifierNode::match(str, matcher, curInd); + if (t != -1) return matchInternal(str, matcher, t, min); + return t; +} +int NFAGreedyQuantifierNode::matchInternal(const bkstring & str, Matcher * matcher, const int curInd, const int soFar) const +{ + if (soFar >= max) return next->match(str, matcher, curInd); + + int i, j; + + i = inner->match(str, matcher, curInd); + if (i != -1) + { + j = matchInternal(str, matcher, i, soFar + 1); + if (j != -1) return j; + } + return next->match(str, matcher, curInd); +} + +// NFALazyQuantifierNode + +NFALazyQuantifierNode::NFALazyQuantifierNode(Pattern * pat, NFANode * internal, const int minMatch, const int maxMatch) + : NFAQuantifierNode(pat, internal, minMatch, maxMatch) { } +int NFALazyQuantifierNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int i, j, m = NFAQuantifierNode::match(str, matcher, curInd); + + if (m == -1) return -1; + + for (i = min; i < max; ++i) + { + j = next->match(str, matcher, m); + if (j == -1) + { + j = inner->match(str, matcher, m); + // if j < m, then j is -1, so we bail. + // if j == m, then we would just go and call next->match on the same index, + // but it already failed trying to match right there, so we know we can + // just bail + if (j <= m) return -1; + m = j; + } + else return j; + } + return next->match(str, matcher, m); +} + +// NFAPossessiveQuantifierNode + +NFAPossessiveQuantifierNode::NFAPossessiveQuantifierNode(Pattern * pat, NFANode * internal, const int minMatch, const int maxMatch) + : NFAQuantifierNode(pat, internal, minMatch, maxMatch) { } +int NFAPossessiveQuantifierNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int i, j, m = NFAQuantifierNode::match(str, matcher, curInd); + + if (m == -1) return -1; + for (i = min; i < max; ++i) + { + j = inner->match(str, matcher, m); + if (j <= m) return next->match(str, matcher, m); + m = j; + } + return next->match(str, matcher, m); +} + +// NFAAcceptNode + +NFAAcceptNode::NFAAcceptNode() { } +int NFAAcceptNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (!next) return curInd; + else return next->match(str, matcher, curInd); +} + +// NFAClassNode + +NFAClassNode::NFAClassNode(const bool invert) +{ + inv = invert; +} +NFAClassNode::NFAClassNode(const bkstring & clazz, const bool invert) +{ + inv = invert; + for (int i = 0; i < (int)clazz.size(); ++i) vals[clazz[i]] = 1; +} +int NFAClassNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd < (int)str.size() && ((vals.find(str[curInd]) != vals.end()) ^ inv)) + { + return next->match(str, matcher, curInd + 1); + } + return -1; +} + +// NFACIClassNode + +NFACIClassNode::NFACIClassNode(const bool invert) +{ + inv = invert; +} +NFACIClassNode::NFACIClassNode(const bkstring & clazz, const bool invert) +{ + inv = invert; + for (int i = 0; i < (int)clazz.size(); ++i) vals[to_lower(clazz[i])] = 1; +} +int NFACIClassNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd < (int)str.size() && ((vals.find(to_lower(str[curInd])) != vals.end()) ^ inv)) + { + return next->match(str, matcher, curInd + 1); + } + return -1; +} + +// NFASubStartNode + +NFASubStartNode::NFASubStartNode() { } +int NFASubStartNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + return next->match(str, matcher, curInd); +} + +// NFAOrNode + +NFAOrNode::NFAOrNode(NFANode * first, NFANode * second) : one(first), two(second) { } +void NFAOrNode::findAllNodes(std::map & soFar) +{ + if (one) one->findAllNodes(soFar); + if (two) two->findAllNodes(soFar); + NFANode::findAllNodes(soFar); +} +int NFAOrNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int ci = one->match(str, matcher, curInd); + + if (ci != -1) ci = next->match(str, matcher, ci); + if (ci != -1) return ci; + if (ci == -1) ci = two->match(str, matcher, curInd); + if (ci != -1) ci = next->match(str, matcher, ci); + return ci; +} + +// NFAQuoteNode + +NFAQuoteNode::NFAQuoteNode(const bkstring & quoted) : qStr(quoted) { } +int NFAQuoteNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd + qStr.size() > str.size()) return -1; + if (str.substr(curInd, qStr.size()) != qStr) return -1; + return next->match(str, matcher, curInd + qStr.size()); +} + +// NFACIQuoteNode + +NFACIQuoteNode::NFACIQuoteNode(const bkstring & quoted) : qStr(quoted) { } +int NFACIQuoteNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd + qStr.size() > str.size()) return -1; + if (str_icmp(str.substr(curInd, qStr.size()).c_str(), qStr.c_str())) return -1; + return next->match(str, matcher, qStr.size()); +} + +// NFALookAheadNode + +NFALookAheadNode::NFALookAheadNode(NFANode * internal, const bool positive) : NFANode(), pos(positive), inner(internal) { } +void NFALookAheadNode::findAllNodes(std::map & soFar) +{ + if (inner) inner->findAllNodes(soFar); + NFANode::findAllNodes(soFar); +} +int NFALookAheadNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + return ((inner->match(str, matcher, curInd) == -1) ^ pos) ? next->match(str, matcher, curInd) : -1; +} + +// NFALookBehindNode + +NFALookBehindNode::NFALookBehindNode(const bkstring & str, const bool positive) : pos(positive), mStr(str) { } +int NFALookBehindNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (pos) + { + if (curInd < (int)mStr.size()) return -1; + if (str.substr(curInd - mStr.size(), mStr.size()) == mStr) return next->match(str, matcher, curInd); + } + else + { + if (curInd < (int)mStr.size()) return next->match(str, matcher, curInd); + if (str.substr(curInd - mStr.size(), mStr.size()) == mStr) return -1; + return next->match(str, matcher, curInd); + } + return -1; +} + +// NFAStartOfLineNode + +NFAStartOfLineNode::NFAStartOfLineNode() { } +int NFAStartOfLineNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd == 0 || str[curInd - 1] == '\n' || str[curInd - 1] == '\r') + { + return next->match(str, matcher, curInd); + } + return -1; +} + +// NFAEndOfLineNode + +NFAEndOfLineNode::NFAEndOfLineNode() { } +int NFAEndOfLineNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd >= (int)str.size() || str[curInd] == '\n' || str[curInd] == '\r') + { + return next->match(str, matcher, curInd); + } + return -1; +} + +// NFAReferenceNode + +NFAReferenceNode::NFAReferenceNode(const int groupIndex) : gi(groupIndex) { } +int NFAReferenceNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int len = matcher->ends[gi] - matcher->starts[gi]; + int ni = -1; + if (gi < 1 || matcher->ends[gi] < matcher->starts[gi] || len == 0) ni = curInd; + else if (curInd + len > (int)str.size()) return -1; + else if (str.substr(curInd, len) != str.substr(matcher->starts[gi], len)) return -1; + else ni = curInd + len; + + return next->match(str, matcher, ni); +} + +// NFAStartOfInputNode + +NFAStartOfInputNode::NFAStartOfInputNode() { } +int NFAStartOfInputNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd == 0) return next->match(str, matcher, curInd); + return -1; +} + +// NFAEndOfInputNode + +NFAEndOfInputNode::NFAEndOfInputNode(const bool lookForTerm) : term(lookForTerm) { } +int NFAEndOfInputNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int len = (int)str.size(); + if (curInd == len) return next->match(str, matcher, curInd); + else if (term) + { + if (curInd == len - 1 && (str[curInd] == '\r' || str[curInd] == '\n')) + { + return next->match(str, matcher, curInd); + } + else if (curInd == len - 2 && str.substr(curInd, 2) == "\r\n") + { + return next->match(str, matcher, curInd); + } + } + return -1; +} + +// NFAWordBoundaryNode + +NFAWordBoundaryNode::NFAWordBoundaryNode(const bool positive) : pos(positive) { } +int NFAWordBoundaryNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int len = (int)str.size(); + + char c1 = (curInd - 1 < len && curInd > 0) ? str[curInd - 1] : '\n'; + char c2 = (curInd < len) ? str[curInd ] : '\n'; + + if (curInd == len) return next->match(str, matcher, curInd); + bool ok = is_alpha(c1) != is_alpha(c2); + if (ok && pos) return next->match(str, matcher, curInd); + return -1; +} + +// NFAEndOfMatchNode + +NFAEndOfMatchNode::NFAEndOfMatchNode() { } +int NFAEndOfMatchNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + if (curInd == matcher->lm) return next->match(str, matcher, curInd); + return -1; +} + +// NFAGroupHeadNode + +NFAGroupHeadNode::NFAGroupHeadNode(const int groupIndex) : gi(groupIndex) { } +int NFAGroupHeadNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int ret, o = matcher->starts[gi]; + + matcher->starts[gi] = curInd; + ret = next->match(str, matcher, curInd); + if (ret < 0) matcher->starts[gi] = o; + + return ret; +} + +// NFAGroupTailNode + +NFAGroupTailNode::NFAGroupTailNode(const int groupIndex) : gi(groupIndex) { } +int NFAGroupTailNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int ret, o = matcher->ends[gi]; + + matcher->ends[gi] = curInd; + ret = next->match(str, matcher, curInd); + if (ret < 0) matcher->ends[gi] = o; + + return ret; +} + +// NFAGroupLoopPrologueNode + +NFAGroupLoopPrologueNode::NFAGroupLoopPrologueNode(const int groupIndex) : gi(groupIndex) { } +int NFAGroupLoopPrologueNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int ret, o1 = matcher->groups[gi], o2 = matcher->groupPos[gi], o3 = matcher->groupIndeces[gi]; + + matcher->groups[gi] = 0; + matcher->groupPos[gi] = 0; + matcher->groupIndeces[gi] = -1; + ret = next->match(str, matcher, curInd); + if (ret < 0) + { + matcher->groups[gi] = o1; + matcher->groupPos[gi] = o2; + matcher->groupIndeces[gi] = o3; + } + + return ret; +} + +// NFAGroupLoopNode + +NFAGroupLoopNode::NFAGroupLoopNode(NFANode * internal, const int minMatch, const int maxMatch, + const int groupIndex, const int matchType) +{ + inner = internal; + min = minMatch; + max = maxMatch; + gi = groupIndex; + type = matchType; +} +void NFAGroupLoopNode::findAllNodes(std::map & soFar) +{ + if (inner) inner->findAllNodes(soFar); + NFANode::findAllNodes(soFar); +} +int NFAGroupLoopNode::match(const bkstring & str, Matcher * matcher, const int curInd) const +{ + bool b = (curInd > matcher->groupIndeces[gi]); + + if (b && matcher->groups[gi] < min) + { + ++matcher->groups[gi]; + int o = matcher->groupIndeces[gi]; + matcher->groupIndeces[gi] = curInd; + int ret = inner->match(str, matcher, curInd); + if (ret < 0) + { + matcher->groupIndeces[gi] = o; + --matcher->groups[gi]; + } + return ret; + } + else if (!b || matcher->groups[gi] >= max) + { + return next->match(str, matcher, curInd); + } + else + { + switch (type) + { + case 0: return matchGreedy(str, matcher, curInd); + case 1: return matchLazy(str, matcher, curInd); + case 2: return matchPossessive(str, matcher, curInd); + } + } + return -1; +} +int NFAGroupLoopNode::matchGreedy(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int o = matcher->groupIndeces[gi]; // save our info for backtracking + matcher->groupIndeces[gi] = curInd; // move along + ++matcher->groups[gi]; + int ret = inner->match(str, matcher, curInd); // match internally + if (ret < 0) + { // if we failed, then restore info and match next + --matcher->groups[gi]; + matcher->groupIndeces[gi] = o; + ret = next->match(str, matcher, curInd); + } + return ret; +} +int NFAGroupLoopNode::matchLazy(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int ret = next->match(str, matcher, curInd); // be lazy, just go on + if (ret < 0) + { + int o = matcher->groupIndeces[gi]; // save info for backtracking + matcher->groupIndeces[gi] = curInd; // advance our position + ++matcher->groups[gi]; + ret = inner->match(str, matcher, curInd); // match our internal stuff + if (ret < 0) // if we failed, then restore the info + { + --matcher->groups[gi]; + matcher->groupIndeces[gi] = o; + } + } + return ret; +} +int NFAGroupLoopNode::matchPossessive(const bkstring & str, Matcher * matcher, const int curInd) const +{ + int o = matcher->groupIndeces[gi]; // save info for backtracking + matcher->groupPos[gi] = matcher->groups[gi]; // set a flag stating we have matcher at least this much + matcher->groupIndeces[gi] = curInd; // move along + ++matcher->groups[gi]; + int ret = inner->match(str, matcher, curInd); // try and match again + if (ret < 0) + { // if we fail, back off, but to an extent + --matcher->groups[gi]; + matcher->groupIndeces[gi] = o; + if (matcher->groups[gi] == matcher->groupPos[gi]) ret = next->match(str, matcher, curInd); + } + return ret; +} + +#ifdef _WIN32 + #pragma warning(pop) +#endif diff --git a/plugins/SmileyAdd/src/regexp/Pattern.h b/plugins/SmileyAdd/src/regexp/Pattern.h new file mode 100644 index 0000000000..bb16ad90fa --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/Pattern.h @@ -0,0 +1,1663 @@ +#ifndef __PATTERN_H__ +#define __PATTERN_H__ + +#ifdef _WIN32 + #pragma warning(disable:4786) +#endif + +#include +#include + +#include "bkstring.h" + +class Matcher; +class NFANode; +class NFAQuantifierNode; + +/** + This pattern class is very similar in functionality to Java's + java.util.regex.Pattern class. The pattern class represents an immutable + regular expression object. Instead of having a single object contain both the + regular expression object and the matching object, instead the two objects are + split apart. The {@link Matcher Matcher} class represents the maching + object. + + The Pattern class works primarily off of "compiled" patterns. A typical + instantiation of a regular expression looks like: + +

+  Pattern * p = Pattern::compile("a*b");
+  Matcher * m = p->createMatcher("aaaaaab");
+  if (m->matches()) ...
+  
+ + However, if you do not need to use a pattern more than once, it is often times + okay to use the Pattern's static methods insteads. An example looks like this: + +
+  if (Pattern::matches("a*b", "aaaab")) { ... }
+  
+ + This class does not currently support unicode. The unicode update for this + class is coming soon. + + This class is partially immutable. It is completely safe to call createMatcher + concurrently in different threads, but the other functions (e.g. split) should + not be called concurrently on the same Pattern. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Construct + + Matches + +
+   +
+ Characters +
+ x + + The character x +
+ \\ + + The character \ +
+ \0nn + + The character with octal ASCII value nn +
+ \0nnn + + The character with octal ASCII value nnn +
+ \xhh + + The character with hexadecimal ASCII value hh +
+ \t + + A tab character +
+ \r + + A carriage return character +
+ \n + + A new-line character +
+   +
+ Character Classes +
+ [abc] + + Either a, b, or c +
+ [^abc] + + Any character but a, b, or c +
+ [a-zA-Z] + + Any character ranging from a thru z, or + A thru Z +
+ [^a-zA-Z] + + Any character except those ranging from a thru + z, or A thru Z +
+ [a\-z] + + Either a, -, or z +
+ [a-z[A-Z]] + + Same as [a-zA-Z] +
+ [a-z&&[g-i]] + + Any character in the intersection of a-z and + g-i +
+ [a-z&&[^g-i]] + + Any character in a-z and not in g-i +
+   +
+ Prefefined character classes +
+ . + + Any character. Multiline matching must be compiled into the pattern for + . to match a \r or a \n. + Even if multiline matching is enabled, . will not + match a \r\n, only a \r or a \n. +
+ \d + + [0-9] +
+ \D + + [^\d] +
+ \s + + [ \t\r\n\x0B] +
+ \S + + [^\s] +
+ \w + + [a-zA-Z0-9_] +
+ \W + + [^\w] +
+   +
+ POSIX character classes +
+ \p{Lower} + + [a-z] +
+ \p{Upper} + + [A-Z] +
+ \p{ASCII} + + [\x00-\x7F] +
+ \p{Alpha} + + [a-zA-Z] +
+ \p{Digit} + + [0-9] +
+ \p{Alnum} + + [\w&&[^_]] +
+ \p{Punct} + + [!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~] +
+ \p{XDigit} + + [a-fA-F0-9] +
+   +
+ Boundary Matches +
+ ^ + + The beginning of a line. Also matches the beginning of input. +
+ $ + + The end of a line. Also matches the end of input. +
+ \b + + A word boundary +
+ \B + + A non word boundary +
+ \A + + The beginning of input +
+ \G + + The end of the previous match. Ensures that a "next" match will only + happen if it begins with the character immediately following the end of + the "current" match. +
+ \Z + + The end of input. Will also match if there is a single trailing + \r\n, a single trailing \r, or a single + trailing \n. +
+ \z + + The end of input +
+   +
+ Greedy Quantifiers +
+ x? + + x, either zero times or one time +
+ x* + + x, zero or more times +
+ x+ + + x, one or more times +
+ x{n} + + x, exactly n times +
+ x{n,} + + x, at least n times +
+ x{,m} + + x, at most m times +
+ x{n,m} + + x, at least n times and at most + m times +
+   +
+ Possessive Quantifiers +
+ x?+ + + x, either zero times or one time +
+ x*+ + + x, zero or more times +
+ x++ + + x, one or more times +
+ x{n}+ + + x, exactly n times +
+ x{n,}+ + + x, at least n times +
+ x{,m}+ + + x, at most m times +
+ x{n,m}+ + + x, at least n times and at most + m times +
+   +
+ Reluctant Quantifiers +
+ x?? + + x, either zero times or one time +
+ x*? + + x, zero or more times +
+ x+? + + x, one or more times +
+ x{n}? + + x, exactly n times +
+ x{n,}? + + x, at least n times +
+ x{,m}? + + x, at most m times +
+ x{n,m}? + + x, at least n times and at most + m times +
+   +
+ Operators +
+ xy + + x then y +
+ x|y + + x or y +
+ (x) + + x as a capturing group +
+   +
+ Quoting +
+ \Q + + Nothing, but treat every character (including \s) literally until a + matching \E +
+ \E + + Nothing, but ends its matching \Q +
+   +
+ Special Constructs +
+ (?:x) + + x, but not as a capturing group +
+ (?=x) + + x, via positive lookahead. This means that the + expression will match only if it is trailed by x. + It will not "eat" any of the characters matched by + x. +
+ (?!x) + + x, via negative lookahead. This means that the + expression will match only if it is not trailed by + x. It will not "eat" any of the characters + matched by x. +
+ (?<=x) + + x, via positive lookbehind. x + cannot contain any quantifiers. +
+ (?x) + + x, via negative lookbehind. x + cannot contain any quantifiers. +
+ (?>x) + + x{1}+ +
+   +
+ Registered Expression Matching +
+ {x} + + The registered pattern x +
+ +
+ + Begin Text Extracted And Modified From java.util.regex.Pattern documentation + +

Backslashes, escapes, and quoting

+ +

The backslash character ('\') serves to introduce escaped + constructs, as defined in the table above, as well as to quote characters + that otherwise would be interpreted as unescaped constructs. Thus the + expression \\ matches a single backslash and \{ matches a + left brace. + +

It is an error to use a backslash prior to any alphabetic character that + does not denote an escaped construct; these are reserved for future + extensions to the regular-expression language. A backslash may be used + prior to a non-alphabetic character regardless of whether that character is + part of an unescaped construct. + +

It is necessary to double backslashes in string literals that represent + regular expressions to protect them from interpretation by a compiler. The + string literal "\b", for example, matches a single backspace + character when interpreted as a regular expression, while + "\\b" matches a word boundary. The string litera + "\(hello\)" is illegal and leads to a compile-time error; + in order to match the string (hello) the string literal + "\\(hello\\)" must be used. + +

Character Classes

+ +

Character classes may appear within other character classes, and + may be composed by the union operator (implicit) and the intersection + operator (&&). + The union operator denotes a class that contains every character that is + in at least one of its operand classes. The intersection operator + denotes a class that contains every character that is in both of its + operand classes. + +

The precedence of character-class operators is as follows, from + highest to lowest: + +

+ + + + + + + + + + + + + + + + +
1    Literal escape    \x
2    Rangea-z
3    Grouping[...]
4    Intersection[a-z&&[aeiou]]
5    Union[a-e][i-u]
+ +

Note that a different set of metacharacters are in effect inside + a character class than outside a character class. For instance, the + regular expression . loses its special meaning inside a + character class, while the expression - becomes a range + forming metacharacter. + + + + +

Groups and capturing

+ +

Capturing groups are numbered by counting their opening parentheses from + left to right. In the expression ((A)(B(C))), for example, there + are four such groups:

+ +
+ + + + + + + + + + +
1    ((A)(B(C)))
2    (A)
3    (B(C))
4    (C)
+ +

Group zero always stands for the entire expression. + +

Capturing groups are so named because, during a match, each subsequence + of the input sequence that matches such a group is saved. The captured + subsequence may be used later in the expression, via a back reference, and + may also be retrieved from the matcher once the match operation is complete. + +

The captured input associated with a group is always the subsequence + that the group most recently matched. If a group is evaluated a second time + because of quantification then its previously-captured value, if any, will + be retained if the second evaluation fails. Matching the string + "aba" against the expression (a(b)?)+, for example, leaves + group two set to "b". All captured input is discarded at the + beginning of each match. + +

Groups beginning with (? are pure, non-capturing groups + that do not capture text and do not count towards the group total. + + +

Unicode support

+ +

Coming Soon. + +

Comparison to Perl 5

+ +

The Pattern engine performs traditional NFA-based matching + with ordered alternation as occurs in Perl 5. + +

Perl constructs not supported by this class:

+ +
    + +
  • The conditional constructs (?{X}) and + (?(condition)X|Y), +

  • + +
  • The embedded code constructs (?{code}) + and (??{code}),

  • + +
  • The embedded comment syntax (?#comment), and

  • + +
  • The preprocessing operations \l \u, + \L, and \U.

  • + +
  • Embedded flags

  • + +
+ +

Constructs supported by this class but not by Perl:

+ +
    + +
  • Possessive quantifiers, which greedily match as much as they can + and do not back off, even when doing so would allow the overall match to + succeed.

  • + +
  • Character-class union and intersection as described + above.

  • + +
+ +

Notable differences from Perl:

+ +
    + +
  • In Perl, \1 through \9 are always interpreted + as back references; a backslash-escaped number greater than 9 is + treated as a back reference if at least that many subexpressions exist, + otherwise it is interpreted, if possible, as an octal escape. In this + class octal escapes must always begin with a zero. In this class, + \1 through \9 are always interpreted as back + references, and a larger number is accepted as a back reference if at + least that many subexpressions exist at that point in the regular + expression, otherwise the parser will drop digits until the number is + smaller or equal to the existing number of groups or it is one digit. +

  • + +
  • Perl uses the g flag to request a match that resumes + where the last match left off. This functionality is provided implicitly + by the Matcher class: Repeated invocations of the + find method will resume where the last match left off, + unless the matcher is reset.

  • + +
  • Perl is forgiving about malformed matching constructs, as in the + expression *a, as well as dangling brackets, as in the + expression abc], and treats them as literals. This + class also strict and will not compile a pattern when dangling characters + are encountered.

  • + +
+ + +

For a more precise description of the behavior of regular expression + constructs, please see + Mastering Regular Expressions, 2nd Edition, Jeffrey E. F. Friedl, + O'Reilly and Associates, 2002. +

+

+ + End Text Extracted And Modified From java.util.regex.Pattern documentation + +


+ + @author Jeffery Stuart + @since March 2003, Stable Since November 2004 + @version 1.07.00 + @memo A class used to represent "PERL 5"-ish regular expressions + */ +class Pattern +{ + friend class Matcher; + friend class NFANode; + friend class NFAQuantifierNode; + private: + /** + This constructor should not be called directly. Those wishing to use the + Pattern class should instead use the {@link compile compile} method. + + @param rhs The pattern to compile + @memo Creates a new pattern from the regular expression in rhs. + */ + Pattern(const bkstring & rhs); + protected: + /** + This currently is not used, so don't try to do anything with it. + @memo Holds all the compiled patterns for quick access. + */ + static std::map compiledPatterns; + /** + Holds all of the registered patterns as strings. Due to certain problems + with compilation of patterns, especially with capturing groups, this seemed + to be the best way to do it. + */ + static std::map > registeredPatterns; + protected: + /** + Holds all the NFA nodes used. This makes deletion of a pattern, as well as + clean-up from an unsuccessful compile much easier and faster. + */ + std::map nodes; + /** + Used when methods like split are called. The matcher class uses a lot of + dynamic memeory, so having an instance increases speedup of certain + operations. + */ + Matcher * matcher; + /** + The front node of the NFA. + */ + NFANode * head; + /** + The actual regular expression we rerpesent + */ + bkstring pattern; + /** + Flag used during compilation. Once the pattern is successfully compiled, + error is no longer used. + */ + bool error; + /** + Used during compilation to keep track of the current index into + {@link pattern pattern}. Once the pattern is successfully + compiled, error is no longer used. + */ + int curInd; + /** + The number of capture groups this contains. + */ + int groupCount; + /** + The number of non-capture groups this contains. + */ + int nonCapGroupCount; + /** + The flags specified when this was compiled. + */ + unsigned long flags; + protected: + /** + Raises an error during compilation. Compilation will cease at that point + and compile will return NULL. + */ + void raiseError(); + /** + Convenience function for registering a node in nodes. + @param node The node to register + @return The registered node + */ + NFANode * registerNode(NFANode * node); + + /** + Calculates the union of two strings. This function will first sort the + strings and then use a simple selection algorithm to find the union. + @param s1 The first "class" to union + @param s2 The second "class" to union + @return A new string containing all unique characters. Each character + must have appeared in one or both of s1 and + s2. + */ + bkstring classUnion (bkstring s1, bkstring s2) const; + /** + Calculates the intersection of two strings. This function will first sort + the strings and then use a simple selection algorithm to find the + intersection. + @param s1 The first "class" to intersect + @param s2 The second "class" to intersect + @return A new string containing all unique characters. Each character + must have appeared both s1 and s2. + */ + bkstring classIntersect (bkstring s1, bkstring s2) const; + /** + Calculates the negation of a string. The negation is the set of all + characters between \x00 and \xFF not + contained in s1. + @param s1 The "class" to be negated. + @param s2 The second "class" to intersect + @return A new string containing all unique characters. Each character + must have appeared both s1 and s2. + */ + bkstring classNegate (bkstring s1) const; + /** + Creates a new "class" representing the range from low thru + hi. This function will wrap if low > + hi. This is a feature, not a buf. Sometimes it is useful + to be able to say [\x70-\x10] instead of [\x70-\x7F\x00-\x10]. + @param low The beginning character + @param hi The ending character + @return A new string containing all the characters from low thru hi. + */ + bkstring classCreateRange(char low, char hi) const; + + /** + Extracts a decimal number from the substring of member-variable + {@link pattern pattern} starting at start and + ending at end. + @param start The starting index in {@link pattern pattern} + @param end The last index in {@link pattern pattern} + @return The decimal number in {@link pattern pattern} + */ + int getInt(int start, int end); + /** + Parses a {n,m} string out of the member-variable + {@link pattern pattern} stores the result in sNum + and eNum. + @param sNum Output parameter. The minimum number of matches required + by the curly quantifier are stored here. + @param eNum Output parameter. The maximum number of matches allowed + by the curly quantifier are stored here. + @return Success/Failure. Fails when the curly does not have the proper + syntax + */ + bool quantifyCurly(int & sNum, int & eNum); + /** + Tries to quantify the currently parsed group. If the group being parsed + is indeed quantified in the member-variable + {@link pattern pattern}, then the NFA is modified accordingly. + @param start The starting node of the current group being parsed + @param stop The ending node of the current group being parsed + @param gn The group number of the current group being parsed + @return The node representing the starting node of the group. If the + group becomes quantified, then this node is not necessarily + a GroupHead node. + */ + NFANode * quantifyGroup(NFANode * start, NFANode * stop, const int gn); + + /** + Tries to quantify the last parsed expression. If the character was indeed + quantified, then the NFA is modified accordingly. + @param newNode The recently created expression node + @return The node representing the last parsed expression. If the + expression was quantified, return value != newNode + */ + NFANode * quantify(NFANode * newNode); + /** + Parses the current class being examined in + {@link pattern pattern}. + @return A string of unique characters contained in the current class being + parsed + */ + bkstring parseClass(); + /** + Parses the current POSIX class being examined in + {@link pattern pattern}. + @return A string of unique characters representing the POSIX class being + parsed + */ + bkstring parsePosix(); + /** + Returns a string containing the octal character being parsed + @return The string contained the octal value being parsed + */ + bkstring parseOctal(); + /** + Returns a string containing the hex character being parsed + @return The string contained the hex value being parsed + */ + bkstring parseHex(); + /** + Returns a new node representing the back reference being parsed + @return The new node representing the back reference being parsed + */ + NFANode * parseBackref(); + /** + Parses the escape sequence currently being examined. Determines if the + escape sequence is a class, a single character, or the beginning of a + quotation sequence. + @param inv Output parameter. Whether or not to invert the returned class + @param quo Output parameter. Whether or not this sequence starts a + quotation. + @return The characters represented by the class + */ + bkstring parseEscape(bool & inv, bool & quo); + /** + Parses a supposed registered pattern currently under compilation. If the + sequence of characters does point to a registered pattern, then the + registered pattern is appended to *end. The registered pattern + is parsed with the current compilation flags. + @param end The ending node of the thus-far compiled pattern + @return The new end node of the current pattern + */ + NFANode * parseRegisteredPattern(NFANode ** end); + /** + Parses a lookbehind expression. Appends the necessary nodes + *end. + @param pos Positive or negative look behind + @param end The ending node of the current pattern + @return The new end node of the current pattern + */ + NFANode * parseBehind(const bool pos, NFANode ** end); + /** + Parses the current expression and tacks on nodes until a \E is found. + @return The end of the current pattern + */ + NFANode * parseQuote(); + /** + Parses {@link pattern pattern}. This function is called + recursively when an or (|) or a group is encountered. + @param inParen Are we currently parsing inside a group + @param inOr Are we currently parsing one side of an or (|) + @param end The end of the current expression + @return The starting node of the NFA constructed from this parse + */ + NFANode * parse(const bool inParen = 0, const bool inOr = 0, NFANode ** end = NULL); + public: + /// We should match regardless of case + const static unsigned long CASE_INSENSITIVE; + /// We are implicitly quoted + const static unsigned long LITERAL; + /// @memo We should treat a . as [\x00-\x7F] + const static unsigned long DOT_MATCHES_ALL; + /** ^ and $ should anchor to the beginning and + ending of lines, not all input + */ + const static unsigned long MULTILINE_MATCHING; + /** When enabled, only instances of \n are recognized as + line terminators + */ + const static unsigned long UNIX_LINE_MODE; + /// The absolute minimum number of matches a quantifier can match (0) + const static int MIN_QMATCH; + /// The absolute maximum number of matches a quantifier can match (0x7FFFFFFF) + const static int MAX_QMATCH; + public: + /** + Call this function to compile a regular expression into a + Pattern object. Special values can be assigned to + mode when certain non-standard behaviors are expected from + the Pattern object. + @param pattern The regular expression to compile + @param mode A bitwise or of flags signalling what special behaviors are + wanted from this Pattern object + @return If successful, compile returns a Pattern + pointer. Upon failure, compile returns + NULL + */ + static Pattern * compile (const bkstring & pattern, + const unsigned long mode = 0); + /** + Dont use this function. This function will compile a pattern, and cache + the result. This will eventually be used as an optimization when people + just want to call static methods using the same pattern over and over + instead of first compiling the pattern and then using the compiled + instance for matching. + @param pattern The regular expression to compile + @param mode A bitwise or of flags signalling what special behaviors are + wanted from this Pattern object + @return If successful, compileAndKeep returns a + Pattern pointer. Upon failure, compile + returns NULL. + */ + static Pattern * compileAndKeep (const bkstring & pattern, + const unsigned long mode = 0); + + /** + Searches through replace and replaces all substrings matched + by pattern with str. str may + contain backreferences (e.g. \1) to capture groups. A typical + invocation looks like: +

+ + Pattern::replace("(a+)b(c+)", "abcccbbabcbabc", "\\2b\\1"); + +

+ which would replace abcccbbabcbabc with + cccbabbcbabcba. + @param pattern The regular expression + @param str The replacement text + @param replacementText The string in which to perform replacements + @param mode The special mode requested of the Pattern + during the replacement process + @return The text with the replacement string substituted where necessary + */ + static bkstring replace (const bkstring & pattern, + const bkstring & str, + const bkstring & replacementText, + const unsigned long mode = 0); + + /** + Splits the specified string over occurrences of the specified pattern. + Empty strings can be optionally ignored. The number of strings returned is + configurable. A typical invocation looks like: +

+ + bkstring str(strSize, '\0');
+ FILE * fp = fopen(fileName, "r");
+ fread((char*)str.data(), strSize, 1, fp);
+ fclose(fp);
+
+ std::vector<bkstring> lines = Pattern::split("[\r\n]+", str, true);
+
+
+ + @param pattern The regular expression + @param replace The string to split + @param keepEmptys Whether or not to keep empty strings + @param limit The maximum number of splits to make + @param mode The special mode requested of the Pattern + during the split process + @return All substrings of str split across pattern. + */ + static std::vector split (const bkstring & pattern, + const bkstring & str, + const bool keepEmptys = 0, + const unsigned long limit = 0, + const unsigned long mode = 0); + + /** + Finds all the instances of the specified pattern within the string. You + should be careful to only pass patterns with a minimum length of one. For + example, the pattern a* can be matched by an empty string, so + instead you should pass a+ since at least one character must + be matched. A typical invocation of findAll looks like: +

+ + std::vector<td::string> numbers = Pattern::findAll("\\d+", string); + +

+ + @param pattern The pattern for which to search + @param str The string to search + @param mode The special mode requested of the Pattern + during the find process + @return All instances of pattern in str + */ + static std::vector findAll (const bkstring & pattern, + const bkstring & str, + const unsigned long mode = 0); + + /** + Determines if an entire string matches the specified pattern + + @param pattern The pattern for to match + @param str The string to match + @param mode The special mode requested of the Pattern + during the replacement process + @return True if str is recognized by pattern + */ + static bool matches (const bkstring & pattern, + const bkstring & str, + const unsigned long mode = 0); + + /** + Registers a pattern under a specific name for use in later compilations. + A typical invocation and later use looks like: +

+ + Pattern::registerPattern("ip", "(?:\\d{1,3}\\.){3}\\d{1,3}");
+ Pattern * p1 = Pattern::compile("{ip}:\\d+");
+ Pattern * p2 = Pattern::compile("Connection from ({ip}) on port \\d+");
+
+

+ Multiple calls to registerPattern with the same + name will result in the pattern getting overwritten. + + @param name The name to give to the pattern + @param pattern The pattern to register + @param mode Any special flags to use when compiling pattern + @return Success/Failure. Fails only if pattern has invalid + syntax + */ + static bool registerPattern(const bkstring & name, + const bkstring & pattern, + const unsigned long mode = 0); + + /** + Clears the pattern registry + */ + static void unregisterPatterns(); + /** + Don't use + */ + static void clearPatternCache(); + + /** + Searches through a string for the nth match of the + given pattern in the string. Match indeces start at zero, not one. + A typical invocation looks like this: +

+ + std::pair<bkstring, int> match = Pattern::findNthMatch("\\d{1,3}", "192.168.1.101:22", 1);
+ printf("%s %i\n", match.first.c_str(), match.second);
+
+ Output: 168 4
+
+ + @param pattern The pattern for which to search + @param str The string to search + @param matchNum Which match to find + @param mode Any special flags to use during the matching process + @return A string and an integer. The string is the string matched. The + integer is the starting location of the matched string in + str. You can check for success/failure by making sure + that the integer returned is greater than or equal to zero. + */ + static std::pair findNthMatch (const bkstring & pattern, + const bkstring & str, + const int matchNum, + const unsigned long mode = 0); + public: + /** + Deletes all NFA nodes allocated during compilation + */ + ~Pattern(); + + bkstring replace (const bkstring & str, + const bkstring & replacementText); + std::vector split (const bkstring & str, const bool keepEmptys = 0, + const unsigned long limit = 0); + std::vector findAll (const bkstring & str); + bool matches (const bkstring & str); + /** + Returns the flags used during compilation of this pattern + @return The flags used during compilation of this pattern + */ + unsigned long getFlags () const; + /** + Returns the regular expression this pattern represents + @return The regular expression this pattern represents + */ + bkstring getPattern () const; + /** + Creates a matcher object using the specified string and this pattern. + @param str The string to match against + @return A new matcher using object using this pattern and the specified + string + */ + Matcher * createMatcher (const bkstring & str); +}; + +class NFANode +{ + friend class Matcher; + public: + NFANode * next; + NFANode(); + virtual ~NFANode(); + virtual void findAllNodes(std::map & soFar); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const = 0; + inline virtual bool isGroupHeadNode() const { return false; } + inline virtual bool isStartOfInputNode() const { return false; } +}; +class NFACharNode : public NFANode +{ + protected: + char ch; + public: + NFACharNode(const char c); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFACICharNode : public NFANode +{ + protected: + char ch; + public: + NFACICharNode(const char c); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAStartNode : public NFANode +{ + public: + NFAStartNode(); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAEndNode : public NFANode +{ + public: + NFAEndNode(); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAQuantifierNode : public NFANode +{ + public: + int min, max; + NFANode * inner; + virtual void findAllNodes(std::map & soFar); + NFAQuantifierNode(Pattern * pat, NFANode * internal, + const int minMatch = Pattern::MIN_QMATCH, + const int maxMatch = Pattern::MAX_QMATCH); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAGreedyQuantifierNode : public NFAQuantifierNode +{ + public: + NFAGreedyQuantifierNode(Pattern * pat, NFANode * internal, + const int minMatch = Pattern::MIN_QMATCH, + const int maxMatch = Pattern::MAX_QMATCH); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; + virtual int matchInternal(const bkstring & str, Matcher * matcher, const int curInd, const int soFar) const; +}; +class NFALazyQuantifierNode : public NFAQuantifierNode +{ + public: + NFALazyQuantifierNode(Pattern * pat, NFANode * internal, + const int minMatch = Pattern::MIN_QMATCH, + const int maxMatch = Pattern::MAX_QMATCH); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAPossessiveQuantifierNode : public NFAQuantifierNode +{ + public: + NFAPossessiveQuantifierNode(Pattern * pat, NFANode * internal, + const int minMatch = Pattern::MIN_QMATCH, + const int maxMatch = Pattern::MAX_QMATCH); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAAcceptNode : public NFANode +{ + public: + NFAAcceptNode(); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAClassNode : public NFANode +{ + public: + bool inv; + std::map vals; + NFAClassNode(const bool invert = 0); + NFAClassNode(const bkstring & clazz, const bool invert); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFACIClassNode : public NFANode +{ + public: + bool inv; + std::map vals; + NFACIClassNode(const bool invert = 0); + NFACIClassNode(const bkstring & clazz, const bool invert); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFASubStartNode : public NFANode +{ + public: + NFASubStartNode(); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAOrNode : public NFANode +{ + public: + NFANode * one; + NFANode * two; + NFAOrNode(NFANode * first, NFANode * second); + virtual void findAllNodes(std::map & soFar); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAQuoteNode : public NFANode +{ + public: + bkstring qStr; + NFAQuoteNode(const bkstring & quoted); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFACIQuoteNode : public NFANode +{ + public: + bkstring qStr; + NFACIQuoteNode(const bkstring & quoted); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFALookAheadNode : public NFANode +{ + public: + bool pos; + NFANode * inner; + NFALookAheadNode(NFANode * internal, const bool positive); + virtual void findAllNodes(std::map & soFar); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFALookBehindNode : public NFANode +{ + public: + bool pos; + bkstring mStr; + NFALookBehindNode(const bkstring & str, const bool positive); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAStartOfLineNode : public NFANode +{ + public: + NFAStartOfLineNode(); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAEndOfLineNode : public NFANode +{ + public: + NFAEndOfLineNode(); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAReferenceNode : public NFANode +{ + public: + int gi; + NFAReferenceNode(const int groupIndex); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAStartOfInputNode : public NFANode +{ + public: + NFAStartOfInputNode(); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; + inline virtual bool isStartOfInputNode() const { return true; } +}; +class NFAEndOfInputNode : public NFANode +{ + public: + bool term; + NFAEndOfInputNode(const bool lookForTerm); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAWordBoundaryNode : public NFANode +{ + public: + bool pos; + NFAWordBoundaryNode(const bool positive); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAEndOfMatchNode : public NFANode +{ + public: + NFAEndOfMatchNode(); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAGroupHeadNode : public NFANode +{ + public: + int gi; + NFAGroupHeadNode(const int groupIndex); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; + inline virtual bool isGroupHeadNode() const { return true; } +}; +class NFAGroupTailNode : public NFANode +{ + public: + int gi; + NFAGroupTailNode(const int groupIndex); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAGroupLoopPrologueNode : public NFANode +{ + public: + int gi; + NFAGroupLoopPrologueNode(const int groupIndex); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; +class NFAGroupLoopNode : public NFANode +{ + public: + int gi, min, max, type; + NFANode * inner; + NFAGroupLoopNode(NFANode * internal, const int minMatch, + const int maxMatch, const int groupIndex, const int matchType); + virtual void findAllNodes(std::map & soFar); + virtual int match(const bkstring & str, Matcher * matcher, const int curInd = 0) const; + int matchGreedy(const bkstring & str, Matcher * matcher, const int curInd = 0) const; + int matchLazy(const bkstring & str, Matcher * matcher, const int curInd = 0) const; + int matchPossessive(const bkstring & str, Matcher * matcher, const int curInd = 0) const; +}; + +#endif + diff --git a/plugins/SmileyAdd/src/regexp/WCMatcher.cpp b/plugins/SmileyAdd/src/regexp/WCMatcher.cpp new file mode 100644 index 0000000000..bed5a1944b --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/WCMatcher.cpp @@ -0,0 +1,181 @@ +#include "WCMatcher.h" +#include "WCPattern.h" + +const int WCMatcher::MATCH_ENTIRE_STRING = 0x01; + +/* + Detailed documentation is provided in this class' header file + + @author Jeffery Stuart + @since November 2004 + @version 1.07.00 +*/ + +WCMatcher::WCMatcher(WCPattern * pattern, const bkstring & text) +{ + pat = pattern; + str = &text; + gc = pattern->groupCount; + ncgc = -pattern->nonCapGroupCount; + flags = 0; + matchedSomething = false; + starts = new int[gc + ncgc]; + ends = new int[gc + ncgc]; + groups = new int[gc + ncgc]; + groupPos = new int[gc + ncgc]; + groupIndeces = new int[gc + ncgc]; + starts = starts + ncgc; + ends = ends + ncgc; + groups = groups + ncgc; + groupPos = groupPos + ncgc; + groupIndeces = groupIndeces + ncgc; + for (int i = 0; i < gc; ++i) starts[i] = ends[i] = 0; +} +WCMatcher::~WCMatcher() +{ + delete [] (starts - ncgc); + delete [] (ends - ncgc); + delete [] (groups - ncgc); + delete [] (groupIndeces - ncgc); + delete [] (groupPos - ncgc); +} +void WCMatcher::clearGroups() +{ + int i; + lm = 0; + for (i = 0; i < gc; ++i) groups[i] = starts[i] = ends[i] = -1; + for (i = 1; i <= ncgc; ++i) groups[0 - i] = starts[0 - i] = ends[0 - i] = -1; +} +bkstring WCMatcher::replaceWithGroups(const bkstring & str) +{ + bkstring ret = L""; + + bkstring t = str; + while (t.size() > 0) + { + if (t[0] == (wchar_t)'\\') + { + t.erase(0, 1); + if (t.size() == 0) + { + ret += L"\\"; + } + else if (t[0] < (wchar_t)'0' || t[0] > (wchar_t)'9') + { + ret += t[0]; + t.erase(0, 1); + } + else + { + int gn = 0; + while (t.size() > 0 && t[0] >= (wchar_t)'0' && t[0] <= (wchar_t)'9') + { + gn = gn * 10 + (t[0] - (wchar_t)'0'); + t.erase(0, 1); + } + ret += getGroup(gn); + } + } + else + { + ret += t[0]; + t.erase(0, 1); + } + } + + return ret; +} +unsigned long WCMatcher::getFlags() const +{ + return flags; +} +const bkstring& WCMatcher::getText() const +{ + return *str; +} + +bool WCMatcher::matches() +{ + flags = MATCH_ENTIRE_STRING; + matchedSomething = false; + clearGroups(); + lm = 0; + return pat->head->match(*str, this, 0) == (int)str->size(); +} +bool WCMatcher::findFirstMatch() +{ + starts[0] = 0; + flags = 0; + clearGroups(); + start = 0; + lm = 0; + ends[0] = pat->head->match(*str, this, 0); + if (ends[0] >= 0) + { + matchedSomething = true; + return 1; + } + return 0; +} +bool WCMatcher::findNextMatch() +{ + int s = starts[0], e = ends[0]; + + if (!matchedSomething) return findFirstMatch(); + if (s == e) ++e; + flags = 0; + clearGroups(); + + starts[0] = e; + if (e >= (int)str->size()) return 0; + start = e; + lm = e; + ends[0] = pat->head->match(*str, this, e); + return ends[0] >= 0; +} +std::vector WCMatcher::findAll() +{ + std::vector ret; + reset(); + while (findNextMatch()) + { + ret.push_back(getGroup()); + } + return ret; +} + +void WCMatcher::reset() +{ + lm = 0; + clearGroups(); + matchedSomething = false; +} + +int WCMatcher::getStartingIndex(const int groupNum) const +{ + if (groupNum < 0 || groupNum >= gc) return -1; + return starts[groupNum]; +} +int WCMatcher::getEndingIndex(const int groupNum) const +{ + if (groupNum < 0 || groupNum >= gc) return -1; + return ends[groupNum]; +} +bkstring WCMatcher::getGroup(const int groupNum) const +{ + if (groupNum < 0 || groupNum >= gc) return L""; + if (starts[groupNum] < 0 || ends[groupNum] < 0) return L""; + return str->substr(starts[groupNum], ends[groupNum] - starts[groupNum]); +} +std::vector WCMatcher::getGroups(const bool includeGroupZero) const +{ + int i, start = (includeGroupZero ? 0 : 1); + std::vector ret; + + for (i = start; i < gc; ++i) + { + ret.push_back(getGroup(i)); + } + return ret; +} + diff --git a/plugins/SmileyAdd/src/regexp/WCMatcher.h b/plugins/SmileyAdd/src/regexp/WCMatcher.h new file mode 100644 index 0000000000..23cc49e41f --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/WCMatcher.h @@ -0,0 +1,234 @@ +#ifndef __WCMATCHER_H__ +#define __WCMATCHER_H__ + +#include "bkstring.h" +#include +#include + +/** + A matcher is a non thread-safe object used to scan strings using a given + {@link WCPattern WCPattern} object. Using a WCMatcher is the preferred + method for scanning strings. WCMatchers are not thread-safe. WCMatchers require + very little dynamic memory, hence one is encouraged to create several + instances of a matcher when necessary as opposed to sharing a single instance + of a matcher. +

+ The most common methods needed by the matcher are matches, + findNextMatch, and getGroup. matches + and findNextMatch both return success or failure, and further + details can be gathered from their documentation. +

+ Unlike Java's WCMatcher, this class allows you to change the string + you are matching against. This provides a small optimization, since you no + longer need multiple matchers for a single pattern in a single thread. +

+ This class also provides an extremely handy method for replacing text with + captured data via the replaceWithGroups method. A typical + invocation looks like: +

+  wchar_t buf[10000];
+  bkstring str = "\\5 (user name \\1) uses \\7 for his/her shell and \\6 is their home directory";
+  FILE * fp = fopen("/etc/passwd", "r");
+  WCPattern::registerWCPattern("entry", "[^:]+");
+  WCPattern * p = WCPattern::compile("^({entry}):({entry}):({entry}):({entry}):({entry}):({entry}):({entry})$",
+                                 WCPattern::MULTILINE_MATCHING | WCPattern::UNIX_LINE_MODE);
+  WCMatcher * m = p->createWCMatcher("");
+  while (fgets(buf, 9999, fp))
+  {
+    m->setString(buf);
+    if (m->matches())
+    {
+      printf("%s\n", m->replaceWithGroups(str).c_str());
+    }
+  }
+  fclose(fp);
+
+  
+ Calling any of the following functions before first calling + matches, findFirstMatch, or + findNextMatch results in undefined behavior and may cause your + program to crash. + +
    +
  • replaceWithGroups +
  • getStartingIndex
  • +
  • getEndingIndex
  • +
  • getGroup
  • +
  • getGroups
  • +
+
+

+ The function findFirstMatch will attempt to find the first match + in the input string. The same results can be obtained by first calling + reset followed by findNextMatch. +

+ To eliminate the necessity of looping through a string to find all the + matching substrings, findAll was created. The function will find + all matching substrings and return them in a vector. If you need + to examine specific capture groups within the substrings, then this method + should not be used. + + @author Jeffery Stuart + @since March 2003, Stable Since November 2004 + @version 1.05.00 + @memo Mutable object used on instances of a WCPattern class + */ +class WCMatcher +{ + friend class NFAUNode; + friend class NFAStartUNode; + friend class NFAEndUNode; + friend class NFAGroupHeadUNode; + friend class NFAGroupLoopUNode; + friend class NFAGroupLoopPrologueUNode; + friend class NFAGroupTailUNode; + friend class NFALookBehindUNode; + friend class NFAStartOfLineUNode; + friend class NFAEndOfLineUNode; + friend class NFAEndOfMatchUNode; + friend class NFAReferenceUNode; + friend class WCPattern; + private: + /** + Creates a new matcher object against text using + pattern. + + @param pattern The pattern with which to search + @param text The text in which to search + */ + WCMatcher(WCPattern * pattern, const bkstring & text); + protected: + /// The pattern we use to match + WCPattern * pat; + /// The string in which we are matching + const bkstring * str; + /// The starting point of our match + int start; + /// An array of the starting positions for each group + int * starts; + /// An array of the ending positions for each group + int * ends; + /// An array of private data used by NFAUNodes during matching + int * groups; + /// An array of private data used by NFAUNodes during matching + int * groupIndeces; + /// An array of private data used by NFAUNodes during matching + int * groupPos; + /// The ending index of the last match + int lm; + /// The number of capturing groups we have + int gc; + /// The number of non-capturing groups we havew + int ncgc; + /// Whether or not we have matched something (used only by findFirstMatch and findNextMatch) + int matchedSomething; + /// The flags with which we were made + unsigned long flags; + /// Called by reset to clear the group arrays + void clearGroups(); + public: + /// Used internally by match to signify we want the entire string matched + const static int MATCH_ENTIRE_STRING; + public: + /// Cleans up the dynamic memory used by this matcher + ~WCMatcher(); + /** + Replaces the contents of str with the appropriate captured + text. str should have at least one back reference, otherwise + this function does nothing. + @param str The string in which to replace text + @return A string with all backreferences appropriately replaced + */ + bkstring replaceWithGroups(const bkstring & str); + /** + The flags currently being used by the matcher. + @return Zero + */ + unsigned long getFlags() const; + /** + The text being searched by the matcher. + @return the text being searched by the matcher. + */ + const bkstring& getText() const; + + /** + Scans the string from start to finish for a match. The entire string must + match for this function to return success. Group variables are + appropriately set and can be queried after this function returns. + + @return Success if and only if the entire string matches the pattern + */ + bool matches(); + /** + Scans the string for the first substring matching the pattern. The entire + string does not necessarily have to match for this function to return + success. Group variables are appropriately set and can be queried after + this function returns. + + @return Success if any substring matches the specified pattern + */ + bool findFirstMatch(); + /** + Scans the string for the next substring matching the pattern. If no calls + have been made to findFirstMatch of findNextMatch since the last call to + reset, matches, or setString, then this function's behavior results to + that of findFirstMatch. + + @return Success if another substring can be found that matches the pattern + */ + bool findNextMatch(); + /** + Returns a vector of every substring in order which matches the given + pattern. + + @return Every substring in order which matches the given pattern + */ + std::vector findAll(); + /** + Resets the internal state of the matcher + */ + void reset(); + /** + Same as getText. Left n for backwards compatibilty with old source code + @return Returns the string that is currently being used for matching + */ + inline const bkstring& getString() const { return *str; } + /** + Sets the string to scan + @param newStr The string to scan for subsequent matches + */ + inline void setString(const bkstring & newStr) { str = &newStr; reset(); } + + /** + Returns the starting index of the specified group. + @param groupNum The group to query + @return The starting index of the group if it was matched, -1 for an + invalid group or if the group was not matched + */ + int getStartingIndex(const int groupNum = 0) const; + /** + Returns the ending index of the specified group. + @param groupNum The group to query + @return The ending index of the group if it was matched, -1 for an + invalid group or if the group was not matched + */ + int getEndingIndex(const int groupNum = 0) const; + /** + Returns the specified group. An empty string ("") does not necessarily + mean the group was not matched. A group such as (a*b?) could be matched by + a zero length. If an empty string is returned, getStartingIndex can be + called to determine if the group was actually matched. + @param groupNum The group to query + @return The text of the group + */ + bkstring getGroup(const int groupNum = 0) const; + /** + Returns every capture group in a vector + + @param includeGroupZero Whether or not include capture group zero + @return Every capture group + */ + std::vector getGroups(const bool includeGroupZero = 0) const; +}; + +#endif diff --git a/plugins/SmileyAdd/src/regexp/WCPattern.cpp b/plugins/SmileyAdd/src/regexp/WCPattern.cpp new file mode 100644 index 0000000000..25f379f5e4 --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/WCPattern.cpp @@ -0,0 +1,1747 @@ +/** + From the author (Jeff Stuart) + " + Let me start by saying this file is pretty big. If you feel up to it, you can + try making changes yourself, but you would be better off to just email me at + stuart@cs.ucdavis.edu if you think there is a bug, or have something useful you + would like added. This project is very "near and dear" to me, so I am fairly quick + to make bug fixes. The header files for WCPattern and WCMatcher are fairly well + documented and the function names are pretty self-explanatory, but if you are having + any trouble, feel free to email me at stuart@cs.ucdavis.edu. + + If you email me, make sure you put something like C++RE in the subject because + I tend to delete email if I don't recognize the name and the subject is + something like "I Need Your Help" or "Got A Second" or "I Found It". + " + */ + +/* + Detailed documentation is provided in this class' header file + + @author Jeffery Stuart + @since November 2004 + @version 1.07.00 +*/ + +#ifdef _WIN32 + #pragma warning(push) + #pragma warning(disable:4996) +#endif + +#include +#include +#include +#include +#ifndef _WIN32 + #include +#endif + +std::map WCPattern::compiledWCPatterns; +std::map > WCPattern::registeredWCPatterns; + +const int WCPattern::MIN_QMATCH = 0x00000000; +const int WCPattern::MAX_QMATCH = 0x7FFFFFFF; + +const unsigned long WCPattern::CASE_INSENSITIVE = 0x01; +const unsigned long WCPattern::LITERAL = 0x02; +const unsigned long WCPattern::DOT_MATCHES_ALL = 0x04; +const unsigned long WCPattern::MULTILINE_MATCHING = 0x08; +const unsigned long WCPattern::UNIX_LINE_MODE = 0x10; + +#define to_lower(a) (wchar_t)(UINT_PTR)CharLowerW((LPWSTR)(unsigned)a) +#define is_alpha IsCharAlphaW + +#if defined(_WIN32) + #define str_icmp lstrcmpiW +#elif defined(__CYGWIN__) || defined(__APPLE__) + #include + static inline int str_icmp(const wchar_t * a, const wchar_t * b) + { + while (*a && *b) + { + const int t = (int)towlower(*a) - (int)tolower(*b); + if (t) return t; + ++a; ++b; + } + if (*a) + { + if (*b) return (int)towlower(*a) - (int)tolower(*b); + return 1; + } + else if (*b) return 1; + return 0; + } +#else + #define str_icmp wcscasecmp +#endif + +WCPattern::WCPattern(const bkstring & rhs) +{ + matcher = NULL; + pattern = rhs; + curInd = 0; + groupCount = 0; + nonCapGroupCount = 0; + error = 0; + head = NULL; +} +// convenience function in case we want to add any extra debugging output +void WCPattern::raiseError() +{ +/* switch (pattern[curInd - 1]) + { + case '*': + case ')': + case '+': + case '?': + case ']': + case '}': + fwprintf(stderr, L"%s\n%*c^\n", pattern.c_str(), curInd - 1, ' '); + fwprintf(stderr, L"Syntax Error near here. Possible unescaped meta character.\n"); + break; + default: + fwprintf(stderr, L"%s\n%*c^\n", pattern.c_str(), curInd - 1, ' '); + fwprintf(stderr, L"Syntax Error near here. \n"); + break; + }*/ + error = 1; +} +NFAUNode * WCPattern::registerNode(NFAUNode * node) +{ + nodes[node] = 1; + return node; +} + +bkstring WCPattern::classUnion (bkstring s1, bkstring s2) const +{ + wchar_t * out = new wchar_t[66000]; + std::sort(s1.begin(), s1.end()); + std::sort(s2.begin(), s2.end()); + wchar_t* p = std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), out); *p = 0; + bkstring ret = out; + delete [] out; + return ret; +} +bkstring WCPattern::classIntersect (bkstring s1, bkstring s2) const +{ + wchar_t * out = new wchar_t[66000]; + std::sort(s1.begin(), s1.end()); + std::sort(s2.begin(), s2.end()); + *std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), out) = 0; + bkstring ret = out; + delete [] out; + return ret; +} +bkstring WCPattern::classNegate (bkstring s1) const +{ + wchar_t * out = new wchar_t[66000]; + int i, ind = 0; + std::map m; + + for (i = 0; i < (int)s1.size(); ++i) m[s1[i]] = 1; + for (i = 0xFF; i >= 0; --i) if (m.find((wchar_t)i) == m.end()) out[ind++] = (wchar_t)i; + out[ind] = 0; + bkstring ret(out, ind); + delete [] out; + return ret; +} +bkstring WCPattern::classCreateRange(wchar_t low, wchar_t hi) const +{ + wchar_t out[300]; + int ind = 0; + while (low != hi) out[ind++] = low++; + out[ind++] = low; + return bkstring(out, ind); +} + +int WCPattern::getInt(int start, int end) +{ + int ret = 0; + for (; start <= end; ++start) ret = ret * 10 + (pattern[start] - (wchar_t)'0'); + return ret; +} +bool WCPattern::quantifyCurly(int & sNum, int & eNum) +{ + bool good = 1; + int i, ci = curInd + 1; + int commaInd = ci, endInd = ci, len = pattern.size(); + sNum = eNum = 0; + + while (endInd < len && pattern[endInd ] != (wchar_t)'}') ++endInd; + while (commaInd < endInd && pattern[commaInd] != (wchar_t)',') ++commaInd; + if (endInd >= len) { raiseError(); return 0; } + for (i = ci; good && i < endInd; ++i) if (i != commaInd && !isdigit(pattern[i])) good = 0; + if (!good && commaInd < endInd) { raiseError(); return 0; } + if (!good) return 0; + /* so now everything in here is either a comma (and there is at most one comma) or a digit */ + if (commaInd == ci) // {,*} + { + if (endInd == commaInd + 1) { sNum = MIN_QMATCH; eNum = MAX_QMATCH; } // {,} = * + else { sNum = MIN_QMATCH; eNum = getInt(commaInd + 1, endInd - 1); } // {,+} + } + else if (commaInd == endInd - 1) { sNum = getInt(ci, commaInd - 1); eNum = MAX_QMATCH; } // {+,} + else if (commaInd == endInd) { sNum = getInt(ci, endInd - 1); eNum = sNum; } // {+} + else { sNum = getInt(ci, commaInd - 1); eNum = getInt(commaInd + 1, endInd - 1); } // {+,+} + curInd = endInd + 1; + return 1; +} +NFAUNode * WCPattern::quantifyGroup(NFAUNode * start, NFAUNode * stop, const int gn) +{ + NFAUNode * newNode = NULL; + int type = 0; + + if (curInd < (int)pattern.size()) + { + wchar_t ch = (curInd + 1 >= (int)pattern.size()) ? USHRT_MAX : pattern[curInd + 1]; + switch (pattern[curInd]) + { + case (wchar_t)'*': + ++curInd; + switch (ch) + { + case (wchar_t)'?': ++curInd; type = 1; break; + case (wchar_t)'+': ++curInd; type = 2; break; + } + newNode = registerNode(new NFAGroupLoopPrologueUNode(gn)); + newNode->next = registerNode(new NFAGroupLoopUNode(start, MIN_QMATCH, MAX_QMATCH, gn, type)); + stop->next = newNode->next; + return newNode; + case (wchar_t)'?': + ++curInd; + switch (ch) + { + case (wchar_t)'?': ++curInd; type = 1; break; + case (wchar_t)'+': ++curInd; type = 2; break; + } + newNode = registerNode(new NFAGroupLoopPrologueUNode(gn)); + newNode->next = registerNode(new NFAGroupLoopUNode(start, MIN_QMATCH, 1, gn, type)); + stop->next = newNode->next; + return newNode; + case (wchar_t)'+': + ++curInd; + switch (ch) + { + case (wchar_t)'?': ++curInd; type = 1; break; + case (wchar_t)'+': ++curInd; type = 2; break; + } + newNode = registerNode(new NFAGroupLoopPrologueUNode(gn)); + newNode->next = registerNode(new NFAGroupLoopUNode(start, 1, MAX_QMATCH, gn, type)); + stop->next = newNode->next; + return newNode; + case (wchar_t)'{': + { + int s, e; + if (quantifyCurly(s, e)) + { + ch = (curInd < (int)pattern.size()) ? pattern[curInd] : USHRT_MAX; + switch (ch) + { + case (wchar_t)'?': ++curInd; type = 1; break; + case (wchar_t)'+': ++curInd; type = 2; break; + } + newNode = registerNode(new NFAGroupLoopPrologueUNode(gn)); + newNode->next = registerNode(new NFAGroupLoopUNode(start, s, e, gn, type)); + stop->next = newNode->next; + return newNode; + } + } + default: + break; + } + } + return NULL; +} + +NFAUNode * WCPattern::quantify(NFAUNode * newNode) +{ + if (curInd < (int)pattern.size()) + { + wchar_t ch = (curInd + 1 >= (int)pattern.size()) ? USHRT_MAX : pattern[curInd + 1]; + switch (pattern[curInd]) + { + case (wchar_t)'*': + ++curInd; + switch (ch) + { + case (wchar_t)'?': ++curInd; newNode = registerNode(new NFALazyQuantifierUNode (this, newNode, MIN_QMATCH, MAX_QMATCH)); break; + case (wchar_t)'+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierUNode(this, newNode, MIN_QMATCH, MAX_QMATCH)); break; + default: newNode = registerNode(new NFAGreedyQuantifierUNode (this, newNode, MIN_QMATCH, MAX_QMATCH)); break; + } + break; + case (wchar_t)'?': + ++curInd; + switch (ch) + { + case (wchar_t)'?': ++curInd; newNode = registerNode(new NFALazyQuantifierUNode (this, newNode, MIN_QMATCH, 1)); break; + case (wchar_t)'+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierUNode(this, newNode, MIN_QMATCH, 1)); break; + default: newNode = registerNode(new NFAGreedyQuantifierUNode (this, newNode, MIN_QMATCH, 1)); break; + } + break; + case (wchar_t)'+': + ++curInd; + switch (ch) + { + case (wchar_t)'?': ++curInd; newNode = registerNode(new NFALazyQuantifierUNode (this, newNode, 1, MAX_QMATCH)); break; + case (wchar_t)'+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierUNode(this, newNode, 1, MAX_QMATCH)); break; + default: newNode = registerNode(new NFAGreedyQuantifierUNode (this, newNode, 1, MAX_QMATCH)); break; + } + break; + case (wchar_t)'{': + { + int s, e; + if (quantifyCurly(s, e)) + { + ch = (curInd < (int)pattern.size()) ? pattern[curInd] : USHRT_MAX; + switch (ch) + { + case (wchar_t)'?': ++curInd; newNode = registerNode(new NFALazyQuantifierUNode (this, newNode, s, e)); break; + case (wchar_t)'+': ++curInd; newNode = registerNode(new NFAPossessiveQuantifierUNode(this, newNode, s, e)); break; + default: newNode = registerNode(new NFAGreedyQuantifierUNode (this, newNode, s, e)); break; + } + } + } + break; + default: + break; + } + } + return newNode; +} +bkstring WCPattern::parseClass() +{ + bkstring t, ret = L""; + wchar_t ch, c1, c2; + bool inv = 0, neg = 0, quo = 0; + + if (curInd < (int)pattern.size() && pattern[curInd] == (wchar_t)'^') + { + ++curInd; + neg = 1; + } + while (curInd < (int)pattern.size() && pattern[curInd] != (wchar_t)']') + { + ch = pattern[curInd++]; + if (ch == (wchar_t)'[') + { + t = parseClass(); + ret = classUnion(ret, t); + } + /*else if (ch == (wchar_t)'-') + { + raiseError(); + curInd = pattern.size(); + }*/ + else if (ch == (wchar_t)'&' && curInd < (int)pattern.size() && pattern[curInd] == (wchar_t)'&') + { + if (pattern[++curInd] != (wchar_t)'[') + { + raiseError(); + curInd = pattern.size(); + } + else + { + ++curInd; + t = parseClass(); + ret = classIntersect(ret, t); + } + } + else if (ch == (wchar_t)'\\') + { + t = parseEscape(inv, quo); + if (quo) + { + raiseError(); + curInd = pattern.size(); + } + else if (inv || t.size() > 1) // cant be part of a range (a-z) + { + if (inv) t = classNegate(t); + ret = classUnion(ret, t); + } + else if (curInd < (int)pattern.size() && pattern[curInd] == (wchar_t)'-') // part of a range (a-z) + { + c1 = t[0]; + ++curInd; + if (curInd >= (int)pattern.size()) raiseError(); + else + { + c2 = pattern[curInd++]; + if (c2 == (wchar_t)'\\') + { + t = parseEscape(inv, quo); + if (quo) + { + raiseError(); + curInd = pattern.size(); + } + else if (inv || t.size() > 1) raiseError(); + else ret = classUnion(ret, classCreateRange(c1, c2)); + } + else if (c2 == (wchar_t)'[' || c2 == (wchar_t)']' || c2 == (wchar_t)'-' || c2 == (wchar_t)'&') + { + raiseError(); + curInd = pattern.size(); + } + else ret = classUnion(ret, classCreateRange(c1, c2)); + } + } + else + { + ret = classUnion(ret, t); + } + } + else if (curInd < (int)pattern.size() && pattern[curInd] == (wchar_t)'-') + { + c1 = ch; + ++curInd; + if (curInd >= (int)pattern.size()) raiseError(); + else + { + c2 = pattern[curInd++]; + if (c2 == (wchar_t)'\\') + { + t = parseEscape(inv, quo); + if (quo) + { + raiseError(); + curInd = pattern.size(); + } + else if (inv || t.size() > 1) raiseError(); + else ret = classUnion(ret, classCreateRange(c1, c2)); + } + else if (c2 == (wchar_t)'[' || c2 == (wchar_t)']' || c2 == (wchar_t)'-' || c2 == (wchar_t)'&') + { + raiseError(); + curInd = pattern.size(); + } + else + { + ret = classUnion(ret, classCreateRange(c1, c2)); + } + } + } + else + { + ret += L" "; + ret[ret.size() - 1] = ch; + } + } + if (curInd >= (int)pattern.size() || pattern[curInd] != (wchar_t)']') + { + raiseError(); + ret = L""; + } + else + { + ++curInd; + if (neg) ret = classNegate(ret); + } + return ret; +} +bkstring WCPattern::parsePosix() +{ + bkstring s7 = pattern.substr(curInd, 7); + if (s7 == L"{Lower}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyz"; } + if (s7 == L"{Upper}") { curInd += 7; return L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } + if (s7 == L"{Alpha}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; } + if (s7 == L"{Digit}") { curInd += 7; return L"0123456789"; } + if (s7 == L"{Alnum}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; } + if (s7 == L"{Punct}") { curInd += 7; return L"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } + if (s7 == L"{Graph}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } + if (s7 == L"{Print}") { curInd += 7; return L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; } + if (s7 == L"{Blank}") { curInd += 7; return L" \t"; } + if (s7 == L"{Space}") { curInd += 7; return L" \t\n\x0B\f\r"; } + if (s7 == L"{Cntrl}") + { + bkstring::value_type i; + bkstring s = L" "; + + for (i = 0; i < 5; ++i) s += s; + s += L" "; + for (i = 0; i <= 0x1F; ++i) s[i] = i; + s[0x20] = 0x7F; + curInd += 7; + return s; + } + if (s7 == L"{ASCII}") + { + bkstring s(0x80, (wchar_t)' '); + for (bkstring::value_type i = 0; i <= 0x7f; ++i) s[i] = i; + curInd += 7; + return s; + } + if (pattern.substr(curInd, 8) == L"{XDigit}") { curInd += 8; return L"abcdefABCDEF0123456789"; } + raiseError(); + return L""; +} +NFAUNode * WCPattern::parseBackref() +{ + #define is_dig(x) ((x) >= (wchar_t)'0' && (x) <= (wchar_t)'9') + #define to_int(x) ((x) - (wchar_t)'0') + int ci = curInd; + int oldRef = 0, ref = 0; + + while (ci < (int)pattern.size() && is_dig(pattern[ci]) && (ref < 10 || ref < groupCount)) + { + oldRef = ref; + ref = ref * 10 + to_int(pattern[ci++]); + } + if (ci == (int)pattern.size()) + { + oldRef = ref; + ++ci; + } + if (oldRef < 0 || ci <= curInd) + { + raiseError(); + return registerNode(new NFAReferenceUNode(-1)); + } + curInd = ci; + return registerNode(new NFAReferenceUNode(ref)); + + #undef is_dig + #undef to_int +} +bkstring WCPattern::parseOctal() +{ + #define islowoc(x) ((x) >= (wchar_t)'0' && (x) <= (wchar_t)'3') + #define isoc(x) ((x) >= (wchar_t)'0' && (x) <= (wchar_t)'7') + #define fromoc(x) ((x) - (wchar_t)'0') + int ci = curInd; + wchar_t ch1 = (ci + 0 < (int)pattern.size()) ? pattern[ci + 0] : USHRT_MAX; + wchar_t ch2 = (ci + 1 < (int)pattern.size()) ? pattern[ci + 1] : USHRT_MAX; + wchar_t ch3 = (ci + 2 < (int)pattern.size()) ? pattern[ci + 2] : USHRT_MAX; + bkstring s = L" "; + + if (islowoc(ch1) && isoc(ch2)) + { + curInd += 2; + s[0] = fromoc(ch1) * 8 + fromoc(ch2); + if (isoc(ch3)) + { + ++curInd; + s[0] = s[0] * 8 + fromoc(ch3); + } + } + else if (isoc(ch1) && isoc(ch2)) + { + curInd += 2; + s[0] = fromoc(ch1) * 8 + fromoc(ch2); + } + else raiseError(); + + return s; + #undef islowoc + #undef isoc + #undef fromoc +} +bkstring WCPattern::parseHex() +{ + #define to_low(x) (((x) >= (wchar_t)'A' && (x) <= (wchar_t)'Z') ? ((x) - (wchar_t)'A' + (wchar_t)'a') : (x)) + #define is_dig(x) ((x) >= (wchar_t)'0' && (x) <= (wchar_t)'9') + #define is_hex(x) (is_dig(x) || (to_low(x) >= (wchar_t)'a' && to_low(x) <= (wchar_t)'f')) + #define to_int(x) ((is_dig(x)) ? ((x) - (wchar_t)'0') : (to_low(x) - (wchar_t)'a' + 10)) + + int ci = curInd; + wchar_t ch1 = (ci + 0 < (int)pattern.size()) ? pattern[ci + 0] : USHRT_MAX; + wchar_t ch2 = (ci + 1 < (int)pattern.size()) ? pattern[ci + 1] : USHRT_MAX; + wchar_t ch3 = (ci + 2 < (int)pattern.size()) ? pattern[ci + 2] : USHRT_MAX; + wchar_t ch4 = (ci + 3 < (int)pattern.size()) ? pattern[ci + 3] : USHRT_MAX; + bkstring s = L" "; + + if (is_hex(ch1) && is_hex(ch2) && is_hex(ch3) && is_hex(ch4)) + { + curInd += 2; + s[0] = (to_int(ch1) << 12 & 0xF000) | (to_int(ch2) << 8 & 0x0F00) | + (to_int(ch3) << 4 & 0x0F00) | (to_int(ch4) & 0x000F); + } + else if (is_hex(ch1) && is_hex(ch2)) + { + curInd += 2; + s[0] = (to_int(ch1) << 4 & 0xF0) | (to_int(ch2) & 0x0F); + } + + return s; + #undef to_low + #undef is_dig + #undef is_hex + #undef to_int +} +bkstring WCPattern::parseEscape(bool & inv, bool & quo) +{ + wchar_t ch = pattern[curInd++]; + bkstring classes = L""; + + if (curInd > (int)pattern.size()) + { + raiseError(); + return NULL; + } + + quo = 0; + inv = 0; + switch (ch) + { + case (wchar_t)'p': classes = parsePosix(); break; + case (wchar_t)'P': classes = L"!!"; classes += parsePosix(); break; + case (wchar_t)'d': classes = L"0123456789"; break; + case (wchar_t)'D': classes = L"!!0123456789"; break; + case (wchar_t)'s': classes = L" \t\r\n\f"; break; + case (wchar_t)'S': classes = L"!! \t\r\n\f"; break; + case (wchar_t)'w': classes = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; break; + case (wchar_t)'W': classes = L"!!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; break; + case (wchar_t)'0': classes = parseOctal(); break; + case (wchar_t)'x': classes = parseHex(); break; + + case (wchar_t)'Q': quo = 1; break; + case (wchar_t)'t': classes = L"\t"; break; + case (wchar_t)'r': classes = L"\r"; break; + case (wchar_t)'n': classes = L"\n"; break; + case (wchar_t)'f': classes = L"\f"; break; + case (wchar_t)'a': classes = L"\a"; break; + case (wchar_t)'e': classes = L"\r"; break; + default: classes = L" "; classes[0] = ch; break; + } + if (classes.substr(0, 2) == L"!!") + { + classes = classes.substr(2); + inv = 1; + } + return classes; +} +NFAUNode * WCPattern::parseRegisteredWCPattern(NFAUNode ** end) +{ + int i, j; + bkstring s; + NFAUNode * ret = NULL; + for (i = curInd; i < (int)pattern.size() && pattern[i] != (wchar_t)'}'; ++i) { } + if (pattern[i] != (wchar_t)'}') { raiseError(); return NULL; } + if (i == curInd + 1) { raiseError(); return NULL; } // {} + if ( + !( + (pattern[curInd] >= (wchar_t)'a' && pattern[curInd] <= (wchar_t)'z') || + (pattern[curInd] >= (wchar_t)'A' && pattern[curInd] <= (wchar_t)'Z') || + (pattern[curInd] == (wchar_t)'_') + ) + ) + { + raiseError(); + return NULL; + } + for (j = curInd; !error && j < i; ++j) + { + if ( + !( + (pattern[j] >= (wchar_t)'a' && pattern[j] <= (wchar_t)'z') || + (pattern[j] >= (wchar_t)'A' && pattern[j] <= (wchar_t)'Z') || + (pattern[j] >= (wchar_t)'0' && pattern[j] <= (wchar_t)'9') || + (pattern[j] == (wchar_t)'_') + ) + ) + { + raiseError(); + return NULL; + } + } + s = pattern.substr(curInd, i - curInd); + if (registeredWCPatterns.find(s) == registeredWCPatterns.end()) raiseError(); + else + { + unsigned long oflags = flags; + bkstring op = pattern; + int ci = i + 1; + + pattern = registeredWCPatterns[s].first; + curInd = 0; + flags = registeredWCPatterns[s].second; + + --groupCount; + ret = parse(0, 0, end); + + pattern = op; + curInd = ci; + flags = oflags; + } + if (error) { *end = ret = NULL; } + return ret; +} + +// look behind should interpret everything as a literal (except \\) since the +// pattern must have a concrete length +NFAUNode * WCPattern::parseBehind(const bool pos, NFAUNode ** end) +{ + bkstring t = L""; + while (curInd < (int)pattern.size() && pattern[curInd] != (wchar_t)')') + { + wchar_t ch = pattern[curInd++]; + t += L" "; + if (ch == (wchar_t)'\\') + { + if (curInd + 1 >= (int)pattern.size()) + { + raiseError(); + return *end = registerNode(new NFACharUNode((wchar_t)' ')); + } + ch = pattern[curInd++]; + } + t[t.size() - 1] = ch; + } + if (curInd >= (int)pattern.size() || pattern[curInd] != (wchar_t)')') raiseError(); + else ++curInd; + return *end = registerNode(new NFALookBehindUNode(t, pos)); +} +NFAUNode * WCPattern::parseQuote() +{ + bool done = 0; + bkstring s = L""; + + while (!done) + { + if (curInd >= (int)pattern.size()) + { + raiseError(); + done = 1; + } + else if (pattern.substr(curInd, 2) == L"\\E") + { + curInd += 2; + done = 1; + } + else if (pattern[curInd] == (wchar_t)'\\') + { + s += L" "; + s[s.size() - 1] = pattern[++curInd]; + ++curInd; + } + else + { + s += L" "; + s[s.size() - 1] = pattern[curInd++]; + } + } + if ((flags & WCPattern::CASE_INSENSITIVE) != 0) return registerNode(new NFACIQuoteUNode(s)); + return registerNode(new NFAQuoteUNode(s)); +} +NFAUNode * WCPattern::parse(const bool inParen, const bool inOr, NFAUNode ** end) +{ + NFAUNode * start, * cur, * next = NULL; + bkstring t; + int grc = groupCount++; + bool inv, quo; + bool ahead = 0, pos = 0, noncap = 0, indep = 0; + unsigned long oldFlags = flags; + + if (inParen) + { + if (pattern[curInd] == (wchar_t)'?') + { + ++curInd; + --groupCount; + if (pattern[curInd] == (wchar_t)':') { noncap = 1; ++curInd; grc = --nonCapGroupCount; } + else if (pattern[curInd] == (wchar_t)'=') { ++curInd; ahead = 1; pos = 1; } + else if (pattern[curInd] == (wchar_t)'!') { ++curInd; ahead = 1; pos = 0; } + else if (pattern.substr(curInd, 2) == L"<=") { curInd += 2; return parseBehind(1, end); } + else if (pattern.substr(curInd, 2) == L"') { ++curInd; indep = 1; } + else + { + bool negate = false, done = false; + while (!done) + { + if (curInd >= (int)pattern.size()) + { + raiseError(); + return NULL; + } + else if (negate) + { + switch (pattern[curInd]) + { + case (wchar_t)'i': flags &= ~WCPattern::CASE_INSENSITIVE; break; + case (wchar_t)'d': flags &= ~WCPattern::UNIX_LINE_MODE; break; + case (wchar_t)'m': flags &= ~WCPattern::MULTILINE_MATCHING; break; + case (wchar_t)'s': flags &= ~WCPattern::DOT_MATCHES_ALL; break; + case (wchar_t)':': done = true; break; + case (wchar_t)')': + ++curInd; + *end = registerNode(new NFALookBehindUNode(L"", true)); + return *end; + case (wchar_t)'-': + default: raiseError(); return NULL; + } + } + else + { + switch (pattern[curInd]) + { + case (wchar_t)'i': flags |= WCPattern::CASE_INSENSITIVE; break; + case (wchar_t)'d': flags |= WCPattern::UNIX_LINE_MODE; break; + case (wchar_t)'m': flags |= WCPattern::MULTILINE_MATCHING; break; + case (wchar_t)'s': flags |= WCPattern::DOT_MATCHES_ALL; break; + case (wchar_t)':': done = true; break; + case (wchar_t)'-': negate = true; break; + case (wchar_t)')': + ++curInd; + *end = registerNode(new NFALookBehindUNode(L"", true)); + return *end; + default: raiseError(); return NULL; + } + } + ++curInd; + } + noncap = 1; + grc = --nonCapGroupCount; + } + + if (noncap) cur = start = registerNode(new NFAGroupHeadUNode(grc)); + else cur = start = registerNode(new NFASubStartUNode); + } + else cur = start = registerNode(new NFAGroupHeadUNode(grc)); + } + else cur = start = registerNode(new NFASubStartUNode); + while (curInd < (int)pattern.size()) + { + wchar_t ch = pattern[curInd++]; + + next = NULL; + if (error) return NULL; + switch (ch) + { + case (wchar_t)'^': + if ((flags & WCPattern::MULTILINE_MATCHING) != 0) next = registerNode(new NFAStartOfLineUNode); + else next = registerNode(new NFAStartOfInputUNode); + break; + case (wchar_t)'$': + if ((flags & WCPattern::MULTILINE_MATCHING) != 0) next = registerNode(new NFAEndOfLineUNode); + else next = registerNode(new NFAEndOfInputUNode(0)); + break; + case (wchar_t)'|': + --groupCount; + cur->next = registerNode(new NFAAcceptUNode); + cur = start = registerNode(new NFAOrUNode(start, parse(inParen, 1))); + break; + case (wchar_t)'\\': + if (curInd < (int)pattern.size()) + { + bool eoi = 0; + switch (pattern[curInd]) + { + case (wchar_t)'1': + case (wchar_t)'2': + case (wchar_t)'3': + case (wchar_t)'4': + case (wchar_t)'5': + case (wchar_t)'6': + case (wchar_t)'7': + case (wchar_t)'8': + case (wchar_t)'9': next = parseBackref(); break; + case (wchar_t)'A': ++curInd; next = registerNode(new NFAStartOfInputUNode); break; + case (wchar_t)'B': ++curInd; next = registerNode(new NFAWordBoundaryUNode(0)); break; + case (wchar_t)'b': ++curInd; next = registerNode(new NFAWordBoundaryUNode(1)); break; + case (wchar_t)'G': ++curInd; next = registerNode(new NFAEndOfMatchUNode); break; + case (wchar_t)'Z': eoi = 1; + case (wchar_t)'z': ++curInd; next = registerNode(new NFAEndOfInputUNode(eoi)); break; + default: + t = parseEscape(inv, quo); + //printf("inv quo classes { %c %c %s }\n", inv ? (wchar_t)'t' : (wchar_t)'f', quo ? (wchar_t)'t' : (wchar_t)'f', t.c_str()); + if (!quo) + { + if (t.size() > 1 || inv) + { + if ((flags & WCPattern::CASE_INSENSITIVE) != 0) next = registerNode(new NFACIClassUNode(t, inv)); + else next = registerNode(new NFAClassUNode(t, inv)); + } + else + { + next = registerNode(new NFACharUNode(t[0])); + } + } + else + { + next = parseQuote(); + } + } + } + else raiseError(); + break; + case (wchar_t)'[': + if ((flags & WCPattern::CASE_INSENSITIVE) == 0) + { + NFAClassUNode * clazz = new NFAClassUNode(); + bkstring s = parseClass(); + for (int i = 0; i < (int)s.size(); ++i) clazz->vals[s[i]] = 1; + next = registerNode(clazz); + } + else + { + NFACIClassUNode * clazz = new NFACIClassUNode(); + bkstring s = parseClass(); + for (int i = 0; i < (int)s.size(); ++i) clazz->vals[to_lower(s[i])] = 1; + next = registerNode(clazz); + } + break; + case (wchar_t)'.': + { + bool useN = 1, useR = 1; + NFAClassUNode * clazz = new NFAClassUNode(1); + if ((flags & WCPattern::UNIX_LINE_MODE) != 0) useR = 0; + if ((flags & WCPattern::DOT_MATCHES_ALL) != 0) useN = useR = 0; + if (useN) clazz->vals[(wchar_t)'\n'] = 1; + if (useR) clazz->vals[(wchar_t)'\r'] = 1; + next = registerNode(clazz); + } + break; + case (wchar_t)'(': + { + NFAUNode * end, * t1, * t2; + t1 = parse(1, 0, &end); + if (!t1) raiseError(); + else if (t1->isGroupHeadNode() && (t2 = quantifyGroup(t1, end, grc)) != NULL) + { + cur->next = t2; + cur = t2->next; + } + else + { + cur->next = t1; + cur = end; + } + } + break; + case (wchar_t)')': + if (!inParen) raiseError(); + else if (inOr) + { + --curInd; + cur = cur->next = registerNode(new NFAAcceptUNode); + flags = oldFlags; + return start; + } + else + { + if (ahead) + { + cur = cur->next = registerNode(new NFAAcceptUNode); + flags = oldFlags; + return *end = registerNode(new NFALookAheadUNode(start, pos)); + } + else if (indep) + { + cur = cur->next = registerNode(new NFAAcceptUNode); + flags = oldFlags; + return *end = registerNode(new NFAPossessiveQuantifierUNode(this, start, 1, 1)); + } + else // capping or noncapping, it doesnt matter + { + *end = cur = cur->next = registerNode(new NFAGroupTailUNode(grc)); + next = quantifyGroup(start, *end, grc); + if (next) + { + start = next; + *end = next->next; + } + flags = oldFlags; + return start; + } + } + break; + case (wchar_t)'{': // registered pattern + cur->next = parseRegisteredWCPattern(&next); + if (cur->next) cur = next; + break; + case (wchar_t)'*': + case (wchar_t)'+': + case (wchar_t)'?': +// case (wchar_t)'}': +// case (wchar_t)']': + raiseError(); + break; + default: + if ((flags & WCPattern::CASE_INSENSITIVE) != 0) next = registerNode(new NFACICharUNode(ch)); + else next = registerNode(new NFACharUNode(ch)); + break; + } + if (next) cur = cur->next = quantify(next); + } + if (inParen) raiseError(); + else + { + if (inOr) cur = cur->next = registerNode(new NFAAcceptUNode); + if (end) *end = cur; + } + + flags = oldFlags; + if (error) return NULL; + + return start; +} + +WCPattern * WCPattern::compile(const bkstring & pattern, const unsigned long mode) +{ + WCPattern * p = new WCPattern(pattern); + NFAUNode * end; + + p->flags = mode; + if ((mode & WCPattern::LITERAL) != 0) + { + p->head = p->registerNode(new NFAStartUNode); + if ((mode & WCPattern::CASE_INSENSITIVE) != 0) p->head->next = p->registerNode(new NFACIQuoteUNode(pattern)); + else p->head->next = p->registerNode(new NFAQuoteUNode(pattern)); + p->head->next->next = p->registerNode(new NFAEndUNode); + } + else + { + p->head = p->parse(0, 0, &end); + if (!p->head) + { + delete p; + p = NULL; + } + else + { + if (!(p->head && p->head->isStartOfInputNode())) + { + NFAUNode * n = p->registerNode(new NFAStartUNode); + n->next = p->head; + p->head = n; + } + end->next = p->registerNode(new NFAEndUNode); + } + } + if (p != NULL) + { + p->matcher = new WCMatcher(p, L""); + } + + return p; +} + +WCPattern * WCPattern::compileAndKeep(const bkstring & pattern, const unsigned long mode) +{ + WCPattern * ret = NULL; + std::map::iterator it = compiledWCPatterns.find(pattern); + + if (it != compiledWCPatterns.end()) + { + ret = it->second; + } + else + { + ret = compile(pattern, mode); + compiledWCPatterns[pattern] = ret; + } + + return ret; +} +bkstring WCPattern::replace(const bkstring & pattern, const bkstring & str, + const bkstring & replacementText, const unsigned long mode) +{ + bkstring ret; + WCPattern * p = WCPattern::compile(pattern, mode); + if (p) + { + ret = p->replace(str, replacementText); + delete p; + } + return ret; +} + +std::vector WCPattern::split(const bkstring & pattern, const bkstring & str, const bool keepEmptys, + const unsigned long limit, const unsigned long mode) +{ + std::vector ret; + WCPattern * p = WCPattern::compile(pattern, mode); + if (p) + { + ret = p->split(str, keepEmptys, limit); + delete p; + } + return ret; +} + +std::vector WCPattern::findAll(const bkstring & pattern, const bkstring & str, const unsigned long mode) +{ + std::vector ret; + WCPattern * p = WCPattern::compile(pattern, mode); + if (p) + { + ret = p->findAll(str); + delete p; + } + return ret; +} + +bool WCPattern::matches(const bkstring & pattern, const bkstring & str, const unsigned long mode) +{ + bool ret = 0; + WCPattern * p = compile(pattern, mode); + + if (p) + { + ret = p->matches(str); + delete p; + } + + return ret; +} + +bool WCPattern::registerWCPattern(const bkstring & name, const bkstring & pattern, const unsigned long mode) +{ + WCPattern * p = WCPattern::compile(pattern, mode); + if (!p) return 0; + WCPattern::registeredWCPatterns[name] = std::make_pair(pattern, mode); + delete p; + return 1; +} + +void WCPattern::unregisterWCPatterns() +{ + registeredWCPatterns.clear(); +} +void WCPattern::clearWCPatternCache() +{ + std::map::iterator it; + for (it = compiledWCPatterns.begin(); it != compiledWCPatterns.end(); ++it) + { + delete it->second; + } + compiledWCPatterns.clear(); +} + +std::pair WCPattern::findNthMatch(const bkstring & pattern, const bkstring & str, + const int matchNum, const unsigned long mode) +{ + std::pair ret; + WCPattern * p = WCPattern::compile(pattern, mode); + + ret.second = -1; + if (p) + { + int i = -1; + p->matcher->setString(str); + while (i < matchNum && p->matcher->findNextMatch()) { ++i; } + if (i == matchNum && p->matcher->getStartingIndex() >= 0) + { + ret.first = p->matcher->getGroup(0); + ret.second = p->matcher->getStartingIndex(); + } + delete p; + } + + return ret; +} + +WCPattern::~WCPattern() +{ + /* + nodes.clear(); + if (head) head->findAllNodes(nodes); + */ + if (matcher) delete matcher; + for (std::map::iterator it = nodes.begin(); it != nodes.end(); ++it) delete it->first; +} +bkstring WCPattern::replace(const bkstring & str, const bkstring & replacementText) +{ + int li = 0; + bkstring ret = L""; + + matcher->setString(str); + while (matcher->findNextMatch()) + { + ret += str.substr(li, matcher->getStartingIndex() - li); + ret += matcher->replaceWithGroups(replacementText); + li = matcher->getEndingIndex(); + } + ret += str.substr(li); + + return ret; +} +std::vector WCPattern::split(const bkstring & str, const bool keepEmptys, const unsigned long limit) +{ + unsigned long lim = (limit == 0 ? MAX_QMATCH : limit); + int li = 0; + std::vector ret; + + matcher->setString(str); + + while (matcher->findNextMatch() && ret.size() < lim) + { + if (matcher->getStartingIndex() == 0 && keepEmptys) ret.push_back(L""); + if ((matcher->getStartingIndex() != matcher->getEndingIndex()) || keepEmptys) + { + if (li != matcher->getStartingIndex() || keepEmptys) + { + ret.push_back(str.substr(li, matcher->getStartingIndex() - li)); + } + li = matcher->getEndingIndex(); + } + } + if (li < (int)str.size()) ret.push_back(str.substr(li)); + + return ret; +} +std::vector WCPattern::findAll(const bkstring & str) +{ + matcher->setString(str); + return matcher->findAll(); +} +bool WCPattern::matches(const bkstring & str) +{ + matcher->setString(str); + return matcher->matches(); +} +unsigned long WCPattern::getFlags() const +{ + return flags; +} +bkstring WCPattern::getWCPattern() const +{ + return pattern; +} +WCMatcher * WCPattern::createWCMatcher(const bkstring & str) +{ + return new WCMatcher(this, str); +} + +// NFAUNode + +NFAUNode::NFAUNode() { next = NULL; } +NFAUNode::~NFAUNode() { } +void NFAUNode::findAllNodes(std::map & soFar) +{ + if (soFar.find(this) == soFar.end()) return; + soFar[this] = 1; + if (next) next->findAllNodes(soFar); +} + +// NFACharUNode + +NFACharUNode::NFACharUNode(const wchar_t c) { ch = c; } +int NFACharUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd < (int)str.size() && str[curInd] == ch) return next->match(str, matcher, curInd + 1); + return -1; +} + +// NFACICharUNode + +NFACICharUNode::NFACICharUNode(const wchar_t c) { ch = to_lower(c); } +int NFACICharUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd < (int)str.size() && to_lower(str[curInd]) == ch) return next->match(str, matcher, curInd + 1); + return -1; +} + +// NFAStartUNode + +NFAStartUNode::NFAStartUNode() { } +int NFAStartUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int ret = -1, ci = curInd; + + matcher->starts[0] = curInd; + if ((matcher->getFlags() & WCMatcher::MATCH_ENTIRE_STRING) == (unsigned int)WCMatcher::MATCH_ENTIRE_STRING) + { + if (curInd != 0) + { + matcher->starts[0] = -1; + return -1; + } + return next->match(str, matcher, 0); + } + while ((ret = next->match(str, matcher, ci)) == -1 && ci < (int)str.size()) + { + matcher->clearGroups(); + matcher->starts[0] = ++ci; + } + if (ret < 0) matcher->starts[0] = -1; + return ret; +} + +// NFAEndUNode + +NFAEndUNode::NFAEndUNode() { } +int NFAEndUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + matcher->ends[0] = curInd; + if ((matcher->getFlags() & WCMatcher::MATCH_ENTIRE_STRING) != 0) + { + if (curInd == (int)str.size()) return curInd; + matcher->ends[0] = -1; + return -1; + } + return curInd; +} + +// NFAQuantifierUNode + +void NFAQuantifierUNode::findAllNodes(std::map & soFar) +{ + inner->findAllNodes(soFar); + NFAUNode::findAllNodes(soFar); +} +NFAQuantifierUNode::NFAQuantifierUNode(WCPattern * pat, NFAUNode * internal, const int minMatch, const int maxMatch) +{ + inner = internal; + inner->next = pat->registerNode(new NFAAcceptUNode); + min = (minMatch < WCPattern::MIN_QMATCH) ? WCPattern::MIN_QMATCH : minMatch; + max = (maxMatch > WCPattern::MAX_QMATCH) ? WCPattern::MAX_QMATCH : maxMatch; +} + +int NFAQuantifierUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int i0, i1, i2 = 0; + + i0 = i1 = curInd; + while (i2 < min) + { + + ++i2; + i1 = inner->match(str, matcher, i0); + if (i1 <= i0) return i1; // i1 < i0 means i1 is -1 + i0 = i1; + } + + return i1; +} +// NFAGreedyQuantifierUNode + +NFAGreedyQuantifierUNode::NFAGreedyQuantifierUNode(WCPattern * pat, NFAUNode * internal, const int minMatch, const int maxMatch) + : NFAQuantifierUNode(pat, internal, minMatch, maxMatch) { } +int NFAGreedyQuantifierUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int t = NFAQuantifierUNode::match(str, matcher, curInd); + if (t != -1) return matchInternal(str, matcher, t, min); + return t; +} +int NFAGreedyQuantifierUNode::matchInternal(const bkstring & str, WCMatcher * matcher, const int curInd, const int soFar) const +{ + if (soFar >= max) return next->match(str, matcher, curInd); + + int i, j; + + i = inner->match(str, matcher, curInd); + if (i != -1) + { + j = matchInternal(str, matcher, i, soFar + 1); + if (j != -1) return j; + } + return next->match(str, matcher, curInd); +} + +// NFALazyQuantifierUNode + +NFALazyQuantifierUNode::NFALazyQuantifierUNode(WCPattern * pat, NFAUNode * internal, const int minMatch, const int maxMatch) + : NFAQuantifierUNode(pat, internal, minMatch, maxMatch) { } +int NFALazyQuantifierUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int i, j, m = NFAQuantifierUNode::match(str, matcher, curInd); + + if (m == -1) return -1; + + for (i = min; i < max; ++i) + { + j = next->match(str, matcher, m); + if (j == -1) + { + j = inner->match(str, matcher, m); + // if j < m, then j is -1, so we bail. + // if j == m, then we would just go and call next->match on the same index, + // but it already failed trying to match right there, so we know we can + // just bail + if (j <= m) return -1; + m = j; + } + else return j; + } + return next->match(str, matcher, m); +} + +// NFAPossessiveQuantifierUNode + +NFAPossessiveQuantifierUNode::NFAPossessiveQuantifierUNode(WCPattern * pat, NFAUNode * internal, const int minMatch, const int maxMatch) + : NFAQuantifierUNode(pat, internal, minMatch, maxMatch) { } +int NFAPossessiveQuantifierUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int i, j, m = NFAQuantifierUNode::match(str, matcher, curInd); + + if (m == -1) return -1; + for (i = min; i < max; ++i) + { + j = inner->match(str, matcher, m); + if (j <= m) return next->match(str, matcher, m); + m = j; + } + return next->match(str, matcher, m); +} + +// NFAAcceptUNode + +NFAAcceptUNode::NFAAcceptUNode() { } +int NFAAcceptUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (!next) return curInd; + else return next->match(str, matcher, curInd); +} + +// NFAClassUNode + +NFAClassUNode::NFAClassUNode(const bool invert) +{ + inv = invert; +} +NFAClassUNode::NFAClassUNode(const bkstring & clazz, const bool invert) +{ + inv = invert; + for (int i = 0; i < (int)clazz.size(); ++i) vals[clazz[i]] = 1; +} +int NFAClassUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd < (int)str.size() && ((vals.find(str[curInd]) != vals.end()) ^ inv)) + { + return next->match(str, matcher, curInd + 1); + } + return -1; +} + +// NFACIClassUNode + +NFACIClassUNode::NFACIClassUNode(const bool invert) +{ + inv = invert; +} +NFACIClassUNode::NFACIClassUNode(const bkstring & clazz, const bool invert) +{ + inv = invert; + for (int i = 0; i < (int)clazz.size(); ++i) vals[to_lower(clazz[i])] = 1; +} +int NFACIClassUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd < (int)str.size() && ((vals.find(to_lower(str[curInd])) != vals.end()) ^ inv)) + { + return next->match(str, matcher, curInd + 1); + } + return -1; +} + +// NFASubStartUNode + +NFASubStartUNode::NFASubStartUNode() { } +int NFASubStartUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + return next->match(str, matcher, curInd); +} + +// NFAOrUNode + +NFAOrUNode::NFAOrUNode(NFAUNode * first, NFAUNode * second) : one(first), two(second) { } +void NFAOrUNode::findAllNodes(std::map & soFar) +{ + if (one) one->findAllNodes(soFar); + if (two) two->findAllNodes(soFar); + NFAUNode::findAllNodes(soFar); +} +int NFAOrUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int ci = one->match(str, matcher, curInd); + + if (ci != -1) ci = next->match(str, matcher, ci); + if (ci != -1) return ci; + if (ci == -1) ci = two->match(str, matcher, curInd); + if (ci != -1) ci = next->match(str, matcher, ci); + return ci; +} + +// NFAQuoteUNode + +NFAQuoteUNode::NFAQuoteUNode(const bkstring & quoted) : qStr(quoted) { } +int NFAQuoteUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd + qStr.size() > str.size()) return -1; + if (str.substr(curInd, qStr.size()) != qStr) return -1; + return next->match(str, matcher, curInd + (int)qStr.size()); +} + +// NFACIQuoteUNode + +NFACIQuoteUNode::NFACIQuoteUNode(const bkstring & quoted) : qStr(quoted) { } +int NFACIQuoteUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd + qStr.size() > str.size()) return -1; + if (str_icmp(str.substr(curInd, qStr.size()).c_str(), qStr.c_str())) return -1; + return next->match(str, matcher, (int)qStr.size()); +} + +// NFALookAheadUNode + +NFALookAheadUNode::NFALookAheadUNode(NFAUNode * internal, const bool positive) : NFAUNode(), pos(positive), inner(internal) { } +void NFALookAheadUNode::findAllNodes(std::map & soFar) +{ + if (inner) inner->findAllNodes(soFar); + NFAUNode::findAllNodes(soFar); +} +int NFALookAheadUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + return ((inner->match(str, matcher, curInd) == -1) ^ pos) ? next->match(str, matcher, curInd) : -1; +} + +// NFALookBehindUNode + +NFALookBehindUNode::NFALookBehindUNode(const bkstring & str, const bool positive) : pos(positive), mStr(str) { } +int NFALookBehindUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (pos) + { + if (curInd < (int)mStr.size()) return -1; + if (str.substr(curInd - mStr.size(), mStr.size()) == mStr) return next->match(str, matcher, curInd); + } + else + { + if (curInd < (int)mStr.size()) return next->match(str, matcher, curInd); + if (str.substr(curInd - mStr.size(), mStr.size()) == mStr) return -1; + return next->match(str, matcher, curInd); + } + return -1; +} + +// NFAStartOfLineUNode + +NFAStartOfLineUNode::NFAStartOfLineUNode() { } +int NFAStartOfLineUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd == 0 || str[curInd - 1] == (wchar_t)'\n' || str[curInd - 1] == (wchar_t)'\r') + { + return next->match(str, matcher, curInd); + } + return -1; +} + +// NFAEndOfLineUNode + +NFAEndOfLineUNode::NFAEndOfLineUNode() { } +int NFAEndOfLineUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd >= (int)str.size() || str[curInd] == (wchar_t)'\n' || str[curInd] == (wchar_t)'\r') + { + return next->match(str, matcher, curInd); + } + return -1; +} + +// NFAReferenceUNode + +NFAReferenceUNode::NFAReferenceUNode(const int groupIndex) : gi(groupIndex) { } +int NFAReferenceUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int len = matcher->ends[gi] - matcher->starts[gi]; + int ni = -1; + if (gi < 1 || matcher->ends[gi] < matcher->starts[gi] || len == 0) ni = curInd; + else if (curInd + len > (int)str.size()) return -1; + else if (str.substr(curInd, len) != str.substr(matcher->starts[gi], len)) return -1; + else ni = curInd + len; + + return next->match(str, matcher, ni); +} + +// NFAStartOfInputUNode + +NFAStartOfInputUNode::NFAStartOfInputUNode() { } +int NFAStartOfInputUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd == 0) return next->match(str, matcher, curInd); + return -1; +} + +// NFAEndOfInputUNode + +NFAEndOfInputUNode::NFAEndOfInputUNode(const bool lookForTerm) : term(lookForTerm) { } +int NFAEndOfInputUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int len = (int)str.size(); + if (curInd == len) return next->match(str, matcher, curInd); + else if (term) + { + if (curInd == len - 1 && (str[curInd] == (wchar_t)'\r' || str[curInd] == (wchar_t)'\n')) + { + return next->match(str, matcher, curInd); + } + else if (curInd == len - 2 && str.substr(curInd, 2) == L"\r\n") + { + return next->match(str, matcher, curInd); + } + } + return -1; +} + +// NFAWordBoundaryUNode + +NFAWordBoundaryUNode::NFAWordBoundaryUNode(const bool positive) : pos(positive) { } +int NFAWordBoundaryUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int len = (int)str.size(); + + wchar_t c1 = (curInd - 1 < len && curInd > 0) ? str[curInd - 1] : '\n'; + wchar_t c2 = (curInd < len) ? str[curInd ] : '\n'; + + if (curInd == len) return next->match(str, matcher, curInd); + bool ok = is_alpha(c1) != is_alpha(c2); + if (ok && pos) return next->match(str, matcher, curInd); + return -1; +} + +// NFAEndOfMatchUNode + +NFAEndOfMatchUNode::NFAEndOfMatchUNode() { } +int NFAEndOfMatchUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + if (curInd == matcher->lm) return next->match(str, matcher, curInd); + return -1; +} + +// NFAGroupHeadUNode + +NFAGroupHeadUNode::NFAGroupHeadUNode(const int groupIndex) : gi(groupIndex) { } +int NFAGroupHeadUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int ret, o = matcher->starts[gi]; + + matcher->starts[gi] = curInd; + ret = next->match(str, matcher, curInd); + if (ret < 0) matcher->starts[gi] = o; + + return ret; +} + +// NFAGroupTailUNode + +NFAGroupTailUNode::NFAGroupTailUNode(const int groupIndex) : gi(groupIndex) { } +int NFAGroupTailUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int ret, o = matcher->ends[gi]; + + matcher->ends[gi] = curInd; + ret = next->match(str, matcher, curInd); + if (ret < 0) matcher->ends[gi] = o; + + return ret; +} + +// NFAGroupLoopPrologueUNode + +NFAGroupLoopPrologueUNode::NFAGroupLoopPrologueUNode(const int groupIndex) : gi(groupIndex) { } +int NFAGroupLoopPrologueUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int ret, o1 = matcher->groups[gi], o2 = matcher->groupPos[gi], o3 = matcher->groupIndeces[gi]; + + matcher->groups[gi] = 0; + matcher->groupPos[gi] = 0; + matcher->groupIndeces[gi] = -1; + ret = next->match(str, matcher, curInd); + if (ret < 0) + { + matcher->groups[gi] = o1; + matcher->groupPos[gi] = o2; + matcher->groupIndeces[gi] = o3; + } + + return ret; +} + +// NFAGroupLoopUNode + +NFAGroupLoopUNode::NFAGroupLoopUNode(NFAUNode * internal, const int minMatch, const int maxMatch, + const int groupIndex, const int matchType) +{ + inner = internal; + min = minMatch; + max = maxMatch; + gi = groupIndex; + type = matchType; +} +void NFAGroupLoopUNode::findAllNodes(std::map & soFar) +{ + if (inner) inner->findAllNodes(soFar); + NFAUNode::findAllNodes(soFar); +} +int NFAGroupLoopUNode::match(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + bool b = (curInd > matcher->groupIndeces[gi]); + + if (b && matcher->groups[gi] < min) + { + ++matcher->groups[gi]; + int o = matcher->groupIndeces[gi]; + matcher->groupIndeces[gi] = curInd; + int ret = inner->match(str, matcher, curInd); + if (ret < 0) + { + matcher->groupIndeces[gi] = o; + --matcher->groups[gi]; + } + return ret; + } + else if (!b || matcher->groups[gi] >= max) + { + return next->match(str, matcher, curInd); + } + else + { + switch (type) + { + case 0: return matchGreedy(str, matcher, curInd); + case 1: return matchLazy(str, matcher, curInd); + case 2: return matchPossessive(str, matcher, curInd); + } + } + return -1; +} +int NFAGroupLoopUNode::matchGreedy(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int o = matcher->groupIndeces[gi]; // save our info for backtracking + matcher->groupIndeces[gi] = curInd; // move along + ++matcher->groups[gi]; + int ret = inner->match(str, matcher, curInd); // match internally + if (ret < 0) + { // if we failed, then restore info and match next + --matcher->groups[gi]; + matcher->groupIndeces[gi] = o; + ret = next->match(str, matcher, curInd); + } + return ret; +} +int NFAGroupLoopUNode::matchLazy(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int ret = next->match(str, matcher, curInd); // be lazy, just go on + if (ret < 0) + { + int o = matcher->groupIndeces[gi]; // save info for backtracking + matcher->groupIndeces[gi] = curInd; // advance our position + ++matcher->groups[gi]; + ret = inner->match(str, matcher, curInd); // match our internal stuff + if (ret < 0) // if we failed, then restore the info + { + --matcher->groups[gi]; + matcher->groupIndeces[gi] = o; + } + } + return ret; +} +int NFAGroupLoopUNode::matchPossessive(const bkstring & str, WCMatcher * matcher, const int curInd) const +{ + int o = matcher->groupIndeces[gi]; // save info for backtracking + matcher->groupPos[gi] = matcher->groups[gi]; // set a flag stating we have matcher at least this much + matcher->groupIndeces[gi] = curInd; // move along + ++matcher->groups[gi]; + int ret = inner->match(str, matcher, curInd); // try and match again + if (ret < 0) + { // if we fail, back off, but to an extent + --matcher->groups[gi]; + matcher->groupIndeces[gi] = o; + if (matcher->groups[gi] == matcher->groupPos[gi]) ret = next->match(str, matcher, curInd); + } + return ret; +} + +#ifdef _WIN32 + #pragma warning(pop) +#endif diff --git a/plugins/SmileyAdd/src/regexp/WCPattern.h b/plugins/SmileyAdd/src/regexp/WCPattern.h new file mode 100644 index 0000000000..3d52a7fd2e --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/WCPattern.h @@ -0,0 +1,1663 @@ +#ifndef __WCPATTERN_H__ +#define __WCPATTERN_H__ + +#ifdef _WIN32 + #pragma warning(disable:4786) +#endif + +#include "bkstring.h" + +#include +#include + +class WCMatcher; +class NFAUNode; +class NFAQuantifierUNode; + +/** + This pattern class is very similar in functionality to Java's + java.util.regex.WCPattern class. The pattern class represents an immutable + regular expression object. Instead of having a single object contain both the + regular expression object and the matching object, instead the two objects are + split apart. The {@link WCMatcher WCMatcher} class represents the maching + object. + + The WCPattern class works primarily off of "compiled" patterns. A typical + instantiation of a regular expression looks like: + +

+  WCPattern * p = WCPattern::compile(L"a*b");
+  WCMatcher * m = p->createWCMatcher(L"aaaaaab");
+  if (m->matches()) ...
+  
+ + However, if you do not need to use a pattern more than once, it is often times + okay to use the WCPattern's static methods insteads. An example looks like this: + +
+  if (WCPattern::matches(L"a*b", L"aaaab")) { ... }
+  
+ + This class does not currently support unicode. The unicode update for this + class is coming soon. + + This class is partially immutable. It is completely safe to call createWCMatcher + concurrently in different threads, but the other functions (e.g. split) should + not be called concurrently on the same WCPattern. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Construct + + Matches + +
+   +
+ Characters +
+ x + + The character x +
+ \\ + + The character \ +
+ \0nn + + The character with octal ASCII value nn +
+ \0nnn + + The character with octal ASCII value nnn +
+ \xhh + + The character with hexadecimal ASCII value hh +
+ \t + + A tab character +
+ \r + + A carriage return character +
+ \n + + A new-line character +
+   +
+ Character Classes +
+ [abc] + + Either a, b, or c +
+ [^abc] + + Any character but a, b, or c +
+ [a-zA-Z] + + Any character ranging from a thru z, or + A thru Z +
+ [^a-zA-Z] + + Any character except those ranging from a thru + z, or A thru Z +
+ [a\-z] + + Either a, -, or z +
+ [a-z[A-Z]] + + Same as [a-zA-Z] +
+ [a-z&&[g-i]] + + Any character in the intersection of a-z and + g-i +
+ [a-z&&[^g-i]] + + Any character in a-z and not in g-i +
+   +
+ Prefefined character classes +
+ . + + Any character. Multiline matching must be compiled into the pattern for + . to match a \r or a \n. + Even if multiline matching is enabled, . will not + match a \r\n, only a \r or a \n. +
+ \d + + [0-9] +
+ \D + + [^\d] +
+ \s + + [ \t\r\n\x0B] +
+ \S + + [^\s] +
+ \w + + [a-zA-Z0-9_] +
+ \W + + [^\w] +
+   +
+ POSIX character classes +
+ \p{Lower} + + [a-z] +
+ \p{Upper} + + [A-Z] +
+ \p{ASCII} + + [\x00-\x7F] +
+ \p{Alpha} + + [a-zA-Z] +
+ \p{Digit} + + [0-9] +
+ \p{Alnum} + + [\w&&[^_]] +
+ \p{Punct} + + [!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~] +
+ \p{XDigit} + + [a-fA-F0-9] +
+   +
+ Boundary Matches +
+ ^ + + The beginning of a line. Also matches the beginning of input. +
+ $ + + The end of a line. Also matches the end of input. +
+ \b + + A word boundary +
+ \B + + A non word boundary +
+ \A + + The beginning of input +
+ \G + + The end of the previous match. Ensures that a "next" match will only + happen if it begins with the character immediately following the end of + the "current" match. +
+ \Z + + The end of input. Will also match if there is a single trailing + \r\n, a single trailing \r, or a single + trailing \n. +
+ \z + + The end of input +
+   +
+ Greedy Quantifiers +
+ x? + + x, either zero times or one time +
+ x* + + x, zero or more times +
+ x+ + + x, one or more times +
+ x{n} + + x, exactly n times +
+ x{n,} + + x, at least n times +
+ x{,m} + + x, at most m times +
+ x{n,m} + + x, at least n times and at most + m times +
+   +
+ Possessive Quantifiers +
+ x?+ + + x, either zero times or one time +
+ x*+ + + x, zero or more times +
+ x++ + + x, one or more times +
+ x{n}+ + + x, exactly n times +
+ x{n,}+ + + x, at least n times +
+ x{,m}+ + + x, at most m times +
+ x{n,m}+ + + x, at least n times and at most + m times +
+   +
+ Reluctant Quantifiers +
+ x?? + + x, either zero times or one time +
+ x*? + + x, zero or more times +
+ x+? + + x, one or more times +
+ x{n}? + + x, exactly n times +
+ x{n,}? + + x, at least n times +
+ x{,m}? + + x, at most m times +
+ x{n,m}? + + x, at least n times and at most + m times +
+   +
+ Operators +
+ xy + + x then y +
+ x|y + + x or y +
+ (x) + + x as a capturing group +
+   +
+ Quoting +
+ \Q + + Nothing, but treat every character (including \s) literally until a + matching \E +
+ \E + + Nothing, but ends its matching \Q +
+   +
+ Special Constructs +
+ (?:x) + + x, but not as a capturing group +
+ (?=x) + + x, via positive lookahead. This means that the + expression will match only if it is trailed by x. + It will not "eat" any of the characters matched by + x. +
+ (?!x) + + x, via negative lookahead. This means that the + expression will match only if it is not trailed by + x. It will not "eat" any of the characters + matched by x. +
+ (?<=x) + + x, via positive lookbehind. x + cannot contain any quantifiers. +
+ (?x) + + x, via negative lookbehind. x + cannot contain any quantifiers. +
+ (?>x) + + x{1}+ +
+   +
+ Registered Expression Matching +
+ {x} + + The registered pattern x +
+ +
+ + Begin Text Extracted And Modified From java.util.regex.WCPattern documentation + +

Backslashes, escapes, and quoting

+ +

The backslash character ((wchar_t)'\') serves to introduce escaped + constructs, as defined in the table above, as well as to quote characters + that otherwise would be interpreted as unescaped constructs. Thus the + expression \\ matches a single backslash and \{ matches a + left brace. + +

It is an error to use a backslash prior to any alphabetic character that + does not denote an escaped construct; these are reserved for future + extensions to the regular-expression language. A backslash may be used + prior to a non-alphabetic character regardless of whether that character is + part of an unescaped construct. + +

It is necessary to double backslashes in string literals that represent + regular expressions to protect them from interpretation by a compiler. The + string literal "\b", for example, matches a single backspace + character when interpreted as a regular expression, while + "\\b" matches a word boundary. The string litera + "\(hello\)" is illegal and leads to a compile-time error; + in order to match the string (hello) the string literal + "\\(hello\\)" must be used. + +

Character Classes

+ +

Character classes may appear within other character classes, and + may be composed by the union operator (implicit) and the intersection + operator (&&). + The union operator denotes a class that contains every character that is + in at least one of its operand classes. The intersection operator + denotes a class that contains every character that is in both of its + operand classes. + +

The precedence of character-class operators is as follows, from + highest to lowest: + +

+ + + + + + + + + + + + + + + + +
1    Literal escape    \x
2    Rangea-z
3    Grouping[...]
4    Intersection[a-z&&[aeiou]]
5    Union[a-e][i-u]
+ +

Note that a different set of metacharacters are in effect inside + a character class than outside a character class. For instance, the + regular expression . loses its special meaning inside a + character class, while the expression - becomes a range + forming metacharacter. + + + + +

Groups and capturing

+ +

Capturing groups are numbered by counting their opening parentheses from + left to right. In the expression ((A)(B(C))), for example, there + are four such groups:

+ +
+ + + + + + + + + + +
1    ((A)(B(C)))
2    (A)
3    (B(C))
4    (C)
+ +

Group zero always stands for the entire expression. + +

Capturing groups are so named because, during a match, each subsequence + of the input sequence that matches such a group is saved. The captured + subsequence may be used later in the expression, via a back reference, and + may also be retrieved from the matcher once the match operation is complete. + +

The captured input associated with a group is always the subsequence + that the group most recently matched. If a group is evaluated a second time + because of quantification then its previously-captured value, if any, will + be retained if the second evaluation fails. Matching the string + L"aba" against the expression (a(b)?)+, for example, leaves + group two set to L"b". All captured input is discarded at the + beginning of each match. + +

Groups beginning with (? are pure, non-capturing groups + that do not capture text and do not count towards the group total. + + +

WC support

+ +

Coming Soon. + +

Comparison to Perl 5

+ +

The WCPattern engine performs traditional NFA-based matching + with ordered alternation as occurs in Perl 5. + +

Perl constructs not supported by this class:

+ +
    + +
  • The conditional constructs (?{X}) and + (?(condition)X|Y), +

  • + +
  • The embedded code constructs (?{code}) + and (??{code}),

  • + +
  • The embedded comment syntax (?#comment), and

  • + +
  • The preprocessing operations \l \u, + \L, and \U.

  • + +
  • Embedded flags

  • + +
+ +

Constructs supported by this class but not by Perl:

+ +
    + +
  • Possessive quantifiers, which greedily match as much as they can + and do not back off, even when doing so would allow the overall match to + succeed.

  • + +
  • Character-class union and intersection as described + above.

  • + +
+ +

Notable differences from Perl:

+ +
    + +
  • In Perl, \1 through \9 are always interpreted + as back references; a backslash-escaped number greater than 9 is + treated as a back reference if at least that many subexpressions exist, + otherwise it is interpreted, if possible, as an octal escape. In this + class octal escapes must always begin with a zero. In this class, + \1 through \9 are always interpreted as back + references, and a larger number is accepted as a back reference if at + least that many subexpressions exist at that point in the regular + expression, otherwise the parser will drop digits until the number is + smaller or equal to the existing number of groups or it is one digit. +

  • + +
  • Perl uses the g flag to request a match that resumes + where the last match left off. This functionality is provided implicitly + by the WCMatcher class: Repeated invocations of the + find method will resume where the last match left off, + unless the matcher is reset.

  • + +
  • Perl is forgiving about malformed matching constructs, as in the + expression *a, as well as dangling brackets, as in the + expression abc], and treats them as literals. This + class also strict and will not compile a pattern when dangling characters + are encountered.

  • + +
+ + +

For a more precise description of the behavior of regular expression + constructs, please see + Mastering Regular Expressions, 2nd Edition, Jeffrey E. F. Friedl, + O'Reilly and Associates, 2002. +

+

+ + End Text Extracted And Modified From java.util.regex.WCPattern documentation + +


+ + @author Jeffery Stuart + @since March 2003, Stable Since November 2004 + @version 1.07.00 + @memo A class used to represent "PERL 5"-ish regular expressions + */ +class WCPattern +{ + friend class WCMatcher; + friend class NFAUNode; + friend class NFAQuantifierUNode; + private: + /** + This constructor should not be called directly. Those wishing to use the + WCPattern class should instead use the {@link compile compile} method. + + @param rhs The pattern to compile + @memo Creates a new pattern from the regular expression in rhs. + */ + WCPattern(const bkstring & rhs); + protected: + /** + This currently is not used, so don't try to do anything with it. + @memo Holds all the compiled patterns for quick access. + */ + static std::map compiledWCPatterns; + /** + Holds all of the registered patterns as strings. Due to certain problems + with compilation of patterns, especially with capturing groups, this seemed + to be the best way to do it. + */ + static std::map > registeredWCPatterns; + protected: + /** + Holds all the NFA nodes used. This makes deletion of a pattern, as well as + clean-up from an unsuccessful compile much easier and faster. + */ + std::map nodes; + /** + Used when methods like split are called. The matcher class uses a lot of + dynamic memeory, so having an instance increases speedup of certain + operations. + */ + WCMatcher * matcher; + /** + The front node of the NFA. + */ + NFAUNode * head; + /** + The actual regular expression we rerpesent + */ + bkstring pattern; + /** + Flag used during compilation. Once the pattern is successfully compiled, + error is no longer used. + */ + bool error; + /** + Used during compilation to keep track of the current index into + {@link pattern pattern}. Once the pattern is successfully + compiled, error is no longer used. + */ + int curInd; + /** + The number of capture groups this contains. + */ + int groupCount; + /** + The number of non-capture groups this contains. + */ + int nonCapGroupCount; + /** + The flags specified when this was compiled. + */ + unsigned long flags; + protected: + /** + Raises an error during compilation. Compilation will cease at that point + and compile will return NULL. + */ + void raiseError(); + /** + Convenience function for registering a node in nodes. + @param node The node to register + @return The registered node + */ + NFAUNode * registerNode(NFAUNode * node); + + /** + Calculates the union of two strings. This function will first sort the + strings and then use a simple selection algorithm to find the union. + @param s1 The first "class" to union + @param s2 The second "class" to union + @return A new string containing all unique characters. Each character + must have appeared in one or both of s1 and + s2. + */ + bkstring classUnion (bkstring s1, bkstring s2) const; + /** + Calculates the intersection of two strings. This function will first sort + the strings and then use a simple selection algorithm to find the + intersection. + @param s1 The first "class" to intersect + @param s2 The second "class" to intersect + @return A new string containing all unique characters. Each character + must have appeared both s1 and s2. + */ + bkstring classIntersect (bkstring s1, bkstring s2) const; + /** + Calculates the negation of a string. The negation is the set of all + characters between \x00 and \xFF not + contained in s1. + @param s1 The "class" to be negated. + @param s2 The second "class" to intersect + @return A new string containing all unique characters. Each character + must have appeared both s1 and s2. + */ + bkstring classNegate (bkstring s1) const; + /** + Creates a new "class" representing the range from low thru + hi. This function will wrap if low > + hi. This is a feature, not a buf. Sometimes it is useful + to be able to say [\x70-\x10] instead of [\x70-\x7F\x00-\x10]. + @param low The beginning character + @param hi The ending character + @return A new string containing all the characters from low thru hi. + */ + bkstring classCreateRange(wchar_t low, wchar_t hi) const; + + /** + Extracts a decimal number from the substring of member-variable + {@link pattern pattern} starting at start and + ending at end. + @param start The starting index in {@link pattern pattern} + @param end The last index in {@link pattern pattern} + @return The decimal number in {@link pattern pattern} + */ + int getInt(int start, int end); + /** + Parses a {n,m} string out of the member-variable + {@link pattern pattern} stores the result in sNum + and eNum. + @param sNum Output parameter. The minimum number of matches required + by the curly quantifier are stored here. + @param eNum Output parameter. The maximum number of matches allowed + by the curly quantifier are stored here. + @return Success/Failure. Fails when the curly does not have the proper + syntax + */ + bool quantifyCurly(int & sNum, int & eNum); + /** + Tries to quantify the currently parsed group. If the group being parsed + is indeed quantified in the member-variable + {@link pattern pattern}, then the NFA is modified accordingly. + @param start The starting node of the current group being parsed + @param stop The ending node of the current group being parsed + @param gn The group number of the current group being parsed + @return The node representing the starting node of the group. If the + group becomes quantified, then this node is not necessarily + a GroupHead node. + */ + NFAUNode * quantifyGroup(NFAUNode * start, NFAUNode * stop, const int gn); + + /** + Tries to quantify the last parsed expression. If the character was indeed + quantified, then the NFA is modified accordingly. + @param newNode The recently created expression node + @return The node representing the last parsed expression. If the + expression was quantified, return value != newNode + */ + NFAUNode * quantify(NFAUNode * newNode); + /** + Parses the current class being examined in + {@link pattern pattern}. + @return A string of unique characters contained in the current class being + parsed + */ + bkstring parseClass(); + /** + Parses the current POSIX class being examined in + {@link pattern pattern}. + @return A string of unique characters representing the POSIX class being + parsed + */ + bkstring parsePosix(); + /** + Returns a string containing the octal character being parsed + @return The string contained the octal value being parsed + */ + bkstring parseOctal(); + /** + Returns a string containing the hex character being parsed + @return The string contained the hex value being parsed + */ + bkstring parseHex(); + /** + Returns a new node representing the back reference being parsed + @return The new node representing the back reference being parsed + */ + NFAUNode * parseBackref(); + /** + Parses the escape sequence currently being examined. Determines if the + escape sequence is a class, a single character, or the beginning of a + quotation sequence. + @param inv Output parameter. Whether or not to invert the returned class + @param quo Output parameter. Whether or not this sequence starts a + quotation. + @return The characters represented by the class + */ + bkstring parseEscape(bool & inv, bool & quo); + /** + Parses a supposed registered pattern currently under compilation. If the + sequence of characters does point to a registered pattern, then the + registered pattern is appended to *end. The registered pattern + is parsed with the current compilation flags. + @param end The ending node of the thus-far compiled pattern + @return The new end node of the current pattern + */ + NFAUNode * parseRegisteredWCPattern(NFAUNode ** end); + /** + Parses a lookbehind expression. Appends the necessary nodes + *end. + @param pos Positive or negative look behind + @param end The ending node of the current pattern + @return The new end node of the current pattern + */ + NFAUNode * parseBehind(const bool pos, NFAUNode ** end); + /** + Parses the current expression and tacks on nodes until a \E is found. + @return The end of the current pattern + */ + NFAUNode * parseQuote(); + /** + Parses {@link pattern pattern}. This function is called + recursively when an or (|) or a group is encountered. + @param inParen Are we currently parsing inside a group + @param inOr Are we currently parsing one side of an or (|) + @param end The end of the current expression + @return The starting node of the NFA constructed from this parse + */ + NFAUNode * parse(const bool inParen = 0, const bool inOr = 0, NFAUNode ** end = NULL); + public: + /// We should match regardless of case + const static unsigned long CASE_INSENSITIVE; + /// We are implicitly quoted + const static unsigned long LITERAL; + /// @memo We should treat a . as [\x00-\x7F] + const static unsigned long DOT_MATCHES_ALL; + /** ^ and $ should anchor to the beginning and + ending of lines, not all input + */ + const static unsigned long MULTILINE_MATCHING; + /** When enabled, only instances of \n are recognized as + line terminators + */ + const static unsigned long UNIX_LINE_MODE; + /// The absolute minimum number of matches a quantifier can match (0) + const static int MIN_QMATCH; + /// The absolute maximum number of matches a quantifier can match (0x7FFFFFFF) + const static int MAX_QMATCH; + public: + /** + Call this function to compile a regular expression into a + WCPattern object. Special values can be assigned to + mode when certain non-standard behaviors are expected from + the WCPattern object. + @param pattern The regular expression to compile + @param mode A bitwise or of flags signalling what special behaviors are + wanted from this WCPattern object + @return If successful, compile returns a WCPattern + pointer. Upon failure, compile returns + NULL + */ + static WCPattern * compile (const bkstring & pattern, + const unsigned long mode = 0); + /** + Dont use this function. This function will compile a pattern, and cache + the result. This will eventually be used as an optimization when people + just want to call static methods using the same pattern over and over + instead of first compiling the pattern and then using the compiled + instance for matching. + @param pattern The regular expression to compile + @param mode A bitwise or of flags signalling what special behaviors are + wanted from this WCPattern object + @return If successful, compileAndKeep returns a + WCPattern pointer. Upon failure, compile + returns NULL. + */ + static WCPattern * compileAndKeep (const bkstring & pattern, + const unsigned long mode = 0); + + /** + Searches through replace and replaces all substrings matched + by pattern with str. str may + contain backreferences (e.g. \1) to capture groups. A typical + invocation looks like: +

+ + WCPattern::replace(L"(a+)b(c+)", L"abcccbbabcbabc", L"\\2b\\1"); + +

+ which would replace abcccbbabcbabc with + cccbabbcbabcba. + @param pattern The regular expression + @param str The replacement text + @param replacementText The string in which to perform replacements + @param mode The special mode requested of the WCPattern + during the replacement process + @return The text with the replacement string substituted where necessary + */ + static bkstring replace (const bkstring & pattern, + const bkstring & str, + const bkstring & replacementText, + const unsigned long mode = 0); + + /** + Splits the specified string over occurrences of the specified pattern. + Empty strings can be optionally ignored. The number of strings returned is + configurable. A typical invocation looks like: +

+ + bkstring str(strSize, 0);
+ FILE * fp = fopen(fileName, "r");
+ fread((char*)str.data(), strSize * 2, 1, fp);
+ fclose(fp);
+
+ std::vector<bkstring> lines = WCPattern::split(L"[\r\n]+", str, true);
+
+
+ + @param pattern The regular expression + @param replace The string to split + @param keepEmptys Whether or not to keep empty strings + @param limit The maximum number of splits to make + @param mode The special mode requested of the WCPattern + during the split process + @return All substrings of str split across pattern. + */ + static std::vector split (const bkstring & pattern, + const bkstring & str, + const bool keepEmptys = 0, + const unsigned long limit = 0, + const unsigned long mode = 0); + + /** + Finds all the instances of the specified pattern within the string. You + should be careful to only pass patterns with a minimum length of one. For + example, the pattern a* can be matched by an empty string, so + instead you should pass a+ since at least one character must + be matched. A typical invocation of findAll looks like: +

+ + std::vector<td::string> numbers = WCPattern::findAll(L"\\d+", string); + +

+ + @param pattern The pattern for which to search + @param str The string to search + @param mode The special mode requested of the WCPattern + during the find process + @return All instances of pattern in str + */ + static std::vector findAll (const bkstring & pattern, + const bkstring & str, + const unsigned long mode = 0); + + /** + Determines if an entire string matches the specified pattern + + @param pattern The pattern for to match + @param str The string to match + @param mode The special mode requested of the WCPattern + during the replacement process + @return True if str is recognized by pattern + */ + static bool matches (const bkstring & pattern, + const bkstring & str, + const unsigned long mode = 0); + + /** + Registers a pattern under a specific name for use in later compilations. + A typical invocation and later use looks like: +

+ + WCPattern::registerWCPattern(L"ip", L"(?:\\d{1,3}\\.){3}\\d{1,3}");
+ WCPattern * p1 = WCPattern::compile(L"{ip}:\\d+");
+ WCPattern * p2 = WCPattern::compile(L"Connection from ({ip}) on port \\d+");
+
+

+ Multiple calls to registerWCPattern with the same + name will result in the pattern getting overwritten. + + @param name The name to give to the pattern + @param pattern The pattern to register + @param mode Any special flags to use when compiling pattern + @return Success/Failure. Fails only if pattern has invalid + syntax + */ + static bool registerWCPattern(const bkstring & name, + const bkstring & pattern, + const unsigned long mode = 0); + + /** + Clears the pattern registry + */ + static void unregisterWCPatterns(); + /** + Don't use + */ + static void clearWCPatternCache(); + + /** + Searches through a string for the nth match of the + given pattern in the string. Match indeces start at zero, not one. + A typical invocation looks like this: +

+ + std::pair<bkstring, int> match = WCPattern::findNthMatch(L"\\d{1,3}", L"192.168.1.101:22", 1);
+ wprintf(L"%s %i\n", match.first.c_str(), match.second);
+
+ Output: 168 4
+
+ + @param pattern The pattern for which to search + @param str The string to search + @param matchNum Which match to find + @param mode Any special flags to use during the matching process + @return A string and an integer. The string is the string matched. The + integer is the starting location of the matched string in + str. You can check for success/failure by making sure + that the integer returned is greater than or equal to zero. + */ + static std::pair findNthMatch (const bkstring & pattern, + const bkstring & str, + const int matchNum, + const unsigned long mode = 0); + public: + /** + Deletes all NFA nodes allocated during compilation + */ + ~WCPattern(); + + bkstring replace (const bkstring & str, + const bkstring & replacementText); + std::vector split (const bkstring & str, const bool keepEmptys = 0, + const unsigned long limit = 0); + std::vector findAll (const bkstring & str); + bool matches (const bkstring & str); + /** + Returns the flags used during compilation of this pattern + @return The flags used during compilation of this pattern + */ + unsigned long getFlags () const; + /** + Returns the regular expression this pattern represents + @return The regular expression this pattern represents + */ + bkstring getWCPattern () const; + /** + Creates a matcher object using the specified string and this pattern. + @param str The string to match against + @return A new matcher using object using this pattern and the specified + string + */ + WCMatcher * createWCMatcher (const bkstring & str); +}; + +class NFAUNode +{ + friend class WCMatcher; + public: + NFAUNode * next; + NFAUNode(); + virtual ~NFAUNode(); + virtual void findAllNodes(std::map & soFar); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const = 0; + inline virtual bool isGroupHeadNode() const { return false; } + inline virtual bool isStartOfInputNode() const { return false; } +}; +class NFACharUNode : public NFAUNode +{ + protected: + wchar_t ch; + public: + NFACharUNode(const wchar_t c); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFACICharUNode : public NFAUNode +{ + protected: + wchar_t ch; + public: + NFACICharUNode(const wchar_t c); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAStartUNode : public NFAUNode +{ + public: + NFAStartUNode(); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAEndUNode : public NFAUNode +{ + public: + NFAEndUNode(); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAQuantifierUNode : public NFAUNode +{ + public: + int min, max; + NFAUNode * inner; + virtual void findAllNodes(std::map & soFar); + NFAQuantifierUNode(WCPattern * pat, NFAUNode * internal, + const int minMatch = WCPattern::MIN_QMATCH, + const int maxMatch = WCPattern::MAX_QMATCH); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAGreedyQuantifierUNode : public NFAQuantifierUNode +{ + public: + NFAGreedyQuantifierUNode(WCPattern * pat, NFAUNode * internal, + const int minMatch = WCPattern::MIN_QMATCH, + const int maxMatch = WCPattern::MAX_QMATCH); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; + virtual int matchInternal(const bkstring & str, WCMatcher * matcher, const int curInd, const int soFar) const; +}; +class NFALazyQuantifierUNode : public NFAQuantifierUNode +{ + public: + NFALazyQuantifierUNode(WCPattern * pat, NFAUNode * internal, + const int minMatch = WCPattern::MIN_QMATCH, + const int maxMatch = WCPattern::MAX_QMATCH); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAPossessiveQuantifierUNode : public NFAQuantifierUNode +{ + public: + NFAPossessiveQuantifierUNode(WCPattern * pat, NFAUNode * internal, + const int minMatch = WCPattern::MIN_QMATCH, + const int maxMatch = WCPattern::MAX_QMATCH); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAAcceptUNode : public NFAUNode +{ + public: + NFAAcceptUNode(); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAClassUNode : public NFAUNode +{ + public: + bool inv; + std::map vals; + NFAClassUNode(const bool invert = 0); + NFAClassUNode(const bkstring & clazz, const bool invert); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFACIClassUNode : public NFAUNode +{ + public: + bool inv; + std::map vals; + NFACIClassUNode(const bool invert = 0); + NFACIClassUNode(const bkstring & clazz, const bool invert); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFASubStartUNode : public NFAUNode +{ + public: + NFASubStartUNode(); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAOrUNode : public NFAUNode +{ + public: + NFAUNode * one; + NFAUNode * two; + NFAOrUNode(NFAUNode * first, NFAUNode * second); + virtual void findAllNodes(std::map & soFar); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAQuoteUNode : public NFAUNode +{ + public: + bkstring qStr; + NFAQuoteUNode(const bkstring & quoted); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFACIQuoteUNode : public NFAUNode +{ + public: + bkstring qStr; + NFACIQuoteUNode(const bkstring & quoted); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFALookAheadUNode : public NFAUNode +{ + public: + bool pos; + NFAUNode * inner; + NFALookAheadUNode(NFAUNode * internal, const bool positive); + virtual void findAllNodes(std::map & soFar); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFALookBehindUNode : public NFAUNode +{ + public: + bool pos; + bkstring mStr; + NFALookBehindUNode(const bkstring & str, const bool positive); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAStartOfLineUNode : public NFAUNode +{ + public: + NFAStartOfLineUNode(); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAEndOfLineUNode : public NFAUNode +{ + public: + NFAEndOfLineUNode(); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAReferenceUNode : public NFAUNode +{ + public: + int gi; + NFAReferenceUNode(const int groupIndex); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAStartOfInputUNode : public NFAUNode +{ + public: + NFAStartOfInputUNode(); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; + inline virtual bool isStartOfInputNode() const { return false; } +}; +class NFAEndOfInputUNode : public NFAUNode +{ + public: + bool term; + NFAEndOfInputUNode(const bool lookForTerm); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAWordBoundaryUNode : public NFAUNode +{ + public: + bool pos; + NFAWordBoundaryUNode(const bool positive); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAEndOfMatchUNode : public NFAUNode +{ + public: + NFAEndOfMatchUNode(); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAGroupHeadUNode : public NFAUNode +{ + public: + int gi; + NFAGroupHeadUNode(const int groupIndex); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; + inline virtual bool isGroupHeadNode() const { return false; } +}; +class NFAGroupTailUNode : public NFAUNode +{ + public: + int gi; + NFAGroupTailUNode(const int groupIndex); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAGroupLoopPrologueUNode : public NFAUNode +{ + public: + int gi; + NFAGroupLoopPrologueUNode(const int groupIndex); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; +class NFAGroupLoopUNode : public NFAUNode +{ + public: + int gi, min, max, type; + NFAUNode * inner; + NFAGroupLoopUNode(NFAUNode * internal, const int minMatch, + const int maxMatch, const int groupIndex, const int matchType); + virtual void findAllNodes(std::map & soFar); + virtual int match(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; + int matchGreedy(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; + int matchLazy(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; + int matchPossessive(const bkstring & str, WCMatcher * matcher, const int curInd = 0) const; +}; + +#endif + diff --git a/plugins/SmileyAdd/src/regexp/test.cpp b/plugins/SmileyAdd/src/regexp/test.cpp new file mode 100644 index 0000000000..bb41566f96 --- /dev/null +++ b/plugins/SmileyAdd/src/regexp/test.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +int main() +{ + { + Pattern * p = Pattern::compile("^([^:]*)://([^/:]*)((?::[0-9]+)?)/?(([^?]*)((?:\\?.*)?))$"); + Matcher * m0 = p->createMatcher("http://www.example.com:80/test.php?a=1&a=1&a=1"); + + if (m0->matches()) + { + std::vector groups = m0->getGroups(true); + for (int i = 0; i < (int)groups.size(); ++i) + { + printf("m->group(%d): %s\n", i, groups[i].c_str()); + } + } + } + { + std::wstring pat = L"^([^:]*)://([^/:]*)((?::[0-9]+)?)/?(([^?]*)((?:\\?.*)?))$"; + std::wstring mat = L"http://www.example.com:80/test.php?a=1&a=1&a=1"; + UnicodePattern * p = UnicodePattern::compile(pat); + UnicodeMatcher * m0 = p->createUnicodeMatcher(mat); + + if (m0->matches()) + { + std::vector groups = m0->getGroups(true); + for (int i = 0; i < (int)groups.size(); ++i) + { + wprintf(L"m->group(%d): %s\n", i, groups[i].c_str()); + } + } + } + + return 0; +} diff --git a/plugins/SmileyAdd/src/resource.h b/plugins/SmileyAdd/src/resource.h new file mode 100644 index 0000000000..bdf799fe2c --- /dev/null +++ b/plugins/SmileyAdd/src/resource.h @@ -0,0 +1,49 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDI_SMILINGICON 124 +#define IDD_OPT_SMILEYS 245 +#define IDC_CATEGORYLIST 1017 +#define IDC_PLUGENABLED 1019 +#define IDC_INPUTSMILEYS 1020 +#define IDC_DCURSORSMILEY 1021 +#define IDC_LIBNAME 1023 +#define IDC_SPACES 1024 +#define IDC_LIBAUTHOR 1026 +#define IDC_LIBVERSION 1027 +#define IDC_SCALETOTEXTHEIGHT 1037 +#define IDC_APPENDSPACES 1040 +#define IDC_SMLOPTBUTTON 1045 +#define IDC_SCALEALLSMILEYS 1046 +#define IDC_IEVIEWSTYLE 1047 +#define IDC_ANIMATESEL 1048 +#define IDC_USESTDPACK 1049 +#define IDC_ANIMATEDLG 1051 +#define IDC_DISABLECUSTOM 1052 +#define IDC_DISABLECUSTOM2 1053 +#define IDC_HQSCALING 1053 +#define IDC_SELCLR 1055 +#define IDC_NEWCATEGORY 1058 +#define IDC_ADDCATEGORY 1059 +#define IDC_DELETECATEGORY 1060 +#define IDC_SMLBUT 1061 +#define IDC_MAXCUSTSMSZ 1062 +#define IDC_MAXCUSTSPIN 1063 +#define IDC_MINSMSZ 1064 +#define IDC_MINSPIN 1065 +#define IDC_BROWSE 1184 +#define IDC_FILENAME 1271 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 127 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1064 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/SmileyAdd/src/richcall.cpp b/plugins/SmileyAdd/src/richcall.cpp new file mode 100644 index 0000000000..d9b9123c48 --- /dev/null +++ b/plugins/SmileyAdd/src/richcall.cpp @@ -0,0 +1,554 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "smileys.h" +#include "smileyroutines.h" +#include "services.h" +#include "options.h" +#include "SmileyBase.h" + +#include +#include + +typedef struct +{ + HWND hwnd; + HANDLE hContact; + WNDPROC wpOrigWndProc; + HWND hToolTip; + int tipActive; + bool inputarea; + bool dontReplace; +} RichEditData; + +typedef struct +{ + HWND hwnd; + WNDPROC wpOrigWndProc; + HWND hwndInput; + HWND hwndLog; +} RichEditOwnerData; + +static int CompareRichEditData(const RichEditData* p1, const RichEditData* p2) +{ + return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); +} +static LIST g_RichEditList(10, CompareRichEditData); + + +static int CompareRichEditData(const RichEditOwnerData* p1, const RichEditOwnerData* p2) +{ + return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); +} +static LIST g_RichEditOwnerList(5, CompareRichEditData); + + +static void SetPosition(HWND hwnd) +{ + IRichEditOle* RichEditOle; + if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return; + + ITextDocument* TextDocument; + if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) + { + RichEditOle->Release(); + return; + } + + // retrieve text range + ITextRange* TextRange; + if (TextDocument->Range(0, 0, &TextRange) != S_OK) + { + TextDocument->Release(); + RichEditOle->Release(); + return; + } + TextDocument->Release(); + + int objectCount = RichEditOle->GetObjectCount(); + for (int i = objectCount - 1; i >= 0; i--) + { + REOBJECT reObj = {0}; + reObj.cbStruct = sizeof(REOBJECT); + + HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ); + if (FAILED(hr)) continue; + + ISmileyBase *igsc = NULL; + if (reObj.clsid == CLSID_NULL) + reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc); + + reObj.poleobj->Release(); + if (igsc == NULL) continue; + + TextRange->SetRange(reObj.cp, reObj.cp); + + BOOL res; + POINT pt; + RECT rect; + hr = TextRange->GetPoint(tomStart | TA_BOTTOM | TA_LEFT, &pt.x, &pt.y); + if (hr == S_OK) + { + res = ScreenToClient(hwnd, &pt); + rect.bottom = pt.y; + rect.left = pt.x; + } + else + rect.bottom = -1; + + hr = TextRange->GetPoint(tomStart | TA_TOP | TA_LEFT, &pt.x, &pt.y); + if (hr == S_OK) + { + res = ScreenToClient(hwnd, &pt); + rect.top = pt.y; + rect.left = pt.x; + } + else + rect.top = -1; + + igsc->SetPosition(hwnd, &rect); + igsc->Release(); + } + TextRange->Release(); + RichEditOle->Release(); +} + +static void SetTooltip(long x, long y, HWND hwnd, RichEditData* rdt) +{ + TCHAR* smltxt; + int needtip = CheckForTip(x, y, hwnd, &smltxt); + if (needtip != rdt->tipActive) + { + TOOLINFO ti = {0}; + ti.cbSize = sizeof(ti); + ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + ti.hwnd = hwnd; + ti.uId = (UINT_PTR)ti.hwnd; + + if (needtip != -1) + { + if (rdt->tipActive == -1) + { + rdt->hToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), + TTS_NOPREFIX | WS_POPUP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + hwnd, NULL, g_hInst, NULL); + + SendMessage(rdt->hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti); + } + + ti.lpszText = smltxt; + SendMessage(rdt->hToolTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); + SendMessage(rdt->hToolTip, TTM_ACTIVATE, TRUE, 0); + } + else + { + if (rdt->tipActive != -1) + { + SendMessage(rdt->hToolTip, TTM_ACTIVATE, FALSE, 0); + DestroyWindow(rdt->hToolTip); + rdt->hToolTip = NULL; + } + } + rdt->tipActive = needtip; + } +} + +static const CHARRANGE allsel = { 0, LONG_MAX }; + + +static void ReplaceContactSmileys(RichEditData *rdt, const CHARRANGE &sel, bool ignoreLast, bool unFreeze) +{ + if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; + SmileyPackCType *smcp = NULL; + SmileyPackType* SmileyPack = GetSmileyPack(NULL, rdt->hContact, rdt->inputarea ? NULL : &smcp); + ReplaceSmileys(rdt->hwnd, SmileyPack, smcp, sel, false, ignoreLast, unFreeze); +} + +static void ReplaceContactSmileysWithText(RichEditData *rdt, CHARRANGE &sel, bool freeze) +{ + if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; + ReplaceSmileysWithText(rdt->hwnd, sel, freeze); +} + +static void SmileyToTextCutPrep(RichEditData* rdt) +{ + if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; + + SendMessage(rdt->hwnd, WM_SETREDRAW, FALSE, 0); + CHARRANGE sel; + SendMessage(rdt->hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + ReplaceContactSmileysWithText(rdt, sel, true); +} + +static void SmileyToTextCutRest(RichEditData* rdt) +{ + if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; + + CHARRANGE sel; + SendMessage(rdt->hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + ReplaceContactSmileys(rdt, sel, false, true); + SendMessage(rdt->hwnd, WM_SETREDRAW, TRUE, 0); + RedrawWindow(rdt->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + + +static LRESULT CALLBACK RichEditSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RichEditData* rdt = g_RichEditList.find((RichEditData*)&hwnd); + if (rdt == NULL) return 0; + + CHARRANGE sel; + + WNDPROC wpOrigWndProc = rdt->wpOrigWndProc; + + switch(uMsg) + { + case WM_DESTROY: + CloseRichCallback(hwnd, false); + break; + + case WM_COPY: + case WM_CUT: + SmileyToTextCutPrep(rdt); + break; + + case WM_PAINT: + SetPosition(hwnd); + break; + + case EM_STREAMOUT: + if (wParam & SFF_SELECTION) + SmileyToTextCutPrep(rdt); + else + { + sel = allsel; + ReplaceContactSmileysWithText(rdt, sel, true); + } + break; + + case WM_KEYDOWN: + if ((wParam == 'C' || wParam == VK_INSERT) && (GetKeyState(VK_CONTROL) & 0x8000)) + { + SmileyToTextCutPrep(rdt); + } + else if ((wParam == 'X' && (GetKeyState(VK_CONTROL) & 0x8000)) || + (wParam == VK_DELETE && (GetKeyState(VK_SHIFT) & 0x8000))) + { + SmileyToTextCutPrep(rdt); + } + else if (wParam == VK_TAB && ((GetKeyState(VK_CONTROL) | GetKeyState(VK_SHIFT)) & 0x8000) == 0) + { + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + sel.cpMin = max(sel.cpMin - 20, 0); + + ReplaceContactSmileysWithText(rdt, sel, true); + } + break; + } + + LRESULT result = CallWindowProc(wpOrigWndProc, hwnd, uMsg, wParam, lParam); + + switch(uMsg) + { + case WM_DESTROY: + CloseRichCallback(hwnd, true); + break; + + case WM_MOUSEMOVE: + SetTooltip(LOWORD(lParam), HIWORD(lParam), hwnd, rdt); + break; + + case WM_PAINT: + case WM_HSCROLL: + case WM_VSCROLL: + SetPosition(hwnd); + break; + + case WM_COPY: + case WM_CUT: + SmileyToTextCutRest(rdt); + break; + + case EM_STREAMOUT: + if (wParam & SFF_SELECTION) + SmileyToTextCutRest(rdt); + else + ReplaceContactSmileys(rdt, allsel, false, true); + break; + + case WM_KEYDOWN: + if ((wParam == 'C' || wParam == VK_INSERT) && (GetKeyState(VK_CONTROL) & 0x8000)) + { + SmileyToTextCutRest(rdt); + } + else if ((wParam == 'X' && (GetKeyState(VK_CONTROL) & 0x8000)) || + (wParam == VK_DELETE && (GetKeyState(VK_SHIFT) & 0x8000))) + { + SmileyToTextCutRest(rdt); + } + else if (wParam == VK_TAB && ((GetKeyState(VK_CONTROL) | GetKeyState(VK_SHIFT)) & 0x8000) == 0) + { + sel.cpMax = LONG_MAX; + bool hascont = rdt->hContact != NULL; + ReplaceContactSmileys(rdt, sel, false, hascont); + } + break; + + case WM_CHAR: + if (!rdt->inputarea || (rdt->inputarea && !opt.InputSmileys)) + break; + + if (lParam & (1 << 28)) // ALT key + break; + + if ((lParam & 0xFF) > 2) // Repeat rate + break; + + if (wParam > ' ' && opt.EnforceSpaces) + break; + + if (wParam == 0x16) + { + ReplaceContactSmileys(rdt, allsel, false, false); + break; + } + + if (opt.DCursorSmiley) + { + ReplaceContactSmileys(rdt, allsel, true, true); + } + else + { + if (wParam >= ' ' || wParam == '\n' || wParam == '\r') + { + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + sel.cpMin = max(sel.cpMin - 20, 0); + sel.cpMax += 20; + + ReplaceContactSmileysWithText(rdt, sel, true); + ReplaceContactSmileys(rdt, sel, false, true); + } + } + break; + + case EM_PASTESPECIAL: + case WM_PASTE: + case EM_REPLACESEL: + case WM_SETTEXT: + case EM_SETTEXTEX: + if (rdt->inputarea) + ReplaceContactSmileys(rdt, allsel, false, false); + break; + + case WM_REMAKERICH: + ReplaceContactSmileys(rdt, allsel, false, false); + break; + } + + return result; +} + +void CloseRichCallback(HWND hwnd, bool force) +{ + int ind = g_RichEditList.getIndex((RichEditData*)&hwnd); + if ( ind != -1 ) + { + RichEditData* rdt = g_RichEditList[ind]; + bool richsub = GetWindowLongPtr(hwnd, GWLP_WNDPROC) == (LONG_PTR)RichEditSubclass; + if (richsub) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)rdt->wpOrigWndProc); + if (richsub || force) + { + if (rdt->hToolTip) DestroyWindow(rdt->hToolTip); + delete rdt; + g_RichEditList.remove(ind); + } + } +} + +bool SetRichCallback(HWND hwnd, HANDLE hContact, bool subany, bool subnew) +{ + RichEditData* rdt = g_RichEditList.find((RichEditData*)&hwnd); + if (rdt == NULL) + { + IRichEditOle* RichEditOle; + if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return false; + RichEditOle->Release(); + + rdt = new RichEditData; + + rdt->hwnd = hwnd; + rdt->hContact = hContact; + rdt->inputarea = (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) == 0; + rdt->dontReplace = false; + rdt->tipActive = -1; + rdt->wpOrigWndProc = NULL; + rdt->hToolTip = NULL; + g_RichEditList.insert(rdt); + + if (subnew) + rdt->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditSubclass); + } + else + { + if (hContact && !rdt->hContact) rdt->hContact = hContact; + if (subany && rdt->wpOrigWndProc == NULL) + rdt->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditSubclass); + } + return true; +} + +static LRESULT CALLBACK RichEditOwnerSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RichEditOwnerData* rdto = g_RichEditOwnerList.find((RichEditOwnerData*)&hwnd); + if (rdto == NULL) return 0; + + WNDPROC wpOrigWndProc = rdto->wpOrigWndProc; + + switch(uMsg) + { + case WM_DESTROY: + { + RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); + if (rdt && (!rdt->inputarea || opt.InputSmileys)) + { + CHARRANGE sel = allsel; + rdt->dontReplace = true; + ReplaceSmileysWithText(rdt->hwnd, sel, false); + } + } + CloseRichOwnerCallback(hwnd, false); + break; + + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == 1624) + { + RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); + if (rdt && (!rdt->inputarea || opt.InputSmileys)) + { + rdt->dontReplace = true; + CHARRANGE sel = allsel; + ReplaceSmileysWithText(rdt->hwnd, sel, false); + } + } + break; + } + + LRESULT result = CallWindowProc(wpOrigWndProc, hwnd, uMsg, wParam, lParam); + + switch(uMsg) + { + case WM_DESTROY: + CloseRichOwnerCallback(hwnd, true); + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == 1624) // && lParam == 0) + { + RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); + if (rdt) + { + CHARRANGE sel = allsel; + if (!result) ReplaceContactSmileys(rdt, sel, false, false); + rdt->dontReplace = false; + } + } + break; + } + return result; +} + +void CloseRichOwnerCallback(HWND hwnd, bool force) +{ + int ind = g_RichEditOwnerList.getIndex((RichEditOwnerData*)&hwnd); + if ( ind != -1 ) + { + RichEditOwnerData* rdto = g_RichEditOwnerList[ind]; + bool richsub = GetWindowLongPtr(hwnd, GWLP_WNDPROC) == (LONG_PTR)RichEditOwnerSubclass; + if (richsub) + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)rdto->wpOrigWndProc); + rdto->wpOrigWndProc = NULL; + } + if (force) + { + CloseRichCallback(rdto->hwndInput, true); + CloseRichCallback(rdto->hwndLog, true); + + delete rdto; + g_RichEditOwnerList.remove(ind); + } + } +} + +void SetRichOwnerCallback(HWND hwnd, HWND hwndInput, HWND hwndLog) +{ + RichEditOwnerData* rdto = g_RichEditOwnerList.find((RichEditOwnerData*)&hwnd); + if (rdto == NULL) + { + rdto = new RichEditOwnerData; + + rdto->hwnd = hwnd; + rdto->hwndInput = hwndInput; + rdto->hwndLog = hwndLog; + rdto->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditOwnerSubclass); + g_RichEditOwnerList.insert(rdto); + } + else + { + if (rdto->hwndInput == NULL) rdto->hwndInput = hwndInput; + if (rdto->hwndLog == NULL) rdto->hwndLog = hwndLog; + } +} + +void ProcessAllInputAreas(bool restoreText) +{ + for (int i=g_RichEditList.getCount(); i--; ) + { + RichEditData* rdt = g_RichEditList[i]; + if (rdt->inputarea) + { + if (restoreText) + { + CHARRANGE sel = allsel; + ReplaceContactSmileysWithText(rdt, sel, false); + } + else + { + ReplaceContactSmileys(rdt, allsel, false, false); + } + } + } +} + + +void RichEditData_Destroy(void) +{ + int i; + for (i=g_RichEditList.getCount(); i--; ) + CloseRichCallback(g_RichEditList[i]->hwnd, true); + g_RichEditList.destroy(); + + for (i=g_RichEditOwnerList.getCount(); i--; ) + CloseRichOwnerCallback(g_RichEditOwnerList[i]->hwnd, true); + g_RichEditOwnerList.destroy(); +} diff --git a/plugins/SmileyAdd/src/services.cpp b/plugins/SmileyAdd/src/services.cpp new file mode 100644 index 0000000000..fed1b4c7ad --- /dev/null +++ b/plugins/SmileyAdd/src/services.cpp @@ -0,0 +1,590 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "smltool.h" +#include "smileyroutines.h" +#include "services.h" +#include "options.h" + + +//globals, defined int main.cpp +extern HANDLE hEvent1, hContactMenuItem; + +LIST menuHandleArray(5); + +//implementation of service functions + +SmileyPackType* GetSmileyPack(const char* proto, HANDLE hContact, SmileyPackCType** smlc) +{ + bkstring categoryName; + + hContact = DecodeMetaContact(hContact); + if (smlc) *smlc = opt.DisableCustom ? NULL : g_SmileyPackCStore.GetSmileyPack(hContact); + + if (proto != NULL && IsBadStringPtrA(proto, 10)) return NULL; + + if (hContact != NULL) + { + opt.ReadContactCategory(hContact, categoryName); + if (categoryName == _T("")) return NULL; + if (!categoryName.empty() && + g_SmileyCategories.GetSmileyCategory(categoryName) == NULL) + { + categoryName.clear(); + opt.WriteContactCategory(hContact, categoryName); + } + + if (categoryName.empty() && !opt.UseOneForAll) + { + char *protonam = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (protonam != NULL) + { + DBVARIANT dbv; + if (DBGetContactSettingTString(hContact, protonam, "Transport", &dbv) == 0) + { + categoryName = dbv.ptszVal; + DBFreeVariant(&dbv); + } + else + categoryName = A2T_SM(protonam); + } + } + } + + if (categoryName.empty()) + { + if (proto == NULL || proto[0] == 0) + { + categoryName = _T("Standard"); + } + else + { + categoryName = A2T_SM(proto); + if (opt.UseOneForAll) + { + SmileyCategoryType *smc = g_SmileyCategories.GetSmileyCategory(categoryName); + if (smc == NULL || smc->IsProto()) categoryName = _T("Standard"); + } + } + } + + return g_SmileyCategories.GetSmileyPack(categoryName); +} + + +INT_PTR ReplaceSmileysCommand(WPARAM, LPARAM lParam) +{ + SMADD_RICHEDIT3* smre = (SMADD_RICHEDIT3*) lParam; + if (smre == NULL || smre->cbSize < SMADD_RICHEDIT_SIZE_V1) return FALSE; + + SMADD_RICHEDIT3 smrec = {0}; + memcpy(&smrec, smre, min(smre->cbSize, sizeof(smrec))); + + static const CHARRANGE selection = { 0, LONG_MAX }; + if (smre->rangeToReplace == NULL) smrec.rangeToReplace = (CHARRANGE*)&selection; + else if (smrec.rangeToReplace->cpMax < 0) smrec.rangeToReplace->cpMax = LONG_MAX; + + SmileyPackCType* smcp = NULL; + SmileyPackType* SmileyPack = GetSmileyPack(smrec.Protocolname, smrec.hContact, + (smrec.flags & (SAFLRE_OUTGOING | SAFLRE_NOCUSTOM)) ? NULL : &smcp); + + ReplaceSmileys(smre->hwndRichEditControl, SmileyPack, smcp, *smrec.rangeToReplace, + smrec.hContact == NULL, false, false); + + return TRUE; +} + + +INT_PTR ShowSmileySelectionCommand(WPARAM, LPARAM lParam) +{ + SMADD_SHOWSEL3* smaddInfo = (SMADD_SHOWSEL3*) lParam; + + if (smaddInfo == NULL || smaddInfo->cbSize < SMADD_SHOWSEL_SIZE_V1) return FALSE; + HWND parent = smaddInfo->cbSize > SMADD_SHOWSEL_SIZE_V1 ? smaddInfo->hwndParent : NULL; + HANDLE hContact = smaddInfo->cbSize > SMADD_SHOWSEL_SIZE_V2 ? smaddInfo->hContact : NULL; + + SmileyToolWindowParam *stwp = new SmileyToolWindowParam; + stwp->pSmileyPack = GetSmileyPack(smaddInfo->Protocolname, hContact); + stwp->hContact = hContact; + + stwp->hWndParent = parent; + stwp->hWndTarget = smaddInfo->hwndTarget; + stwp->targetMessage = smaddInfo->targetMessage; + stwp->targetWParam = smaddInfo->targetWParam; + stwp->xPosition = smaddInfo->xPosition; + stwp->yPosition = smaddInfo->yPosition; + stwp->direction = smaddInfo->Direction; + + mir_forkthread(SmileyToolThread, stwp); + + return TRUE; +} + +INT_PTR GetSmileyIconCommand(WPARAM, LPARAM lParam) +{ + SMADD_GETICON* smre = (SMADD_GETICON*) lParam; + + if (smre == NULL || smre->cbSize < sizeof(SMADD_GETICON)) return FALSE; + + SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname); + + if (SmileyPack == NULL || IsBadStringPtrA(smre->SmileySequence, MAX_SMILEY_LENGTH)) + { + smre->SmileyIcon = NULL; + smre->Smileylength = 0; + return FALSE; + } + + unsigned start, size; + SmileyType* sml; + FindSmileyInText(SmileyPack, A2T_SM(smre->SmileySequence), start, size, &sml); + + if (size == 0 || start != 0) + { + smre->SmileyIcon = NULL; + smre->Smileylength = 0; + } + else + { + smre->SmileyIcon = sml->GetIcon(); + smre->Smileylength = size; + } + + return TRUE; +} + + +static int GetInfoCommandE(SMADD_INFO2* smre, bool retDup) +{ + if (smre == NULL || smre->cbSize < SMADD_INFO_SIZE_V1) return FALSE; + HANDLE hContact = smre->cbSize > SMADD_INFO_SIZE_V1 ? smre->hContact : NULL; + + SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname, hContact); + + if (SmileyPack == NULL || SmileyPack->SmileyCount() == 0) + { + smre->ButtonIcon = NULL; + smre->NumberOfSmileys = 0; + smre->NumberOfVisibleSmileys = 0; + return FALSE; + } + + SmileyType* sml = FindButtonSmiley(SmileyPack); + + if (sml != NULL) + smre->ButtonIcon = retDup ? sml->GetIconDup() : sml->GetIcon(); + else + smre->ButtonIcon = GetDefaultIcon(retDup); + + smre->NumberOfSmileys = SmileyPack->SmileyCount(); + smre->NumberOfVisibleSmileys = SmileyPack->VisibleSmileyCount(); + + return TRUE; +} + + +INT_PTR GetInfoCommand(WPARAM, LPARAM lParam) +{ + return GetInfoCommandE((SMADD_INFO2*) lParam, false); +} + + +INT_PTR GetInfoCommand2(WPARAM, LPARAM lParam) +{ + return GetInfoCommandE((SMADD_INFO2*) lParam, true); +} + + +INT_PTR ParseText(WPARAM, LPARAM lParam) +{ + SMADD_PARSE* smre = (SMADD_PARSE*) lParam; + + if (smre == NULL || smre->cbSize < sizeof(SMADD_PARSE)) return FALSE; + + SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname); + + if (SmileyPack == NULL) + { + smre->SmileyIcon = NULL; + smre->size = 0; + return FALSE; + } + + unsigned strtChrOff = smre->startChar + smre->size; + char* workstr = smre->str + strtChrOff; + + if (strtChrOff > 1024 || IsBadStringPtrA(workstr, 10)) + { + smre->SmileyIcon = NULL; + smre->size = 0; + return FALSE; + } + + SmileyType* sml; + FindSmileyInText(SmileyPack, A2T_SM(workstr), smre->startChar, smre->size, &sml); + + if (smre->size == 0) + { + smre->SmileyIcon = NULL; + } + else + { + smre->SmileyIcon = sml->GetIconDup(); + smre->startChar += strtChrOff; + } + + return TRUE; +} + + +INT_PTR ParseTextW(WPARAM, LPARAM lParam) +{ + SMADD_PARSEW* smre = (SMADD_PARSEW*) lParam; + + if (smre == NULL || smre->cbSize < sizeof(SMADD_PARSEW)) return FALSE; + + SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname); + + if (SmileyPack == NULL) + { + smre->SmileyIcon = NULL; + smre->size = 0; + return FALSE; + } + + unsigned strtChrOff = smre->startChar + smre->size; + wchar_t* workstr = smre->str + strtChrOff; + + if (strtChrOff > 1024 || IsBadStringPtrW(workstr, 10)) + { + smre->SmileyIcon = NULL; + smre->size = 0; + return FALSE; + } + + SmileyType* sml; + FindSmileyInText(SmileyPack, workstr, smre->startChar, smre->size, &sml); + + if (smre->size == 0) + { + smre->SmileyIcon = NULL; + } + else + { + smre->SmileyIcon = sml->GetIconDup(); + smre->startChar += strtChrOff; + } + + return TRUE; +} + + +INT_PTR ParseTextBatch(WPARAM, LPARAM lParam) +{ + SMADD_BATCHPARSE2* smre = (SMADD_BATCHPARSE2*) lParam; + + if (smre == NULL || smre->cbSize < SMADD_BATCHPARSE_SIZE_V1) return FALSE; + HANDLE hContact = smre->cbSize > SMADD_BATCHPARSE_SIZE_V1 ? smre->hContact : NULL; + + SmileyPackCType* smcp = NULL; + SmileyPackType* SmileyPack = GetSmileyPack(smre->Protocolname, hContact, + (smre->flag & (SAFL_OUTGOING | SAFL_NOCUSTOM)) ? NULL : &smcp); + + SmileysQueueType smllist; + + if (smre->flag & SAFL_UNICODE) + LookupAllSmileys(SmileyPack, smcp, W2T_SM(smre->wstr), smllist, false); + else + LookupAllSmileys(SmileyPack, smcp, A2T_SM(smre->astr), smllist, false); + + if (smllist.getCount() == 0) return 0; + + SMADD_BATCHPARSERES *res = new SMADD_BATCHPARSERES[smllist.getCount()]; + SMADD_BATCHPARSERES* cres = res; + for (int j = 0; j < smllist.getCount(); j++) + { + cres->startChar = smllist[j].loc.cpMin; + cres->size = smllist[j].loc.cpMax - smllist[j].loc.cpMin; + if (smllist[j].sml) + { + if (smre->flag & SAFL_PATH) + cres->filepath = smllist[j].sml->GetFilePath().c_str(); + else + cres->hIcon = smllist[j].sml->GetIconDup(); + } + else + { + if (smre->flag & SAFL_PATH) + cres->filepath = smllist[j].smlc->GetFilePath().c_str(); + else + cres->hIcon = smllist[j].smlc->GetIcon(); + } + + cres++; + } + + smre->numSmileys = smllist.getCount(); + + smre->oflag = smre->flag | SAFL_UNICODE; + + return (INT_PTR)res; +} + +INT_PTR FreeTextBatch(WPARAM, LPARAM lParam) +{ + delete[] (SMADD_BATCHPARSERES*)lParam; + return TRUE; +} + +INT_PTR RegisterPack(WPARAM, LPARAM lParam) +{ + SMADD_REGCAT* smre = (SMADD_REGCAT*) lParam; + + if (smre == NULL || smre->cbSize < sizeof(SMADD_REGCAT)) return FALSE; + if (IsBadStringPtrA(smre->name, 50) || IsBadStringPtrA(smre->dispname, 50)) return FALSE; + + + unsigned lpcp = (unsigned)CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); + if (lpcp == CALLSERVICE_NOTFOUND) lpcp = CP_ACP; + + + + bkstring nmd(A2W_SM(smre->dispname, lpcp)); + + + bkstring nm(A2T_SM(smre->name)); + g_SmileyCategories.AddAndLoad(nm, nmd); + + return TRUE; +} + +INT_PTR CustomCatMenu(WPARAM wParam, LPARAM lParam) +{ + const HANDLE hContact = (HANDLE)wParam; + if (lParam != 0) + { + SmileyCategoryType* smct = g_SmileyCategories.GetSmileyCategory((unsigned)lParam - 3); + if (smct != NULL) + opt.WriteContactCategory(hContact, smct->GetName()); + else + { + bkstring empty; + if (lParam == 1) empty = _T(""); + opt.WriteContactCategory(hContact, empty); + } + NotifyEventHooks(hEvent1, (WPARAM)hContact, 0); + } + + for (int i = 0; i < menuHandleArray.getCount(); i++) + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)menuHandleArray[i], 0); + menuHandleArray.destroy(); + + return TRUE; +} + + +int RebuildContactMenu(WPARAM wParam, LPARAM) +{ + int i; + CLISTMENUITEM mi = {0}; + + mi.cbSize = sizeof(mi); + mi.flags = CMIM_FLAGS | CMIF_ROOTPOPUP | CMIF_ICONFROMICOLIB; + + SmileyCategoryListType::SmileyCategoryVectorType& smc = *g_SmileyCategories.GetSmileyCategoryList(); + + char* protnam = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + bool haveMenu = IsSmileyProto(protnam); + if (haveMenu && opt.UseOneForAll) + { + unsigned cnt = 0; + for (i = 0; i < smc.getCount(); ++i) + cnt += smc[i].IsCustom(); + haveMenu = cnt != 0; + } + + if (!haveMenu) mi.flags |= CMIF_HIDDEN; + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuItem, (LPARAM)&mi); + + for (i = 0; i < menuHandleArray.getCount(); ++i) + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)menuHandleArray[i], 0); + menuHandleArray.destroy(); + + if (haveMenu) + { + bkstring cat; + opt.ReadContactCategory((HANDLE)wParam, cat); + + mi.pszPopupName = (char*)hContactMenuItem; + mi.flags = CMIF_CHILDPOPUP | CMIM_FLAGS | CMIF_TCHAR; + mi.pszService = MS_SMILEYADD_CUSTOMCATMENU; + + bool nonecheck = true; + HGENMENU hMenu; + + for (i = 0; i < smc.getCount(); i++) + { + if (smc[i].IsExt() || (smc[i].IsProto() && opt.UseOneForAll)) continue; + + const int ind = i + 3; + + mi.position = ind; + mi.popupPosition = ind; + mi.ptszName = (TCHAR*)smc[i].GetDisplayName().c_str(); + + if (cat == smc[i].GetName()) + { + mi.flags |= CMIF_CHECKED; + nonecheck = false; + } + + hMenu = Menu_AddContactMenuItem(&mi); + menuHandleArray.insert(hMenu); + mi.flags &= ~CMIF_CHECKED; + } + + mi.position = 1; + mi.popupPosition = 1; + mi.ptszName = _T(""); + if (cat == _T("")) { + mi.flags |= CMIF_CHECKED; + nonecheck = false; + } + + hMenu = Menu_AddContactMenuItem(&mi); + menuHandleArray.insert(hMenu); + + mi.position = 2; + mi.popupPosition = 2; + mi.ptszName = _T("Protocol specific"); + if (nonecheck) mi.flags |= CMIF_CHECKED; else mi.flags &= ~CMIF_CHECKED; + + hMenu = Menu_AddContactMenuItem(&mi); + menuHandleArray.insert(hMenu); + } + + return 0; +} + +INT_PTR ReloadPack(WPARAM, LPARAM lParam) +{ + if (lParam) + { + bkstring categoryName = A2T_SM((char*)lParam); + SmileyCategoryType *smc = g_SmileyCategories.GetSmileyCategory(categoryName); + if (smc != NULL) smc->Load(); + } + else + g_SmileyCategories.ClearAndLoadAll(); + + NotifyEventHooks(hEvent1, 0, 0); + return 0; +} + +INT_PTR LoadContactSmileys(WPARAM, LPARAM lParam) +{ + if (opt.DisableCustom) return 0; + + SMADD_CONT* cont = (SMADD_CONT*)lParam; + + switch (cont->type) + { + case 0: + g_SmileyPackCStore.AddSmileyPack(cont->hContact, cont->path); + NotifyEventHooks(hEvent1, (WPARAM)cont->hContact, 0); + break; + + case 1: + g_SmileyPackCStore.AddSmiley(cont->hContact, cont->path); + NotifyEventHooks(hEvent1, (WPARAM)cont->hContact, 0); + break; + } + return 0; +} + +int AccountListChanged(WPARAM wParam, LPARAM lParam) +{ + PROTOACCOUNT* acc = (PROTOACCOUNT*)lParam; + + switch (wParam) + { + case PRAC_ADDED: + if (acc != NULL) + { + bkstring catname(_T("Standard")); + const bkstring& defaultFile = g_SmileyCategories.GetSmileyCategory(catname)->GetFilename(); + g_SmileyCategories.AddAccountAsCategory(acc, defaultFile); + } + break; + + case PRAC_CHANGED: + if (acc != NULL && acc->szModuleName != NULL) + { + bkstring name(A2T_SM(acc->szModuleName)); + SmileyCategoryType* smc = g_SmileyCategories.GetSmileyCategory(name); + if (smc != NULL) + { + if (acc->tszAccountName) name = acc->tszAccountName; + smc->SetDisplayName(name); + } + } + break; + + case PRAC_REMOVED: + g_SmileyCategories.DeleteAccountAsCategory(acc); + break; + + case PRAC_CHECKED: + if (acc != NULL) + { + if (acc->bIsEnabled) + { + bkstring catname(_T("Standard")); + const bkstring& defaultFile = g_SmileyCategories.GetSmileyCategory(catname)->GetFilename(); + g_SmileyCategories.AddAccountAsCategory(acc, defaultFile); + } + else + { + g_SmileyCategories.DeleteAccountAsCategory(acc); + } + } + break; + } + return 0; +} + +int DbSettingChanged(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + DBCONTACTWRITESETTING* cws = (DBCONTACTWRITESETTING*)lParam; + + if (hContact == NULL) return 0; + if (cws->value.type == DBVT_DELETED) return 0; + + if (strcmp(cws->szSetting, "Transport") == 0) + { + bkstring catname(_T("Standard")); + SmileyCategoryType *smc = g_SmileyCategories.GetSmileyCategory(catname); + if (smc != NULL) + g_SmileyCategories.AddContactTransportAsCategory(hContact, smc->GetFilename()); + } + return 0; +} diff --git a/plugins/SmileyAdd/src/services.h b/plugins/SmileyAdd/src/services.h new file mode 100644 index 0000000000..9311e3637d --- /dev/null +++ b/plugins/SmileyAdd/src/services.h @@ -0,0 +1,48 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef SMILEYADD_SERVICES_H_ +#define SMILEYADD_SERVICES_H_ + +#include "m_smileyadd.h" +#include "m_smileyadd_deprecated.h" + +// service commands +INT_PTR ReplaceSmileysCommand(WPARAM wParam, LPARAM lParam); +INT_PTR GetSmileyIconCommand(WPARAM wParam, LPARAM lParam); +INT_PTR ShowSmileySelectionCommand(WPARAM wParam, LPARAM lParam); +INT_PTR GetInfoCommand(WPARAM wParam, LPARAM); +INT_PTR GetInfoCommand2(WPARAM wParam, LPARAM); +INT_PTR ParseText(WPARAM wParam, LPARAM lParam); +INT_PTR ParseTextW(WPARAM wParam, LPARAM lParam); +INT_PTR RegisterPack(WPARAM wParam, LPARAM lParam); +INT_PTR ParseTextBatch(WPARAM wParam, LPARAM lParam); +INT_PTR FreeTextBatch(WPARAM wParam, LPARAM lParam); +INT_PTR CustomCatMenu(WPARAM, LPARAM lParam); +int RebuildContactMenu(WPARAM wParam, LPARAM); +INT_PTR ReloadPack(WPARAM, LPARAM lParam); +INT_PTR LoadContactSmileys(WPARAM, LPARAM lParam); +int AccountListChanged(WPARAM wParam, LPARAM lParam); +int DbSettingChanged(WPARAM wParam, LPARAM lParam); + +SmileyPackType* GetSmileyPack(const char* proto, HANDLE hContact = NULL, SmileyPackCType** smlc = NULL); + + +#endif // SMILEYADD_SERVICES_H_ + diff --git a/plugins/SmileyAdd/src/smileyroutines.cpp b/plugins/SmileyAdd/src/smileyroutines.cpp new file mode 100644 index 0000000000..ba136d7ed5 --- /dev/null +++ b/plugins/SmileyAdd/src/smileyroutines.cpp @@ -0,0 +1,610 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "smileyroutines.h" +#include "SmileyBase.h" +#include "options.h" + +#include +#include + +ISmileyBase* CreateSmileyObject(SmileyType* sml); +ISmileyBase* CreateAniSmileyObject(SmileyType* sml, COLORREF clr, bool ishpp); + + + +bool g_HiddenTextSupported = true; + + +// {8CC497C0-A1DF-11CE-8098-00AA0047BE5D} +const GUID IID_ITextDocument = +{ 0x8CC497C0, 0xA1DF, 0x11CE, { 0x80,0x98,0x00,0xAA,0x00,0x47,0xBE,0x5D } }; + +void LookupAllSmileys(SmileyPackType* smileyPack, SmileyPackCType* smileyCPack, const TCHAR* lpstrText, + SmileysQueueType& smllist, const bool firstOnly) +{ + if (lpstrText == NULL || *lpstrText == 0) return; + + SmileyPackType::SmileyLookupType* sml = smileyPack ? smileyPack->GetSmileyLookup() : NULL; + SmileyPackCType::SmileyLookupType* smlc = smileyCPack ? &smileyCPack->GetSmileyLookup() : NULL; + + // Precompute number of smileys + int smlszo = sml ? sml->getCount() : 0; + int smlszc = smlc ? smlc->getCount() : 0; + int smlsz = smlszo + smlszc; + + if (smlsz == 0) return; + + // All possible smileys + SmileyLookup::SmileyLocVecType* smileys = new SmileyLookup::SmileyLocVecType [smlsz]; + + // Find all possible smileys + bkstring tmpstr(lpstrText); + int i = 0; + + if (sml) + { + for (int j=0; jgetCount(); j++) + { + (*sml)[j].find(tmpstr, smileys[i], false); + i++; + } + } + + if (smlc) + { + for (int j=0; jgetCount(); j++) + { + (*smlc)[j].find(tmpstr, smileys[i], false); + i++; + } + } + + int* csmlit = (int*)alloca(smlsz * sizeof(int)); + if (csmlit == NULL) return; + memset(csmlit, 0, smlsz * sizeof(int)); + + long numCharsSoFar = 0; + bkstring::size_type smloff = 0; + + for (;;) + { + int firstSml = -1; + int firstSmlRef = -1; + SmileyLookup::SmileyLocVecType* smlf = NULL; + + for (int csml=0; csml= smloff) + { + if (firstSmlRef == -1 || smlv[tsml].pos < (*smlf)[firstSmlRef].pos || + (smlv[tsml].pos == (*smlf)[firstSmlRef].pos && smlv[tsml].len > (*smlf)[firstSmlRef].len)) + { + firstSmlRef = tsml; + firstSml = csml; + smlf = &smileys[csml]; + } + break; + } + } + csmlit[csml] = tsml; + } + + // Check if smiley found + if (firstSml != -1) + { + ReplaceSmileyType *dat = new ReplaceSmileyType; + + const TCHAR* textToSearch = lpstrText + smloff; + const TCHAR* textSmlStart = lpstrText + (*smlf)[firstSmlRef].pos; + const TCHAR* textSmlEnd = textSmlStart + (*smlf)[firstSmlRef].len; + + // check if leading space exist + const TCHAR* prech = _tcsdec(textToSearch, textSmlStart); + dat->ldspace = prech != NULL ? _istspace(*prech) != 0 : smloff == 0; + + // check if trailing space exist + dat->trspace = *textSmlEnd == 0 || _istspace(*textSmlEnd); + + // compute text location in RichEdit + dat->loc.cpMin = (long)_tcsnccnt(textToSearch, (*smlf)[firstSmlRef].pos - smloff) + numCharsSoFar; + dat->loc.cpMax = numCharsSoFar = (long)_tcsnccnt(textSmlStart, (*smlf)[firstSmlRef].len) + dat->loc.cpMin; + + if (!opt.EnforceSpaces || (dat->ldspace && dat->trspace)) + { + dat->ldspace |= !opt.SurroundSmileyWithSpaces; + dat->trspace |= !opt.SurroundSmileyWithSpaces; + + if (firstSml < smlszo) + { + dat->sml = smileyPack->GetSmiley((*sml)[firstSml].GetIndex()); + dat->smlc = NULL; + } + else + { + dat->smlc = smileyCPack->GetSmiley((*smlc)[firstSml-smlszo].GetIndex()); + dat->sml = NULL; + } + + if (dat->sml != NULL || dat->smlc != NULL) + { + // First smiley found record it + smllist.insert(dat); + if (firstOnly) break; + } + else + delete dat; + } + else + delete dat; + + // Advance string pointer to search for the next smiley + smloff = (*smlf)[firstSmlRef].pos + (*smlf)[firstSmlRef].len; + csmlit[firstSml]++; + } + else + // Nothing to parse exit + break; + } + delete[] smileys; +} + + +void FindSmileyInText(SmileyPackType* smp, const TCHAR* str, + unsigned& first, unsigned& size, SmileyType** sml) +{ + SmileysQueueType smllist; + LookupAllSmileys(smp, NULL, str, smllist, true); + if (smllist.getCount() == 0) + { + size = 0; + *sml = NULL; + } + else + { + first = smllist[0].loc.cpMin; + size = smllist[0].loc.cpMax - smllist[0].loc.cpMin; + *sml = smllist[0].sml; + } +} + + +SmileyType* FindButtonSmiley(SmileyPackType* smp) +{ + unsigned start, size; + SmileyType* sml; + + FindSmileyInText(smp, smp->GetButtonSmiley(), start, size, &sml); + + return sml; +} + +void UpdateSelection(CHARRANGE& sel, int pos, int dif) +{ + if (sel.cpMax == sel.cpMin) + { + if (sel.cpMax < LONG_MAX && sel.cpMax > pos) + { + sel.cpMax += dif; + sel.cpMin += dif; + } + } + else + { + if (sel.cpMax >= pos && sel.cpMax < LONG_MAX) sel.cpMax += dif; + if (sel.cpMin > pos) sel.cpMin += dif; + } +} + +void ReplaceSmileys(HWND hwnd, SmileyPackType* smp, SmileyPackCType* smcp, const CHARRANGE& sel, + bool useHidden, bool ignoreLast, bool unFreeze) +{ +/* + LARGE_INTEGER freq, strt, end; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&strt); +*/ + IRichEditOle* RichEditOle; + if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return; + + ITextDocument* TextDocument; + if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) + { + RichEditOle->Release(); + return; + } + + long cnt; + if (smp == NULL && smcp == NULL) + { + if (unFreeze) TextDocument->Unfreeze(&cnt); + TextDocument->Release(); + RichEditOle->Release(); + return; + } + + // retrieve text range + ITextRange* TextRange; + if (TextDocument->Range(sel.cpMin, sel.cpMax, &TextRange) != S_OK) + { + TextDocument->Release(); + RichEditOle->Release(); + return; + } + + // retrieve text to parse for smileys + BSTR btxt = 0; + if (TextRange->GetText(&btxt) != S_OK) + { + TextRange->Release(); + TextDocument->Release(); + RichEditOle->Release(); + return; + } + + TextRange->Release(); + + SmileysQueueType smllist; + + + LookupAllSmileys(smp, smcp, W2T_SM(btxt), smllist, false); + + SysFreeString(btxt); + + if (smllist.getCount() != 0) + { + // disable screen updates + TextDocument->Freeze(&cnt); + + TCHAR classname[20]; + GetClassName(hwnd, classname, SIZEOF(classname)); + bool ishpp = (_tcsncmp(classname, _T("THppRichEdit"), 12) == 0); + + SetRichCallback(hwnd, NULL, false, true); + + bool rdo = (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) != 0; + if (rdo) SendMessage(hwnd, EM_SETREADONLY, FALSE, 0); + + ITextSelection* TextSelection; + TextDocument->GetSelection(&TextSelection); + + ITextFont *TextFont; + TextSelection->GetFont(&TextFont); + + //save selection + CHARRANGE oldSel; + TextSelection->GetStart(&oldSel.cpMin); + TextSelection->GetEnd(&oldSel.cpMax); + + CHARFORMAT2 chf; + + chf.cbSize = sizeof(chf); + chf.dwMask = CFM_ALL2; + + // Determine background color + // This logic trying to minimize number of background color changes + static COLORREF bkgColor = GetSysColor(COLOR_WINDOW); +// if (!insemf) +// { + COLORREF bkgColorPv = (COLORREF)SendMessage(hwnd, EM_SETBKGNDCOLOR, 0, bkgColor); + if (bkgColorPv != bkgColor) + { + bkgColor = bkgColorPv; + SendMessage(hwnd, EM_SETBKGNDCOLOR, 0, bkgColor); + } +// } + + HDC hdc = GetDC(hwnd); + int sclX = GetDeviceCaps(hdc, LOGPIXELSX); + int sclY = GetDeviceCaps(hdc, LOGPIXELSY); + + unsigned numBTBSm = 0; + + BSTR spaceb = SysAllocString(L" "); + + // Replace smileys specified in the list in RichEdit + for (int j = smllist.getCount(); j--; ) + { + CHARRANGE& smlpos = smllist[j].loc; + if (ignoreLast && oldSel.cpMax == smlpos.cpMax) continue; + + smlpos.cpMin += sel.cpMin; + smlpos.cpMax += sel.cpMin; + + // Find all back to back smileys and for propper hidden text detection + if ( numBTBSm == 0 ) + { + CHARRANGE lastPos = smlpos; + for (int jn = j; jn--; ) + { + if (jn != j && smllist[jn].loc.cpMax != lastPos.cpMin) + break; + + ++numBTBSm; + lastPos.cpMin = smllist[jn].loc.cpMin; + } + TextSelection->SetRange(lastPos.cpMin, lastPos.cpMax); + long hid; + TextFont->GetHidden(&hid); + if (hid == tomFalse) numBTBSm = 0; + } + if ( numBTBSm != 0 ) + { + --numBTBSm; + continue; + } + + SmileyType* sml = smllist[j].sml; + SmileyCType* smlc = smllist[j].smlc; + if (sml == NULL && smlc == NULL) continue; + + // Select text analyze + TextSelection->SetRange(smlpos.cpMin, smlpos.cpMax); + + BSTR btxt = NULL; + + if (smlc == NULL && sml->IsText()) + { + btxt = SysAllocString(T2W_SM(sml->GetToolText().c_str())); + TextSelection->SetText(btxt); + } + else + { + TextSelection->GetText(&btxt); + + // Get font properties + SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&chf); + + //do not look for smileys in hyperlinks + if ((chf.dwEffects & (CFE_LINK | CFE_HIDDEN)) != 0) continue; + + SIZE osize; + if (sml) + sml->GetSize(osize); + else + smlc->GetSize(osize); + + if (osize.cx == 0 || osize.cy == 0) continue; + + int sizeX, sizeY; + if (opt.ScaleToTextheight) + { + sizeY = CalculateTextHeight(hdc, &chf); + sizeX = osize.cx * sizeY / osize.cy; + + int dx = osize.cx - sizeX; + sizeX += dx & 1; + + int dy = osize.cy - sizeY; + sizeY += dy & 1; + } + else + { + sizeX = osize.cx; + sizeY = osize.cy; + } + + if (smlc != NULL && opt.MaxCustomSmileySize && (unsigned)sizeY > opt.MaxCustomSmileySize) + { + sizeY = opt.MaxCustomSmileySize; + sizeX = osize.cx * sizeY / osize.cy; + + int dx = osize.cx - sizeX; + sizeX += dx & 1; + + int dy = osize.cy - opt.MaxCustomSmileySize; + sizeY += dy & 1; + } + + if (opt.MinSmileySize && (unsigned)sizeY < opt.MinSmileySize) + { + sizeY = opt.MinSmileySize; + sizeX = osize.cx * sizeY / osize.cy; + + int dx = osize.cx - sizeX; + sizeX += dx & 1; + + int dy = osize.cy - opt.MinSmileySize; + sizeY += dy & 1; + } + + // Convert pixel to HIMETRIC + SIZEL sizehm; + sizehm.cx = (2540 * (sizeX+1) + (sclX >> 1)) / sclX; + sizehm.cy = (2540 * (sizeY+1) + (sclY >> 1)) / sclY; + + // If font does not have designated background use control background + if (chf.dwEffects & CFE_AUTOBACKCOLOR) chf.crBackColor = bkgColor; + + // insert space after + if (!smllist[j].trspace && useHidden) + { + TextSelection->SetStart(smlpos.cpMax); + TextSelection->TypeText(spaceb); + UpdateSelection(oldSel, smlpos.cpMax , 1); + + // Restore selection + TextSelection->SetRange(smlpos.cpMin, smlpos.cpMax); + } + + if (g_HiddenTextSupported && useHidden) + { + TextFont->SetHidden(tomTrue); + TextSelection->SetEnd(smlpos.cpMin); + UpdateSelection(oldSel, smlpos.cpMin , 1); + } + else + { + UpdateSelection(oldSel, smlpos.cpMin, -(int)SysStringLen(btxt)+1); + } + + ISmileyBase* smileyBase = CreateAniSmileyObject(smlc ? smlc : sml, chf.crBackColor, ishpp); + if (smileyBase == NULL) continue; + + smileyBase->SetExtent(DVASPECT_CONTENT, &sizehm); + smileyBase->SetHint(W2T_SM(btxt)); + + smileyBase->SetPosition(hwnd, NULL); + + // Get the RichEdit container site + IOleClientSite *pOleClientSite; + RichEditOle->GetClientSite(&pOleClientSite); + + // Now Add the object to the RichEdit + REOBJECT reobject = { 0 }; + + reobject.cbStruct = sizeof(REOBJECT); + reobject.cp = REO_CP_SELECTION; + reobject.dvaspect = DVASPECT_CONTENT; + reobject.poleobj = smileyBase; + reobject.polesite = pOleClientSite; + reobject.dwFlags = REO_BELOWBASELINE | REO_BLANK; + reobject.dwUser = (DWORD)smileyBase; + + // Insert the bitmap at the current location in the richedit control + RichEditOle->InsertObject(&reobject); + + smileyBase->Release(); + + // insert space before + if (!smllist[j].ldspace && useHidden) + { + TextSelection->SetRange(smlpos.cpMin, smlpos.cpMin); + TextSelection->TypeText(spaceb); + UpdateSelection(oldSel, smlpos.cpMin , 1); + } + } + SysFreeString(btxt); + } + SysFreeString(spaceb); + + TextSelection->SetRange(oldSel.cpMin, oldSel.cpMax); + if (rdo) SendMessage(hwnd, EM_SETREADONLY, TRUE, 0); + + TextFont->Release(); + TextSelection->Release(); + + ReleaseDC(hwnd, hdc); + + TextDocument->Unfreeze(&cnt); + if (cnt == 0) UpdateWindow(hwnd); + } + + if (unFreeze) + { + TextDocument->Unfreeze(&cnt); + if (cnt == 0) UpdateWindow(hwnd); + } + + TextDocument->Release(); + RichEditOle->Release(); + +/* + QueryPerformanceCounter(&end); + unsigned dif = (end.QuadPart - strt.QuadPart)/(freq.QuadPart/1000); + TCHAR mess[300]; + wsprintf(mess, _T("Time elapsed: %u"), dif); + MessageBox(NULL, mess, _T(""), MB_OK); +*/ +} + + +void ReplaceSmileysWithText(HWND hwnd, CHARRANGE& sel, bool keepFrozen) +{ + IRichEditOle* RichEditOle; + if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return; + + ITextDocument* TextDocument; + if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) + { + RichEditOle->Release(); + return; + } + + // retrieve text range + ITextRange* TextRange; + if (TextDocument->Range(0, 0, &TextRange) != S_OK) + { + TextDocument->Release(); + RichEditOle->Release(); + return; + } + + long cnt; + TextDocument->Freeze(&cnt); + + bool rdo = (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) != 0; + if (rdo) SendMessage(hwnd, EM_SETREADONLY, FALSE, 0); + + CHARRANGE oldSel; + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&oldSel); + + int objectCount = RichEditOle->GetObjectCount(); + for (int i = objectCount - 1; i >= 0; i--) + { + REOBJECT reObj = {0}; + reObj.cbStruct = sizeof(REOBJECT); + + HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ); + if (FAILED(hr)) continue; + + if (reObj.cp < sel.cpMin) + { + reObj.poleobj->Release(); + break; + } + + ISmileyBase *igsc = NULL; + if (reObj.cp < sel.cpMax && reObj.clsid == CLSID_NULL) + reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc); + + reObj.poleobj->Release(); + if (igsc == NULL) continue; + + TextRange->SetRange(reObj.cp, reObj.cp + 1); + + BSTR bstr = NULL; + igsc->GetTooltip(&bstr); + TextRange->SetText(bstr); + + unsigned int len = SysStringLen(bstr); + UpdateSelection(oldSel, reObj.cp, len-1); + UpdateSelection(sel, reObj.cp, len-1); + + SysFreeString(bstr); + + igsc->Release(); + } + + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&oldSel); + if (rdo) SendMessage(hwnd, EM_SETREADONLY, TRUE, 0); + if (!keepFrozen) TextDocument->Unfreeze(&cnt); + + TextRange->Release(); + TextDocument->Release(); + RichEditOle->Release(); +} diff --git a/plugins/SmileyAdd/src/smileyroutines.h b/plugins/SmileyAdd/src/smileyroutines.h new file mode 100644 index 0000000000..6b12ee6ead --- /dev/null +++ b/plugins/SmileyAdd/src/smileyroutines.h @@ -0,0 +1,49 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef _SMILEYROUTINES_ +#define _SMILEYROUTINES_ + +#include "smileys.h" +#include "customsmiley.h" + +typedef struct ReplaceSmileyType_tag +{ + CHARRANGE loc; + SmileyType* sml; + SmileyCType* smlc; + bool ldspace; + bool trspace; +} ReplaceSmileyType; + +// Queue to store smileys found +typedef SMOBJLIST SmileysQueueType; + + + +void LookupAllSmileys(SmileyPackType* smileyPack, SmileyPackCType* smileyCPack, const TCHAR* lpstrText, + SmileysQueueType& smllist, const bool firstOnly); +void ReplaceSmileys(HWND hwnd, SmileyPackType* smp, SmileyPackCType* smcp, const CHARRANGE& sel, + bool useHidden, bool ignoreLast, bool unFreeze); +void ReplaceSmileysWithText(HWND hwnd, CHARRANGE& sel, bool keepFrozen); +void FindSmileyInText(SmileyPackType* smp, const TCHAR* str, + unsigned& first, unsigned& size, SmileyType** index); +SmileyType* FindButtonSmiley(SmileyPackType* smp); + +#endif diff --git a/plugins/SmileyAdd/src/smileys.cpp b/plugins/SmileyAdd/src/smileys.cpp new file mode 100644 index 0000000000..2f16cee51e --- /dev/null +++ b/plugins/SmileyAdd/src/smileys.cpp @@ -0,0 +1,1146 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + + +#include "smileys.h" +#include "smileyroutines.h" +#include "options.h" +#include "download.h" + +SmileyPackListType g_SmileyPacks; +SmileyCategoryListType g_SmileyCategories; + +extern HANDLE hNetlibUser; + +// +// SmileyType +// + + +SmileyType::SmileyType(void) +{ + m_SmileyIcon = NULL; + m_xepimg = NULL; + m_flags = 0; + m_index = 0; + m_size.cx = 0; + m_size.cy = 0; +} + +SmileyType::~SmileyType() +{ + if (m_xepimg) m_xepimg->Release(); + m_xepimg = NULL; + + if (m_SmileyIcon != NULL) DestroyIcon(m_SmileyIcon); + m_SmileyIcon = NULL; +} + + +HICON SmileyType::GetIcon(void) +{ + if (m_SmileyIcon == NULL) + { + ImageBase* img = CreateCachedImage(); + if (!img) return NULL; + img->SelectFrame(m_index); + m_SmileyIcon = img->GetIcon(); + img->Release(); + } + return m_SmileyIcon; +} + + +HICON SmileyType::GetIconDup(void) +{ + ImageBase* img = CreateCachedImage(); + img->SelectFrame(m_index); + HICON hIcon = img->GetIcon(); + img->Release(); + return hIcon; +} + + +bool SmileyType::LoadFromImage(IStream* pStream) +{ + if (m_xepimg) m_xepimg->Release(); + + bkstring name; + m_xepimg = new ImageType(0, name, pStream); + + return true; +} + + +bool SmileyType::LoadFromResource(const bkstring& file, const int index) +{ + m_index = index; + m_filepath = file; + + return true; +} + + +void SmileyType::GetSize(SIZE& size) +{ + if (m_size.cy == 0) + { + ImageBase* img = CreateCachedImage(); + if (img) + { + img->GetSize(m_size); + img->Release(); + } + } + size = m_size; +} + + +ImageBase* SmileyType::CreateCachedImage(void) +{ + if (m_xepimg) + { + m_xepimg->AddRef(); + return m_xepimg; + } + return AddCacheImage(m_filepath, m_index); +} + + +void SmileyType::SetImList(HIMAGELIST hImLst, long i) +{ + if (m_xepimg) m_xepimg->Release(); + m_xepimg = new ImageListItemType(0, hImLst, i); +} + + +HBITMAP SmileyType::GetBitmap(COLORREF bkgClr, int sizeX, int sizeY) +{ + ImageBase* img = CreateCachedImage(); + if (!img) return NULL; + img->SelectFrame(m_index); + HBITMAP hBmp = img->GetBitmap(bkgClr, sizeX, sizeY); + img->Release(); + + return hBmp; +} + + +// +// SmileyPackType +// + +SmileyPackType::SmileyPackType() +{ + m_hSmList = NULL; + errorFound = false; +} + +SmileyType* SmileyPackType::GetSmiley(unsigned index) +{ + return (index < (unsigned)m_SmileyList.getCount()) ? &m_SmileyList[index] : NULL; +} + + +static DWORD_PTR ConvertServiceParam(HANDLE hContact, const TCHAR *param) +{ + DWORD_PTR ret; + if (param == NULL) + ret = 0; + else if (_tcsicmp(_T("hContact"), param) == 0) + ret = (DWORD_PTR)hContact; + else if (_istdigit(*param)) + ret = _ttoi(param); + else + ret = (DWORD_PTR)param; + + return ret; +} + + +void SmileyType::CallSmileyService(HANDLE hContact) +{ + _TPattern * srvsplit = _TPattern::compile(_T("(.*)\\|(.*)\\|(.*)")); + _TMatcher * m0 = srvsplit->createTMatcher(GetTriggerText()); + m0->findFirstMatch(); + + bkstring name = m0->getGroup(1); + bkstring par1 = m0->getGroup(2); + bkstring par2 = m0->getGroup(3); + + delete m0; + delete srvsplit; + + char str[MAXMODULELABELLENGTH]; + const char *proto = ""; + + if (name[0] == '/') + { + proto = (const char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (proto == NULL) return; + } + mir_snprintf(str, sizeof(str), "%s%s", proto, T2A_SM(name.c_str())); + CallService(str, + ConvertServiceParam(hContact, par1.c_str()), + ConvertServiceParam(hContact, par2.c_str())); +} + + + +SmileyPackType::~SmileyPackType() +{ + if (m_hSmList != NULL) ImageList_Destroy(m_hSmList); +} + +static const TCHAR urlRegEx[] = + _T("(?:ftp|https|http|file|aim|webcal|irc|msnim|xmpp|gopher|mailto|news|nntp|telnet|wais|prospero)://?[\\w.?%:/$+;]*"); +static const TCHAR pathRegEx[] = _T("[\\s\"][a-zA-Z]:[\\\\/][\\w.\\-\\\\/]*"); +static const TCHAR timeRegEx[] = _T("\\d{1,2}:\\d{2}:\\d{2}|\\d{1,2}:\\d{2}"); + +void SmileyPackType::AddTriggersToSmileyLookup(void) +{ + _TPattern * p = _TPattern::compile(_T("\\s+")); + + { + bkstring emptystr; + m_SmileyLookup.insert(new SmileyLookup(urlRegEx, true, -1, emptystr)); + m_SmileyLookup.insert(new SmileyLookup(pathRegEx, true, -1, emptystr)); + m_SmileyLookup.insert(new SmileyLookup(timeRegEx, true, -1, emptystr)); + } + + for (int dist = 0; dist < m_SmileyList.getCount(); dist++) + { + if (m_SmileyList[dist].IsRegEx()) + { + SmileyLookup* dats = new SmileyLookup(m_SmileyList[dist].GetTriggerText(), true, dist, GetFilename()); + if (dats->IsValid()) + m_SmileyLookup.insert(dats); + else + errorFound = true; + if (m_SmileyList[dist].m_InsertText.empty()) m_SmileyList[dist].m_InsertText = m_SmileyList[dist].m_ToolText; + } + else if (!m_SmileyList[dist].IsService()) + { + bool first = true; + int li = 0; + _TMatcher * m0 = p->createTMatcher(m_SmileyList[dist].GetTriggerText()); + while (m0->findNextMatch()) + { + int stind = m0->getStartingIndex(); + if (li != stind) + { + bkstring out; + ReplaceAllSpecials(m0->getString().substr(li, stind - li), out); + SmileyLookup *dats = new SmileyLookup(out, false, dist, GetFilename()); + if (dats->IsValid()) + { + m_SmileyLookup.insert(dats); + if (first) + { + m_SmileyList[dist].m_InsertText = out; + first = false; + } + } + } + li = m0->getEndingIndex(); + } + + int stind = (int)m0->getString().size(); + if (li < stind) + { + bkstring out; + ReplaceAllSpecials(m0->getString().substr(li, stind - li), out); + SmileyLookup *dats = new SmileyLookup(out, false, dist, GetFilename()); + if (dats->IsValid()) + { + m_SmileyLookup.insert(dats); + if (first) + { + m_SmileyList[dist].m_InsertText = out; + first = false; + } + } + } + delete m0; + } + } + delete p; +} + + +void SmileyPackType::ReplaceAllSpecials(const bkstring& Input, bkstring& Output) +{ + Output = _TPattern::replace(_T("%%_{1,2}%%"), Input, _T(" ")); + Output = _TPattern::replace(_T("%%''%%"), Output, _T("\"")); +} + + +void SmileyPackType::Clear(void) +{ + m_SmileyList.destroy(); + m_SmileyLookup.destroy(); + if (m_hSmList != NULL) { ImageList_Destroy(m_hSmList); m_hSmList = NULL; } + m_Filename.clear(); + m_Name.clear(); + m_Date.clear(); + m_Version.clear(); + m_Author.clear(); + m_VisibleCount = 0; + m_ButtonSmiley.clear(); + errorFound = false; +} + +bool SmileyPackType::LoadSmileyFile(const bkstring& filename, bool onlyInfo, bool noerr) +{ + Clear(); + + if (filename.empty()) + { + m_Name = _T("Nothing loaded"); + return false; + } + + bkstring modpath; + pathToAbsolute(filename, modpath); + + // Load xep file + int fh = _topen(modpath.c_str(), _O_BINARY | _O_RDONLY); + if (fh == -1) + { + if (!noerr) + { + static const TCHAR errmsg[] = _T("Smiley Pack %s not found.\n") + _T("Select correct Smiley Pack in the Miranda Options | Customize | Smileys."); + TCHAR msgtxt[1024]; + mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), modpath.c_str()); + ReportError(msgtxt); + } + + m_Name = _T("Nothing loaded"); + return false; + } + + m_Filename = filename; + + // Find file size + const long flen = _filelength(fh); + + // Allocate file buffer + char* buf = new char[flen + sizeof(wchar_t)]; + + // Read xep file in + int len = _read(fh, buf, flen); + *(wchar_t*)(buf+len) = 0; + + // Close file + _close(fh); + + bkstring tbuf; + + if (len>2 && *(wchar_t*)buf == 0xfeff) + { + tbuf = W2T_SM((wchar_t*)buf+1); + } + else if (len>3 && buf[0]=='\xef' && buf[1]=='\xbb' && buf[2]=='\xbf') + { + tbuf = W2T_SM(A2W_SM(buf+3, CP_UTF8)); + } + else + { + tbuf = A2T_SM(buf); + } + + delete[] buf; + + bool res; + if (filename.find(_T(".xep")) == filename.npos) + res = LoadSmileyFileMSL(tbuf, onlyInfo, modpath); + else + res = LoadSmileyFileXEP(tbuf, onlyInfo, modpath); + + if (errorFound) ReportError(TranslateT("There were problems loading smiley pack (it should be corrected).\nSee Network Log for details.")); + + return res; +} + +bool SmileyPackType::LoadSmileyFileMSL(bkstring& tbuf, bool onlyInfo, bkstring& modpath) +{ + _TPattern * pathsplit = _TPattern::compile(_T("(.*\\\\)(.*)\\.|$")); + _TMatcher * m0 = pathsplit->createTMatcher(modpath); + + m0->findFirstMatch(); + const bkstring pathstr = m0->getGroup(1); + const bkstring packstr = m0->getGroup(2); + + delete m0; + delete pathsplit; + + _TPattern * otherf = _TPattern::compile( + _T("^\\s*(Name|Author|Date|Version|ButtonSmiley)\\s*=\\s*\"(.*)\""), + _TPattern::MULTILINE_MATCHING); + + m0 = otherf->createTMatcher(tbuf); + + while (m0->findNextMatch()) + { + if (m0->getGroup(1) == _T("Name")) m_Name = m0->getGroup(2); + if (m0->getGroup(1) == _T("Author")) m_Author = m0->getGroup(2); + if (m0->getGroup(1) == _T("Date")) m_Date = m0->getGroup(2); + if (m0->getGroup(1) == _T("Version")) m_Version = m0->getGroup(2); + if (m0->getGroup(1) == _T("ButtonSmiley")) m_ButtonSmiley = m0->getGroup(2); + } + delete m0; + delete otherf; + + if (!onlyInfo) + { + selec.x = 0; + selec.y = 0; + win.x = 0; + win.y = 0; + { + _TPattern * pat = _TPattern::compile( + _T("^\\s*(Selection|Window)Size\\s*=\\s*(\\d+)\\s*,\\s*(\\d+)"), + _TPattern::MULTILINE_MATCHING); + _TMatcher * m0 = pat->createTMatcher(tbuf); + while (m0->findNextMatch()) + { + POINT tpt; + tpt.x = _ttol(m0->getGroup(2).c_str()); + tpt.y = _ttol(m0->getGroup(3).c_str()); + + if (m0->getGroup(1) == _T("Selection")) + selec = tpt; + else if (m0->getGroup(1) == _T("Window")) + win = tpt; + } + delete m0; + delete pat; + } + + _TPattern * smiley = _TPattern::compile( + _T("^\\s*Smiley(\\*)?\\s*=") // Is Hidden + _T("(?:\\s*\"(.*)\")") // Smiley file name + _T("(?:[\\s,]+(\\-?\\d+))") // Icon resource id + _T("(?:[\\s,]+(R|S)?\"(.*?)\")") // Trigger text + _T("(?:[\\s,]+\"(.*?)\")?") // Tooltip or insert text + _T("(?:[\\s,]+\"(.*?)\")?"), // Tooltip text + _TPattern::MULTILINE_MATCHING); + + _TMatcher * m0 = smiley->createTMatcher(tbuf); + + SmileyVectorType hiddenSmileys; + + unsigned smnum = 0; + while (m0->findNextMatch()) + { + bkstring resname = m0->getGroup(2); + if (resname.find(_T("http://")) != resname.npos) + { + if (GetSmileyFile(resname, packstr)) continue; + } + else + { + if (!resname.empty()) resname.insert(0, pathstr); + } + + SmileyType *dat = new SmileyType; + + const int iconIndex = _ttol(m0->getGroup(3).c_str()); + + dat->SetHidden(m0->getStartingIndex(1) >= 0); + if (m0->getStartingIndex(4) >= 0) + { + dat->SetRegEx(m0->getGroup(4) == _T("R")); + dat->SetService(m0->getGroup(4) == _T("S")); + } + dat->m_TriggerText = m0->getGroup(5); + if (dat->IsRegEx()) + { + if (m0->getStartingIndex(6) >= 0) + ReplaceAllSpecials(m0->getGroup(6), dat->m_InsertText); + + if (m0->getStartingIndex(7) >= 0) + ReplaceAllSpecials(m0->getGroup(7), dat->m_ToolText); + else + dat->m_ToolText = dat->m_InsertText; + } + else + { + if (m0->getStartingIndex(6) >= 0) + ReplaceAllSpecials(m0->getGroup(6), dat->m_ToolText); + else + ReplaceAllSpecials(dat->m_TriggerText, dat->m_ToolText); + } + + bool noerr; + if (resname.empty()) + { + dat->SetHidden(true); + dat->SetText(true); + noerr = true; + } + else + noerr = dat->LoadFromResource(resname, iconIndex); + + if (dat->IsHidden()) + hiddenSmileys.insert(dat); + else + m_SmileyList.insert(dat); + + if (!noerr) + { + static const TCHAR errmsg[] = _T("Smiley #%u in file %s for Smiley Pack %s not found."); + TCHAR msgtxt[1024]; + mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), smnum, resname.c_str(), modpath.c_str()); + CallService(MS_NETLIB_LOG,(WPARAM) hNetlibUser, (LPARAM)(char*)T2A_SM(msgtxt)); + errorFound = true; + } + smnum++; + } + delete m0; + delete smiley; + + m_VisibleCount = m_SmileyList.getCount(); + + m_SmileyList.splice(hiddenSmileys); + + AddTriggersToSmileyLookup(); + } + + return true; +} + + +static void DecodeHTML(bkstring& str) +{ + if (str.find('&') != str.npos) + { + str = _TPattern::replace(bkstring(_T("<")), str, bkstring(_T("<"))); + str = _TPattern::replace(bkstring(_T(">")), str, bkstring(_T(">"))); + } +} + + +static IStream* DecodeBase64Data(const char* data) +{ + NETLIBBASE64 nlb64; + nlb64.pszEncoded = (char*)data; + nlb64.cchEncoded = (int)strlen(data); + nlb64.cbDecoded = Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded); + + IStream* pStream = NULL; + + // Read image list + HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, nlb64.cbDecoded); + if (hBuffer) + { + nlb64.pbDecoded = (PBYTE)GlobalLock(hBuffer); + CallService(MS_NETLIB_BASE64DECODE, 0, (LPARAM)&nlb64); + GlobalUnlock(hBuffer); + + CreateStreamOnHGlobal(hBuffer, TRUE, &pStream); + } + + return pStream; +} + + +bool SmileyPackType::LoadSmileyFileXEP(bkstring& tbuf, bool onlyInfo, bkstring& ) +{ + _TMatcher *m0, *m1, *m2; + + _TPattern * dbname_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"), + _TPattern::MULTILINE_MATCHING); + _TPattern * author_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"), + _TPattern::MULTILINE_MATCHING); + _TPattern * settings_re = _TPattern::compile(_T("(.*?)"), + _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL); + + m0 = settings_re->createTMatcher(tbuf); + if (m0->findFirstMatch()) + { + bkstring settings = m0->getGroup(1); + + m1 = author_re->createTMatcher(settings); + if (m1->findFirstMatch()) + { + m_Author = m1->getGroup(1); + DecodeHTML(m_Author); + } + delete m1; + + m1 = dbname_re->createTMatcher(settings); + if (m1->findFirstMatch()) + { + m_Name = m1->getGroup(1); + DecodeHTML(m_Name); + } + delete m1; + } + delete m0; + + delete dbname_re; + delete author_re; + delete settings_re; + + if (!onlyInfo) + { + _TPattern * record_re = _TPattern::compile(_T("(?:\\s*\"(.*?)\")?(.*?)"), + _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL); + _TPattern * expression_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"), + _TPattern::MULTILINE_MATCHING); + _TPattern * pastetext_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"), + _TPattern::MULTILINE_MATCHING); + _TPattern * images_re = _TPattern::compile(_T("(.*?)"), + _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL); + _TPattern * image_re = _TPattern::compile(_T("(.*?)"), + _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL); + _TPattern * imagedt_re = _TPattern::compile(_T(""), + _TPattern::MULTILINE_MATCHING ); + + m0 = images_re->createTMatcher(tbuf); + if (m0->findFirstMatch()) + { + bkstring images = m0->getGroup(1); + + m1 = imagedt_re->createTMatcher(images); + if (m1->findFirstMatch()) + { + IStream* pStream = DecodeBase64Data(T2A_SM(m1->getGroup(1).c_str())); + if (pStream != NULL) + { + if (m_hSmList != NULL) ImageList_Destroy(m_hSmList); + m_hSmList = ImageList_Read(pStream); + pStream->Release(); + } + } + delete m1; + } + delete m0; + + m0 = record_re->createTMatcher(tbuf); + while (m0->findNextMatch()) + { + SmileyType *dat = new SmileyType; + + dat->SetRegEx(true); + dat->SetImList(m_hSmList, _ttol(m0->getGroup(1).c_str())); + dat->m_ToolText = m0->getGroup(2); + DecodeHTML(dat->m_ToolText); + + bkstring rec = m0->getGroup(3); + + m1 = expression_re->createTMatcher(rec); + if (m1->findFirstMatch()) + { + dat->m_TriggerText = m1->getGroup(1); + DecodeHTML(dat->m_TriggerText); + } + delete m1; + + m1 = pastetext_re->createTMatcher(rec); + if (m1->findFirstMatch()) + { + dat->m_InsertText = m1->getGroup(1); + DecodeHTML(dat->m_InsertText); + } + delete m1; + dat->SetHidden(dat->m_InsertText.empty()); + + m1 = image_re->createTMatcher(rec); + if (m1->findFirstMatch()) + { + bkstring images = m1->getGroup(1); + + m2 = imagedt_re->createTMatcher(images); + if (m2->findFirstMatch()) + { + IStream* pStream = DecodeBase64Data(T2A_SM(m2->getGroup(1).c_str())); + if (pStream != NULL) + { + dat->LoadFromImage(pStream); + pStream->Release(); + } + } + delete m2; + } + delete m1; + + m_SmileyList.insert(dat); + } + delete m0; + + delete record_re; + delete expression_re; + delete pastetext_re; + delete images_re; + delete image_re; + delete imagedt_re; + } + + m_VisibleCount = m_SmileyList.getCount(); + + AddTriggersToSmileyLookup(); + + selec.x = 0; + selec.y = 0; + win.x = 0; + win.y = 0; + + return true; +} + + +// +// SmileyPackListType +// + + +bool SmileyPackListType::AddSmileyPack(bkstring& filename) +{ + bool res = true; + if (GetSmileyPack(filename) == NULL) + { //not exist yet, so add + SmileyPackType *smileyPack = new SmileyPackType; + + res = smileyPack->LoadSmileyFile(filename, FALSE); + if (res) + m_SmileyPacks.insert(smileyPack); + else + delete smileyPack; + } + return res; +} + + +SmileyPackType* SmileyPackListType::GetSmileyPack(bkstring& filename) +{ + bkstring modpath; + pathToAbsolute(filename, modpath); + + for (int i = 0; i < m_SmileyPacks.getCount(); i++) + { + bkstring modpath1; + pathToAbsolute(m_SmileyPacks[i].GetFilename(), modpath1); + if (lstrcmpi(modpath.c_str(), modpath1.c_str()) == 0) return &m_SmileyPacks[i]; + } + return NULL; +} + +void SmileyPackListType::ClearAndFreeAll() +{ + m_SmileyPacks.destroy(); +} + + +// +// SmileyCategoryType +// + + +SmileyCategoryType::SmileyCategoryType(SmileyPackListType* pSPS, const bkstring& name, + const bkstring& displayName, + const bkstring& defaultFilename, SmcType typ) +{ + m_pSmileyPackStore = pSPS; + type = typ; + m_Name = name; + m_DisplayName = displayName; + + opt.ReadPackFileName(m_Filename, m_Name, defaultFilename); +} + + +void SmileyCategoryType::Load(void) +{ + if (!opt.UseOneForAll || type != smcProto) + m_pSmileyPackStore->AddSmileyPack(m_Filename); +} + + +SmileyPackType* SmileyCategoryType::GetSmileyPack(void) +{ + return m_pSmileyPackStore->GetSmileyPack(m_Filename); +} + + +void SmileyCategoryType::SaveSettings(void) +{ + opt.WritePackFileName(m_Filename, m_Name); +} + +// +// SmileyCategoryListType +// + +void SmileyCategoryListType::ClearAndLoadAll(void) +{ + m_pSmileyPackStore->ClearAndFreeAll(); + + for (int i = 0; i < m_SmileyCategories.getCount(); i++) + m_SmileyCategories[i].Load(); +} + + +SmileyCategoryType* SmileyCategoryListType::GetSmileyCategory(const bkstring& name) +{ + for (int i = 0; i < m_SmileyCategories.getCount(); i++) + { + if (name.comparei(m_SmileyCategories[i].GetName()) == 0) return &m_SmileyCategories[i]; + } + return NULL; +} + + +SmileyCategoryType* SmileyCategoryListType::GetSmileyCategory(unsigned index) +{ + return index < (unsigned)m_SmileyCategories.getCount() ? &m_SmileyCategories[index] : NULL; +} + + +SmileyPackType* SmileyCategoryListType::GetSmileyPack(bkstring& categoryname) +{ + SmileyCategoryType* smc = GetSmileyCategory(categoryname); + return smc != NULL ? smc->GetSmileyPack() : NULL; +} + + +void SmileyCategoryListType::SaveSettings(void) +{ + bkstring catstr; + for (int i = 0; i < m_SmileyCategories.getCount(); i++) + { + m_SmileyCategories[i].SaveSettings(); + if (m_SmileyCategories[i].IsCustom()) + { + if (!catstr.empty()) catstr += '#'; + catstr += m_SmileyCategories[i].GetName(); + } + } + opt.WriteCustomCategories(catstr); +} + + +void SmileyCategoryListType::AddAndLoad(const bkstring& name, const bkstring& displayName) +{ + if (GetSmileyCategory(name) != NULL) return; + + AddCategory(name, displayName, smcExt); + // Load only if other smileys have been loaded already + if (m_SmileyCategories.getCount() > 1) + m_SmileyCategories[m_SmileyCategories.getCount()-1].Load(); +} + + +void SmileyCategoryListType::AddCategory(const bkstring& name, const bkstring& displayName, + SmcType typ, const bkstring& defaultFilename) +{ + if (GetSmileyCategory(name) == NULL) + m_SmileyCategories.insert(new SmileyCategoryType(m_pSmileyPackStore, name, + displayName, defaultFilename, typ)); +} + + +bool SmileyCategoryListType::DeleteCustomCategory(int index) +{ + if (index < m_SmileyCategories.getCount()) + { + if (m_SmileyCategories[index].IsCustom()) + { + m_SmileyCategories.remove(index); + return true; + } + + } + return false; +} + +void SmileyCategoryListType::AddAccountAsCategory(PROTOACCOUNT *acc, const bkstring& defaultFile) +{ + if (IsAccountEnabled(acc) && acc->szProtoName && IsSmileyProto(acc->szModuleName)) + { + bkstring displayName(acc->tszAccountName ? acc->tszAccountName : A2T_SM(acc->szModuleName)); + + const char* packnam = acc->szProtoName; + if (strcmp(packnam, "JABBER") == 0) + packnam = "JGMail"; + else if (strstr(packnam, "SIP") != NULL) + packnam = "MSN"; + + char path[MAX_PATH]; + mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packnam); + + bkstring paths = A2T_SM(path), patha; + pathToAbsolute(paths, patha); + + if (_taccess(patha.c_str(), 0) != 0) + paths = defaultFile; + + bkstring tname(A2T_SM(acc->szModuleName)); + AddCategory(tname, displayName, smcProto, paths); + } +} + +void SmileyCategoryListType::DeleteAccountAsCategory(PROTOACCOUNT *acc) +{ + bkstring tname(A2T_SM(acc->szModuleName)); + + HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + char* proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (proto) + { + DBVARIANT dbv; + if (DBGetContactSettingTString(hContact, proto, "Transport", &dbv) == 0) + { + bool found = (tname.comparei(dbv.ptszVal) == 0); + DBFreeVariant(&dbv); + if (found) return; + } + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + + for (int i = 0; i < m_SmileyCategories.getCount(); i++) + { + if (tname.comparei(m_SmileyCategories[i].GetName()) == 0) + { + m_SmileyCategories.remove(i); + break; + } + } +} + +void SmileyCategoryListType::AddContactTransportAsCategory(HANDLE hContact, const bkstring& defaultFile) +{ + char* proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (proto == NULL) return; + + DBVARIANT dbv; + if (DBGetContactSettingTString(hContact, proto, "Transport", &dbv) == 0) + { + if (dbv.ptszVal[0] == '\0') + { + DBFreeVariant(&dbv); + return; + } + char* trsp = mir_strdup(T2A_SM(dbv.ptszVal)); + _strlwr(trsp); + + const char *packname = NULL; + if (strstr(trsp, "msn") != NULL) + packname = "msn"; + else if (strstr(trsp, "icq") != NULL) + packname = "icq"; + else if (strstr(trsp, "yahoo") != NULL) + packname = "yahoo"; + else if (strstr(trsp, "aim") != NULL) + packname = "aim"; + else if (strstr(trsp, "lcs") != NULL) + packname = "msn"; + + mir_free(trsp); + + bkstring displayName = dbv.ptszVal; + if (packname != NULL) + { + char path[MAX_PATH]; + mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packname); + + bkstring paths = A2T_SM(path), patha; + pathToAbsolute(paths, patha); + + if (_taccess(patha.c_str(), 0) != 0) + paths = defaultFile; + + AddCategory(displayName, displayName, smcProto, paths); + } + else + AddCategory(displayName, displayName, smcProto, defaultFile); + + DBFreeVariant(&dbv); + } +} + + +void SmileyCategoryListType::AddAllProtocolsAsCategory(void) +{ + bkstring displayName = TranslateT("Standard"); + bkstring tname = _T("Standard"); + AddCategory(tname, displayName, smcStd); + + const bkstring& defaultFile = GetSmileyCategory(tname)->GetFilename(); + + + unsigned lpcp = (unsigned)CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); + if (lpcp == CALLSERVICE_NOTFOUND) lpcp = CP_ACP; + + + PROTOCOLDESCRIPTOR **protoList; + PROTOACCOUNT **accList; + int protoCount; + + if (ProtoEnumAccounts(&protoCount, &accList) == CALLSERVICE_NOTFOUND || (protoCount > 0 && accList[0]->cbSize == 0)) + { + CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&protoCount, (LPARAM)&protoList); + for (int i = 0; i < protoCount; i++) + { + if (protoList[i]->type != PROTOTYPE_PROTOCOL) continue; + + if (IsSmileyProto(protoList[i]->szName)) + { + const char* packnam = protoList[i]->szName; + if (strcmp(packnam, "JABBER") == 0) + packnam = "JGMail"; + else if (strstr(packnam, "SIP") != NULL) + packnam = "MSN"; + + char path[MAX_PATH]; + mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packnam); + + bkstring paths = A2T_SM(path), patha; + pathToAbsolute(paths, patha); + + if (_taccess(patha.c_str(), 0) != 0) + paths = defaultFile; + + char protoName[128]; + CallProtoService(protoList[i]->szName, PS_GETNAME, sizeof(protoName), (LPARAM)protoName); + + + displayName = A2W_SM(protoName, lpcp); + + tname = A2T_SM(protoList[i]->szName); + AddCategory(tname, displayName, smcProto, paths); + } + } + } + else + { + for (int i = 0; i < protoCount; i++) + AddAccountAsCategory(accList[i], defaultFile); + } + + HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + AddContactTransportAsCategory(hContact, defaultFile); + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + + bkstring cats; + opt.ReadCustomCategories(cats); + + bkstring::size_type cppv = 0; + for (;;) + { + bkstring::size_type cp = cats.find('#', cppv); + if (cp != cats.npos) + { + displayName = cats.substr(cppv, cp - cppv); + AddCategory(displayName, displayName, smcCustom, defaultFile); + cppv = cp + 1; + } + else break; + } + if (cppv != cats.size()) + { + displayName = cats.substr(cppv, cats.size() - cppv); + AddCategory(displayName, displayName, smcCustom, defaultFile); + } +} + + +SmileyLookup::SmileyLookup(const bkstring& str, const bool regexs, const int ind, const bkstring& smpt) +{ + TCHAR msgtxt[1024]; + + m_ind = ind; + if (regexs) + { + static const bkstring testString(_T("Test String")); + m_pattern = _TPattern::compile(str); + m_valid = m_pattern != NULL; + if (m_valid) + { + _TMatcher* matcher = m_pattern->createTMatcher(testString); + m_valid &= (!matcher->findFirstMatch() || + matcher->getStartingIndex() != matcher->getEndingIndex()); + if (!m_valid) + { + static const TCHAR errmsg[] = _T("Regular Expression \"%s\" in smiley pack \"%s\" could produce \"empty matches\"."); + mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), str.c_str(), smpt.c_str()); + } + delete matcher; + } + else + { + static const TCHAR errmsg[] = _T("Regular Expression \"%s\" in smiley pack \"%s\" malformed.") ; + mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), str.c_str(), smpt.c_str()); + } + + if (!m_valid) CallService(MS_NETLIB_LOG, (WPARAM) hNetlibUser, (LPARAM)(char*)T2A_SM(msgtxt)); + } + else + { + m_text = str; + m_pattern = NULL; + m_valid = !str.empty(); + } +} + + +SmileyLookup::~SmileyLookup() +{ + if (m_pattern) delete m_pattern; +} + + +void SmileyLookup::find(const bkstring& str, SmileyLocVecType& smlcur, bool firstOnly) const +{ + if (!m_valid) return; + + if (m_text.empty()) + { + _TMatcher* matcher = m_pattern->createTMatcher(str); + while( matcher->findNextMatch()) + { + bkstring::size_type st = matcher->getStartingIndex(); + bkstring::size_type sz = matcher->getEndingIndex() - st; + if (sz != 0) + { + smlcur.insert(new SmileyLocType(st, sz)); + if (firstOnly && m_ind != -1) return; + } + } + delete matcher; + } + else + { + const TCHAR* pos = str.c_str(); + while( (pos = _tcsstr(pos, m_text.c_str())) != NULL ) + { + smlcur.insert(new SmileyLocType(pos - str.c_str(), m_text.size())); + pos += m_text.size(); + if (firstOnly && m_ind != -1) return; + } + } +} diff --git a/plugins/SmileyAdd/src/smileys.h b/plugins/SmileyAdd/src/smileys.h new file mode 100644 index 0000000000..2b127eb225 --- /dev/null +++ b/plugins/SmileyAdd/src/smileys.h @@ -0,0 +1,287 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef SMILEYADD_SMILEYS_H_ +#define SMILEYADD_SMILEYS_H_ + +#include "general.h" +#include "smltool.h" +#include "imagecache.h" + +#define MS_SMILEYADD_CUSTOMCATMENU "SmileyAdd/CustomCatMenu" + +const unsigned HiddenSmiley = 1; +const unsigned RegExSmiley = 2; +const unsigned ServiceSmiley = 4; +const unsigned TextSmiley = 8; +const unsigned SoundSmiley = 16; + +class SmileyType +{ +protected: + unsigned m_flags; + int m_index; + + SIZE m_size; + + HICON m_SmileyIcon; + ImageBase* m_xepimg; + + bkstring m_filepath; + + void SetFlagsBit(unsigned flag, bool set) + { if (set) m_flags |= flag; else m_flags &= ~flag; } + +public: + + bkstring m_TriggerText; + bkstring m_ToolText; + bkstring m_InsertText; + + SmileyType(void); + ~SmileyType(); + + const bkstring& GetTriggerText(void) const { return m_TriggerText; } + const bkstring& GetToolText(void) const { return m_ToolText; } + const bkstring& GetInsertText(void) const { return m_InsertText; } + const bkstring& GetFilePath(void) const { return m_filepath; } + + bool IsHidden(void) const { return (m_flags & HiddenSmiley) != 0; } + bool IsRegEx(void) const { return (m_flags & RegExSmiley) != 0; } + bool IsService(void) const { return (m_flags & ServiceSmiley) != 0; } + bool IsSound(void) const { return (m_flags & SoundSmiley) != 0; } + bool IsText(void) const { return (m_flags & TextSmiley) != 0; } + + bool IsFileFound(void) { return _taccess(m_filepath.c_str(), 0) == 0; } + bool IsValid(void) { return m_size.cx != 0; } + + ImageBase* CreateCachedImage(void); + + void GetSize(SIZE& size); + int GetStaticFrame(void) const { return m_index; } + + HICON GetIcon(void); + HICON GetIconDup(void); + HBITMAP GetBitmap(COLORREF bkgClr, int sizeX, int sizeY); + + void CallSmileyService(HANDLE hContact); + + void SetHidden(bool hid) { SetFlagsBit(HiddenSmiley, hid); } + void SetRegEx(bool regex) { SetFlagsBit(RegExSmiley, regex); } + void SetService(bool service) { SetFlagsBit(ServiceSmiley, service); } + void SetSound(bool sound) { SetFlagsBit(SoundSmiley, sound); } + void SetText(bool text) { SetFlagsBit(TextSmiley, text); } + + void SetImList(HIMAGELIST hImLst, long i); + + bool LoadFromResource(const bkstring& file, const int index); + bool LoadFromImage(IStream* pStream); +}; + + +class SmileyLookup +{ +private: + _TPattern* m_pattern; + + int m_ind; + bkstring m_text; + bool m_valid; + +public: + struct SmileyLocType + { + size_t pos, len; + SmileyLocType(size_t p, size_t l) : pos(p), len(l) {} + SmileyLocType() {} + }; + typedef SMOBJLIST SmileyLocVecType; + + SmileyLookup() { m_ind = 0; m_valid = false; m_pattern = NULL; }; + SmileyLookup(const bkstring& str, const bool regexs, const int ind, const bkstring& smpt); + ~SmileyLookup(); + + void find(const bkstring& str, SmileyLocVecType& smlcur, bool firstOnly) const; + int GetIndex(void) const { return m_ind; } + bool IsValid(void) const { return m_valid; } +}; + + +class SmileyPackType +{ +public: + typedef SMOBJLIST SmileyVectorType; + typedef SMOBJLIST SmileyLookupType; + + POINT selec, win; + +private: + bkstring m_Filename; //used as identification + bkstring m_Name; + bkstring m_Author; + bkstring m_Date; + bkstring m_Version; + bkstring m_ButtonSmiley; + + HIMAGELIST m_hSmList; + + int m_VisibleCount; + + SmileyVectorType m_SmileyList; + SmileyLookupType m_SmileyLookup; + + bool errorFound; + + void InsertLookup(SmileyType& sml, bkstring& lk, bool first); + void AddTriggersToSmileyLookup(void); + void ReplaceAllSpecials(const bkstring& Input, bkstring& Output); + bool LoadSmileyFileMSL(bkstring& tbuf, bool onlyInfo, bkstring& modpath); + bool LoadSmileyFileXEP(bkstring& tbuf, bool onlyInfo, bkstring& modpath); + +public: + SmileyPackType(); + ~SmileyPackType(); + + SmileyVectorType& GetSmileyList(void) { return m_SmileyList; } + SmileyLookupType* GetSmileyLookup(void) { return &m_SmileyLookup; } + + const bkstring& GetFilename(void) const { return m_Filename; } + const bkstring& GetName(void) const { return m_Name; } + const bkstring& GetAuthor(void) const { return m_Author; } + const bkstring& GetDate(void) const { return m_Date; } + const bkstring& GetVersion(void) const { return m_Version; } + + int SmileyCount(void) const { return m_SmileyList.getCount(); } + int VisibleSmileyCount(void) const { return m_VisibleCount; } + + SmileyType* GetSmiley(unsigned index); + + const TCHAR* GetButtonSmiley(void) const { return m_ButtonSmiley.c_str(); } + + bool LoadSmileyFile(const bkstring& filename, bool onlyInfo, bool noerr = false); + + void Clear(void); +}; + + +class SmileyPackListType +{ +public: + typedef SMOBJLIST SmileyPackVectorType; + +private: + SmileyPackVectorType m_SmileyPacks; + +public: + int NumberOfSmileyPacks(void) { return m_SmileyPacks.getCount(); } + + bool AddSmileyPack(bkstring& filename); + void ClearAndFreeAll(void); + SmileyPackType* GetSmileyPack(bkstring& filename); +}; + + +typedef enum +{ + smcNone, + smcStd, + smcProto, + smcCustom, + smcExt +} SmcType; + + +class SmileyCategoryType +{ +private: + bkstring m_Name; + bkstring m_DisplayName; + bkstring m_Filename; //functions as identification + + SmcType type; + + SmileyPackListType* m_pSmileyPackStore; + +public: + SmileyCategoryType() { type = smcNone; m_pSmileyPackStore = NULL; }; + SmileyCategoryType(SmileyPackListType* pSPS, const bkstring& name, + const bkstring& displayName, const bkstring& defaultFilename, SmcType typ); + + const bkstring& GetDisplayName(void) const { return m_DisplayName; } + const bkstring& GetName(void) const { return m_Name; } + const bkstring& GetFilename(void) const { return m_Filename; } + + bool IsCustom(void) { return type == smcCustom; } + bool IsProto(void) { return type == smcProto; } + bool IsExt(void) { return type == smcExt; } + + SmcType GetType(void) { return type; } + + SmileyPackType* GetSmileyPack(void); + + void SetFilename(bkstring& name) { m_Filename = name; } + void SetDisplayName(bkstring& name) { m_DisplayName = name; } + + void ClearFilename(void) { m_Filename.clear(); } + void SaveSettings(void); + + void Load(void); +}; + + +class SmileyCategoryListType +{ +public: + typedef SMOBJLIST SmileyCategoryVectorType; + +private: + SmileyCategoryVectorType m_SmileyCategories; + SmileyPackListType* m_pSmileyPackStore; + +public: + void SetSmileyPackStore(SmileyPackListType* pSPS) { m_pSmileyPackStore = pSPS; } + + SmileyCategoryType* GetSmileyCategory(const bkstring& name); + SmileyCategoryType* GetSmileyCategory(unsigned index); + SmileyPackType* GetSmileyPack(bkstring& name); + SmileyCategoryVectorType* GetSmileyCategoryList(void) { return &m_SmileyCategories; }; + + int NumberOfSmileyCategories(void) { return m_SmileyCategories.getCount(); } + + void AddCategory(const bkstring& name, const bkstring& displayName, SmcType typ, + const bkstring& defaultFilename = bkstring(_T("Smileys\\nova\\default.msl"))); + void AddAndLoad(const bkstring& name, const bkstring& displayName); + void AddAllProtocolsAsCategory(void); + void AddAccountAsCategory(PROTOACCOUNT *acc, const bkstring& defaultFile); + void AddContactTransportAsCategory(HANDLE hContact, const bkstring& defaultFile); + + void ClearAndLoadAll(void); + void ClearAll(void) + { m_pSmileyPackStore->ClearAndFreeAll(); m_SmileyCategories.destroy(); } + + bool DeleteCustomCategory(int index); + void DeleteAccountAsCategory(PROTOACCOUNT *acc); + + void SaveSettings(void); +}; + +extern SmileyPackListType g_SmileyPacks; +extern SmileyCategoryListType g_SmileyCategories; + +#endif //SMILEYADD_SMILEYS_H_ diff --git a/plugins/SmileyAdd/src/smltool.cpp b/plugins/SmileyAdd/src/smltool.cpp new file mode 100644 index 0000000000..31695a516a --- /dev/null +++ b/plugins/SmileyAdd/src/smltool.cpp @@ -0,0 +1,785 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "general.h" +#include "options.h" +#include "smileys.h" +#include "smltool.h" +#include "anim.h" + +#define SB_MYMOVE 20 + +// +// SmileyToolwindowType +// +class SmileyToolWindowType +{ +private: + unsigned m_NumberOfVerticalButtons; + unsigned m_NumberOfHorizontalButtons; + SIZE m_BitmapWidth; + SIZE m_ButtonSize; + unsigned m_ButtonSpace; + unsigned m_NumberOfButtons; + int m_WindowSizeY; + + HWND m_hwndDialog; + HWND m_hToolTip; + HWND m_hWndTarget; + SmileyPackType* m_pSmileyPack; + int m_CurrentHotTrack; + int m_XPosition; + int m_YPosition; + int m_Direction; + UINT m_TargetMessage; + WPARAM m_TargetWParam; + HANDLE m_hContact; + int rowSel; + bool m_Choosing; + + AnimatedPack* m_AniPack; + + void InitDialog(LPARAM lParam); + void PaintWindow(void); + void InsertSmiley(void); + void MouseMove(int x, int y); + void KeyUp(WPARAM wParam, LPARAM lParam); + void SmileySel(int but); + void ScrollV(int action, int dist = 0); + + int GetRowSize(void) const { return m_ButtonSize.cy + m_ButtonSpace; } + + void CreateSmileyBitmap(HDC hdc); + void CreateSmileyWinDim(void); + RECT CalculateButtonToCoordinates(int buttonPosition, int scroll); + int CalculateCoordinatesToButton(POINT pt, int scroll); + +public: + SmileyToolWindowType(HWND hWnd); + LRESULT DialogProcedure(UINT msg, WPARAM wParam, LPARAM lParam); +}; + + +LRESULT CALLBACK DlgProcSmileyToolWindow(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + SmileyToolWindowType* pOD; + LRESULT Result; + + pOD = (SmileyToolWindowType*) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (pOD == NULL) { + pOD = new SmileyToolWindowType(hwndDlg); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pOD); + } + + Result = pOD->DialogProcedure(msg, wParam, lParam); + // SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result); + + if (msg == WM_NCDESTROY) + { + delete pOD; + Result = FALSE; + } + + return Result; +} + + +SmileyToolWindowType::SmileyToolWindowType(HWND hWnd) +{ + m_hwndDialog = hWnd; + rowSel = -1; + m_AniPack = NULL; + + m_NumberOfVerticalButtons = 0; + m_NumberOfHorizontalButtons = 0; + m_BitmapWidth.cx = 0; + m_BitmapWidth.cy = 0; + m_ButtonSize.cx = 0; + m_ButtonSize.cy = 0; + m_ButtonSpace = 1; + m_NumberOfButtons = 0; +} + + +LRESULT SmileyToolWindowType::DialogProcedure(UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT Result = FALSE; + + switch (msg) + { + case WM_ACTIVATE: + if (wParam == WA_INACTIVE) + DestroyWindow(m_hwndDialog); + break; + + case WM_PAINT: + PaintWindow(); + break; + + case WM_TIMER: + if (m_AniPack) m_AniPack->ProcessTimerTick(m_hwndDialog); + break; + + case WM_DESTROY: + KillTimer(m_hwndDialog, 1); + if (m_AniPack) delete m_AniPack; + m_AniPack = NULL; + DestroyWindow(m_hToolTip); + PostQuitMessage(0); + if (m_Choosing) + SetFocus(m_hWndTarget); + break; + + case WM_KEYUP: + KeyUp(wParam, lParam); + break; + + case WM_CREATE: + InitDialog(lParam); + break; + + case WM_VSCROLL: + ScrollV(LOWORD(wParam)); + break; + + case WM_MOUSEMOVE: + MouseMove(LOWORD(lParam), HIWORD(lParam)); + break; + + case WM_LBUTTONUP: + InsertSmiley(); + break; + + case WM_MOUSEWHEEL: + ScrollV(SB_MYMOVE, ((short)HIWORD(wParam))/-120); + MouseMove(LOWORD(lParam), HIWORD(lParam)); + break; + + default: + Result = DefWindowProc(m_hwndDialog, msg, wParam, lParam); + break; + } + + return Result; +} + +struct smlsrvstruct +{ + smlsrvstruct(SmileyType *tsml, HANDLE thContact) + : sml(tsml), hContact(thContact) {} + SmileyType *sml; + HANDLE hContact; +}; + +void CALLBACK smileyServiceCallback(void* arg) +{ + smlsrvstruct* p = (smlsrvstruct*)arg; + p->sml->CallSmileyService(p->hContact); + delete p; +} + +void SmileyToolWindowType::InsertSmiley(void) +{ + if (m_CurrentHotTrack >= 0 && m_hWndTarget != NULL) + { + SmileyType *sml = m_pSmileyPack->GetSmiley(m_CurrentHotTrack); + + if (sml->IsService()) + { + smlsrvstruct* p = new smlsrvstruct(sml, m_hContact); + CallFunctionAsync(smileyServiceCallback, p); + } + else + { + bkstring insertText; + + if (opt.SurroundSmileyWithSpaces) insertText = ' '; + insertText += sml->GetInsertText(); + if (opt.SurroundSmileyWithSpaces) insertText += ' '; + + SendMessage(m_hWndTarget, m_TargetMessage, m_TargetWParam, (LPARAM) insertText.c_str()); + } + m_Choosing = true; + DestroyWindow(m_hwndDialog); + } + else if (m_hWndTarget == NULL) + DestroyWindow(m_hwndDialog); +} + +void SmileyToolWindowType::SmileySel(int but) +{ + if (but != m_CurrentHotTrack) + { + SCROLLINFO si; + si.cbSize = sizeof (si); + si.fMask = SIF_POS; + si.nPos = 0; + GetScrollInfo (m_hwndDialog, SB_VERT, &si); + + HDC hdc = GetDC(m_hwndDialog); + if (m_CurrentHotTrack >= 0) + { + RECT rect = CalculateButtonToCoordinates(m_CurrentHotTrack, si.nPos); + DrawFocusRect(hdc, &rect); + m_CurrentHotTrack = -1; + SendMessage(m_hToolTip, TTM_ACTIVATE, FALSE, 0); + } + m_CurrentHotTrack = but; + if (m_CurrentHotTrack >= 0) + { + TOOLINFO ti = {0}; + ti.cbSize = sizeof(ti); + ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + ti.hwnd = m_hwndDialog; + ti.uId = (UINT_PTR)m_hwndDialog; + + const bkstring& toolText = m_pSmileyPack->GetSmiley(m_CurrentHotTrack)->GetToolText(); + ti.lpszText = const_cast(toolText.c_str()); + SendMessage(m_hToolTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); + SendMessage(m_hToolTip, TTM_ACTIVATE, TRUE, 0); + + RECT rect = CalculateButtonToCoordinates(m_CurrentHotTrack, si.nPos); + DrawFocusRect(hdc, &rect); + if (m_AniPack) m_AniPack->SetSel(rect); + } + ReleaseDC(m_hwndDialog, hdc); + } +} + + +void SmileyToolWindowType::ScrollV(int action, int dist) +{ + SCROLLINFO si; + si.cbSize = sizeof (si); + si.fMask = SIF_ALL; + GetScrollInfo (m_hwndDialog, SB_VERT, &si); + + // Save the position for comparison later on + int yPos = si.nPos; + switch (action) + { + // user clicked the HOME keyboard key + case SB_TOP: + si.nPos = si.nMin; + break; + + // user clicked the END keyboard key + case SB_BOTTOM: + si.nPos = si.nMax; + break; + + // user clicked the top arrow + case SB_LINEUP: + si.nPos -= 1; + break; + + // user clicked the bottom arrow + case SB_LINEDOWN: + si.nPos += 1; + break; + + // user clicked the scroll bar shaft above the scroll box + case SB_PAGEUP: + si.nPos -= si.nPage; + break; + + // user clicked the scroll bar shaft below the scroll box + case SB_PAGEDOWN: + si.nPos += si.nPage; + break; + + // user dragged the scroll box + case SB_THUMBTRACK: + si.nPos = si.nTrackPos; + break; + + // user dragged the scroll box + case SB_MYMOVE: + si.nPos += dist; + break; + } + // Set the position and then retrieve it. Due to adjustments + // by Windows it may not be the same as the value set. + si.fMask = SIF_POS; + SetScrollInfo (m_hwndDialog, SB_VERT, &si, TRUE); + GetScrollInfo (m_hwndDialog, SB_VERT, &si); + // If the position has changed, scroll window and update it + if (si.nPos != yPos) + { + if (m_AniPack) m_AniPack->SetOffset(si.nPos*GetRowSize()); + + ScrollWindowEx(m_hwndDialog, 0, (yPos - si.nPos) * GetRowSize(), + NULL, NULL, NULL, NULL, SW_INVALIDATE); + + UpdateWindow (m_hwndDialog); + } +} + + +void SmileyToolWindowType::MouseMove(int xposition, int yposition) +{ + if (m_CurrentHotTrack == -2) return; //prevent focussing when not drawn yet! + // SetFocus(m_hwndDialog); + + + SCROLLINFO si; + si.cbSize = sizeof (si); + si.fMask = SIF_POS; + si.nPos = 0; + GetScrollInfo (m_hwndDialog, SB_VERT, &si); + + POINT pt = { xposition, yposition }; + int but = CalculateCoordinatesToButton(pt, si.nPos); + SmileySel(but); +} + + + +void SmileyToolWindowType::KeyUp(WPARAM wParam, LPARAM lParam) +{ + int colSel = -1, numKey = -1; + int but = m_CurrentHotTrack; + + switch(wParam) + { + case VK_END: + but = m_NumberOfButtons-1; + break; + + case VK_HOME: + but = 0; + break; + + case VK_LEFT: + but -= (opt.IEViewStyle ? 1 : m_NumberOfVerticalButtons) * LOWORD(lParam); + break; + + case VK_UP: + but -= (opt.IEViewStyle ? m_NumberOfHorizontalButtons : 1) * LOWORD(lParam); + break; + + case VK_RIGHT: + but += (opt.IEViewStyle ? 1 : m_NumberOfVerticalButtons) * LOWORD(lParam); + break; + + case VK_DOWN: + but += (opt.IEViewStyle ? m_NumberOfHorizontalButtons : 1) * LOWORD(lParam); + break; + + case VK_SPACE: + case VK_RETURN: + if (but != -1) InsertSmiley(); + return; + + case VK_ESCAPE: + DestroyWindow(m_hwndDialog); + return; + + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + if ((GetKeyState(VK_NUMLOCK) & 1) != 0) + numKey = (int)wParam - VK_NUMPAD1; + else + { + rowSel = -1; + return; + } + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + numKey = (int)wParam - '1'; + break; + + default: + rowSel = -1; + return; + } + + if (numKey != -1) + { + if (rowSel == -1) + { + rowSel = numKey; + but = (opt.IEViewStyle ? m_NumberOfHorizontalButtons : 1) * rowSel; + } + else + { + colSel = numKey; + if (opt.IEViewStyle) + but = colSel + m_NumberOfHorizontalButtons * rowSel; + else + but = rowSel + m_NumberOfVerticalButtons * colSel; + } + } + + if (but < 0) but = 0; + if (but >= (int)m_NumberOfButtons) but = m_NumberOfButtons-1; + + SmileySel(but); + if (colSel != -1) InsertSmiley(); +} + + +void SmileyToolWindowType::InitDialog(LPARAM lParam) +{ + LPCREATESTRUCT createStruct = (LPCREATESTRUCT)lParam; + SmileyToolWindowParam* stwp = (SmileyToolWindowParam*) createStruct->lpCreateParams; + + m_pSmileyPack = stwp->pSmileyPack; + m_XPosition = stwp->xPosition; + m_YPosition = stwp->yPosition; + m_hWndTarget = stwp->hWndTarget; + m_TargetMessage = stwp->targetMessage; + m_TargetWParam = stwp->targetWParam; + m_Direction = stwp->direction; + m_hContact = stwp->hContact; + + m_CurrentHotTrack = -2; + m_Choosing = false; + + CreateSmileyWinDim(); + + int width = m_BitmapWidth.cx; + int height = m_BitmapWidth.cy; + + const int colsz = GetRowSize(); + const int heightn = m_WindowSizeY; + + SCROLLINFO si; + + si.cbSize = sizeof(si); + si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; + si.nMin = 0; + si.nMax = height / colsz - 1; + si.nPage = heightn / colsz; + si.nPos = 0; + SetScrollInfo(m_hwndDialog, SB_VERT, &si, TRUE); + + if (GetWindowLongPtr(m_hwndDialog, GWL_STYLE) & WS_VSCROLL) + width += GetSystemMetrics(SM_CXVSCROLL); + + RECT rc = { 0, 0, width, heightn }; + AdjustWindowRectEx(&rc, GetWindowLongPtr(m_hwndDialog, GWL_STYLE), + FALSE, GetWindowLongPtr(m_hwndDialog, GWL_EXSTYLE)); + + width = rc.right - rc.left; + height = rc.bottom - rc.top; + + switch (m_Direction) + { + case 1: + m_XPosition-=width; + break; + case 2: + m_XPosition-=width; + m_YPosition-=height; + break; + case 3: + m_YPosition-=height; + break; + } + + // Get screen dimentions + int xoScreen = GetSystemMetrics(SM_XVIRTUALSCREEN); + int yoScreen = GetSystemMetrics(SM_YVIRTUALSCREEN); + + int xScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN); + int yScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + if (xScreen == 0) xScreen = GetSystemMetrics(SM_CXSCREEN); + if (yScreen == 0) yScreen = GetSystemMetrics(SM_CYSCREEN); + + xScreen += xoScreen; + yScreen += yoScreen; + + // Prevent window from opening off-screen + if (m_YPosition + height > yScreen) m_YPosition = yScreen - height; + if (m_XPosition + width > xScreen) m_XPosition = xScreen - width; + if (m_YPosition < yoScreen) m_YPosition = yoScreen; + if (m_XPosition < xoScreen) m_XPosition = xoScreen; + + // Move window to desired location + SetWindowPos(m_hwndDialog, NULL, m_XPosition, m_YPosition, + width, height, SWP_NOZORDER); + + m_AniPack = new AnimatedPack(m_hwndDialog, height, m_ButtonSize, opt.SelWndBkgClr); + + SmileyPackType::SmileyVectorType &sml = m_pSmileyPack->GetSmileyList(); + for (unsigned i=0; iAdd(&sml[i], CalculateButtonToCoordinates(i, 0), opt.IEViewStyle); + } + } + m_AniPack->SetOffset(0); + + if (opt.AnimateSel) SetTimer(m_hwndDialog, 1, 100, NULL); + + //add tooltips + m_hToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), + TTS_NOPREFIX | WS_POPUP, 0, 0, 0, 0, m_hwndDialog, NULL, g_hInst, NULL); + TOOLINFO ti = {0}; + ti.cbSize = sizeof(ti); + ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + ti.hwnd = m_hwndDialog; + ti.uId = (UINT_PTR)m_hwndDialog; + ti.lpszText = TranslateT("d'Oh!"); + SendMessage(m_hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti); +} + + +void SmileyToolWindowType::PaintWindow(void) +{ + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = 0; + GetScrollInfo(m_hwndDialog, SB_VERT, &si); + + PAINTSTRUCT ps; + HDC hdc = BeginPaint(m_hwndDialog, &ps); + + HBITMAP hBmp = CreateCompatibleBitmap(hdc, m_BitmapWidth.cx, m_BitmapWidth.cy); + HDC hdcMem = CreateCompatibleDC(hdc); + HANDLE hOld = SelectObject(hdcMem, hBmp); + + CreateSmileyBitmap(hdcMem); + + if (m_AniPack) m_AniPack->Draw(hdcMem); + + BitBlt(hdc, 0, 0, m_BitmapWidth.cx, m_WindowSizeY, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, hOld); + DeleteObject(hBmp); + DeleteDC(hdcMem); + + if (m_CurrentHotTrack == -2) m_CurrentHotTrack = -1; + + EndPaint(m_hwndDialog, &ps); +} + + +void SmileyToolWindowType::CreateSmileyWinDim(void) +{ + m_NumberOfButtons = m_pSmileyPack->VisibleSmileyCount(); + + if (m_NumberOfButtons == 0) return; + + // Find largest smiley + if (m_pSmileyPack->selec.x == 0 || m_pSmileyPack->selec.y == 0) + { + if (opt.ScaleAllSmileys) + { + m_pSmileyPack->GetSmiley(0)->GetSize(m_ButtonSize); + ++m_ButtonSize.cx; ++m_ButtonSize.cy; + } + else + { + m_ButtonSize.cx = 0; + m_ButtonSize.cy = 0; + SmileyPackType::SmileyVectorType &sml = m_pSmileyPack->GetSmileyList(); + for (unsigned i=0; iselec; + } + + if (m_pSmileyPack->win.x == 0 || m_pSmileyPack->win.y == 0) + { + if (opt.IEViewStyle) + { + // All integer square root + unsigned i; + for (i=1; i*iwin.x; + m_NumberOfVerticalButtons = m_NumberOfButtons / m_NumberOfHorizontalButtons + + (m_NumberOfButtons % m_NumberOfHorizontalButtons != 0); + } + + m_BitmapWidth.cx = m_NumberOfHorizontalButtons * (m_ButtonSize.cx + m_ButtonSpace) + m_ButtonSpace; + m_BitmapWidth.cy = m_NumberOfVerticalButtons * (m_ButtonSize.cy + m_ButtonSpace) + m_ButtonSpace; + + const int colsz = m_ButtonSize.cy + m_ButtonSpace; + int wndsz = min((int)m_BitmapWidth.cy, GetSystemMetrics(SM_CYSCREEN) / 2); + if (opt.IEViewStyle) wndsz = min(wndsz, 250); + + if (m_pSmileyPack->win.x != 0 && m_pSmileyPack->win.y != 0) + wndsz = min(wndsz, m_pSmileyPack->win.y * (m_ButtonSize.cy + (int)m_ButtonSpace) + (int)m_ButtonSpace); + + m_WindowSizeY = wndsz - (wndsz % colsz) + m_ButtonSpace; +} + + +void SmileyToolWindowType::CreateSmileyBitmap(HDC hdc) +{ + const RECT rc = { 0, 0, m_BitmapWidth.cx, m_WindowSizeY }; + + SetBkColor(hdc, opt.SelWndBkgClr); + const HBRUSH hBkgBrush = CreateSolidBrush(opt.SelWndBkgClr); + FillRect(hdc, &rc, hBkgBrush); + DeleteObject(hBkgBrush); + + if (opt.IEViewStyle) + { + HPEN hpen = CreatePen(PS_DOT, 1, 0); + HGDIOBJ hOldPen = SelectObject(hdc, hpen); + + POINT pts[2] = { {0, 0}, {m_BitmapWidth.cx, 0} }; + + for (unsigned i=0; i<=m_NumberOfVerticalButtons; i++) + { + pts[0].y = pts[1].y = i * (m_ButtonSize.cy + m_ButtonSpace); + if (pts[0].y > m_WindowSizeY) break; + Polyline(hdc, pts, 2); + } + + pts[0].y = 0; pts[1].y = m_BitmapWidth.cy; + for (unsigned j=0; j<=m_NumberOfHorizontalButtons; j++) + { + pts[0].x = pts[1].x = j * (m_ButtonSize.cx + m_ButtonSpace); + Polyline(hdc, pts, 2); + } + + SelectObject(hdc, hOldPen); + DeleteObject(hpen); + } +} + + +RECT SmileyToolWindowType::CalculateButtonToCoordinates(int buttonPosition, int scroll) +{ + int row, rowpos; + + if (opt.IEViewStyle) + { + row = buttonPosition / m_NumberOfHorizontalButtons; + rowpos = buttonPosition % m_NumberOfHorizontalButtons; + } + else + { + row = buttonPosition % m_NumberOfVerticalButtons; + rowpos = buttonPosition / m_NumberOfVerticalButtons; + } + + RECT pt; + pt.left = rowpos * (m_ButtonSize.cx + m_ButtonSpace) + m_ButtonSpace; + pt.top = (row - scroll) * (m_ButtonSize.cy + m_ButtonSpace) + m_ButtonSpace; + pt.right = pt.left + m_ButtonSize.cx; + pt.bottom = pt.top + m_ButtonSize.cy; + + return pt; +} + + +int SmileyToolWindowType::CalculateCoordinatesToButton(POINT pt, int scroll) +{ + const int rowpos = (pt.x - m_ButtonSpace) / (m_ButtonSize.cx + m_ButtonSpace); + const int row = (pt.y - m_ButtonSpace) / (m_ButtonSize.cy + m_ButtonSpace) + scroll; + + int pos; + if (opt.IEViewStyle) + pos = m_NumberOfHorizontalButtons * row + rowpos; + else + pos = m_NumberOfVerticalButtons * rowpos + row; + + if (pos >= (int)m_NumberOfButtons) pos = -1; + + return pos; +} + +void __cdecl SmileyToolThread(void *arg) +{ + SmileyToolWindowParam* stwp = (SmileyToolWindowParam*)arg; + if (stwp->pSmileyPack && stwp->pSmileyPack->VisibleSmileyCount()) + { + WNDCLASSEX wndclass; + wndclass.cbSize = sizeof(wndclass); + wndclass.style = CS_SAVEBITS; + wndclass.lpfnWndProc = DlgProcSmileyToolWindow; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 4; + wndclass.hInstance = g_hInst; + wndclass.hIcon = NULL; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = CreateSolidBrush(opt.SelWndBkgClr); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = _T("SmileyTool"); + wndclass.hIconSm = NULL; + RegisterClassEx(&wndclass); + + CreateWindowEx(WS_EX_TOPMOST | WS_EX_NOPARENTNOTIFY, _T("SmileyTool"), NULL, + WS_BORDER | WS_POPUP | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + ((SmileyToolWindowParam*)arg)->hWndParent, NULL, g_hInst, arg); + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); + + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + UnregisterClass(_T("SmileyTool"), g_hInst); + } + delete stwp; +} diff --git a/plugins/SmileyAdd/src/smltool.h b/plugins/SmileyAdd/src/smltool.h new file mode 100644 index 0000000000..89fb786862 --- /dev/null +++ b/plugins/SmileyAdd/src/smltool.h @@ -0,0 +1,45 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef SMILEYADD_SMLTOOL_H_ +#define SMILEYADD_SMLTOOL_H_ + +class SmileyPackType; + +struct SmileyToolWindowParam +{ + SmileyPackType* pSmileyPack; + int xPosition; + int yPosition; + int direction; + HWND hWndTarget; + HWND hWndParent; + UINT targetMessage; + WPARAM targetWParam; + HANDLE hContact; +}; + + +void __cdecl SmileyToolThread(void *arg); + +#ifndef min +#define min(A, B) ((A) < (B) ? (A) : (B)) +#endif + +#endif // SMILEYADD_SMLTOOL_H_ diff --git a/plugins/SmileyAdd/src/version.h b/plugins/SmileyAdd/src/version.h new file mode 100644 index 0000000000..104839a3a2 --- /dev/null +++ b/plugins/SmileyAdd/src/version.h @@ -0,0 +1,3 @@ +#define __FILEVERSION_STRING 0,2,3,17 +#define __VERSION_STRING "0.2.3.17" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 2, 3, 17) diff --git a/plugins/SmileyAdd/version.h b/plugins/SmileyAdd/version.h deleted file mode 100644 index 104839a3a2..0000000000 --- a/plugins/SmileyAdd/version.h +++ /dev/null @@ -1,3 +0,0 @@ -#define __FILEVERSION_STRING 0,2,3,17 -#define __VERSION_STRING "0.2.3.17" -#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 2, 3, 17) -- cgit v1.2.3