windows-nt/Source/XPSP1/NT/windows/richedit/re41/rtfread2.cpp

1205 lines
28 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
* 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.
*
* Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved.
*/
#include "_common.h"
#include "_rtfread.h"
#include "_coleobj.h"
//#include "_nlsprcs.h"
#include "_disp.h"
#include "_dxfrobj.h"
const char szFontsel[]="\\f";
ASSERTDATA
/*
* CRTFRead::HandleFieldInstruction()
*
* @mfunc
* Handle field instruction
*
* @rdesc
* EC The error code
*/
extern WCHAR pchStartField[];
EC CRTFRead::HandleFieldInstruction()
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldInstruction");
BYTE *pch, *pch1;
for(pch1 = _szText; *pch1 == ' '; pch1++) // Bypass any leading blanks
;
for(pch = pch1; *pch && *pch != ' '; pch++)
;
if(W32->ASCIICompareI(pch1, (BYTE *) "SYMBOL", 6))
{
//Remove the start field character added when we saw the \fldinst
CTxtRange rg(*_prg);
rg.Move(-2, TRUE);
Assert(rg.CRchTxtPtr::GetChar() == STARTFIELD);
rg.Delete(0, SELRR_IGNORE);
BYTE szSymbol[2] = {0,0};
HandleFieldSymbolInstruction(pch, szSymbol); // SYMBOL
HandleText(szSymbol, CONTAINS_NONASCII);
_fSymbolField = TRUE;
}
else
HandleText(pch1, CONTAINS_NONASCII);
TRACEERRSZSC("HandleFieldInstruction()", - _ecParseError);
return _ecParseError;
}
/*
* CRTFRead::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).
* There were comments saying that we should parse font and font size from
* fldrslt, but I don't know why. Field instruction seems to and should contain
* all relevant data.
*/
EC CRTFRead::HandleFieldSymbolInstruction(
BYTE *pch, //@parm Pointer to SYMBOL field instruction
BYTE *szSymbol)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldInstruction");
BYTE ch;
BYTE chSymbol = 0;
const char *pchFontsel = szFontsel;
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 && IsXDigit(ch))
{
chSymbol <<= 4;
chSymbol += (ch <= '9') ? ch - '0' : (ch & 0x4f) - 'A' + 10;
ch = *pch++;
}
}
else // Decimal
{
ch = *pch;
while (ch && IsDigit(ch))
{
chSymbol *= 10;
chSymbol += ch - '0' ;
ch = *++pch;
}
}
szSymbol[0] = chSymbol;
// 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"
}
TRACEERRSZSC("HandleFieldInstruction()", - _ecParseError);
return _ecParseError;
}
/*
* CRTFRead::HandleFieldSymbolFont(pch)
*
* @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) //@parm Ptr to symbol field
{
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 = (SHORT)_nCodePage;
ptf->iCharRep = DEFAULT_INDEX; // SYMBOL_INDEX ??
}
SelectCurrentFont(i);
exit:
// needs to go back to normal
_szText = szTextBAK;
return _ecParseError;
}
/*
* CRTFRead::ReadData(pbBuffer, cbBuffer)
*
* @mfunc
* Read in object data. This must be called only after all initial
* object header info has been read.
*
* @rdesc
* LONG count of bytes read in
*/
LONG CRTFRead::ReadData(
BYTE * pbBuffer, //@parm Ptr to buffer where to put data
LONG cbBuffer) //@parm How many bytes to read in
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::ReadData");
BYTE bChar0, bChar1;
LONG cbLeft = cbBuffer;
while (cbLeft && (bChar0 = GetHexSkipCRLF()) < 16 &&
(bChar1 = GetHexSkipCRLF()) < 16 &&
_ecParseError == ecNoError)
{
*pbBuffer++ = bChar0 << 4 | bChar1;
cbLeft--;
}
return cbBuffer - cbLeft ;
}
/*
* CRTFRead::ReadBinaryData(pbBuffer, cbBuffer)
*
* @mfunc
* Read cbBuffer bytes into pbBuffer
*
* @rdesc
* Count of bytes read in
*/
LONG CRTFRead::ReadBinaryData(
BYTE * pbBuffer, //@parm Ptr to buffer where to put data
LONG cbBuffer) //@parm How many bytes to read in
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::ReadBinaryData");
LONG cbLeft = min(_cbBinLeft, cbBuffer);
cbBuffer = cbLeft;
for (; cbLeft > 0 && _ecParseError == ecNoError ; cbLeft--)
*pbBuffer++ = GetChar();
_cbBinLeft -= cbBuffer;
return cbBuffer ;
}
/*
* CRTFRead::SkipBinaryData(cbSkip)
*
* @mfunc
* Skip cbSkip bytes in input streamd
*
* @rdesc
* LONG count of bytes skipped
*/
LONG CRTFRead::SkipBinaryData(
LONG cbSkip) //@parm Count of bytes to skip
{
BYTE rgb[1024];
_cbBinLeft = cbSkip;
while(ReadBinaryData(rgb, sizeof(rgb)) > 0 && _ecParseError == ecNoError)
;
return cbSkip;
}
/*
* CRTFRead::ReadRawText(pszRawText)
*
* @mfunc
* Read in raw text until }. A buffer is allocated to save the text.
* The caller is responsible to free the buffer later.
*
* @rdesc
* LONG count of bytes read
*/
LONG CRTFRead::ReadRawText(
char **pszRawText) //@parm Address of the buffer containing the raw text
{
LONG cch=0;
char *szRawTextStart = NULL;
char *szRawText = NULL;
char chLast=0;
char ch;
short cRBrace=0;
LONG cchBuffer = 0;
bool fNeedBuffer = (pszRawText != NULL);
if (fNeedBuffer)
{
*pszRawText = NULL;
cchBuffer = 128;
szRawText = szRawTextStart = (char *)PvAlloc(128, GMEM_ZEROINIT);
if(!szRawTextStart)
{
_ecParseError = ecNoMemory;
return 0;
}
}
while (_ecParseError == ecNoError)
{
ch = GetChar();
if (ch == 0)
break; // error case
if (ch == LF || ch == CR)
continue; // Ignore noise characters
if (ch == '}' && chLast != '\\')
{
if (!cRBrace)
{
// Done
UngetChar();
if (fNeedBuffer)
*szRawText = '\0';
break;
}
cRBrace--; // count the RBrace so we will ignore the matching pair of LBrace
}
if (ch == '{' && chLast != '\\')
cRBrace++;
chLast = ch;
cch++;
if (fNeedBuffer)
{
*szRawText = ch;
if (cch == cchBuffer)
{
// Re-alloc a bigger buffer
char *pNewBuff = (char *)PvReAlloc(szRawTextStart, cchBuffer + 64);
if (!pNewBuff)
{
_ecParseError = ecNoMemory;
break;
}
cchBuffer += 64;
szRawTextStart = pNewBuff;
szRawText = szRawTextStart + cch;
}
else
szRawText++;
}
}
if (fNeedBuffer)
{
if (_ecParseError == ecNoError)
*pszRawText = szRawTextStart;
else
FreePv(szRawTextStart);
}
return cch;
}
/*
* CRTFRead::StrAlloc(ppsz, sz)
*
* @mfunc
* Set up a pointer to a newly allocated space to hold a string
*
* @rdesc
* EC The error code
*/
EC CRTFRead::StrAlloc(
WCHAR ** ppsz, //@parm Ptr to ptr to string that needs allocation
BYTE * sz) //@parm String to be copied into allocated space
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::StrAlloc");
int Length = strlen((CHAR *)sz)+1 ;
*ppsz = (WCHAR *) PvAlloc((Length + 1)*sizeof(WCHAR), 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()
*
* @mfunc
* 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(preobj)
*
* @mfunc
* Read dwFlags and dwUser bytes from a container specific stream
*
* @rdesc
* BOOL TRUE if successfully read the bytes
*/
BOOL CRTFRead::ObjectReadSiteFlags(
REOBJECT * preobj) //@parm REOBJ from where to copy flags. This preobj is
// then later put out in a site
{
return (::ObjectReadSiteFlags(preobj) == NOERROR);
}
/*
* ObjectReadEBookImageInfoFromEditStream()
*
* @mfunc
* Reads in information about the EBook Image
* At this point we don't read in the actual data
* We just get info about the dimensions of the data
*
* Added
* VikramM - esp. for e-books
*
* @rdesc
* BOOL TRUE on success, FALSE on failure.
*/
BOOL CRTFRead::ObjectReadEBookImageInfoFromEditStream()
{
HRESULT hr = E_FAIL;
BOOL fRet = FALSE;
REOBJECT reobj = { 0 };
COleObject * pObj = NULL;
LPARAM EBookID = 0;
SIZE size;
DWORD dwFlags;
CObjectMgr *ObjectMgr = _ped->GetObjectMgr();
if (! ObjectMgr)
goto Cleanup;
if(!_prtfObject->szName)
goto Cleanup;
// eBooks implies advanced layout, ensure the bit is on
_ped->OnSetTypographyOptions(TO_ADVANCEDLAYOUT, TO_ADVANCEDLAYOUT);
reobj.cbStruct = sizeof(REOBJECT);
reobj.cp = _prg->GetCp();
// Read the object size from here. The size is in Device Units
if(!_ped->fInHost2() || (_ped->GetHost())->TxEBookLoadImage(_prtfObject->szName, &EBookID, &size,&dwFlags) != S_OK )
goto Cleanup;
// For objects, xExt and yExt need to be in Twips ..
_prtfObject->xExt = size.cx;
_prtfObject->yExt = size.cy;
{
CRchTxtPtr rtp(_ped, 0);
CDisplay * pdp = _ped->_pdp;
reobj.sizel.cx = pdp->DUtoHimetricU(_prtfObject->xExt) * _prtfObject->xScale / 100;
reobj.sizel.cy = pdp->DVtoHimetricV(_prtfObject->yExt) * _prtfObject->yScale / 100;
}
// what does this do ??
reobj.dvaspect = DVASPECT_CONTENT; // OLE 1 forces DVASPECT_CONTENT
reobj.dwFlags &= ~REO_BLANK;
reobj.dwFlags |= dwFlags; //Ebook Float Flags
pObj = new COleObject(_ped);
if(!pObj)
goto Cleanup;
pObj->SetEBookImageID(EBookID);
pObj->IsEbookImage(TRUE);
pObj->SetEBookImageSizeDP(size);
reobj.polesite = pObj;
#ifndef NOINKOBJECT
if(IsEqualCLSID(reobj.clsid, CLSID_Ink))
Apply_CF();
else
#endif
_prg->Set_iCF(-1);
if(hr = ObjectMgr->InsertObject(_prg, &reobj, NULL))
goto Cleanup;
fRet = TRUE;
Cleanup:
// InsertObject AddRefs the object, so we need to release it
SafeReleaseAndNULL((IUnknown**)&pObj);
return fRet;
}
/*
* CRTFRead::ObjectReadFromStream()
*
* @mfunc
* Reads an OLE object from the RTF output stream.
*
* @rdesc
* BOOL TRUE on success, FALSE on failure.
*/
BOOL CRTFRead::ObjectReadFromEditStream()
{
BOOL fRet = FALSE;
HRESULT hr;
CObjectMgr * pObjectMgr = _ped->GetObjectMgr();
LPOLECACHE polecache = NULL;
LPRICHEDITOLECALLBACK precall=NULL;
LPENUMSTATDATA penumstatdata = NULL;
REOBJECT reobj = { 0 };
STATDATA statdata;
if(!pObjectMgr)
goto Cleanup;
precall = pObjectMgr->GetRECallback();
// If no IRichEditOleCallback exists, then fail
if (!precall)
goto Cleanup;
// AssertSz(_prtfObject->szClass,"ObFReadFromEditstream: reading unknown class");
if (_prtfObject->szClass)
CLSIDFromProgID(_prtfObject->szClass, &reobj.clsid);
// Get storage for the object from the application
if (precall->GetNewStorage(&reobj.pstg))
goto Cleanup;
hr = OleConvertOLESTREAMToIStorage((LPOLESTREAM) &RTFReadOLEStream, reobj.pstg, NULL);
if (FAILED(hr))
goto Cleanup;
// Create another object site for the new object
_ped->GetClientSite(&reobj.polesite) ;
if(!reobj.polesite)
goto Cleanup;
if(OleLoad(reobj.pstg, IID_IOleObject, reobj.polesite, (LPVOID *)&reobj.poleobj))
{
if(!reobj.polesite->Release()) // OleLoad() may AddRef reobj.polesite
reobj.polesite = NULL;
goto Cleanup;
}
CLSID clsid;
// Get the actual clsid from the object
if (reobj.poleobj->GetUserClassID(&clsid) == NOERROR)
reobj.clsid = clsid;
reobj.cbStruct = sizeof(REOBJECT);
reobj.cp = _prg->GetCp();
reobj.sizel.cx = HimetricFromTwips(_prtfObject->xExt)
* _prtfObject->xScale / 100;
reobj.sizel.cy = HimetricFromTwips(_prtfObject->yExt)
* _prtfObject->yScale / 100;
// Read any container flags which may have been previously saved
if (!ObjectReadSiteFlags(&reobj))
reobj.dwFlags = REO_RESIZABLE; // If no flags, make best guess
reobj.dvaspect = DVASPECT_CONTENT; // OLE 1 forces DVASPECT_CONTENT
// Ask the cache if it knows what to display
if (!reobj.poleobj->QueryInterface(IID_IOleCache, (void**)&polecache) &&
!polecache->EnumCache(&penumstatdata))
{
// Go look for the best cached presentation CF_METAFILEPICT
while (penumstatdata->Next(1, &statdata, NULL) == S_OK)
{
if (statdata.formatetc.cfFormat == CF_METAFILEPICT)
{
LPDATAOBJECT pdataobj = NULL;
STGMEDIUM med;
BOOL fUpdate;
ZeroMemory(&med, sizeof(STGMEDIUM));
if (!polecache->QueryInterface(IID_IDataObject, (void**)&pdataobj) &&
!pdataobj->GetData(&statdata.formatetc, &med))
{
HANDLE hGlobal = med.hGlobal;
if( FIsIconMetafilePict(hGlobal) )
{
OleStdSwitchDisplayAspect(reobj.poleobj, &reobj.dvaspect,
DVASPECT_ICON, med.hGlobal, TRUE, FALSE, NULL, &fUpdate);
}
}
ReleaseStgMedium(&med);
if (pdataobj)
pdataobj->Release();
break;
}
}
polecache->Release();
penumstatdata->Release();
}
// EVIL HACK ALERT. This code is borrowed from RichEdit 1.0; Word generates
// bogus objects, so we need to compensate.
if( reobj.dvaspect == DVASPECT_CONTENT )
{
IStream *pstm = NULL;
BYTE bT;
BOOL fUpdate;
if (!reobj.pstg->OpenStream(OLESTR("\3ObjInfo"), 0, STGM_READ |
STGM_SHARE_EXCLUSIVE, 0, &pstm) &&
!pstm->Read(&bT, sizeof(BYTE), NULL) &&
(bT & 0x40))
{
_fNeedIcon = TRUE;
_fNeedPres = TRUE;
_pobj = (COleObject *)reobj.polesite;
OleStdSwitchDisplayAspect(reobj.poleobj, &reobj.dvaspect, DVASPECT_ICON,
NULL, TRUE, FALSE, NULL, &fUpdate);
}
if( pstm )
pstm->Release();
}
// Since we are loading an object, it shouldn't be blank
reobj.dwFlags &= ~REO_BLANK;
#ifndef NOINKOBJECT
if(IsEqualCLSID(reobj.clsid, CLSID_Ink))
Apply_CF();
else
#endif
_prg->Set_iCF(-1);
hr = pObjectMgr->InsertObject(_prg, &reobj, NULL);
if(hr)
goto Cleanup;
// EVIL HACK ALERT!! Word doesn't give us objects with presenation
// caches; as a result, we can't draw them! In order to get around this,
// we check to see if there is a presentation cache (via the same way
// RE 1.0 did) using a GetExtent call. If that fails, we'll just use
// the presentation stored in the RTF.
//
// COMPATIBILITY ISSUE: RE 1.0, instead of using the presentation stored
// in RTF, would instead call IOleObject::Update. There are two _big_
// drawbacks to this approach: 1. it's incredibly expensive (potentially,
// MANY SECONDS per object), and 2. it doesn't work if the object server
// is not installed on the machine.
SIZE sizeltemp;
if( reobj.poleobj->GetExtent(reobj.dvaspect, &sizeltemp) != NOERROR )
{
_fNeedPres = TRUE;
_pobj = (COleObject *)reobj.polesite;
}
fRet = TRUE;
Cleanup:
if (reobj.pstg) reobj.pstg->Release();
if (reobj.polesite) reobj.polesite->Release();
if (reobj.poleobj) reobj.poleobj->Release();
return fRet;
}
/*
* ObHBuildMetafilePict(prtfobject, hBits)
*
* @func
* Build a METAFILEPICT from RTFOBJECT and the raw data.
*
* @rdesc
* HGLOBAL Handle to a METAFILEPICT
*/
HGLOBAL ObHBuildMetafilePict(
RTFOBJECT * prtfobject, //@parm Details we picked up from RTF
HGLOBAL hBits) //@parm Handle to the raw data
{
#ifndef NOMETAFILES
ULONG cbBits;
HGLOBAL hmfp = NULL;
LPBYTE pbBits;
LPMETAFILEPICT pmfp = NULL;
SCODE sc = E_OUTOFMEMORY;
// Allocate the METAFILEPICT structure
hmfp = GlobalAlloc(GHND, sizeof(METAFILEPICT));
if (!hmfp)
goto Cleanup;
// Lock it down
pmfp = (LPMETAFILEPICT) GlobalLock(hmfp);
if (!pmfp)
goto Cleanup;
// Put in the header information
pmfp->mm = prtfobject->sPictureType;
pmfp->xExt = prtfobject->xExt;
pmfp->yExt = prtfobject->yExt;
// Set the metafile bits
pbBits = (LPBYTE) GlobalLock(hBits);
cbBits = GlobalSize(hBits);
pmfp->hMF = SetMetaFileBitsEx(cbBits, pbBits);
// We can throw away the data now since we don't need it anymore
GlobalUnlock(hBits);
GlobalFree(hBits);
if (!pmfp->hMF)
goto Cleanup;
GlobalUnlock(hmfp);
sc = S_OK;
Cleanup:
if (sc && hmfp)
{
if (pmfp)
{
if (pmfp->hMF)
::DeleteMetaFile(pmfp->hMF);
GlobalUnlock(hmfp);
}
GlobalFree(hmfp);
hmfp = NULL;
}
TRACEERRSZSC("ObHBuildMetafilePict", sc);
return hmfp;
#else
return NULL;
#endif
}
/*
* ObHBuildBitmap(prtfobject, hBits)
*
* @func
* Build a BITMAP from RTFOBJECT and the raw data
*
* @rdesc
* HGLOBAL Handle to a BITMAP
*/
HGLOBAL ObHBuildBitmap(
RTFOBJECT * prtfobject, //@parm Details we picked up from RTF
HGLOBAL hBits) //@parm Handle to the raw data
{
HBITMAP hbm = NULL;
LPVOID pvBits = GlobalLock(hBits);
if(pvBits)
{
hbm = CreateBitmap(prtfobject->xExt, prtfobject->yExt,
prtfobject->cColorPlanes, prtfobject->cBitsPerPixel,
pvBits);
}
GlobalUnlock(hBits);
GlobalFree(hBits);
return hbm;
}
/*
* ObHBuildDib(prtfobject, hBits)
*
* @func
* Build a DIB from RTFOBJECT and the raw data
*
* @rdesc
* HGLOBAL Handle to a DIB
*/
HGLOBAL ObHBuildDib(
RTFOBJECT * prtfobject, //@parm Details we picked up from RTF
HGLOBAL hBits) //@parm Handle to the raw data
{
// Apparently DIB's are just a binary dump
return hBits;
}
/*
* CRTFRead::StaticObjectReadFromEditstream(cb)
*
* @mfunc
* Reads a picture from the RTF output stream.
*
* @rdesc
* BOOL TRUE on success, FALSE on failure.
*/
#define cbBufferMax 16384
#define cbBufferStep 1024
#define cbBufferMin 1024
BOOL CRTFRead::StaticObjectReadFromEditStream(
int cb) //@parm Count of bytes to read
{
LONG cbBuffer;
LONG cbRead;
DWORD dwAdvf;
DWORD dwConn;
BOOL fBackground = _pstateStackTop && _pstateStackTop->fBackground;
FORMATETC formatetc;
BOOL fRet = FALSE;
HGLOBAL hBits = NULL;
HRESULT hr = E_FAIL;
LPBYTE pbBuffer = NULL;
CDocInfo * pDocInfo = _ped->GetDocInfoNC();
CObjectMgr *pObjectMgr = _ped->GetObjectMgr();
LPOLECACHE polecache = NULL;
LPPERSISTSTORAGE pperstg = NULL;
LPRICHEDITOLECALLBACK precall;
LPSTREAM pstm = NULL;
REOBJECT reobj = { 0 };
STGMEDIUM stgmedium;
HGLOBAL (*pfnBuildPict)(RTFOBJECT *, HGLOBAL) = NULL;
if(!pObjectMgr)
goto Cleanup;
// precall may end up being null (e.g. Windows CE).
precall = pObjectMgr->GetRECallback();
// Initialize various data structures
formatetc.ptd = NULL;
formatetc.dwAspect = DVASPECT_CONTENT;
formatetc.lindex = -1;
formatetc.tymed = TYMED_NULL;
switch (_prtfObject->sType)
{
case ROT_Metafile:
reobj.clsid = CLSID_StaticMetafile;
formatetc.cfFormat = CF_METAFILEPICT;
formatetc.tymed = TYMED_MFPICT;
pfnBuildPict = ObHBuildMetafilePict;
break;
case ROT_Bitmap:
reobj.clsid = CLSID_StaticDib;
formatetc.cfFormat = CF_BITMAP;
formatetc.tymed = TYMED_GDI;
pfnBuildPict = ObHBuildBitmap;
break;
case ROT_DIB:
reobj.clsid = CLSID_StaticDib;
formatetc.cfFormat = CF_DIB;
formatetc.tymed = TYMED_HGLOBAL;
pfnBuildPict = ObHBuildDib;
break;
case ROT_PNG:
case ROT_JPEG:
// We convert these types of pictures to a bitmap
reobj.clsid = CLSID_StaticDib;
formatetc.cfFormat = CF_BITMAP;
formatetc.tymed = TYMED_GDI;
break;
}
reobj.sizel.cx = (LONG) HimetricFromTwips(_prtfObject->xExtGoal)
* _prtfObject->xScale / 100;
reobj.sizel.cy = (LONG) HimetricFromTwips(_prtfObject->yExtGoal)
* _prtfObject->yScale / 100;
stgmedium.tymed = formatetc.tymed;
stgmedium.pUnkForRelease = NULL;
if (precall)
{
if( !_fNeedPres )
{
// Get storage for the object from the application
if (precall->GetNewStorage(&reobj.pstg))
goto Cleanup;
}
// Let's create a stream on HGLOBAL
if (hr = CreateStreamOnHGlobal(NULL, FALSE, &pstm))
goto Cleanup;
// Allocate a buffer, preferably a big one
for (cbBuffer = cbBufferMax;
cbBuffer >= cbBufferMin;
cbBuffer -= cbBufferStep)
{
pbBuffer = (unsigned char *)PvAlloc(cbBuffer, 0);
if (pbBuffer)
break;
}
}
else
{
cbBuffer = cb;
if(!cb)
{
// This means we didn't understand the picture type; so just
// skip it without failing.
fRet = TRUE;
goto Cleanup;
}
hBits = GlobalAlloc(GMEM_FIXED, cb);
pbBuffer = (BYTE *) GlobalLock(hBits);
}
if (!pbBuffer)
goto Cleanup;
// Copy the data from RTF into our HGLOBAL
while ((cbRead = RTFReadOLEStream.lpstbl->Get(&RTFReadOLEStream,pbBuffer,cbBuffer)) > 0)
{
if (_ecParseError != ecNoError)
goto Cleanup;
if(pstm)
{
hr = pstm->Write(pbBuffer, cbRead, NULL);
if(hr != NOERROR)
{
TRACEERRSZSC("ObFReadStaticFromEditstream: Write", GetScode(hr));
goto Cleanup;
}
}
}
if (hBits)
{
Assert(!precall);
GlobalUnlock(hBits);
pbBuffer = NULL; // To avoid free below
}
if (pstm && (hr = GetHGlobalFromStream(pstm, &hBits)))
{
TRACEERRSZSC("ObFReadStaticFromEditstream: no hglobal from stm", GetScode(hr));
goto Cleanup;
}
if(pDocInfo && fBackground)
{
pDocInfo->_bPicFormat = (BYTE)_prtfObject->sType;
pDocInfo->_bPicFormatParm = (BYTE)_prtfObject->sPictureType;
pDocInfo->_xExt = _prtfObject->xExt;
pDocInfo->_yExt = _prtfObject->yExt;
pDocInfo->_xScale = _prtfObject->xScale;
pDocInfo->_yScale = _prtfObject->yScale;
pDocInfo->_xExtGoal = _prtfObject->xExtGoal;
pDocInfo->_yExtGoal = _prtfObject->yExtGoal;
pDocInfo->_xExtPict = _prtfObject->xExtPict;
pDocInfo->_yExtPict = _prtfObject->yExtPict;
pDocInfo->_rcCrop = _prtfObject->rectCrop;
pDocInfo->_hdata = hBits;
}
// Build the picture
if(_prtfObject->sType == ROT_JPEG || _prtfObject->sType == ROT_PNG)
{
HBITMAP hbmp = W32->GetPictureBitmap(pstm);
if (!hbmp)
{
hr = E_FAIL;
goto Cleanup;
}
stgmedium.hGlobal = hbmp;
}
else if( pfnBuildPict )
stgmedium.hGlobal = pfnBuildPict(_prtfObject, hBits);
else
{
// This means we didn't understand the picture type; so just
// skip it without failing.
fRet = TRUE;
goto Cleanup;
}
if( precall )
{
if(!stgmedium.hGlobal)
goto Cleanup;
if( !_fNeedPres )
{
// Create the default handler
hr = OleCreateDefaultHandler(reobj.clsid, NULL, IID_IOleObject, (void **)&reobj.poleobj);
if (hr)
{
TRACEERRSZSC("ObFReadStaticFromEditstream: no def handler", GetScode(hr));
goto Cleanup;
}
// Get the IPersistStorage and initialize it
if ((hr = reobj.poleobj->QueryInterface(IID_IPersistStorage,(void **)&pperstg)) ||
(hr = pperstg->InitNew(reobj.pstg)))
{
TRACEERRSZSC("ObFReadStaticFromEditstream: InitNew", GetScode(hr));
goto Cleanup;
}
dwAdvf = ADVF_PRIMEFIRST;
}
else
{
Assert(_pobj);
_pobj->GetIUnknown()->QueryInterface(IID_IOleObject, (void **)&(reobj.poleobj));
dwAdvf = ADVF_NODATA;
formatetc.dwAspect = _fNeedIcon ? DVASPECT_ICON : DVASPECT_CONTENT;
}
// Get the IOleCache and put the picture data there
if (hr = reobj.poleobj->QueryInterface(IID_IOleCache,(void **)&polecache))
{
TRACEERRSZSC("ObFReadStaticFromEditstream: QI: IOleCache", GetScode(hr));
goto Cleanup;
}
if (FAILED(hr = polecache->Cache(&formatetc, dwAdvf, &dwConn)))
{
TRACEERRSZSC("ObFReadStaticFromEditstream: Cache", GetScode(hr));
goto Cleanup;
}
if (hr = polecache->SetData(&formatetc, &stgmedium, TRUE))
{
TRACEERRSZSC("ObFReadStaticFromEditstream: SetData", GetScode(hr));
goto Cleanup;
}
}
if( !_fNeedPres )
{
// Create another object site for the new object
_ped->GetClientSite(&reobj.polesite);
if (!reobj.polesite )
goto Cleanup;
// Set the client site
if (reobj.poleobj && (hr = reobj.poleobj->SetClientSite(reobj.polesite)))
{
TRACEERRSZSC("ObFReadStaticFromEditstream: SetClientSite", GetScode(hr));
goto Cleanup;
}
else if (!reobj.poleobj)
{
if(_prtfObject->sType == ROT_DIB)
{
// Windows CE static object Save the data and mark it.
COleObject *pobj = (COleObject *)reobj.polesite;
COleObject::ImageInfo *pimageinfo = new COleObject::ImageInfo;
pobj->SetHdata(hBits);
pimageinfo->xScale = _prtfObject->xScale;
pimageinfo->yScale = _prtfObject->yScale;
pimageinfo->xExtGoal = _prtfObject->xExtGoal;
pimageinfo->yExtGoal = _prtfObject->yExtGoal;
pimageinfo->cBytesPerLine = _prtfObject->cBytesPerLine;
pobj->SetImageInfo(pimageinfo);
}
else
goto Cleanup; // There has been a mistake
}
// Put object into the edit control
reobj.cbStruct = sizeof(REOBJECT);
reobj.cp = _prg->GetCp();
reobj.dvaspect = DVASPECT_CONTENT;
reobj.dwFlags = fBackground ? REO_RESIZABLE | REO_USEASBACKGROUND
: REO_RESIZABLE;
// Since we are loading an object, it shouldn't be blank
reobj.dwFlags &= ~REO_BLANK;
if(_pstateStackTop->fShape && _ped->fUseObjectWrapping())
reobj.dwFlags |= _dwFlagsShape;
#ifndef NOINKOBJECT
if(IsEqualCLSID(reobj.clsid, CLSID_Ink))
Apply_CF();
else
#endif
_prg->Set_iCF(-1);
hr = pObjectMgr->InsertObject(_prg, &reobj, NULL);
if(hr)
goto Cleanup;
}
else
{
// The new presentation may have a different idea about how big the
// object is supposed to be. Make sure the object stays the correct
// size.
_pobj->ResetSize((SIZEUV&)reobj.sizel);
}
fRet = TRUE;
Cleanup:
// Do not display backgrounds.
if(pDocInfo && fBackground)
pDocInfo->_nFillType=-1;
if (polecache) polecache->Release() ;
if (reobj.pstg) reobj.pstg->Release();
if (reobj.polesite) reobj.polesite->Release();
if (reobj.poleobj) reobj.poleobj->Release();
if (pperstg) pperstg->Release();
if (pstm) pstm->Release();
FreePv(pbBuffer);
_fNeedIcon = FALSE;
_fNeedPres = FALSE;
_pobj = NULL;
return fRet;
}
/*
* CRTFRead::HandleSTextFlow(mode)
*
* @mfunc
* Handle STextFlow setting.
*/
void CRTFRead::HandleSTextFlow(
int mode) //@parm TextFlow mode
{
static BYTE bTFlow[9] = // Rotate @Font
{ 0, // 0 0
tflowSW | 0x80, // 270 1
tflowNE, // 90 0
tflowSW, // 270 0
0x80, // 0 1
0, // ?
tflowNE | 0x80, // 90 1
tflowWN | 0x80, // 180 1
tflowWN // 180 0
};
if (IN_RANGE(0, mode, 8))
{
_ped->_fUseAtFont = bTFlow[mode] >> 7;
_ped->_pdp->SetTflow(bTFlow[mode] & 0x03);
}
}