📄 rtfread.cpp
字号:
* @rdesc
* Standard color index corresponding to the color associated with _iParam
*/
LONG CRTFRead::GetStandardColorIndex()
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::GetColorIndex");
if((DWORD)_iParam >= _colors.Count()) // Illegal _iParam:
return 0; // use autocolor
COLORREF Color = *_colors.Elem(_iParam);
LONG i;
for(i = 0; i < 16; i++)
{
if(Color == g_Colors[i])
return i + 1;
}
return 0; // Not there: use autocolor
}
/*
* CRTFRead::HandleChar(ch)
*
* @mfunc
* Handle single Unicode character <p ch>
*
* @rdesc
* EC The error code
*/
EC CRTFRead::HandleChar(
WORD ch) // @parm char token to be handled
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleChar");
if(!_ped->TxGetMultiLine() && IsASCIIEOP(ch))
{
_ecParseError = ecTruncateAtCRLF;
}
else
{
Assert(ch <= 0x7F || ch > 0xFF || FTokIsSymbol(ch));
_CF.bInternalMask |= CFMI_RUNISDBCS;
_CF.bInternalEffects &= ~CFEI_RUNISDBCS;
AddText(&ch, 1, CharGetsNumbering(ch));
}
TRACEERRSZSC("HandleChar()", - _ecParseError);
return _ecParseError;
}
/*
* CRTFRead::HandleEndOfPara()
*
* @mfunc
* Insert EOP and apply current paraformat
*
* @rdesc
* EC the error code
*/
EC CRTFRead::HandleEndOfPara()
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleEndOfPara");
if(_pstateStackTop->fInTable) // Our simple table model can't
{ // have numbering
_PF.wNumbering = 0;
_PF.dwMask |= PFM_NUMBERING;
}
if(!_ped->TxGetMultiLine()) // No EOPs permitted in single-
{ // line controls
Apply_PF(); // Apply any paragraph formatting
_ecParseError = ecTruncateAtCRLF; // Cause RTF reader to finish up
return ecTruncateAtCRLF;
}
Apply_CF(); // Apply _CF and save iCF, since
LONG iFormat = _prg->Get_iCF(); // it may get changed to iCF
// that follows EOP
EC ec = _ped->Get10Mode() // If RichEdit 1.0 compatibility
? HandleText((BYTE *)szaCRLF, ALL_ASCII) // mode, use CRLF; else CR or VT
: HandleChar((unsigned)(_token == tokenLineBreak ? VT : CR));
if(ec == ecNoError)
{
Apply_PF();
_cpThisPara = _prg->GetCp(); // New para starts after CRLF
}
_prg->Set_iCF(iFormat); // Restore iFormat if changed
ReleaseFormats(iFormat, -1); // Release iFormat (AddRef'd by
// Get_iCF())
return _ecParseError;
}
/*
* CRTFRead::HandleText(szText, iAllASCII)
*
* @mfunc
* Handle the string of Unicode characters <p szText>
*
* @rdesc
* EC The error code
*/
EC CRTFRead::HandleText(
BYTE * szText, // @parm string to be handled
int iAllASCII) // @parm enum indicating if string is all ASCII chars
// (<= 0x7F)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleText");
LONG cch;
LONG cch_szUnicode = cachTextMax;
TCHAR * pch;
STATE * pstate = _pstateStackTop;
// TODO: what if szText cuts off in middle of DBCS?
if(!*szText)
{
goto CleanUp;
}
if(iAllASCII == ALL_ASCII || pstate->nCodePage == SYMBOL_CODEPAGE)
{
// Don't use MBTWC() in cases where text contains
// only ASCII chars (which don't require conversion)
for(cch = 0, pch = _szUnicode; *szText && (cch < cch_szUnicode); cch++)
{
Assert(*szText <= 0x7F || _CF.bCharSet == SYMBOL_CHARSET);
*pch++ = (TCHAR)*szText++;
}
*pch = 0;
_CF.bInternalMask |= CFMI_RUNISDBCS;
_CF.bInternalEffects &= ~CFEI_RUNISDBCS;
// fall through to AddText at end of HandleText()
}
else
{
TEXTFONT *ptf;
BOOL fMissingCodePage;
ptf = pstate->ptf;
// Run of text contains bytes > 0x7F.
// Ensure that we have the correct codepage with which to interpret
// these (possibly DBCS) bytes.
if(ptf->sCodePage == INVALID_CODEPAGE && !ptf->fCpgFromSystem)
{
// Determine codepage from the font name
if(CpgInfoFromFaceName(pstate->ptf))
{
SelectCurrentFont(pstate->ptf->sHandle);
Assert(ptf->sCodePage != INVALID_CODEPAGE);
}
else
{
// Here, we were not able to determine a cpg/charset value
// from the font name. We have two choices: (1) either choose
// some fallback value like 1252/0 or (2) rely on the
// document-level cpg value.
//
// I think choosing the document-level cpg value will give
// us the best results. In FE cases, it will likely err
// on the side of tagging too many runs as CFEI_RUNISDBCS, but
// that is safer than using a western cpg and potentially missing
// runs which should be CFEI_RUNISDBCS.
}
Assert(ptf->fCpgFromSystem);
}
Assert(!(_dwFlags & SFF_UTF8) || pstate->nCodePage == CP_UTF8);
#ifdef PWD_JUPITER
// GuyBark JupiterJ:
// Always treat a MBCS string which is invalid for the code page
// as something that should generate an error. Otherwise we lose
// the text. At least when the error is trapped we take action
// to try to compensate.
cch = MBTWC(pstate->nCodePage, MB_ERR_INVALID_CHARS,
#else
cch = MBTWC(pstate->nCodePage, 0,
#endif // PWD_JUPITER
(char *)szText, -1,
_szUnicode, cachTextMax, &fMissingCodePage);
AssertSz(cch > 0, "CRTFRead::HandleText(): MBTWC implementation changed"
" such that it returned a value <= 0");
if(!fMissingCodePage || pstate->nCodePage == INVALID_CODEPAGE)
{
// Use result of MBTWC if:
// (1) we converted some chars and did the conversion with the codepage
// provided.
// (2) we converted some chars but couldn't use the codepage provided,
// but the codepage is invalid. Since the codepage is invalid,
// we can't do anything more sophisticated with the text before
// adding to the backing store
cch--; // don't want char count to including terminating NULL
_CF.bInternalMask |= CFMI_RUNISDBCS;
if(fMissingCodePage)
{
_CF.bInternalEffects |= CFEI_RUNISDBCS;
}
else
{
_CF.bInternalEffects &= ~CFEI_RUNISDBCS;
}
// fall through to AddText at end of HandleText()
}
else
{
// Conversion to Unicode failed. Break up the string of
// text into runs of ASCII and non-ASCII characters.
// FUTURE(BradO): Here, I am saving dwMask and restoring it before
// each AddText. I'm not sure this is neccessary. When I have
// the time, I should revisit this save/restoring and
// determine that it is indeed neccessary.
BOOL fPrevIsASCII = ((*szText <= 0x7F) ? TRUE : FALSE);
BOOL fCurrentIsASCII = FALSE;
BOOL fLastChunk = FALSE;
DWORD dwMaskSave = _CF.dwMask;
#ifdef DEBUG
CCharFormat cfSave = _CF;
#endif
pch = _szUnicode;
cch = 0;
// (!*szText && *pch) is the case where we do the AddText for the
// last chunk of text
while((*szText || fLastChunk) && (cch<cch_szUnicode))
{
// fCurrentIsASCII assumes that no byte <= 0x7F is a
// DBCS lead-byte
if(fLastChunk ||
(fPrevIsASCII != (fCurrentIsASCII = ((*szText <= 0x7F) ?
TRUE : FALSE))))
{
_CF.dwMask = dwMaskSave;
#ifdef DEBUG
_CF = cfSave;
#endif
*pch = 0;
_CF.bInternalMask |= CFMI_RUNISDBCS;
if( fPrevIsASCII )
{
_CF.bInternalEffects &= ~CFEI_RUNISDBCS;
}
else
{
_CF.bInternalEffects |= CFEI_RUNISDBCS;
}
Assert(cch);
pch = _szUnicode;
AddText(pch, cch, TRUE);
cch = 0;
fPrevIsASCII = fCurrentIsASCII;
// My assumption in saving _CF.dwMask is that the remainder
// of the _CF is unchanged by AddText. This assert verifies
// this assumption.
AssertSz(!memcmp(&cfSave.dwEffects, &_CF.dwEffects,
((BYTE *)((CHARFORMAT2 *)&_CF + 1)) -
(BYTE *)&_CF.dwEffects),
"CRTFRead::HandleText(): AddText has been changed "
"and now alters the _CF structure.");
if(fLastChunk)
{
// Last chunk of text was AddText'd
break;
}
}
// Not the last chunck of text.
Assert(*szText);
// Advance szText pointer
if(!fCurrentIsASCII && *(szText + 1) &&
IsLeadByte(*szText, pstate->nCodePage))
{
// current byte is a lead-byte of a DBCS character
*pch++ = *szText++;
++cch;
}
if (cch<cch_szUnicode)
{
*pch++ = *szText++;
++cch;
}
// Must do an AddText for the last chunk of text.
if(!*szText)
{
fLastChunk = TRUE;
}
}
goto CleanUp;
}
}
if(cch > 0)
{
pch = _szUnicode;
AddText(pch, cch, TRUE);
}
CleanUp:
TRACEERRSZSC("HandleText()", - _ecParseError);
return _ecParseError;
}
/*
* CRTFRead::AddText(pch, cch, fNumber)
*
* @mfunc
* Add <p cch> chars of the string <p pch> to the range _prg
*
* @rdesc
* error code placed in _ecParseError
*/
EC CRTFRead::AddText(
TCHAR * pch, // @parm text to add
LONG cch, // @parm count of chars to add
BOOL fNumber) // @parm indicates whether or not to prepend numbering
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::AddText");
LONG cchAdded;
LONG cchT;
STATE * const pstate = _pstateStackTop;
TCHAR * szDst;
DWORD cchLen = _ped->GetAdjustedTextLength();
// AROO: No saving state before this point (other than pstate)
// AROO: This would mess up recursion below
AssertSz(pstate, "CRTFRead::AddText: no state");
if((DWORD)cch > _cchMax)
{
cch = (LONG)_cchMax;
_ecParseError = ecTextMax;
}
if (!cch)
return _ecParseError;
// FUTURE(BradO): This strategy for \pntext is prone to bugs, I believe.
// The recursive call to AddText to add the \pntext will trounce the
// accumulated _CF diffs associated with the text for which AddText is
// called. I believe we should save and restore _CF before and after
// the recursive call to AddText below. Also, it isn't sufficient to
// accumulate bits of \pntext as below, since each bit might be formatted
// with different _CF properties. Instead, we should accumulate a mini-doc
// complete with multiple text, char and para runs (or some stripped down
// version of this strategy).
if (pstate->sDest == destParaNumText)
{
szDst = _szNumText + _cchUsedNumText;
cch = min(cch, cchMaxNumText - 1 - _cchUsedNumText);
if (cch > 0)
{
MoveMemory((BYTE *)szDst, (BYTE *)pch, cch*2);
szDst[cch] = TEXT('\0'); // HandleText() takes sz
_cchUsedNumText += cch;
}
return ecNoError;
}
if(_cchUsedNumText && fNumber) // Some \pntext available
{
// Bug 3496 - The fNumber flag is an ugly hack to work around RTF
// commonly written by Word. Often, to separate a numbered list
// by page breaks, Word will write:
// <NUMBERING INFO> \page <PARAGRAPH TEXT>
// The paragraph numbering should precede the paragraph text rather
// than the page break. The fNumber flag is set to FALSE when the
// the text being added should not be prepended with the para-numbering,
// as is the case with \page (mapped to FF).
cchT = _cchUsedNumText;
_cchUsedNumText = 0; // Prevent infinite recursion
if(!pstate->fBullet)
{
// If there are any _CF diffs to be injected, they will be trounced
// by this recursive call (see FUTURE comment above).
// Since we didn't save _CF data from calls to AddText with
// pstate->sDest == destParaNumText, we have no way of setting up
// CFEI_RUNISDBCS and CFMI_RUNISDBCS (see FUTURE comment above).
AddText(_szNumText, cchT, FALSE);
}
else if(_PF.IsListNumbered() && _szNumText[cchT - 1] == TAB)
{
WCHAR ch = _szNumText[cchT - 2];
_wNumberingStyle = (_wNumberingStyle & ~0xF00)
| (ch == '.' ? PFNS_PERIOD :
ch != ')' ? PFNS_PLAIN :
_szNumText[0] == '(' ? PFNS_PARENS : PFNS_PAREN);
}
}
if (_cpFirst && _prg->GetCp() == _cpFirst && _prg->GetPF()->InTable() &&
_cCell && !_prg->_rpTX.IsAfterEOP())
{
// FUTURE: handle more general table insertions into other tables
return _ecParseError = ecGeneralFailure;
}
Apply_CF(); // Apply formatting changes in _CF
// BUGS 1577 & 1565 -
// CTxtRange::ReplaceRange will change the character formatting
// and possibly adjust the _rpCF forward if the current char
// formatting includes protection. The changes affected by
// CTxtRange::ReplaceRange are necessary only for non-streaming
// input, so we save state before and restore it after the call
// to CTxtRange::ReplaceRange
LONG iFormatSave = _prg->Get_iCF(); // Save state
cchAdded = _prg->ReplaceRange(cch, pch, NULL, SELRR_IGNORE);
_prg->Set_iCF(iFormatSave); // Restore state
ReleaseFormats(iFormatSave, -1);
Assert(_prg->GetCch() == 0);
if (cchAdded != cch)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -