summaryrefslogtreecommitdiff
path: root/Help/streaminout.c
diff options
context:
space:
mode:
Diffstat (limited to 'Help/streaminout.c')
-rw-r--r--Help/streaminout.c713
1 files changed, 713 insertions, 0 deletions
diff --git a/Help/streaminout.c b/Help/streaminout.c
new file mode 100644
index 0000000..1f8f9b5
--- /dev/null
+++ b/Help/streaminout.c
@@ -0,0 +1,713 @@
+/*
+Miranda IM Help Plugin
+Copyright (C) 2002 Richard Hughes, 2005-2007 H. Herkenrath
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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 (Help-License.txt); if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <tchar.h>
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#if !defined(VK_OEM_PLUS)
+#define _WIN32_WINNT 0x0500
+#include <win2k.h>
+#endif
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_system.h>
+#include "help.h"
+
+#include <richedit.h>
+
+struct EditStreamData {
+ PBYTE pbBuff;
+ int cbBuff;
+ int iCurrent;
+};
+
+#ifndef EDITOR
+struct HyperlinkData {
+ CHARRANGE range;
+ char *szLink;
+} static *hyperlink=NULL;
+static int hyperlinkCount=0;
+#endif
+
+static DWORD CALLBACK EditStreamInRtf(DWORD dwCookie,LPBYTE pbBuff,LONG cb,LONG *pcb)
+{
+ struct EditStreamData *esd=(struct EditStreamData*)dwCookie;
+ *pcb=min(esd->cbBuff-esd->iCurrent,cb);
+ CopyMemory(pbBuff,esd->pbBuff,*pcb);
+ esd->iCurrent+=*pcb;
+ return 0;
+}
+
+#ifdef EDITOR
+static DWORD CALLBACK EditStreamOutRtf(DWORD dwCookie,LPBYTE pbBuff,LONG cb,LONG *pcb)
+{
+ struct EditStreamData *esd=(struct EditStreamData*)dwCookie;
+ PBYTE buf=(PBYTE)mir_realloc(esd->pbBuff,esd->cbBuff+cb+1);
+ if(buf==NULL) return 0;
+ esd->pbBuff=buf;
+ esd->cbBuff+=cb;
+ CopyMemory(esd->pbBuff+esd->iCurrent,pbBuff,cb);
+ esd->iCurrent+=cb;
+ esd->pbBuff[esd->iCurrent]='\0';
+ *pcb=cb;
+ return 0;
+}
+#endif
+
+struct {
+ const char *szSym;
+ char ch;
+} static const htmlSymbolChars[]={
+ {"lt",'<'},
+ {"gt",'>'},
+ {"amp",'&'},
+ {"quot",'\"'},
+ {"nbsp",' '},
+};
+
+struct {
+ const char *szName;
+ const char *szClr;
+} static const htmlColourNames[]={
+ {"black","000000"},
+ {"maroon","800000"},
+ {"green","008000"},
+ {"olive","808000"},
+ {"navy","000080"},
+ {"purple","800080"},
+ {"teal","008080"},
+ {"silver","C0C0C0"},
+ {"gray","808080"},
+ {"red","FF0000"},
+ {"lime","00FF00"},
+ {"yellow","FFFF00"},
+ {"blue","0000FF"},
+ {"fuchsia","FF00FF"},
+ {"aqua","00FFFF"},
+ {"white","FFFFFF"},
+};
+
+// a quick test to see who's read their comp.lang.c FAQ:
+#define stringize2(n) #n
+#define stringize(n) stringize2(n)
+
+struct {
+ const char *szHtml;
+ const char *szRtf;
+} static const simpleHtmlRtfConversions[]={
+ {"i","i"},
+ {"/i","i0"},
+ {"b","b"},
+ {"/b","b0"},
+ {"u","ul"},
+ {"/u","ul0"},
+ {"big","fs" stringize(TEXTSIZE_BIG)},
+ {"/big","fs" stringize(TEXTSIZE_NORMAL)},
+ {"small","fs" stringize(TEXTSIZE_SMALL)},
+ {"/small","fs" stringize(TEXTSIZE_NORMAL)},
+ {"/font","cf0"}
+};
+
+// mir_free() the return value
+char *GetHtmlTagAttribute(const char *pszTag,const char *pszAttr)
+{
+ int iAttrName,iAttrNameEnd,iAttrEquals,iAttrValue,iAttrValueEnd,iAttrEnd;
+ int attrLen=lstrlenA(pszAttr);
+
+ for(iAttrName=0;!isspace(pszTag[iAttrName]) && pszTag[iAttrName]!='>';iAttrName++);
+ for(;;) {
+ for(;isspace(pszTag[iAttrName]);iAttrName++);
+ if(pszTag[iAttrName]=='>' || pszTag[iAttrName]=='\0') break;
+ for(iAttrNameEnd=iAttrName;isalnum(pszTag[iAttrNameEnd]);iAttrNameEnd++);
+ for(iAttrEquals=iAttrNameEnd;isspace(pszTag[iAttrEquals]);iAttrEquals++);
+ if(pszTag[iAttrEquals]!='=') {iAttrName=iAttrEquals; continue;}
+ for(iAttrValue=iAttrEquals+1;isspace(pszTag[iAttrValue]);iAttrValue++);
+ if(pszTag[iAttrValue]=='>' || pszTag[iAttrValue]=='\0') break;
+ if(pszTag[iAttrValue]=='"' || pszTag[iAttrValue]=='\'') {
+ for(iAttrValueEnd=iAttrValue+1;pszTag[iAttrValueEnd] && pszTag[iAttrValueEnd]!=pszTag[iAttrValue];iAttrValueEnd++);
+ iAttrValue++;
+ iAttrEnd=iAttrValueEnd+1;
+ }
+ else {
+ for(iAttrValueEnd=iAttrValue;pszTag[iAttrValueEnd] && pszTag[iAttrValueEnd]!='>' && !isspace(pszTag[iAttrValueEnd]);iAttrValueEnd++);
+ iAttrEnd=iAttrValueEnd;
+ }
+ if(pszTag[iAttrValueEnd]=='\0') break;
+ if(attrLen==iAttrNameEnd-iAttrName && !_strnicmp(pszAttr,pszTag+iAttrName,attrLen)) {
+ char *szValue;
+ szValue=(char*)mir_alloc(iAttrValueEnd-iAttrValue+1);
+ if(szValue!=NULL) {
+ CopyMemory(szValue,pszTag+iAttrValue,iAttrValueEnd-iAttrValue);
+ szValue[iAttrValueEnd-iAttrValue]='\0';
+ }
+ return szValue;
+ }
+ iAttrName=iAttrEnd;
+ }
+ return NULL;
+}
+
+void StreamInHtml(HWND hwndEdit,const char *szHtml,UINT codepage,COLORREF clrBkgrnd)
+{
+ EDITSTREAM stream;
+ struct EditStreamData esd;
+ struct ResizableCharBuffer header,body;
+ COLORREF *colourTbl=NULL;
+ int colourTblCount=0;
+ const char *pszHtml;
+ char *szThisTagHref=NULL;
+ int keywordAtBeginning=1,paragraphBefore=0,lineBreakBefore=1;
+ int charCount=0;
+
+ ZeroMemory(&stream,sizeof(stream));
+ ZeroMemory(&esd,sizeof(esd));
+ ZeroMemory(&header,sizeof(header));
+ ZeroMemory(&body,sizeof(body));
+
+#ifndef EDITOR
+ FreeHyperlinkData();
+#endif
+ AppendToCharBuffer(&header,"{\\rtf1\\ansi\\ansicpg%u\\deff0{\\fonttbl{\\f0 Tahoma;}}",codepage);
+ for(pszHtml=szHtml;*pszHtml!='\0';) {
+ if(*pszHtml=='<') {
+ const char *pszTagEnd;
+ int iNameEnd,i;
+ char szTagName[16];
+
+ pszTagEnd=strchr(pszHtml+1,'>');
+ if(pszTagEnd==NULL) break;
+ for(iNameEnd=1;pszHtml[iNameEnd]!='\0' && pszHtml[iNameEnd]!='>' && !isspace(pszHtml[iNameEnd]);iNameEnd++);
+ CopyMemory(szTagName,pszHtml+1,min(sizeof(szTagName),iNameEnd));
+ szTagName[min(sizeof(szTagName),iNameEnd)-1]='\0';
+
+ for(i=0;i<SIZEOF(simpleHtmlRtfConversions);i++) {
+ if(!lstrcmpiA(szTagName,simpleHtmlRtfConversions[i].szHtml)) {
+ AppendToCharBuffer(&body,"\\%s ",simpleHtmlRtfConversions[i].szRtf);
+ break;
+ }
+ }
+ if(i==SIZEOF(simpleHtmlRtfConversions)) {
+ if(!lstrcmpiA(szTagName,"br")) {
+ AppendToCharBuffer(&body,"\\par ");
+ charCount++; // linebreaks are characters
+ lineBreakBefore=1;
+ } else if(!lstrcmpiA(szTagName,"p") || !lstrcmpiA(szTagName,"/p")) {
+ if(charCount) paragraphBefore=1;
+ } else if(!lstrcmpiA(szTagName,"a")) {
+ mir_free(szThisTagHref); // does NULL check
+ szThisTagHref=GetHtmlTagAttribute(pszHtml,"href");
+#ifdef EDITOR
+ if(szThisTagHref!=NULL)
+ AppendToCharBuffer(&body,"\\strike ");
+#else
+ if(szThisTagHref!=NULL) {
+ struct HyperlinkData *buf=(struct HyperlinkData*)mir_realloc(hyperlink,sizeof(struct HyperlinkData)*(hyperlinkCount+1));
+ if(buf!=NULL) { // hyperlinkCount increased at </a>
+ hyperlink=buf;
+ hyperlink[hyperlinkCount].range.cpMin=paragraphBefore?(charCount+2):charCount;
+ hyperlink[hyperlinkCount].range.cpMax=-1;
+ hyperlink[hyperlinkCount].szLink=NULL;
+ } else {
+ mir_free(szThisTagHref);
+ szThisTagHref=NULL;
+ }
+ }
+#endif
+ }
+ else if(!lstrcmpiA(szTagName,"/a")) {
+ if(szThisTagHref) {
+#ifdef EDITOR
+ AppendToCharBuffer(&body,":%s\\strike0 ",szThisTagHref);
+ mir_free(szThisTagHref);
+#else
+#if defined(_UNICODE)
+ mir_utf8decodecp(szThisTagHref,CP_ACP,NULL);
+#endif
+ hyperlink[hyperlinkCount].range.cpMax=charCount;
+ hyperlink[hyperlinkCount].szLink=szThisTagHref;
+ hyperlinkCount++;
+#endif
+ szThisTagHref=NULL;
+ }
+ }
+ else if(!lstrcmpiA(szTagName,"font")) {
+ char *szColour=GetHtmlTagAttribute(pszHtml,"color");
+ if(szColour!=NULL) {
+ int i,freeColour=1;
+ if(szColour[0]!='#' || lstrlenA(szColour)!=7) {
+ for(i=0;i<SIZEOF(htmlColourNames);i++) {
+ if(!lstrcmpiA(szColour,htmlColourNames[i].szName)) {
+ mir_free(szColour);
+ szColour=(char*)htmlColourNames[i].szClr;
+ freeColour=0;
+ break;
+ }
+ }
+ } else szColour++;
+ if(szColour!=NULL) {
+ COLORREF colour;
+ char szRed[3],szGreen[3],szBlue[3];
+ szRed[0]=szColour[0]; szRed[1]=szColour[1]; szRed[2]='\0';
+ szGreen[0]=szColour[2]; szGreen[1]=szColour[3]; szGreen[2]='\0';
+ szBlue[0]=szColour[4]; szBlue[1]=szColour[5]; szBlue[2]='\0';
+ colour=RGB(strtol(szRed,NULL,16),strtol(szGreen,NULL,16),strtol(szBlue,NULL,16));
+ if(freeColour) mir_free(szColour);
+#ifndef EDITOR
+ if(colour!=clrBkgrnd) { // ensure color is visible
+#else
+ UNREFERENCED_PARAMETER(clrBkgrnd);
+#endif // !defined EDITOR
+ for(i=0;i<colourTblCount;i++)
+ if(colourTbl[i]==colour) break;
+ if(i==colourTblCount) {
+ COLORREF *buf=(COLORREF*)mir_realloc(colourTbl,(colourTblCount+1)*sizeof(COLORREF));
+ if(buf!=NULL) {
+ colourTbl=buf;
+ colourTblCount++;
+ colourTbl[i]=colour;
+ }
+ }
+ AppendToCharBuffer(&body,"\\cf%d ",i+2);
+#ifndef EDITOR
+ }
+#endif
+ }
+ }
+ } // endif font
+ }
+ pszHtml=pszTagEnd+1;
+ }
+ else if(*pszHtml=='&') {
+ const char *pszTagEnd;
+ char szTag[16];
+ int i;
+
+ pszTagEnd=strchr(pszHtml+1,';');
+ if(pszTagEnd==NULL) break;
+ CopyMemory(szTag,pszHtml+1,min(SIZEOF(szTag),pszTagEnd-pszHtml));
+ szTag[min(sizeof(szTag),pszTagEnd-pszHtml)-1]='\0';
+ if(szTag[0]=='#') {
+ int ch;
+ if(szTag[1]=='x' || szTag[1]=='X') ch=strtol(szTag+2,NULL,16);
+ else ch=strtol(szTag+1,NULL,10);
+ if(ch>=0x100) AppendToCharBuffer(&body,"\\u%d",ch);
+ else AppendToCharBuffer(&body,"\\'%02x ",ch);
+ }
+ else {
+ for(i=0;i<SIZEOF(htmlSymbolChars);i++) {
+ if(!lstrcmpiA(szTag,htmlSymbolChars[i].szSym)) {
+ AppendCharToCharBuffer(&body,htmlSymbolChars[i].ch);
+ charCount++;
+ break;
+ }
+ }
+ }
+ pszHtml=pszTagEnd+1;
+ }
+ else if(*pszHtml!=' ' || (!lineBreakBefore && !paragraphBefore)) {
+ lineBreakBefore=0;
+ if(paragraphBefore) {
+ AppendToCharBuffer(&body,"\\par\\par ");
+ charCount+=2; // linebreaks are characters
+ paragraphBefore=0;
+ }
+ if((BYTE)*pszHtml>=' ') charCount++;
+ if(*pszHtml=='\\' || *pszHtml=='{' || *pszHtml=='}')
+ AppendCharToCharBuffer(&body,'\\');
+ AppendCharToCharBuffer(&body,*pszHtml++);
+ }
+ else pszHtml++;
+ }
+ mir_free(szThisTagHref); // does NULL check
+
+ { int i;
+ COLORREF clr=GetSysColorBrush(COLOR_HOTLIGHT)?GetSysColor(COLOR_HOTLIGHT):RGB(0,0,255);
+ AppendToCharBuffer(&header,"{\\colortbl ;\\red%d\\green%d\\blue%d;",GetRValue(clr),GetGValue(clr),GetBValue(clr));
+ for(i=0;i<colourTblCount;i++)
+ AppendToCharBuffer(&header,"\\red%d\\green%d\\blue%d;",GetRValue(colourTbl[i]),GetGValue(colourTbl[i]),GetBValue(colourTbl[i]));
+ }
+ AppendToCharBuffer(&header,"}\\pard\\fs16\\uc0");
+ if(keywordAtBeginning) AppendCharToCharBuffer(&header,' ');
+ mir_free(colourTbl); // does NULL check
+
+ if(header.sz!=NULL) {
+ AppendToCharBuffer(&header,"%s}",body.sz?body.sz:"");
+ esd.pbBuff=(PBYTE)header.sz;
+ esd.cbBuff=header.iEnd;
+ stream.dwCookie=(DWORD)&esd;
+ stream.pfnCallback=EditStreamInRtf;
+ SendMessage(hwndEdit,EM_STREAMIN,SF_RTF,(LPARAM)&stream);
+ mir_free(header.sz);
+ }
+ mir_free(body.sz); // does NULL check
+
+#ifndef EDITOR
+ { int i;
+ CHARFORMAT cf;
+ ZeroMemory(&cf,sizeof(cf));
+ cf.cbSize=sizeof(cf);
+ cf.dwMask=CFM_UNDERLINE|CFM_COLOR; // CFE_LINK always uses RGB(0,0,255) instead of GetSysColor(COLOR_HOTLIGHT)
+ cf.dwEffects=CFE_UNDERLINE; // and ignores CFM_COLOR, so selfimplementing
+ cf.crTextColor=GetSysColorBrush(COLOR_HOTLIGHT)?GetSysColor(COLOR_HOTLIGHT):RGB(0,0,255);
+ for(i=0;i<hyperlinkCount;i++) {
+ SendMessage(hwndEdit,EM_EXSETSEL,0,(LPARAM)&hyperlink[i].range);
+ SendMessage(hwndEdit,EM_SETCHARFORMAT,SCF_SELECTION,(LPARAM)&cf);
+ }
+ SendMessage(hwndEdit,EM_SETSEL,0,0);
+ }
+#endif
+}
+
+#ifndef EDITOR
+void FreeHyperlinkData(void)
+{
+ int i;
+ for(i=0;i<hyperlinkCount;i++)
+ mir_free(hyperlink[i].szLink); // does NULL check
+ mir_free(hyperlink); // does NULL check
+ hyperlink=NULL;
+ hyperlinkCount=0;
+}
+
+int IsHyperlink(LONG cpPos,LONG *pcpMin,LONG *pcpMax,char **ppszLink)
+{
+ int i;
+ for(i=0;i<hyperlinkCount;i++)
+ if(cpPos>=hyperlink[i].range.cpMin && cpPos<=hyperlink[i].range.cpMax) {
+ if(pcpMin) *pcpMin=hyperlink[i].range.cpMin;
+ if(pcpMax) *pcpMax=hyperlink[i].range.cpMax;
+ if(ppszLink) *ppszLink=hyperlink[i].szLink;
+ return 1;
+ }
+ if(pcpMin) *pcpMin=-1;
+ if(pcpMax) *pcpMax=-1;
+ if(ppszLink) *ppszLink=NULL;
+ return 0;
+}
+
+#endif // !defined EDITOR
+
+#ifdef EDITOR
+struct RtfGroupStackData {
+ BYTE bold,italic,underline,strikeout;
+ BYTE isDestination,isColourTbl,isFontTbl;
+ int colour;
+ int fontSize;
+ int unicodeSkip;
+ int charset;
+};
+
+char *StreamOutHtml(HWND hwndEdit)
+{
+ EDITSTREAM stream;
+ struct EditStreamData esd;
+ struct ResizableCharBuffer htmlOut,hyperlink,*output;
+ COLORREF *colourTbl=NULL;
+ int colourTblCount=0;
+ struct RtfGroupStackData *groupStack;
+ int groupLevel;
+ int inFontTag=0,inAnchorTag=0,inBigTag=0,inSmallTag=0,lineBreakBefore=0;
+ char *pszRtf;
+ int *fontTblCharsets=NULL;
+ int fontTblCount=0;
+ int normalTextSize=0;
+ void *buf;
+
+ ZeroMemory(&stream,sizeof(stream));
+ ZeroMemory(&esd,sizeof(esd));
+ ZeroMemory(&htmlOut,sizeof(htmlOut));
+ ZeroMemory(&hyperlink,sizeof(hyperlink));
+ ZeroMemory(&output,sizeof(output));
+
+ stream.dwCookie=(DWORD)&esd;
+ stream.pfnCallback=EditStreamOutRtf;
+#if defined(_UNICODE)
+ SendMessage(hwndEdit,EM_STREAMOUT,(WPARAM)(CP_UTF8<<16)|SF_USECODEPAGE|SF_RTFNOOBJS|SFF_PLAINRTF,(LPARAM)&stream);
+#else
+ SendMessage(hwndEdit,EM_STREAMOUT,SF_RTFNOOBJS|SFF_PLAINRTF,(LPARAM)&stream);
+#endif
+ if(esd.pbBuff==NULL) return NULL;
+
+ output=&htmlOut;
+ groupStack=(struct RtfGroupStackData*)mir_calloc(sizeof(struct RtfGroupStackData));
+ if(groupStack!=NULL) {
+ groupLevel=0;
+ groupStack[0].unicodeSkip=1;
+ for(pszRtf=(char*)esd.pbBuff;*pszRtf!='\0';) {
+ if(*pszRtf=='{') {
+ buf=(struct RtfGroupStackData*)mir_realloc(groupStack,sizeof(struct RtfGroupStackData)*(groupLevel+2));
+ if(buf==NULL) break;
+ groupStack=(struct RtfGroupStackData*)buf;
+ groupStack[groupLevel]=groupStack[groupLevel];
+ groupLevel++;
+ pszRtf++;
+ }
+ else if(*pszRtf=='}') {
+ groupLevel--;
+ if(groupStack[groupLevel].bold!=groupStack[groupLevel+1].bold)
+ AppendToCharBuffer(output,groupStack[groupLevel].bold?"<b>":"</b>");
+ if(groupStack[groupLevel].italic!=groupStack[groupLevel+1].italic)
+ AppendToCharBuffer(output,groupStack[groupLevel].bold?"<i>":"</i>");
+ if(groupStack[groupLevel].underline!=groupStack[groupLevel+1].underline)
+ AppendToCharBuffer(output,groupStack[groupLevel].bold?"<u>":"</u>");
+ if(groupStack[groupLevel].strikeout!=groupStack[groupLevel+1].strikeout && groupStack[groupLevel+1].strikeout)
+ if(inAnchorTag) {AppendToCharBuffer(output,"</a>"); inAnchorTag=0;}
+ if(groupStack[groupLevel].colour!=groupStack[groupLevel+1].colour)
+ if(inFontTag) {AppendToCharBuffer(output,"</font>"); inFontTag=0;}
+ if(groupStack[groupLevel].fontSize!=groupStack[groupLevel+1].fontSize) {
+ if(inBigTag) {AppendToCharBuffer(output,"</big>"); inBigTag=0;}
+ if(inSmallTag) {AppendToCharBuffer(output,"</small>"); inSmallTag=0;}
+ if(groupStack[groupLevel].fontSize<normalTextSize)
+ {AppendToCharBuffer(output,"<small>"); inSmallTag=1;}
+ else if(groupStack[groupLevel].fontSize>normalTextSize)
+ {AppendToCharBuffer(output,"<big>"); inBigTag=1;}
+ }
+ if(groupLevel==0) break;
+ pszRtf++;
+ }
+ else if(*pszRtf=='\\' && pszRtf[1]=='*') {
+ groupStack[groupLevel].isDestination=1;
+ pszRtf+=2;
+ }
+ else if(*pszRtf=='\\' && pszRtf[1]=='\'') {
+ char szHex[3]="\0\0";
+ char szChar[2];
+ szHex[0]=pszRtf[2];
+ if(pszRtf[2]) szHex[1]=pszRtf[3];
+ else pszRtf--;
+ szChar[0]=(char)strtol(szHex,NULL,16); szChar[1]='\0';
+ if(groupStack[groupLevel].charset) {
+ WCHAR szwChar[2];
+ CHARSETINFO csi;
+ TranslateCharsetInfo((PDWORD)groupStack[groupLevel].charset,&csi,TCI_SRCCHARSET);
+ MultiByteToWideChar(csi.ciACP,0,szChar,1,szwChar,2);
+ AppendToCharBuffer(output,"&#%u;",(WORD)szwChar[0]);
+ }
+ else AppendToCharBuffer(output,"&#%u;",(BYTE)szChar[0]);
+ pszRtf+=4;
+ }
+ else if(*pszRtf=='\\' && isalpha(pszRtf[1])) {
+ char szControlWord[32];
+ int iWordEnd;
+ int hasParam=0;
+ int param=-1;
+
+ for(iWordEnd=1;isalpha(pszRtf[iWordEnd]);iWordEnd++);
+ CopyMemory(szControlWord,pszRtf+1,min(sizeof(szControlWord),iWordEnd));
+ szControlWord[min(sizeof(szControlWord),iWordEnd)-1]='\0';
+ if(isdigit(pszRtf[iWordEnd]) || pszRtf[iWordEnd]=='-') {
+ hasParam=1;
+ param=strtol(pszRtf+iWordEnd,&pszRtf,10);
+ }
+ else pszRtf=pszRtf+iWordEnd;
+ if(*pszRtf==' ') pszRtf++;
+ if(!lstrcmpiA(szControlWord,"colortbl")) {
+ groupStack[groupLevel].isColourTbl=1;
+ buf=(COLORREF*)mir_realloc(colourTbl,sizeof(COLORREF));
+ if(buf!=NULL) {
+ colourTbl=(COLORREF*)buf;
+ colourTblCount=1;
+ colourTbl[0]=0;
+ }
+ groupStack[groupLevel].isDestination=1;
+ }
+ else if(!lstrcmpiA(szControlWord,"fonttbl")) {
+ groupStack[groupLevel].isFontTbl=1;
+ groupStack[groupLevel].isDestination=1;
+ }
+ else if(!lstrcmpiA(szControlWord,"stylesheet")) {
+ groupStack[groupLevel].isDestination=1;
+ }
+ else if(!lstrcmpiA(szControlWord,"red")) {
+ if(!hasParam || !colourTblCount) break;
+ colourTbl[colourTblCount-1]&=~RGB(255,0,0);
+ colourTbl[colourTblCount-1]|=RGB(param,0,0);
+ }
+ else if(!lstrcmpiA(szControlWord,"green")) {
+ if(!hasParam || !colourTblCount) break;
+ colourTbl[colourTblCount-1]&=~RGB(0,255,0);
+ colourTbl[colourTblCount-1]|=RGB(0,param,0);
+ }
+ else if(!lstrcmpiA(szControlWord,"blue")) {
+ if(!hasParam || !colourTblCount) break;
+ colourTbl[colourTblCount-1]&=~RGB(0,0,255);
+ colourTbl[colourTblCount-1]|=RGB(0,0,param);
+ }
+ else if(!lstrcmpiA(szControlWord,"f")) {
+ if(groupStack[groupLevel].isFontTbl) {
+ buf=(int*)mir_realloc(fontTblCharsets,sizeof(int)*(fontTblCount+1));
+ if(buf!=NULL) {
+ fontTblCharsets=(int*)buf;
+ fontTblCharsets[fontTblCount]=0;
+ fontTblCount++;
+ }
+ }
+ else {
+ if(hasParam && param>=0 && param<fontTblCount)
+ groupStack[groupLevel].charset=fontTblCharsets[param];
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"fcharset")) {
+ if(groupStack[groupLevel].isFontTbl && fontTblCount && hasParam)
+ fontTblCharsets[fontTblCount-1]=param;
+ }
+ else if(!lstrcmpiA(szControlWord,"cf")) {
+ if(inFontTag) AppendToCharBuffer(output,"</font>");
+ if(hasParam && param) {
+ int i;
+ char szColour[7];
+ wsprintfA(szColour,"%02x%02x%02x",GetRValue(colourTbl[param]),GetGValue(colourTbl[param]),GetBValue(colourTbl[param]));
+ for(i=0;i<SIZEOF(htmlColourNames);i++) {
+ if(!lstrcmpiA(szColour,htmlColourNames[i].szClr)) {
+ AppendToCharBuffer(output,"<font color=\"%s\">",htmlColourNames[i].szName);
+ break;
+ }
+ }
+ if(i==SIZEOF(htmlColourNames))
+ AppendToCharBuffer(output,"<font color=\"#%s\">",szColour);
+ inFontTag=1;
+ groupStack[groupLevel].colour=param;
+ }
+ else groupStack[groupLevel].colour=0;
+ }
+ else if(!lstrcmpiA(szControlWord,"fs")) {
+ if(normalTextSize==0 && hasParam) {
+ normalTextSize=param;
+ groupStack[0].fontSize=normalTextSize;
+ }
+ if(inBigTag) {AppendToCharBuffer(output,"</big>"); inBigTag=0;}
+ if(inSmallTag) {AppendToCharBuffer(output,"</small>"); inSmallTag=0;}
+ if(hasParam) {
+ groupStack[groupLevel].fontSize=param;
+ if(groupStack[groupLevel].fontSize<normalTextSize)
+ {AppendToCharBuffer(output,"<small>"); inSmallTag=1;}
+ else if(groupStack[groupLevel].fontSize>normalTextSize)
+ {AppendToCharBuffer(output,"<big>"); inBigTag=1;}
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"uc")) {
+ if(hasParam) groupStack[groupLevel].unicodeSkip=param;
+ }
+ else if(!lstrcmpiA(szControlWord,"u")) {
+ if(hasParam) {
+ AppendToCharBuffer(output,"&#%u;",param);
+ pszRtf+=groupStack[groupLevel].unicodeSkip;
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"b")) {
+ if(!hasParam || param) {
+ groupStack[groupLevel].bold=1;
+ AppendToCharBuffer(output,"<b>");
+ }
+ else {
+ groupStack[groupLevel].bold=0;
+ AppendToCharBuffer(output,"</b>");
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"i")) {
+ if(!hasParam || param) {
+ groupStack[groupLevel].italic=1;
+ AppendToCharBuffer(output,"<i>");
+ }
+ else {
+ groupStack[groupLevel].italic=0;
+ AppendToCharBuffer(output,"</i>");
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"ul")) {
+ if(!hasParam || param) {
+ groupStack[groupLevel].underline=1;
+ AppendToCharBuffer(output,"<u>");
+ }
+ else {
+ groupStack[groupLevel].underline=0;
+ AppendToCharBuffer(output,"</u>");
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"ulnone")) {
+ groupStack[groupLevel].underline=0;
+ AppendToCharBuffer(output,"</u>");
+ }
+ else if(!lstrcmpiA(szControlWord,"strike")) {
+ if(!hasParam || param) {
+ groupStack[groupLevel].strikeout=1;
+ mir_free(hyperlink.sz); // does NULL check
+ hyperlink.iEnd=hyperlink.cbAlloced=0;
+ hyperlink.sz=NULL;
+ output=&hyperlink;
+ }
+ else {
+ groupStack[groupLevel].strikeout=0;
+ if(hyperlink.iEnd && hyperlink.sz!=NULL) {
+ char *pszColon;
+ output=&htmlOut;
+ pszColon=strchr(hyperlink.sz,':');
+ if(pszColon==NULL) pszColon="";
+ else *pszColon++='\0';
+ AppendToCharBuffer(output,"<a href=\"%s\">%s</a>",pszColon,hyperlink.sz);
+ mir_free(hyperlink.sz);
+ hyperlink.iEnd=hyperlink.cbAlloced=0;
+ hyperlink.sz=NULL;
+ }
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"par")) {
+ if(lineBreakBefore) AppendToCharBuffer(output,"<br>");
+ lineBreakBefore=1; // richedit puts a \par right at the end
+ }
+ }
+ else {
+ int i;
+ if(*pszRtf=='\\') pszRtf++;
+ if(!groupStack[groupLevel].isDestination) {
+ if(lineBreakBefore && (BYTE)*pszRtf>=' ') {AppendToCharBuffer(output,"<br>"); lineBreakBefore=0;}
+ if(*pszRtf==' ')
+ AppendCharToCharBuffer(output,*pszRtf);
+ else {
+ for(i=0;i<SIZEOF(htmlSymbolChars);i++) {
+ if(*pszRtf==htmlSymbolChars[i].ch) {
+ AppendToCharBuffer(output,"&%s;",htmlSymbolChars[i].szSym);
+ break;
+ }
+ }
+ if(i==SIZEOF(htmlSymbolChars))
+ AppendCharToCharBuffer(output,*pszRtf);
+ }
+ }
+ else if(groupStack[groupLevel].isColourTbl && *pszRtf==';') {
+ buf=(COLORREF*)mir_realloc(colourTbl,sizeof(COLORREF)*(colourTblCount+2));
+ if(buf!=NULL) {
+ colourTbl=(COLORREF*)buf;
+ colourTbl[colourTblCount]=0;
+ colourTblCount++;
+ }
+ }
+ pszRtf++;
+ }
+ }
+ mir_free(groupStack);
+ }
+ mir_free(colourTbl); // does NULL check
+ mir_free(fontTblCharsets); // does NULL check
+ mir_free(hyperlink.sz); // does NULL check
+
+ mir_free(esd.pbBuff);
+ return htmlOut.sz;
+}
+#endif // defined EDITOR