1098 lines
25 KiB
C++
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;
|
|
}
|