📄 rtfwrit.cpp
字号:
if(!fInTable && (pPF->dxOffset &&
!PutCtrlWord(CWF_VAL, i_fi, -pPF->dxOffset) ||
pPF->dxStartIndent + pPF->dxOffset &&
!PutCtrlWord(CWF_VAL, i_li, pPF->dxStartIndent + pPF->dxOffset) ||
pPF->dxRightIndent &&
!PutCtrlWord(CWF_VAL, i_ri, pPF->dxRightIndent)))
{
goto CleanUp;
}
if (pPF->dySpaceBefore &&
!PutCtrlWord(CWF_VAL, i_sb, pPF->dySpaceBefore) ||
pPF->dySpaceAfter &&
!PutCtrlWord(CWF_VAL, i_sa, pPF->dySpaceAfter))
{
goto CleanUp;
}
if (dwRule) // Special line spacing active
{
i = 0; // Default "At Least" or
if (dwRule == tomLineSpaceExactly) // "Exactly" line spacing
dy = -abs(dy); // Use negative for "Exactly"
else if(dwRule == tomLineSpaceMultiple) // RichEdit uses 20 units/line
{ // RTF uses 240 units/line
i++;
dy *= 12;
}
else if (dwRule != tomLineSpaceAtLeast && dy > 0)
{
i++; // Multiple line spacing
if (dwRule <= tomLineSpaceDouble) // 240 units per line
dy = 120 * (dwRule + 2);
}
if (!PutCtrlWord(CWF_VAL, i_sl, dy) ||
!PutCtrlWord(CWF_VAL, i_slmult, i))
{
goto CleanUp;
}
}
dwEffects = pPF->wEffects & ((1 << CPFEFFECTS) - 1);
for(c = CPFEFFECTS; dwEffects && c--; // Output PARAFORMAT2 effects
dwEffects >>= 1)
{
// rgiszPFEffects[] contains PF effect keywords in the
// order max PFE_xx to min PFE-xx
AssertSz(rgiszPFEffects[2] == i_hyphpar,
"CRTFWrite::WriteParaFormat(): rgiszPFEffects is out-of-sync with PFE_XXX");
// \hyphpar has opposite logic to our PFE_DONOTHYPHEN so we emit
// \hyphpar0 to toggle the property off
if (dwEffects & 1 &&
!PutCtrlWord((c == 2) ? CWF_VAL : CWF_STR, rgiszPFEffects[c], 0))
{
goto CleanUp;
}
}
if (!fInTable && IN_RANGE(PFA_RIGHT, pPF->wAlignment, PFA_JUSTIFY) &&
!PutCtrlWord(CWF_STR, rgiszAlignment[pPF->wAlignment - 1]))
{
goto CleanUp;
}
for (i = 0; i < cTab; i++)
{
pPF->GetTab(i, &tabPos, &tabAlign, &tabLead);
AssertSz (tabAlign <= tomAlignBar && tabLead <= 5,
"CRTFWrite::WriteParaFormat: illegal tab leader/alignment");
i_t = i_tb; // Default \tb (bar tab)
if (tabAlign != tomAlignBar) // It isn't a bar tab
{
i_t = i_tx; // Use \tx for tabPos
if (tabAlign && // Put nonleft alignment
!PutCtrlWord(CWF_STR, rgiszTabAlign[tabAlign-1]))
{
goto CleanUp;
}
}
if (tabLead && // Put nonzero tab leader
!PutCtrlWord(CWF_STR, rgiszTabLead[tabLead-1]) ||
!PutCtrlWord(CWF_VAL, i_t, tabPos))
{
goto CleanUp;
}
}
CleanUp:
return _ecParseError;
}
/*
* CRTFWrite::WriteText(cwch, lpcwstr, nCodePage, fIsDBCS)
*
* @mfunc
* Write out <p cwch> chars from the Unicode text string <p lpcwstr> taking care to
* escape any special chars. The Unicode text string is scanned for characters which
* map directly to RTF strings, and the surrounding chunks of Unicode are written
* by calling WriteTextChunk.
*
* @rdesc
* EC The error code
*/
EC CRTFWrite::WriteText(
LONG cwch, // @parm # chars in buffer
LPCWSTR lpcwstr, // @parm Pointer to text
INT nCodePage, // @parm code page to use to convert to DBCS
BOOL fIsDBCS) // @parm indicates whether lpcwstr is a Unicode string
// or a DBCS string stuffed into a WSTR
{
TRACEBEGIN(TRCSUBSYSRTFW, TRCSCOPEINTERN, "CRTFWrite::WriteText");
WCHAR *pwchScan;
WCHAR *pwchStart;
if (_fBulletPending)
{
_fBulletPending = FALSE;
if(!_nNumber)
{
if(!printF(szBulletGroup, _symbolFont))
goto CleanUp;
}
else if(!_pPF->IsNumberSuppressed())
{
WCHAR szNumber[CCHMAXNUMTOSTR];
_pPF->NumToStr(szNumber, ++_nNumber);
if (!printF(szBeginNumberGroup, _nFont) ||
WritePcData(szNumber, _cpg, FALSE) ||
!printF(szEndNumberGroup))
{
goto CleanUp;
}
}
}
if(_fCheckInTable)
{
CheckInTable(TRUE);
if(_ecParseError)
goto CleanUp;
}
pwchScan = const_cast<LPWSTR>(lpcwstr);
pwchStart = pwchScan;
if(_CF.bCharSet == SYMBOL_CHARSET)
{
pwchScan += cwch;
cwch = 0;
}
// Step through the Unicode buffer, weeding out characters that have
// known translations to RTF strings
while(cwch-- > 0)
{
WCHAR wch = *pwchScan;
// If this is a string for which the MultiByteToUnicode conversion
// failed, the buffer will be filled with ANSI bytes stuffed into
// wchar's (one per). In this case, we don't want to map trail bytes
// to RTF strings.
if(fIsDBCS && IsLeadByte(wch, nCodePage))
{
#ifdef PWD_JUPITER
// GuyBark JupiterJ:
// If there is no trailing byte then that wasn't really a
// lead byte. It was probably an extended ansi character
// which incorrectly had a FE font applied to it.
if(cwch > 0)
{
#endif // PWD_JUPITER
Assert(cwch);
cwch--;
pwchScan += 2;
continue;
#ifdef PWD_JUPITER
}
#endif // PWD_JUPITER
}
// if the char is one for which there is an appropriate RTF string
// write the preceding chars and output the RTF string
if(!IN_RANGE(' ', wch, 'Z') &&
!IN_RANGE('a', wch, 'z') &&
!IN_RANGE(chOptionalHyphen + 1, wch, ENSPACE - 1) &&
#ifdef PWD_JUPITER
// GuyBark Jupiter: Handle the special character for CRLF in table cells.
(wch <= BULLET || wch == PWD_CRLFINCELL) &&
#else
wch <= BULLET &&
#endif // PWD_JUPITER
MapsToRTFKeywordW(wch))
{
if (pwchScan != pwchStart &&
WriteTextChunk(pwchScan - pwchStart, pwchStart, nCodePage,
fIsDBCS))
{
goto CleanUp;
}
// map the char(s) to the RTF string
int cwchUsed = MapToRTFKeyword(pwchScan, cwch, MAPTOKWD_UNICODE);
cwch -= cwchUsed;
pwchScan += cwchUsed;
// start of next run of unprocessed chars is one past current char
pwchStart = pwchScan + 1;
#ifdef TARGET_NT // V-GUYB: Don;t change device code at this late stage.
if(cwch)
{
_fCheckInTable = FALSE;
}
#endif // TARGET_NT
}
pwchScan++;
}
// write the last chunk
if (pwchScan != pwchStart &&
WriteTextChunk(pwchScan - pwchStart, pwchStart, nCodePage, fIsDBCS))
{
goto CleanUp;
}
CleanUp:
return _ecParseError;
}
/*
* CRTFWrite::WriteTextChunk(cwch, lpcwstr, nCodePage, fIsDBCS)
*
* @mfunc
* Write out <p cwch> chars from the Unicode text string <p lpcwstr> taking care to
* escape any special chars. Unicode chars which cannot be converted to
* DBCS chars using the supplied codepage, <p nCodePage>, are written using the
* \u RTF tag.
*
* @rdesc
* EC The error code
*/
EC CRTFWrite::WriteTextChunk(
LONG cwch, // @parm # chars in buffer
LPCWSTR lpcwstr, // @parm Pointer to text
INT nCodePage, // @parm code page to use to convert to DBCS
BOOL fIsDBCS) // @parm indicates whether lpcwstr is a Unicode string
// or a DBCS string stuffed into a WSTR
{
// FUTURE(BradO): There is alot of commonality b/t this routine and
// WritePcData. We should re-examine these routines and consider
// combining them into a common routine.
TRACEBEGIN(TRCSUBSYSRTFW, TRCSCOPEINTERN, "CRTFWrite::WriteTextChunk");
BYTE b;
LONG cbAnsi;
LONG cbAnsiBufferSize;
BYTE * pbAnsiBuffer;
BYTE * pbAnsi;
BOOL fUsedDefault = FALSE;
BOOL fMultiByte;
BOOL fMissingCodePage = FALSE;
#ifdef PWD_JUPITER
// GuyBark: If we're going to output J text below, then we must make
// sure a J font is current for the text chunk. RichEdit and Word97
// don;t care, as they look at the unicode, but Word95 relies on the
// MBCS equivalent of the unicode. While Word95 and Word97 always have
// a J font selected for the run, the Word converters may not.
BOOL bSetJFont = FALSE;
#endif // PWD_JUPITER
// When WideCharToMultiByte fails to convert a char, the following default
// char is used as a placeholder in the string being converted
// GuyBark JupiterJ 50783:
// Originally we were passing a default character os '\0' through to
// WideCharToMultiByte(). But the OS code says, if the codepage is FE,
// then the MBCS we may end up getting is either one or two bytes
// depending on what the second byte if the default character is. But
// we shouldn't have to care what the second byte is. If the first
// byte is zero (ie the low byte) then we can't have supplied a DBCS
// character. Anyway, pass in two zero bytes here.
const char szDBCSDefault[2] = {0, 0};
// Allocate temp buffer for ANSI text we convert to
cbAnsiBufferSize = cachBufferMost * (nCodePage == CP_UTF8 ? 3 : MB_LEN_MAX);
if (!_pbAnsiBuffer)
{
// If the code page was CP_UTF8, it will always be CP_UTF8 for this instance
_pbAnsiBuffer = (BYTE *)PvAlloc(cbAnsiBufferSize, GMEM_FIXED);
if (!_pbAnsiBuffer)
goto RAMError;
}
pbAnsiBuffer = _pbAnsiBuffer;
// Convert Unicode (or fIsDBCS) buffer to ANSI
if(fIsDBCS)
{
// Supply some bogus code page which will force direct conversion
// from wchar to bytes (losing high byte of wchar).
// Also, don't want to use default char replacement in this case.
cbAnsi = WCTMB(INVALID_CODEPAGE, 0, lpcwstr, cwch,
(char *)pbAnsiBuffer, cbAnsiBufferSize,
NULL, NULL, NULL);
}
else
{
cbAnsi = WCTMB(nCodePage, 0, lpcwstr, cwch,
(char *)pbAnsiBuffer, cbAnsiBufferSize,
szDBCSDefault, &fUsedDefault,
&fMissingCodePage);
}
Assert(cbAnsi > 0);
pbAnsi = pbAnsiBuffer;
fMultiByte = (cbAnsi > cwch) || fIsDBCS || fMissingCodePage;
while (!_ecParseError && cbAnsi-- > 0)
{
b = *pbAnsi;
// Compare ASCII chars to their Unicode counterparts to check
// that we're in sync
AssertSz(cwch <= 0 || *lpcwstr > 127 || b == *lpcwstr,
"CRTFWrite::WriteText: Unicode and DBCS strings out of sync");
// FUTURE(BradO): MurrayS made a clever change to this code which
// caused the RTF writer to output the \uN tag for all ASCII characters
// greater than 0x7F. This change was necessitated by the behaviour
// of WCTMB whereby Unicode chars which should fail the conversion to ANSI
// are converted to some "best-match" for the codepage
// (ex. alpha's convert to 'a' with cpg==1252).
//
// This change was pulled out at the request of Outlook, but should
// be considered for RE2.1. This change can be found in version 75 of
// this file. Note: NT 5.0 plans to introduce the flag
// WC_NO_BEST_FIT_CHARS, which should make our current algorithm output
// \uN values whenever the system cannot convert a character correctly.
if (!IN_RANGE(' ', b, 'z') && !IN_RANGE('A', b, 'Z') &&
MapsToRTFKeywordA(b))
{
int cchUsed = MapToRTFKeyword(pbAnsi, cbAnsi, MAPTOKWD_ANSI);
cbAnsi -= cchUsed;
pbAnsi += cchUsed;
}
else if(nCodePage == CP_UTF8)
{
PutChar(b); // Output 1st byte in any
if(b >= 0xC0) // case. At least 2-byte
{ // At least 2-byte lead
pbAnsi++; // byte, so output a
Assert(cbAnsi && IN_RANGE(0x80, *pbAnsi, 0xBF));
cbAnsi--; // trail byte
PutChar(*pbAnsi);
if(b >= 0xE0) // 3-byte lead byte, so
{ // output another trail
pbAnsi++; // byte
Assert(cbAnsi && IN_RANGE(0x80, *pbAnsi, 0xBF));
cbAnsi--;
PutChar(*pbAnsi);
}
}
}
else if(fMultiByte && cbAnsi && IsLeadByte(b, nCodePage))
{
#ifdef PWD_JUPITER
// GuyBark: If we have the UNICODE value for the character, output it here.
// Then follow it by the MBCS value. This allows the output RTF file to
// be more portable later, if it's read on a system that doesn't have the
// required code page for the MBCS.
if(!fIsDBCS)
{
// If this is a lead byte, then we will try to output a DBCS value.
// This means the UNICODE will ALWAYS be followed by 2 MBCS values.
int cb = 2;
// Is the current \ucN value good to use?
if(cb != _UnicodeBytesPerChar)
{
// No, so set up \uc2
if(!PutCtrlWord(CWF_VAL, i_uc, cb))
{
goto CleanUp;
}
_UnicodeBytesPerChar = cb;
}
// Now output the unicode value.
if(!PutCtrlWord(CWF_VAL, i_u, (int)*lpcwstr))
{
goto CleanUp;
}
}
// If the code page is missing, then the pbAnsi buffer was artifically
// created to hold one byte per character. In which case we never want
// to jump two bytes per character.
if(!fMissingCodePage)
{
#endif // PWD_JUPITER
pbAnsi++; // Output DBCS pair
cbAnsi--;
#ifdef PWD_JUPITER
}
#endif // PWD_JUPITER
if(fIsDBCS)
{
lpcwstr++;
cwch--;
}
printF(szEscape2CharFmt, b, *pbAnsi);
}
else
{
// GuyBark 3/10/98 17827:
// If the character being output is not a character from the lower character set
// of an ansi font, then output it with the matching unicode token. Otherwise we
// have problems preserving characters from non-existing fonts. The
// following test means that we will write out the unicode more often than we
// need too, but that just means the output rtf is pretty darn portable.
#ifdef PWD_JUPITER
if(*lpcwstr != (WCHAR)b)
{
// The unicode char value is not the same as the equivalent ansi value.
// GuyBark: 3/27/97 This is what we'd do if we're were happy always writing
// the non-unicode representation as one byte, (ie with the \uc1 token).
// But some unicode values we output here can only be represented as double
// byte, so we will need to \uc2 token in this case.
/*
if(!PutCtrlWord(CWF_VAL, i_u, ((cwch > 0) ? (int)*lpcwstr : TEXT('?'))) ||
!printF(szEscapeCharFmt, b))
{
goto CleanUp;
}
*/
int cb, nCodePageUse = nCodePage;
BYTE sza[2] = {0};
// If we're outputting J text here, we must make sure a J font is selected.
// IMPORTANT: This check was originally added to make sure J text is output
// with a font with the J code page. This worked around a problem with the
// Office converters, whereby J text may still the 1252 code page selected.
// This workaround is never needed here now, as we trap this problem during
// the stream in process instead. Keep this code here anyway in case the
// stream in failed to recognize the problem.
if((_pwdDefaultJFont != -1) && // We have a J
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -