windows-nt/Source/XPSP1/NT/windows/richedit/re30/rtfread2.cpp
2020-09-26 16:20:57 +08:00

1098 lines
25 KiB
C++

/*
* 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-1997, Microsoft Corporation. All rights reserved.
*/
#include "_common.h"
#include "_rtfread.h"
#include "_coleobj.h"
//#include "_nlsprcs.h"
const char szFontsel[]="\\f";
ASSERTDATA
/*
* CRTFRead::HandleFieldInstruction()
*
* @mfunc
* Handle field instruction
*
* @rdesc
* EC The error code
*/
EC CRTFRead::HandleFieldInstruction()
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldInstruction");
//TODO rewrite this function for common case
//FUTURE save field instruction
BYTE *pch, *pch1;
for(pch1 = _szText; *pch1 == ' '; pch1++) // Bypass any leading blanks
;
for(pch = pch1; *pch && *pch != ' '; pch++)
;
_fHyperlinkField = FALSE;
if(W32->ASCIICompareI(pch1, (BYTE *) "SYMBOL", 6))
HandleFieldSymbolInstruction(pch); // SYMBOL
else if (W32->ASCIICompareI(pch1, (BYTE *) "HYPERLINK", 9))
{
_fHyperlinkField = TRUE;
HandleFieldHyperlink(pch);
}
// save the current formatting for the field result
_FieldCF = _CF;
_ptfField = _pstateStackTop->ptf;
_nFieldCodePage = _pstateStackTop->nCodePage;
_dwMaskFieldCF = _dwMaskCF;
_dwMaskFieldCF2 = _dwMaskCF2;
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).
*/
EC CRTFRead::HandleFieldSymbolInstruction(
BYTE *pch ) //@parm Pointer to SYMBOL field instruction
{
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;
}
}
_szSymbolFieldResult = (BYTE *)PvAlloc(2, GMEM_ZEROINIT);
if (NULL == _szSymbolFieldResult)
{
_ecParseError = ecNoMemory;
goto CleanUp;
}
_szSymbolFieldResult[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"
}
// ASSERTION font & font size will be in field result \flds
// BUGBUG: A more robust implementation would parse the font
// and font size from both \fldinst and \fldrslt (RE1.0 does this)
CleanUp:
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->bCharSet = DEFAULT_CHARSET; // SYMBOL_CHARSET ??
}
SelectCurrentFont(i);
exit:
// needs to go back to normal
_szText = szTextBAK;
return _ecParseError;
}
/*
* CRTFRead::HandleFieldHyperlink(pch)
*
* @mfunc
* Handle HYPERLINK field
*
* @rdesc
* EC The error code
*/
EC CRTFRead::HandleFieldHyperlink(
BYTE *pch) //@parm Pointer to HYPERLINK field instruction
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldHyperlink");
BYTE *pBuffer;
for( ; *pch == ' '; pch++) ; // Skip leading blanks
// allocate the buffer and add the string to it
_cchHyperlinkFldinst = MAX_PATH;
_cchHyperlinkFldinstUsed = 1;
pBuffer = (BYTE *)PvAlloc( MAX_PATH, GMEM_FIXED );
if ( !pBuffer )
return ( _ecParseError = ecNoMemory );
pBuffer[0] = ' ';
pBuffer[1] = '\0';
_szHyperlinkFldinst = pBuffer;
if ( *pch )
{
_ecParseError = AppendString( &_szHyperlinkFldinst, pch, &_cchHyperlinkFldinst, &_cchHyperlinkFldinstUsed );
}
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)
{
*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 ; 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)
;
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 noice 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(
TCHAR ** 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 = (TCHAR *) PvAlloc((Length + 1)*sizeof(TCHAR), 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);
}
/*
* CRTFRead::ObjectReadFromStream()
*
* @mfunc
* Reads an OLE object from the RTF output stream.
*
* @rdesc
* BOOL TRUE on success, FALSE on failure.
*/
BOOL CRTFRead::ObjectReadFromEditStream()
{
WCHAR ch = WCH_EMBEDDING;
BOOL fGotClsid = TRUE;
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");
//$ REVIEW: MAC This call is incorrect for the Mac. It may not matter though
// if ole support in RichEdit is not needed for the Mac.
if (!(_prtfObject->szClass &&
CLSIDFromProgID(_prtfObject->szClass, &reobj.clsid) == NOERROR))
{
fGotClsid = FALSE;
}
// 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 ||
OleLoad(reobj.pstg, IID_IOleObject, reobj.polesite,
(LPVOID *) &reobj.poleobj))
{
goto Cleanup;
}
if(!fGotClsid)
{
// We weren't able to obtain a clsid from the progid
// in the \objclass RTF tag
reobj.poleobj->GetUserClassID(&reobj.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 RichEdit1.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;
_prg->Set_iCF(-1);
_prg->ReplaceRange(1, &ch, NULL, SELRR_IGNORE);
hr = pObjectMgr->InsertObject(reobj.cp, &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
// RE1.0 did) using a GetExtent call. If that fails, we'll just use
// the presentation stored in the RTF.
//
// COMPATIBILITY ISSUE: RE1.0, instead of using the presenation 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;
WCHAR ch = WCH_EMBEDDING;
DWORD dwAdvf;
DWORD dwConn;
FORMATETC formatetc;
BOOL fRet = FALSE;
HGLOBAL hBits = NULL;
HRESULT hr;
CObjectMgr *pObjectMgr = _ped->GetObjectMgr();
LPPERSISTSTORAGE pperstg = NULL;
LPOLECACHE polecache = NULL;
REOBJECT reobj = { 0 };
LPBYTE pbBuffer = NULL;
LPSTREAM pstm = NULL;
STGMEDIUM stgmedium;
HGLOBAL (*pfnBuildPict)(RTFOBJECT *, HGLOBAL) = NULL;
LPRICHEDITOLECALLBACK precall ;
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;
}
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 (pstm && (hr = pstm->Write( pbBuffer, cbRead, NULL)))
{
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;
}
// Build the picture
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 && !stgmedium.hGlobal )
goto Cleanup;
if( precall )
{
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 = REO_RESIZABLE;
// Since we are loading an object, it shouldn't be blank
reobj.dwFlags &= ~REO_BLANK;
_prg->Set_iCF(-1);
_prg->ReplaceRange(1, &ch, NULL, SELRR_IGNORE);
hr = pObjectMgr->InsertObject(reobj.cp, &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->ResetSizel(reobj.sizel);
}
fRet = TRUE;
Cleanup:
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;
}