/* * 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); } }