📄 rtfread2.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
* rtfread2.cpp
*
* Description:
* This file contains the object functions for RichEdit RTF reader
*
* Original RichEdit 1.0 RTF converter: Anthony Francisco
* Conversion to C++ and RichEdit 2.0: Murray Sargent
*
* * NOTE:
* * All sz's in the RTF*.? files refer to a LPSTRs, not LPTSTRs, unless
* * noted as a szW.
*
*/
#include "_common.h"
#include "_rtfread.h"
#include "_coleobj.h"
const char szFontsel[]="\\f";
ASSERTDATA
/*
* CRTFRead::HandleFieldInstruction()
*
* Purpose:
* Handle field instruction
*
* Returns:
* EC The error code
*/
EC CRTFRead::HandleFieldInstruction()
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldInstruction");
//TODO rewrite this function for common case
//FUTURE save field instruction
BYTE *pch, *pch1;
for(pch1 = _szText; *pch1 == ' '; pch1++) // Bypass any leading blanks
;
for(pch = pch1; *pch && *pch != ' '; pch++)
;
_fHyperlinkField = FALSE;
if(W32->ASCIICompareI(pch1, (BYTE *) "SYMBOL", 6))
HandleFieldSymbolInstruction(pch); // SYMBOL
else if (W32->ASCIICompareI(pch1, (BYTE *) "HYPERLINK", 9))
{
_fHyperlinkField = TRUE;
HandleFieldHyperlink(pch);
}
#ifdef PWD_JUPITER
// GuyBark JupiterJ 49674: This field instruction is an Equation field!
// These are used in FE RTF to specify Rubi text and the text beneath it.
// I've seen the field results for such fields to be empty, which means
// that unless we take special action here, we'll lose the text completely.
// So note that we're in an equation field.
else if (W32->ASCIICompareI(pch1, (BYTE *) "eq", 2))
{
LPSTR pOverstrikeStart = "\\o";
// We can only handle this group if it contains the overstrike group.
if(strstr((LPSTR)pch1, pOverstrikeStart))
{
_fEquationField = TRUE;
// Store the cp at the start of the equation field.
_cpFieldInstruction = _prg->GetCp();
// Set up the current text y offset from this equation string.
SetupEquationOffset((LPSTR)pch1);
}
}
#endif // PWD_JUPITER
// save the current formatting for the field result
_FieldCF = _CF;
_ptfField = _pstateStackTop->ptf;
_nFieldCodePage = _pstateStackTop->nCodePage;
TRACEERRSZSC("HandleFieldInstruction()", - _ecParseError);
return _ecParseError;
}
/*
* HandleFieldSymbolInstruction(pch)
*
* @mfunc
* Handle specific symbol field
*
* @rdesc
* EC The error code
*
* @devnote
* FUTURE: the two whiles below can be combined into one fairly easily;
* Look at the definitions of IsXDigit() and IsDigit() and introduce
* a variable flag as well as a variable base multiplier (= 10 or 16).
*/
EC CRTFRead::HandleFieldSymbolInstruction(
BYTE *pch ) //@parm Pointer to SYMBOL field instruction
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldInstruction");
BYTE ch;
BYTE chSymbol = 0;
const char *pchFontsel = szFontsel;
STATE * pstate = _pstateStackTop;
while (*pch == ' ') // Eat spaces
++pch;
// Collect symbol char's code
if (*pch == '0' && // which may be in decimal
(*++pch | ' ') == 'x') // or hex
{ // It's in hex
ch = *++pch;
while (ch && ch != ' ')
{
if (IsXDigit(ch))
{
chSymbol <<= 4;
chSymbol += (ch <= '9') ? ch - '0' : (ch & 0x4f) - 'A' + 10;
}
else
{
_ecParseError = ecUnexpectedChar;
goto CleanUp;
}
ch = *pch++;
}
}
else // Decimal
{
ch = *pch;
while (ch && ch != ' ')
{
if (IsDigit(ch))
{
chSymbol *= 10;
chSymbol += ch - '0' ;
}
else
{
_ecParseError = ecUnexpectedChar;
goto CleanUp;
}
ch = *++pch;
}
}
_szSymbolFieldResult = (BYTE *)PvAlloc(2, GMEM_ZEROINIT);
if (NULL != _szSymbolFieldResult)
{
_szSymbolFieldResult[0] = chSymbol;
}
else
{
Assert(_szSymbolFieldResult); //give us a chance to debug
}
// now check for the \\f "Facename" construct
// and deal with it
while (*pch == ' ') // Eat spaces
{
++pch;
}
while (*pch && *pch == *pchFontsel) // Make sure *pch is a \f
{
++pch;
++pchFontsel;
}
if (! (*pchFontsel) )
{
_ecParseError = HandleFieldSymbolFont(pch); // \\f "Facename"
}
// ASSERTION font & font size will be in field result \flds
// BUGBUG: A more robust implementation would parse the font
// and font size from both \fldinst and \fldrslt (RE1.0 does this)
CleanUp:
TRACEERRSZSC("HandleFieldInstruction()", - _ecParseError);
return _ecParseError;
}
/*
* HandleFieldSymbolFont()
*
* @mfunc
* Handle the \\f "Facename" instruction in the SYMBOL field
*
* @rdesc
* EC The error code
*
* @devnote WARNING: may change _szText
*/
EC CRTFRead::HandleFieldSymbolFont(BYTE *pch)
{
SHORT iFont = _fonts.Count();
TEXTFONT tf;
TEXTFONT *ptf = &tf;
_pstateStackTop->ptf = &tf;
// ReadFontName tries to append
tf.szName[0] = '\0';
// skip the initial blanks and quotes
while (*pch && (*pch == ' ' || *pch == '\"'))
{
++pch;
}
// DONT WORRY, we'll get it back to normal
// ReadFontName depends on _szText, so we need to alter it and then restore
// it's just too bad we have to do it ...
BYTE* szTextBAK = _szText;
BOOL fAllAscii = TRUE;
_szText = pch;
// transform the trailing quote into ';'
while (*pch)
{
if (*pch == '\"')
{
*pch = ';';
break;
}
if(*pch > 0x7f)
{
fAllAscii = FALSE;
}
++pch;
}
// NOW we can read the font name!!
ReadFontName(_pstateStackTop, fAllAscii ? ALL_ASCII : CONTAINS_NONASCII);
// Try to find this face name in the font table
BOOL fFontFound = FALSE;
for (SHORT i = 0; i < iFont; ++i)
{
TEXTFONT *ptfTab = _fonts.Elem(i);
if (0 == wcscmp(ptf->szName, ptfTab->szName))
{
fFontFound = TRUE;
i = ptfTab->sHandle;
break;
}
}
// did we find the face name?
if (!fFontFound)
{
Assert(i == iFont);
i+= RESERVED_FONT_HANDLES;
// Make room in font table for
// font to be inserted
if (!(ptf =_fonts.Add(1,NULL)))
{
_ped->GetCallMgr()->SetOutOfMemory();
_ecParseError = ecNoMemory;
goto exit;
}
// repeating inits from tokenFontSelect
ptf->sHandle = i; // Save handle
wcscpy(ptf->szName, tf.szName);
ptf->bPitchAndFamily = 0;
ptf->fNameIsDBCS = FALSE;
ptf->sCodePage = _nCodePage;
ptf->bCharSet = DEFAULT_CHARSET; // SYMBOL_CHARSET ??
}
SelectCurrentFont(i);
exit:
// needs to go back to normal
_szText = szTextBAK;
return _ecParseError;
}
/*
* HandleFieldHyperlink(pch)
*
* @mfunc
* Handle HYPERLINK field
*
* @rdesc
* EC The error code
*/
EC CRTFRead::HandleFieldHyperlink(
BYTE *pch ) //@parm Pointer to HYPERLINK field instruction
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldHyperlink");
BYTE *pBuffer;
if ( *pch )
{
for( ; *pch == ' '; pch++) ; // Skip leading blanks
}
// allocate the buffer and add the string to it
_cchHyperlinkFldinst = MAX_PATH;
_cchHyperlinkFldinstUsed = 1;
pBuffer = (BYTE *)PvAlloc( MAX_PATH, GMEM_FIXED );
if ( !pBuffer )
{
return ( _ecParseError = ecNoMemory );
}
pBuffer[0] = ' ';
pBuffer[1] = '\0';
_szHyperlinkFldinst = pBuffer;
if ( *pch )
{
_ecParseError = AppendString( &_szHyperlinkFldinst, pch, &_cchHyperlinkFldinst, &_cchHyperlinkFldinstUsed );
}
return _ecParseError;
}
/*
* CRTFRead::ReadData(pbBuffer, cbBuffer)
*
* Purpose:
* Read in object data. This must be called only after all initial
* object header info has been read.
*
* Arguments:
* pbBuffer pointer to buffer where to put data
* cbBuffer how many bytes to read in
*
* Returns:
* LONG number of bytes read in
*
*/
LONG CRTFRead::ReadData(BYTE * pbBuffer, LONG cbBuffer)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::ReadData");
LONG cbLeft = cbBuffer;
BYTE bChar0;
BYTE bChar1;
while (cbLeft && (bChar0 = GetHexSkipCRLF()) < 16 &&
(bChar1 = GetHexSkipCRLF()) < 16)
{
*pbBuffer++ = bChar0 << 4 | bChar1;
cbLeft--;
}
return cbBuffer - cbLeft ;
}
/*
* CRTFRead::ReadBinaryData(pbBuffer, cbBuffer)
*
* Purpose:
*
* Arguments:
* pbBuffer pointer to buffer where to put data
* cbBuffer how many bytes to read in
*
* Returns:
* LONG number of bytes read in
*/
LONG CRTFRead::ReadBinaryData(BYTE *pbBuffer, LONG cbBuffer)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::ReadBinaryData");
LONG cbLeft = min(_cbBinLeft, cbBuffer);
cbBuffer = cbLeft;
for (; cbLeft >0 ; cbLeft--)
{
*pbBuffer++ = GetChar();
}
_cbBinLeft -= cbBuffer;
return cbBuffer ;
}
/*
* CRTFRead::SkipBinaryData(cbBuffer)
*
* Purpose:
*
* Arguments:
* cbBuffer how many bytes to skip
*
* Returns:
* LONG number of bytes skipped
*/
LONG CRTFRead::SkipBinaryData(LONG cbSkip)
{
BYTE rgb[1024];
_cbBinLeft = cbSkip;
while(ReadBinaryData(rgb, sizeof(rgb)) > 0)
{
}
return cbSkip;
}
/*
* CRTFRead::StrAlloc(ppsz, sz)
*
* Purpose:
* Set up a pointer to a newly allocated space to hold a string
*
* Arguments:
* ppsz Ptr to ptr to string that needs allocation
* sz String to be copied into allocated space
*
* Returns:
* EC The error code
*/
EC CRTFRead::StrAlloc(TCHAR ** ppsz, BYTE * sz)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::StrAlloc");
int Length = strlen((CHAR *)sz)+1 ;
*ppsz = (TCHAR *) PvAlloc((Length + 1)*sizeof(TCHAR), GMEM_ZEROINIT);
if (!*ppsz)
{
_ped->GetCallMgr()->SetOutOfMemory();
_ecParseError = ecNoMemory;
goto Quit;
}
MultiByteToWideChar(CP_ACP,0,(char *)sz,-1,*ppsz,Length) ;
Quit:
return _ecParseError;
}
/*
* CRTFRead::FreeRtfObject()
*
* Purpose:
* Cleans up memory used by prtfobject
*/
void CRTFRead::FreeRtfObject()
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::FreeRtfObject");
if (_prtfObject)
{
FreePv(_prtfObject->szClass);
FreePv(_prtfObject->szName);
FreePv(_prtfObject);
_prtfObject = NULL;
}
}
/*
* CRTFRead::ObjectReadSiteFlags
*
* Purpose:
* Read the dwFlags and dwUser bytes from a container specific stream
*
* Arguments:
* preobj The REOBJ from where to copy the flags this preobj is
* then later put out in a site
*
* Returns:
* BOOL TRUE if successfully read the bytes
*/
BOOL CRTFRead::ObjectReadSiteFlags( REOBJECT * preobj)
{
return (::ObjectReadSiteFlags(preobj) == NOERROR);
}
/*
* ObjectReadFromStream
*
* Purpose:
* Reads an OLE object from the RTF output stream.
*
*
* Returns:
* BOOL TRUE on success, FALSE on failure.
*/
BOOL CRTFRead::ObjectReadFromEditStream(void)
{
HRESULT hr;
BOOL fRet = FALSE;
REOBJECT reobj = { 0 };
LPRICHEDITOLECALLBACK precall=NULL;
WCHAR ch = WCH_EMBEDDING;
LPOLECACHE polecache = NULL;
LPENUMSTATDATA penumstatdata = NULL;
STATDATA statdata;
BOOL fGotClsid = TRUE;
CObjectMgr *ObjectMgr = _ped->GetObjectMgr();
if (! ObjectMgr)
goto Cleanup;
precall = ObjectMgr->GetRECallback();
// If no IRichEditOleCallback exists, then fail
if (!precall)
goto Cleanup;
// AssertSz(_prtfObject->szClass,"ObFReadFromEditstream: reading unknown class");
//$ REVIEW: MAC This call is incorrect for the Mac. It may not matter though
// if ole support in RichEdit is not needed for the Mac.
if (!(_prtfObject->szClass &&
pCLSIDFromProgID(_prtfObject->szClass, &reobj.clsid)
== NOERROR))
{
fGotClsid = FALSE;
}
// Get storage for the object from the application
if (FAILED(precall->GetNewStorage(&reobj.pstg)))
{
goto Cleanup;
}
hr = pOleConvertOLESTREAMToIStorage((LPOLESTREAM) &RTFReadOLEStream, reobj.pstg, NULL);
if (FAILED(hr))
goto Cleanup;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -