📄 rtf2htmlconverter.cpp
字号:
DWORD r=0,g=0,b=0;
COLORREF ref=m_arrColors[lActColor];
r=GetRValue(ref);
g=GetGValue(ref);
b=GetBValue(ref);
CString strHTMLColor;
strHTMLColor.Format("#%02x%02x%02x",r,g,b);
m_strActFontColor = strHTMLColor;
}
}
//font size
strTestTag="fs";
if ((pElement->m_enNodeType==CHTMLElement::c_nodInvalid)&&(strRTFTag.GetLength()>=strTestTag.GetLength())&&(strRTFTag.Left(strTestTag.GetLength())==strTestTag))
{
pElement->m_enNodeType=CHTMLElement::c_nodHTMLBegin;
pElement->m_strNodeText= "font";
m_strActFontSize = strRTFTag;
m_strActFontSize.Delete(0, strTestTag.GetLength());
ASSERT(m_strActFontSize.GetLength()>0); //Invalid RTF
m_strActFontSize=LongToString(StringToLong(m_strActFontSize)/2); //RTF stores the doubled font size
}
//font name
strTestTag="f"; //f+number
if ((pElement->m_enNodeType==CHTMLElement::c_nodInvalid)&&(strRTFTag.GetLength()>=strTestTag.GetLength())&&(strRTFTag.Left(strTestTag.GetLength())==strTestTag)&&(strRTFTag.Mid(1).SpanIncluding("01234567890")==strRTFTag.Mid(1)))
{
CString strActFontDsgn = strRTFTag;
pElement->m_enNodeType=CHTMLElement::c_nodHTMLBegin;
pElement->m_strNodeText= "font";
ASSERT(strActFontDsgn.GetLength()>0); //Invalid RTF
CString strActFontName;
BOOL bFound=m_mapFontNames.Lookup(strActFontDsgn,strActFontName);
ASSERT(bFound); //Font not found in font table, don't change font
if (bFound) m_strActFontName=strActFontName;
}
//New font tag ?
if ((pElement->m_enNodeType==CHTMLElement::c_nodHTMLBegin)&&(pElement->m_strNodeText=="font"))
{
BOOL bMustClose=FALSE;
//Look if we first must close paragraph
for (int iLastElements=m_arrHTMLElements.GetSize()-1;iLastElements>=0;iLastElements--)
{
CHTMLElement* pElementTest = m_arrHTMLElements[iLastElements];
if ((pElementTest->m_enNodeType==CHTMLElement::c_nodHTMLEnd)&&(pElementTest->m_strNodeText=="font")) break; //everything is OK
if ((pElementTest->m_enNodeType==CHTMLElement::c_nodHTMLBegin)&&(pElementTest->m_strNodeText=="font"))
{
bMustClose=TRUE;
break; //everything is OK
}
}
if (bMustClose)
{
//Insert Closing </p>
CHTMLElement* pElementClose = new CHTMLElement();
pElementClose->m_enNodeType=CHTMLElement::c_nodHTMLEnd;
pElementClose->m_strNodeText = "font";
m_arrHTMLElements.Add(pElementClose);
}
//Set font tag options
pElement->m_mapParams.SetAt("color", "\""+m_strActFontColor+"\"");
pElement->m_mapParams.SetAt("style", "\"font-size: "+m_strActFontSize+"pt; font-family:"+m_strActFontName+";\"");
}
if (pElement->m_enNodeType!=CHTMLElement::c_nodInvalid)
m_arrHTMLElements.Add(pElement);
else
delete pElement;
}
void CRTF_HTMLConverter::R2H_GetRTFTags(const CString& strRTFSource, CStringArray& arrTgt)
{
//Go thru RTF main string
for (int iStrPos=0;iStrPos<strRTFSource.GetLength();iStrPos++)
{
CString strChTest=strRTFSource[iStrPos];
if (strChTest=="\\")
{
CString strTag=R2H_GetRTFTag(strRTFSource, iStrPos);
arrTgt.Add(strTag);
iStrPos+=strTag.GetLength();
if (((iStrPos+1)<strRTFSource.GetLength())&&(strRTFSource[iStrPos+1]==' ')) iStrPos++; //Ignore Blank after Tag
}
} //loop thru string
}
//! Gets the created HTML elements as HTML text
void CRTF_HTMLConverter::R2H_GetHTMLElements(CString& strHTML)
{
strHTML="";
// remove invalid trailing elements
int iElemCount = m_arrHTMLElements.GetSize();
while (iElemCount--)
{
CHTMLElement* pElem = m_arrHTMLElements[iElemCount];
if (pElem->m_enNodeType==CHTMLElement::c_nodHTMLEnd)
{
iElemCount++; // we want this element
break;
}
else if (pElem->m_enNodeType==CHTMLElement::c_nodText)
{
CString sText = pElem->m_strNodeText;
sText.TrimLeft();
sText.TrimRight();
if (!sText.IsEmpty() && sText != "br" && sText != "\n" && sText != "\r\n")
{
iElemCount++; // we want this element
break;
}
}
}
// Loop thru what's remaining of the HTML elements
CMap<CString, LPCTSTR, int, int> mapOpenTags;
for (int iElem=0;iElem<iElemCount;iElem++)
{
CHTMLElement* pElem = m_arrHTMLElements[iElem];
CString sElem;
if (pElem->m_enNodeType==CHTMLElement::c_nodHTMLBegin)
{
// look ahead so that we can strip out empty tag pairs (typically 'font')
bool bEmpty = false;
if (iElem + 1 < m_arrHTMLElements.GetSize())
{
CHTMLElement* pElemNext = m_arrHTMLElements[iElem + 1];
if (pElemNext->m_enNodeType==CHTMLElement::c_nodHTMLEnd &&
pElemNext->m_strNodeText == pElem->m_strNodeText)
{
TRACE ("CRTF_HTMLConverter::R2H_GetHTMLElements(removing '%s')\n", pElemNext->m_strNodeText);
bEmpty = true;
}
}
if (bEmpty)
iElem++; // remove end tag too
else
{
// keep track of opentags
int nCount = 0;
mapOpenTags.Lookup(pElem->m_strNodeText, nCount);
mapOpenTags[pElem->m_strNodeText] = ++nCount;
// HTML element open tag
sElem = "<";
sElem += pElem->m_strNodeText;
// HTML element parameters (<font param1="test" param2="hugo">
POSITION pos = pElem->m_mapParams.GetStartPosition();
while (pos)
{
CString strKey, strValue;
pElem->m_mapParams.GetNextAssoc(pos, strKey, strValue);
sElem+= " "+strKey+" = "+strValue;
}
sElem+= ">";
}
}
else if (pElem->m_enNodeType==CHTMLElement::c_nodHTMLEnd)
{
sElem.Format("</%s>", pElem->m_strNodeText);
// decrement open tag count
int nCount = 0;
mapOpenTags.Lookup(pElem->m_strNodeText, nCount);
if (nCount > 0)
mapOpenTags[pElem->m_strNodeText] = --nCount;
}
else if (pElem->m_enNodeType==CHTMLElement::c_nodText)
{
sElem = pElem->m_strNodeText;
}
else
{
ASSERT(FALSE); //internal error (wrong html tag)
}
if (!sElem.IsEmpty())
{
// TRACE ("CRTF_HTMLConverter::R2H_GetHTMLElements(adding '%s')\n", sElem);
strHTML += sElem;
}
}
// any open tags remaining?
POSITION pos = mapOpenTags.GetStartPosition();
while (pos)
{
CString sTag, sClose;
int nCount = 0;
mapOpenTags.GetNextAssoc(pos, sTag, nCount);
if (nCount && sTag != "br")
{
sClose.Format("</%s>", sTag);
while (nCount--)
strHTML += sClose;
}
}
if (strHTML.GetLength() < 210)
TRACE ("CRTF_HTMLConverter::R2H_GetHTMLElements(%s)\n", strHTML);
}
int CRTF_HTMLConverter::GetCodePage(const CString& sRtf)
{
const CString CPGTAG("\\ansicpg");
int nFind = sRtf.Find(CPGTAG);
if (nFind != -1)
return atoi((LPCTSTR)sRtf + (nFind + CPGTAG.GetLength()));
return -1;
}
BOOL CRTF_HTMLConverter::HasMultiByteChars(const CString& sRtf)
{
// return FALSE;
const CString MULTIBYTETAG("\\'");
return (sRtf.Find(MULTIBYTETAG) >= 0);
}
void CRTF_HTMLConverter::R2H_CreateHTMLElements(const CString& strRTFSource)
{
//Go thru RTF main string
CString strCurrentText;
for (int iStrPos=0;iStrPos<strRTFSource.GetLength();iStrPos++)
{
CString strChTest=strRTFSource[iStrPos];
#ifdef _DEBUG
const char* szPos = (LPCTSTR)strRTFSource + iStrPos;
#endif
if (strChTest=="\\")
{
// check for multi-byte char
/*
if (strRTFSource.Find(MULTIBYTETAG, iStrPos) == iStrPos)
{
// extract next two elements as a single wide char
CString sLow = strRTFSource.Mid(iStrPos + 2, 2);
CString sHigh = strRTFSource.Mid(iStrPos + 6, 2);
wchar_t wChar = (WORD)strtol(sHigh + sLow, NULL, 16);
CString sChar = Misc::WideToMultiByte(wChar);
strCurrentText += sChar;
iStrPos += 7;
continue;
}
*/
//New tag
if (strCurrentText!="")
{
CHTMLElement* pElement = new CHTMLElement();
pElement->m_enNodeType=CHTMLElement::c_nodText;
pElement->m_strNodeText = strCurrentText;
m_arrHTMLElements.Add(pElement);
strCurrentText="";
}
CString strTag=R2H_GetRTFTag(strRTFSource, iStrPos);
R2H_InterpretTag(strTag);
iStrPos+=strTag.GetLength();
if (((iStrPos+1)<strRTFSource.GetLength())&&(strRTFSource[iStrPos+1]==' '))
iStrPos++; //Ignore Blank after Tag
}
else if (strChTest=="\n" || strChTest=="\r")
{
// line endings
strCurrentText+=strChTest;
}
else
{
//Normal character
strCurrentText+=CHtmlCharMap::ConvertToRep(strChTest);
}
} //loop thru string
//Add last text
if (strCurrentText!="")
{
CHTMLElement* pElement = new CHTMLElement();
pElement->m_enNodeType=CHTMLElement::c_nodText;
pElement->m_strNodeText = strCurrentText;
m_arrHTMLElements.Add(pElement);
strCurrentText="";
}
}
CRTF_HTMLConverter::CRTFNode CRTF_HTMLConverter::R2H_BuildTree(const CString& strSource, CRTFNode* pNodeParent)
{
//Initializing
CString strName;
//Extract Node's Name
if ((strSource.GetLength()>2)&&(strSource[0]=='{')&&(strSource[1]=='\\'))
{
for (int iStrPos=2;iStrPos<strSource.GetLength();iStrPos++)
{
CString strChTest=strSource[iStrPos];
if (strChTest.SpanIncluding(" {}\\\r")!="")
{
break;
}
else
{
strName+=strChTest;
}
}
}
else
{
//Invalid RTF Node. RTF Nodes must start with a { and then contain a \NAME identifier
ASSERT(FALSE);
return CRTFNode();
}
//Extract pure text
CString strNodeText=strSource;
strNodeText.Delete(0,1);
strNodeText.Delete(strNodeText.GetLength()-1, 1);
//Add node into tree
CRTFNodeA nodeA;
nodeA.m_strCode = strSource;
nodeA.m_strName = strName;
CRTFNode nodeThis;
if (pNodeParent)
{
nodeThis = pNodeParent->AddNode(nodeA);
}
else
{
nodeThis = m_RTFTree->AddNode(nodeA);
}
//Looking for children
CString strNodeNew;
CString strThisCode;
long lLevel=0; //# Of opened '{'
int iStrPos;
for (iStrPos=0;iStrPos<strNodeText.GetLength();iStrPos++)
{
CString strChTest=strNodeText[iStrPos];
if (strChTest=="{")
{
//New element
if (lLevel==0)
{
strNodeNew="";
}
// else Nested Element, will be added during recurse
lLevel++;
}
if (lLevel>0)
{
strNodeNew+=strChTest;
}
else
{
strThisCode+=strChTest;
}
if (strChTest=="}")
{
ASSERT(lLevel>0); //Invalid RTF, more closing } than opening 磠
lLevel--;
if (lLevel==0)
{
//Recurse (new Sub-Node (child) ready
R2H_BuildTree(strNodeNew,&nodeThis);
}
// else Nested Element, will be added during recurse
}
} //loop thru string
ASSERT(lLevel==0); //Invalid RTF, more opening { than closing }
//Get the plain text (without \)
CString strPlain;
for (iStrPos=0;iStrPos<strNodeText.GetLength();iStrPos++)
{
CString strChTest=strNodeText[iStrPos];
if (strChTest=="\\")
{
CString strTag=R2H_GetRTFTag(strNodeText, iStrPos);
iStrPos+=strTag.GetLength();
if (((iStrPos+1)<strNodeText.GetLength())&&(strNodeText[iStrPos+1]==' '))
iStrPos++; //Ignore Blank after Tag
}
else
{
strPlain+=strChTest;
}
} //loop thru string
nodeThis->m_strPlain=strPlain;
nodeThis->m_strThisCode = strThisCode;
return nodeThis;
}
CString& operator<< ( CString& os, CRTF_HTMLConverter& conv )
{
//For streaming operations
if (conv.m_enMode==CRTF_HTMLConverter::c_modRTF2HTML)
{
os = conv.m_strHTML;
}
else
{
os = conv.m_strHTML;
}
return os;
}
CString& operator>> ( CString& is, CRTF_HTMLConverter& conv )
{
//For streaming operations
CString strTemp;
strTemp = is;
//RTF->HTML
if (conv.m_enMode==CRTF_HTMLConverter::c_modRTF2HTML)
{
conv.m_strRTF = strTemp;
conv.ConvertRTF2HTML(TRUE);
}
return is;
}
CRTF_HTMLConverter::CHTMLElement::CHTMLElement(THTMLNodeType type, LPCTSTR szText)
: m_enNodeType(type), m_strNodeText(szText)
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -