📄 rtfwrit.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.
//
/*
* @doc INTERNAL
*
* @module RTFWRIT.CPP - RichEdit RTF Writer (w/o objects) |
*
* This file contains the implementation of the RTF writer
* for the RichEdit control, except for embedded objects,
* which are handled mostly in rtfwrit2.cpp
*
* Authors: <nl>
* Original RichEdit 1.0 RTF converter: Anthony Francisco <nl>
* Conversion to C++ and RichEdit 2.0: Murray Sargent <nl>
* Lots of enhancements: Brad Olenick <nl>
*
*/
#include "_common.h"
#include "_rtfwrit.h"
#include "_objmgr.h"
#include "_coleobj.h"
ASSERTDATA
extern KEYWORD rgKeyword[];
//========================= Global String Constants ==================================
BYTE bCharSetANSI = ANSI_CHARSET; // ToDo: make more general
#ifdef DEBUG
// Quick way to find out what went wrong: rgszParseError[ecParseError]
//
CHAR * rgszParseError[] =
{
"No error",
"Can't convert to Unicode", // FF
"Color table overflow", // FE
"Expecting '\\rtf'", // FD
"Expecting '{'", // FC
"Font table overflow", // FB
"General failure", // FA
"Keyword too long", // F9
"Lexical analyzer initialize failed", // F8
"No memory", // F7
"Parser is busy", // F6
"PutChar() function failed", // F5
"Stack overflow", // F4
"Stack underflow", // F3
"Unexpected character", // F2
"Unexpected end of file", // F1
"Unexpected token", // F0
"UnGetChar() function failed", // EF
"Maximum text length reached", // EE
"Streaming out object failed", // ED
"Streaming in object failed", // EC
"Truncated at CR or LF", // EB
"Format-cache failure", // EA
NULL // End of list marker
};
CHAR * szDest[] =
{
"RTF",
"Color Table",
"Font Table",
"Binary",
"Object",
"Object Class",
"Object Name",
"Object Data",
"Field",
"Field Result",
"Field Instruction",
"Symbol",
"Paragraph Numbering",
"Picture"
};
#endif
// Most control-word output is done with the following printf formats
static const CHAR * rgszCtrlWordFormat[] =
{
"\\%s", "\\%s%d", "{\\%s", "{\\*\\%s", "{\\%s%d"
};
// Special control-word formats
static const CHAR szBeginFontEntryFmt[] = "{\\f%d\\%s";
static const CHAR szBulletGroup[] = "{\\pntext\\f%d\\'B7\\tab}";
static const CHAR szBulletFmt[] = "{\\*\\pn\\pnlvlblt\\pnf%d\\pnindent%d{\\pntxtb\\'B7}}";
static const CHAR szBeginNumberGroup[] = "{\\pntext\\f%d ";
static const CHAR szEndNumberGroup[] = "\\tab}";
static const CHAR szBeginNumberFmt[] = "{\\*\\pn\\pnlvl%s\\pnf%d\\pnindent%d\\pnstart%d";
static const CHAR szpntxtb[] = "{\\pntxtb(}";
static const CHAR szpntxta[] = "{\\pntxta%c}";
static const CHAR szColorEntryFmt[] = "\\red%d\\green%d\\blue%d;";
static const CHAR szEndFontEntry[] = ";}";
const CHAR szEndGroupCRLF[] = "}\r\n";
static const CHAR szEscape2CharFmt[] = "\\'%02x\\'%02x";
static const CHAR szLiteralCharFmt[] = "\\%c";
static const CHAR szPar[] = "\\par\r\n";
static const CHAR szObjPosHolder[] = "\\objattph\\'20";
static const CHAR szDefaultFont[] = "\\deff0";
static const CHAR szHorzdocGroup[] = "{\\horzdoc}";
static const CHAR szNormalStyle[] = "{ Normal;}";
static const CHAR szHeadingStyle[] = "{\\s%d heading %d;}";
static const CHAR szEndRow[] = "\\row\r\n";
static const CHAR szPwdComment[] = "{\\*\\pwdcomment ";
#define szEscapeCharFmt &szEscape2CharFmt[6]
const WORD rgiszTerminators[] =
{ i_cell, 0, i_tab, 0, i_line, i_page};
// Keep these indices in sync with the special character values in _common.h
const WORD rgiszSpecial[] =
{
i_enspace,
i_emspace,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
i_endash,
i_emdash,
0,
0,
0,
i_lquote,
i_rquote,
0,
0,
i_ldblquote,
i_rdblquote,
0,
0,
0,
0,
i_bullet
};
const WORD rgiszEffects[] =
{ // Effects keywords
i_revised, i_disabled, i_impr, i_embo, // Ordered max CFE_xx to
i_shad, i_outl, i_v, i_caps, i_scaps, // min CFE_xx
i_disabled, i_protect, i_strike, i_ul, i_i, i_b // (see WriteCharFormat())
};
#define CEFFECTS ARRAY_SIZE(rgiszEffects)
const WORD rgiszPFEffects[] = // PF effects keywords
{ // Ordered max PFE_xx to
i_collapsed, i_sbys, i_hyphpar, i_nowidctlpar, // min PFE_xx
i_noline, i_pagebb, i_keepn, i_keep, i_rtlpar
}; // (see WriteParaFormat())
#define CPFEFFECTS ARRAY_SIZE(rgiszPFEffects)
const WORD rgiszUnderlines[] =
{
i_ul, i_ulw, i_uldb, i_uld, // Std Word underlines
i_uldash, i_uldashd, i_uldashdd, i_ulwave, i_ulth, i_ulhair
};
#define CUNDERLINES ARRAY_SIZE(rgiszUnderlines)
const WORD rgiszFamily[] = // Font family RTF name
{ // keywords in order of
i_fnil, i_froman, i_fswiss, i_fmodern, // bPitchAndFamily
i_fscript, i_fdecor
// , i_ftech, i_fbidi // TODO
};
const WORD rgiszAlignment[] = // Alignment keywords
{ // Keep in sync with
i_ql, i_qr, i_qc, i_qj // alignment constants
};
const WORD rgiszTabAlign[] = // Tab alignment keywords
{ // Keep in sync with tab
i_tqc, i_tqr, i_tqdec // alignment constants
};
const WORD rgiszTabLead[] = // Tab leader keywords
{ // Keep in sync with tab
i_tldot, i_tlhyph, i_tlul, i_tlth, i_tleq // leader constants
};
const WORD rgiszNumberStyle[] = // Numbering style keywords
{ // Keep in sync with TOM
i_pndec, i_pnlcltr, i_pnucltr, // values
i_pnlcrm, i_pnucrm,
i_pnaiueod, i_pnirohad // GuyBark JupiterJ: added these
};
const WORD rgiszBorders[] = // Border combination keywords
{
i_box,
i_brdrt, i_brdrl, i_brdrb, i_brdrr,
i_trbrdrt, i_trbrdrl, i_trbrdrb, i_trbrdrr,
i_clbrdrt, i_clbrdrl, i_clbrdrb, i_clbrdrr
};
const WORD rgiszBorderStyles[] = // Border style keywords
{
i_brdrdash, i_brdrdashsm, i_brdrdb, i_brdrdot,
i_brdrhair, i_brdrs, i_brdrth, i_brdrtriple
};
#define CBORDERSTYLES ARRAY_SIZE(rgiszBorderStyles)
const WORD rgiszBorderEffects[] = // Border effect keywords
{
i_brdrbar, i_brdrbtw, i_brdrsh // Reverse order from bits
};
const WORD rgiszShadingStyles[] = // Shading style keywords
{
i_bgbdiag, i_bgcross, i_bgdcross, i_bgdkbdiag,
i_bgdkcross, i_bgdkdcross, i_bgdkfdiag, i_bgdkhoriz,
i_bgdkvert, i_bgfdiag, i_bghoriz, i_bgvert
};
#define CSHADINGSTYLES ARRAY_SIZE(rgiszShadingStyles)
// RGB with 2 bits per color type (in BGR order)
const COLORREF g_Colors[] =
{
RGB( 0, 0, 0), // \red0\green0\blue0
RGB( 0, 0, 255), // \red0\green0\blue255
RGB( 0, 255, 255), // \red0\green255\blue255
RGB( 0, 255, 0), // \red0\green255\blue0
RGB(255, 0, 255), // \red255\green0\blue255
RGB(255, 0, 0), // \red255\green0\blue0
RGB(255, 255, 0), // \red255\green255\blue0
RGB(255, 255, 255), // \red255\green255\blue255
RGB( 0, 0, 128), // \red0\green0\blue128
RGB( 0, 128, 128), // \red0\green128\blue128
RGB( 0, 128, 0), // \red0\green128\blue0
RGB(128, 0, 128), // \red128\green0\blue128
RGB(128, 0, 0), // \red128\green0\blue0
RGB(128, 128, 0), // \red128\green128\blue0
RGB(128, 128, 128), // \red128\green128\blue128
RGB(192, 192, 192), // \red192\green192\blue192
};
/*
* CRTFWrite::MapsToRTFKeywordW(wch)
*
* @mfunc
* Returns a flag indicating whether the character maps to an RTF keyword
*
* @rdesc
* BOOL TRUE if char maps to RTF keyword
*/
inline BOOL CRTFWrite::MapsToRTFKeywordW(WCHAR wch)
{
return
IN_RANGE(TAB, wch, CR) ||
#ifdef PWD_JUPITER
// GuyBark Jupiter: Handle the special character for CRLF in table cells.
wch == PWD_CRLFINCELL ||
#endif // PWD_JUPITER
wch == CELL ||
wch == CELL ||
wch == BSLASH ||
wch == LBRACE ||
wch == RBRACE ||
IN_RANGE(ENSPACE, wch, EMSPACE) ||
IN_RANGE(ENDASH, wch, EMDASH) ||
IN_RANGE(LQUOTE, wch, RQUOTE) ||
IN_RANGE(LDBLQUOTE, wch, RDBLQUOTE) ||
wch == BULLET ||
wch == chOptionalHyphen ||
wch == chNonBreakingSpace;
}
/*
* CRTFWrite::MapsToRTFKeywordA(ch)
*
* @mfunc
* Returns a flag indicating whether the character maps to an RTF keyword
*
* @rdesc
* BOOL TRUE if char maps to RTF keyword
*/
inline BOOL CRTFWrite::MapsToRTFKeywordA(char ch)
{
return IN_RANGE(TAB, ch, CR) ||
ch == CELL ||
ch == BSLASH ||
ch == LBRACE ||
ch == RBRACE;
}
/*
* CRTFWrite::MapToRTFKeywordW(pv, cch, iCharEncoding)
*
* @mfunc
* Examines the first character in the string pointed to by pv and
* writes out the corresponding RTF keyword. In situations where
* the first and subsequent characters map to a single keyword, we
* return the number of additional characters used in the mapping.
*
* @rdesc
* int indicates the number of additional characters used when
* the mapping to an RTF keyword involves > 1 characters.
*/
int CRTFWrite::MapToRTFKeyword(
void * pv, //@parm ptr to ansi or Unicode string
int cch,
int iCharEncoding)
{
Assert(iCharEncoding == MAPTOKWD_ANSI || iCharEncoding == MAPTOKWD_UNICODE);
WCHAR ch = ((iCharEncoding == MAPTOKWD_ANSI) ? *(char *)pv : *(WCHAR *)pv);
int cchRet = 0;
Assert((iCharEncoding == MAPTOKWD_ANSI) ? MapsToRTFKeywordA(ch) : MapsToRTFKeywordW(ch));
switch(ch)
{
#ifdef PWD_JUPITER
// GuyBark Jupiter: We've hit the special character inserting when
// reading the file, to represent a CRLF in a table cell.
case PWD_CRLFINCELL:
{
// Mimic the rtf output by Word97 in this situation.
char szParInTable[] = "\r\n\\par";
Puts(szParInTable, strlen(szParInTable));
break;
}
#endif // PWD_JUPITER
case BULLET:
case EMDASH:
case EMSPACE:
case ENDASH:
case ENSPACE:
case LDBLQUOTE:
case LQUOTE:
case RDBLQUOTE:
case RQUOTE:
Assert(ch > 0xFF);
if(iCharEncoding != MAPTOKWD_ANSI)
{
AssertSz(rgiszSpecial[ch - ENSPACE] != 0,
"CRTFWrite::WriteText(): rgiszSpecial out-of-sync");
PutCtrlWord(CWF_STR, rgiszSpecial[ch - ENSPACE]);
}
break;
case FF:
case VT:
case TAB:
case CELL:
PutCtrlWord(CWF_STR, rgiszTerminators[ch - CELL]);
break;
case CR:
{
WCHAR ch1;
WCHAR ch2;
if(iCharEncoding == MAPTOKWD_ANSI)
{
char *pch = (char *)pv;
ch1 = pch[1];
ch2 = pch[2];
}
else
{
WCHAR *pch = (WCHAR *)pv;
ch1 = pch[1];
ch2 = pch[2];
}
if(cch > 1 && ch1 == CR && ch2 == LF)
{
// Translate CRCRLF to a blank (represents soft line break)
PutChar(' ');
cchRet = 2;
break;
}
if(cch && ch1 == LF) // Ignore LF after CR
{
cchRet = 1;
}
if(_pPF->InTable()) // CR terminates a row in our simple
{ // table model, so output \row
Puts(szEndRow, sizeof(szEndRow) - 1);
_fCheckInTable = TRUE;
break;
}
} // Fall thru to LF (EOP) case
case LF:
Puts(szPar, sizeof(szPar) - 1);
if(_fBullet)
{
if(cch > 0)
{
if(!_nNumber)
printF(szBulletGroup, _symbolFont);
else if(!_pPF->IsNumberSuppressed())
{
WCHAR szNumber[CCHMAXNUMTOSTR];
_pPF->NumToStr(szNumber, ++_nNumber);
printF(szBeginNumberGroup, _nFont);
WritePcData(szNumber, _cpg, FALSE);
printF(szEndNumberGroup);
}
}
else
_fBulletPending = TRUE;
}
break;
case chOptionalHyphen:
ch = '-'; // Fall thru to printFLiteral
printFLiteral:
case BSLASH:
case LBRACE:
case RBRACE:
printF(szLiteralCharFmt, ch);
break;
case chNonBreakingSpace:
ch = '~';
goto printFLiteral;
}
return cchRet;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -