📄 rtfread.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 RTFREAD.CPP - RichEdit RTF reader (w/o objects) |
*
* This file contains the nonobject code of RichEdit RTF reader.
* See rtfread2.cpp for embedded-object code.
*
* Authors:<nl>
* Original RichEdit 1.0 RTF converter: Anthony Francisco <nl>
* Conversion to C++ and RichEdit 2.0 w/o objects: Murray Sargent
* Lots of enhancements/maintenance: Brad Olenick
*
* @devnote
* All sz's in the RTF*.? files refer to a LPSTRs, not LPTSTRs, unless
* noted as a szW.
*
* @todo
* 1. Unrecognized RTF. Also some recognized won't round trip <nl>
* 2. In font.c, add overstrike for CFE_DELETED and underscore for
* CFE_REVISED. Would also be good to change color for CF.bRevAuthor
*
*/
#include "_common.h"
#ifdef PWD_JUPITER
// GuyBark JupiterJ 49674: Must be able to select and remove equation field text.
#include "_select.h"
#endif // PWD_JUPITER
#include "_rtfread.h"
#include "_util.h"
ASSERTDATA
/*
* Global Variables
*/
#define PFM_ALLRTF (PFM_ALL2 | PFM_COLLAPSED | PFM_OUTLINELEVEL | PFM_BOX)
#pragma BEGIN_CODESPACE_DATA
// for object attachment placeholder list
#define cobPosInitial 8
#define cobPosChunk 8
#pragma END_CODESPACE_DATA
#ifdef PWD_JUPITER
// GuyBark: Strip font decorations during stream in, and add them again on stream out.
// PWord on the device doesn't need the decorations as the font can display text from
// multiple character sets. But we must stream out the decorated fonts as Word95 uses
// them in determining the character set of the font.
FontDecorations const fontDec[] = { {" Baltic", BALTIC_CHARSET},
{" CE", EASTEUROPE_CHARSET},
{" Cyr", RUSSIAN_CHARSET},
{" Greek", GREEK_CHARSET},
{" Tur", TURKISH_CHARSET},
{" Turkish", TURKISH_CHARSET},
{NULL, 0} }; // <- This indicates the end of the array.
#endif // PWD_JUPITER
#if CFE_SMALLCAPS != 0x40 || CFE_ALLCAPS != 0x80 || CFE_HIDDEN != 0x100 \
|| CFE_OUTLINE != 0x200 || CFE_SHADOW != 0x400
#error "Need to change RTF char effect conversion routines
#endif
// for RTF tag coverage testing
#if defined(DEBUG)
#define TESTPARSERCOVERAGE() \
{ \
if(GetProfileIntA("RICHEDIT DEBUG", "RTFCOVERAGE", 0)) \
{ \
TestParserCoverage(); \
} \
}
#define PARSERCOVERAGE_CASE() \
{ \
if(_fTestingParserCoverage) \
{ \
return ecNoError; \
} \
}
#define PARSERCOVERAGE_DEFAULT() \
{ \
if(_fTestingParserCoverage) \
{ \
return ecStackOverflow; /* some bogus error */ \
} \
}
#else
#define TESTPARSERCOVERAGE()
#define PARSERCOVERAGE_CASE()
#define PARSERCOVERAGE_DEFAULT()
#endif
// FF's should not have paragraph number prepended to them
inline BOOL CharGetsNumbering(WORD ch) { return ch != FF; }
// V-GUYB: PWord Converter requires loss notification.
#ifdef REPORT_LOSSAGE
typedef struct
{
IStream *pstm;
BOOL bFirstCallback;
LPVOID *ppwdPWData;
BOOL bLoss;
} LOST_COOKIE;
#endif
//======================== OLESTREAM functions =======================================
DWORD CALLBACK RTFGetFromStream (
RTFREADOLESTREAM *OLEStream, //@parm OleStream
void FAR * pvBuffer, //@parm Buffer to read
DWORD cb) //@parm Bytes to read
{
return OLEStream->Reader->ReadData ((BYTE *)pvBuffer, cb);
}
DWORD CALLBACK RTFGetBinaryDataFromStream (
RTFREADOLESTREAM *OLEStream, //@parm OleStream
void FAR * pvBuffer, //@parm Buffer to read
DWORD cb) //@parm Bytes to read
{
return OLEStream->Reader->ReadBinaryData ((BYTE *)pvBuffer, cb);
}
//============================ STATE Structure =================================
/*
* STATE::AddPF(PF, lDefTab, lDocType)
*
* @mfunc
* If the PF contains new info, this info is applied to the PF for the
* state. If this state was sharing a PF with a previous state, a new
* PF is created for the state, and the new info is applied to it.
*
* @rdesc
* TRUE unless needed new PF and couldn't allocate it
*/
BOOL STATE::AddPF(
const CParaFormat &PF, //@parm Current RTFRead _PF
LONG lDefTab, //@parm Default tab to use if no previous state
LONG lDocType) //@parm Default doc type to use if no prev state
{
// Create a new PF if:
// 1. The state doesn't have one yet
// 2. The state has one, but it is shared by the previous state and
// there are PF deltas to apply to the state's PF
if(!pPF || (PF.dwMask && pstatePrev && pPF == pstatePrev->pPF))
{
Assert(!pstatePrev || pPF);
pPF = new CParaFormat;
if(!pPF)
return FALSE;
// Give the new PF some initial values - either from the previous
// state's PF or by CParaFormat initialization
if(pstatePrev)
{
// Copy the PF from the previous state
*pPF = *pstatePrev->pPF;
}
else
{
// We've just created a new PF for the state - there is no
// previous state to copy from. Use default values.
pPF->InitDefault(lDefTab, lDocType == DT_RTLDOC ? PFE_RTLPARA : 0);
pPF->dwMask = PFM_ALLRTF;
}
}
// Apply the new PF deltas to the state's PF
if(PF.dwMask)
pPF->Apply(&PF);
return TRUE;
}
/*
* STATE::DeletePF()
*
* @mfunc
* If the state's PF is not shared by the previous state, the PF for this
* state is deleted.
*
*/
void STATE::DeletePF()
{
if(pPF && (!pstatePrev || (pPF != pstatePrev->pPF)))
{
delete pPF;
}
pPF = NULL;
}
/*
* STATE::SetCodePage(CodePage, ansicpg)
*
* @mfunc
* If N of \ansicpgN is CP_UTF8, use it for all conversions (yes, even
* for SYMBOL_CHARSET). Else use CodePage.
*/
void STATE::SetCodePage(
LONG CodePage)
{
if(nCodePage != CP_UTF8)
nCodePage = CodePage;
}
//============================ CRTFRead Class ==================================
/*
* CRTFRead::CRTFRead()
*
* @mfunc
* Constructor for RTF reader
*/
CRTFRead::CRTFRead (
CTxtRange * prg, // @parm CTxtRange to read into
EDITSTREAM * pes, // @parm Edit stream to read from
DWORD dwFlags // @parm Read flags
)
: CRTFConverter(prg, pes, dwFlags, TRUE)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::CRTFRead");
Assert(prg->GetCch() == 0);
//TODO(BradO): We should examine the member data in the constructor
// and determine which data we want initialized on construction and
// which at the beginning of every read (in CRTFRead::ReadRtf()).
#ifdef BIDI
_cpThisDirection = _cpThisJoiner = prg->GetCp();
#endif
_sDefaultFont = -1; // No \deff n control word yet
_sDefaultLanguage = INVALID_LANGUAGE;
_sDefaultLanguageFE = INVALID_LANGUAGE;
_sDefaultTabWidth = 0;
_CF.dwMask = 0; // No char format changes yet
_FieldCF.dwMask = 0;
_nFieldCodePage = 0;
_ptfField = NULL;
_fRestoreFieldFormat = FALSE;
_dwFlagsUnion = 0; // No flags yet
_pes->dwError = 0; // No error yet
_cchUsedNumText = 0; // No numbering text yet
_cCell = 0; // No table cells yet
_iCell = 0;
_pstateStackTop = NULL;
_pstateLast = NULL;
_szText =
_pchRTFBuffer = // No input buffer yet
_pchRTFCurrent =
_szSymbolFieldResult =
_pchRTFEnd = NULL;
_prtfObject = NULL;
_pcpObPos = NULL;
_bTabLeader = 0;
_bTabType = 0;
_pobj = 0;
_wAlignment = PFA_LEFT;
_szHyperlinkFldinst = NULL;
_szHyperlinkFldrslt = NULL;
// Does story size exceed the maximum text size?
_cchMax = _ped->TxGetMaxLength() - _ped->GetAdjustedTextLength();
_cchMax = max((LONG)_cchMax, 0);
ZeroMemory(_rgStyles, sizeof(_rgStyles)); // No style levels yet
_bBiDiCharSet = (g_wLang == sLanguageHebrew) ? HEBREW_CHARSET : ARABIC_CHARSET;
#ifdef PWD_JUPITER
// GuyBark Jupiter 31960: We haven't found any collappsed text yet.
_fFoundCollapsedText = FALSE;
#endif // PWD_JUPITER
// init OleStream
RTFReadOLEStream.Reader = this;
if (NULL == RTFReadOLEStream.lpstbl)
{
//something very bizarre happened during init of this object
TRACEWARNSZ("RTFReadOLEStream.lpstbl is NOT initialized");
Assert(RTFReadOLEStream.lpstbl); //bad news to do this in the constructor - debug this
}
else
{
RTFReadOLEStream.lpstbl->Get = (DWORD (CALLBACK* )(LPOLESTREAM, void FAR*, DWORD))
RTFGetFromStream;
RTFReadOLEStream.lpstbl->Put = NULL;
}
#ifdef DEBUG
// TODO: Implement RTF tag logging for the Mac
#if !defined(MACPORT)
_fTestingParserCoverage = FALSE;
_prtflg = NULL;
if(GetProfileIntA("RICHEDIT DEBUG", "RTFLOG", 0))
{
_prtflg = new CRTFLog;
if(_prtflg)
{
if(!_prtflg->FInit())
{
delete _prtflg;
_prtflg = NULL;
}
}
AssertSz(_prtflg, "CRTFRead::CRTFRead: Error creating RTF log");
}
#endif
#endif // DEBUG
}
/*
* CRTFRead::HandleStartGroup()
*
* @mfunc
* Handle start of new group. Alloc and push new state onto state
* stack
*
* @rdesc
* EC The error code
*/
EC CRTFRead::HandleStartGroup()
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleStartGroup");
STATE * pstate = _pstateStackTop;
STATE * pstateNext = NULL;
if (pstate) // At least one STATE already
{ // allocated
Apply_CF(); // Apply any collected char
// Note (igorzv) we don't Apply_PF() here so as not to change para
// properties before we run into \par i.e. not to use paragraph
// properties if we copy only one word from paragraph. We can use an
// assertion here that neither we nor Word use end of group for
// restoring paragraph properties. So everything will be OK with stack
pstate->iCF = _prg->Get_iCF(); // Save current CF
pstate = pstate->pstateNext; // Use previously allocated
if(pstate) // STATE frame if it exists
pstateNext = pstate->pstateNext; // It does; save its forward
} // link for restoration below
if(!pstate) // No new STATE yet: alloc one
{
pstate = new STATE(_dwFlags & SFF_UTF8 ? CP_UTF8 : _nCodePage);
if (!pstate) // Couldn't alloc new STATE
goto memerror;
_pstateLast = pstate; // Update ptr to last STATE
} // alloc'd
STATE *pstateGetsPF;
// Apply the accumulated PF delta's to the old current state or, if there
// is no current state, to the newly created state.
pstateGetsPF = _pstateStackTop ? _pstateStackTop : pstate;
if(!pstateGetsPF->AddPF(_PF, _sDefaultTabWidth, _bDocType))
{
goto memerror;
}
_PF.dwMask = 0; // _PF contains delta's from *_pstateStackTop->pPF
if(_pstateStackTop) // There's a previous STATE
{
*pstate = *_pstateStackTop; // Copy current state info
// N.B. This will cause the current and previous state to share
// the same PF. PF delta's are accumulated in _PF. A new PF
// is created for _pstateStackTop when the _PF deltas are applied.
_pstateStackTop->pstateNext = pstate;
#ifdef BIDI
pstate->fModDirection = FALSE;
pstate->fModJoiner = FALSE;
#endif
}
pstate->pstatePrev = _pstateStackTop; // Link STATEs both ways
pstate->pstateNext = pstateNext;
_pstateStackTop = pstate; // Push stack
done:
TRACEERRSZSC("HandleStartGroup()", -_ecParseError);
return _ecParseError;
memerror:
_ped->GetCallMgr()->SetOutOfMemory();
_ecParseError = ecStackOverflow;
goto done;
}
/*
* CRTFRead::HandleEndGroup()
*
* @mfunc
* Handle end of new group
*
* @rdesc
* EC The error code
*/
EC CRTFRead::HandleEndGroup()
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleEndGroup");
STATE * pstate = _pstateStackTop;
STATE * pstatePrev;
if (!pstate) // No stack to pop
{
_ecParseError = ecStackUnderflow;
goto done;
}
_pstateStackTop = // Pop stack
pstatePrev = pstate->pstatePrev;
if(!pstatePrev)
{
Assert(pstate->pPF);
// We're ending the parse. Copy the final PF into _PF so that
// subsequent calls to Apply_PF will have a PF to apply.
_PF = *pstate->pPF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -