Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1097 lines
25 KiB

  1. /*
  2. * rtfread2.cpp
  3. *
  4. * Description:
  5. * This file contains the object functions for RichEdit RTF reader
  6. *
  7. * Original RichEdit 1.0 RTF converter: Anthony Francisco
  8. * Conversion to C++ and RichEdit 2.0: Murray Sargent
  9. *
  10. * * NOTE:
  11. * * All sz's in the RTF*.? files refer to a LPSTRs, not LPTSTRs, unless
  12. * * noted as a szW.
  13. *
  14. * Copyright (c) 1995-1997, Microsoft Corporation. All rights reserved.
  15. */
  16. #include "_common.h"
  17. #include "_rtfread.h"
  18. #include "_coleobj.h"
  19. //#include "_nlsprcs.h"
  20. const char szFontsel[]="\\f";
  21. ASSERTDATA
  22. /*
  23. * CRTFRead::HandleFieldInstruction()
  24. *
  25. * @mfunc
  26. * Handle field instruction
  27. *
  28. * @rdesc
  29. * EC The error code
  30. */
  31. EC CRTFRead::HandleFieldInstruction()
  32. {
  33. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldInstruction");
  34. //TODO rewrite this function for common case
  35. //FUTURE save field instruction
  36. BYTE *pch, *pch1;
  37. for(pch1 = _szText; *pch1 == ' '; pch1++) // Bypass any leading blanks
  38. ;
  39. for(pch = pch1; *pch && *pch != ' '; pch++)
  40. ;
  41. _fHyperlinkField = FALSE;
  42. if(W32->ASCIICompareI(pch1, (BYTE *) "SYMBOL", 6))
  43. HandleFieldSymbolInstruction(pch); // SYMBOL
  44. else if (W32->ASCIICompareI(pch1, (BYTE *) "HYPERLINK", 9))
  45. {
  46. _fHyperlinkField = TRUE;
  47. HandleFieldHyperlink(pch);
  48. }
  49. // save the current formatting for the field result
  50. _FieldCF = _CF;
  51. _ptfField = _pstateStackTop->ptf;
  52. _nFieldCodePage = _pstateStackTop->nCodePage;
  53. _dwMaskFieldCF = _dwMaskCF;
  54. _dwMaskFieldCF2 = _dwMaskCF2;
  55. TRACEERRSZSC("HandleFieldInstruction()", - _ecParseError);
  56. return _ecParseError;
  57. }
  58. /*
  59. * CRTFRead::HandleFieldSymbolInstruction(pch)
  60. *
  61. * @mfunc
  62. * Handle specific symbol field
  63. *
  64. * @rdesc
  65. * EC The error code
  66. *
  67. * @devnote
  68. * FUTURE: the two whiles below can be combined into one fairly easily;
  69. * Look at the definitions of IsXDigit() and IsDigit() and introduce
  70. * a variable flag as well as a variable base multiplier (= 10 or 16).
  71. */
  72. EC CRTFRead::HandleFieldSymbolInstruction(
  73. BYTE *pch ) //@parm Pointer to SYMBOL field instruction
  74. {
  75. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldInstruction");
  76. BYTE ch;
  77. BYTE chSymbol = 0;
  78. const char *pchFontsel = szFontsel;
  79. while (*pch == ' ') // Eat spaces
  80. ++pch;
  81. // Collect symbol char's code
  82. if (*pch == '0' && // which may be in decimal
  83. (*++pch | ' ') == 'x') // or hex
  84. { // It's in hex
  85. ch = *++pch;
  86. while (ch && IsXDigit(ch))
  87. {
  88. chSymbol <<= 4;
  89. chSymbol += (ch <= '9') ? ch - '0' : (ch & 0x4f) - 'A' + 10;
  90. ch = *pch++;
  91. }
  92. }
  93. else // Decimal
  94. {
  95. ch = *pch;
  96. while (ch && IsDigit(ch))
  97. {
  98. chSymbol *= 10;
  99. chSymbol += ch - '0' ;
  100. ch = *++pch;
  101. }
  102. }
  103. _szSymbolFieldResult = (BYTE *)PvAlloc(2, GMEM_ZEROINIT);
  104. if (NULL == _szSymbolFieldResult)
  105. {
  106. _ecParseError = ecNoMemory;
  107. goto CleanUp;
  108. }
  109. _szSymbolFieldResult[0] = chSymbol;
  110. // now check for the \\f "Facename" construct
  111. // and deal with it
  112. while (*pch == ' ') // Eat spaces
  113. ++pch;
  114. while (*pch && *pch == *pchFontsel) // Make sure *pch is a \f
  115. {
  116. ++pch;
  117. ++pchFontsel;
  118. }
  119. if (! (*pchFontsel) )
  120. {
  121. _ecParseError = HandleFieldSymbolFont(pch); // \\f "Facename"
  122. }
  123. // ASSERTION font & font size will be in field result \flds
  124. // BUGBUG: A more robust implementation would parse the font
  125. // and font size from both \fldinst and \fldrslt (RE1.0 does this)
  126. CleanUp:
  127. TRACEERRSZSC("HandleFieldInstruction()", - _ecParseError);
  128. return _ecParseError;
  129. }
  130. /*
  131. * CRTFRead::HandleFieldSymbolFont(pch)
  132. *
  133. * @mfunc
  134. * Handle the \\f "Facename" instruction in the SYMBOL field
  135. *
  136. * @rdesc
  137. * EC The error code
  138. *
  139. * @devnote WARNING: may change _szText
  140. */
  141. EC CRTFRead::HandleFieldSymbolFont(
  142. BYTE *pch) //@parm Ptr to symbol field
  143. {
  144. SHORT iFont = _fonts.Count();
  145. TEXTFONT tf;
  146. TEXTFONT *ptf = &tf;
  147. _pstateStackTop->ptf = &tf;
  148. // ReadFontName tries to append
  149. tf.szName[0] = '\0';
  150. // skip the initial blanks and quotes
  151. while (*pch && (*pch == ' ' || *pch == '\"'))
  152. ++pch;
  153. // DONT WORRY, we'll get it back to normal
  154. // ReadFontName depends on _szText, so we need to alter it and then restore
  155. // it's just too bad we have to do it ...
  156. BYTE* szTextBAK = _szText;
  157. BOOL fAllAscii = TRUE;
  158. _szText = pch;
  159. // transform the trailing quote into ';'
  160. while (*pch)
  161. {
  162. if (*pch == '\"')
  163. {
  164. *pch = ';';
  165. break;
  166. }
  167. if(*pch > 0x7f)
  168. fAllAscii = FALSE;
  169. ++pch;
  170. }
  171. // NOW we can read the font name!!
  172. ReadFontName(_pstateStackTop, fAllAscii ? ALL_ASCII : CONTAINS_NONASCII);
  173. // Try to find this face name in the font table
  174. BOOL fFontFound = FALSE;
  175. for (SHORT i = 0; i < iFont; ++i)
  176. {
  177. TEXTFONT *ptfTab = _fonts.Elem(i);
  178. if (0 == wcscmp(ptf->szName, ptfTab->szName))
  179. {
  180. fFontFound = TRUE;
  181. i = ptfTab->sHandle;
  182. break;
  183. }
  184. }
  185. // did we find the face name?
  186. if (!fFontFound)
  187. {
  188. Assert(i == iFont);
  189. i+= RESERVED_FONT_HANDLES;
  190. // Make room in font table for
  191. // font to be inserted
  192. if (!(ptf =_fonts.Add(1,NULL)))
  193. {
  194. _ped->GetCallMgr()->SetOutOfMemory();
  195. _ecParseError = ecNoMemory;
  196. goto exit;
  197. }
  198. // repeating inits from tokenFontSelect
  199. ptf->sHandle = i; // Save handle
  200. wcscpy(ptf->szName, tf.szName);
  201. ptf->bPitchAndFamily = 0;
  202. ptf->fNameIsDBCS = FALSE;
  203. ptf->sCodePage = (SHORT)_nCodePage;
  204. ptf->bCharSet = DEFAULT_CHARSET; // SYMBOL_CHARSET ??
  205. }
  206. SelectCurrentFont(i);
  207. exit:
  208. // needs to go back to normal
  209. _szText = szTextBAK;
  210. return _ecParseError;
  211. }
  212. /*
  213. * CRTFRead::HandleFieldHyperlink(pch)
  214. *
  215. * @mfunc
  216. * Handle HYPERLINK field
  217. *
  218. * @rdesc
  219. * EC The error code
  220. */
  221. EC CRTFRead::HandleFieldHyperlink(
  222. BYTE *pch) //@parm Pointer to HYPERLINK field instruction
  223. {
  224. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::HandleFieldHyperlink");
  225. BYTE *pBuffer;
  226. for( ; *pch == ' '; pch++) ; // Skip leading blanks
  227. // allocate the buffer and add the string to it
  228. _cchHyperlinkFldinst = MAX_PATH;
  229. _cchHyperlinkFldinstUsed = 1;
  230. pBuffer = (BYTE *)PvAlloc( MAX_PATH, GMEM_FIXED );
  231. if ( !pBuffer )
  232. return ( _ecParseError = ecNoMemory );
  233. pBuffer[0] = ' ';
  234. pBuffer[1] = '\0';
  235. _szHyperlinkFldinst = pBuffer;
  236. if ( *pch )
  237. {
  238. _ecParseError = AppendString( &_szHyperlinkFldinst, pch, &_cchHyperlinkFldinst, &_cchHyperlinkFldinstUsed );
  239. }
  240. return _ecParseError;
  241. }
  242. /*
  243. * CRTFRead::ReadData(pbBuffer, cbBuffer)
  244. *
  245. * @mfunc
  246. * Read in object data. This must be called only after all initial
  247. * object header info has been read.
  248. *
  249. * @rdesc
  250. * LONG count of bytes read in
  251. */
  252. LONG CRTFRead::ReadData(
  253. BYTE * pbBuffer, //@parm Ptr to buffer where to put data
  254. LONG cbBuffer) //@parm How many bytes to read in
  255. {
  256. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::ReadData");
  257. BYTE bChar0, bChar1;
  258. LONG cbLeft = cbBuffer;
  259. while (cbLeft && (bChar0 = GetHexSkipCRLF()) < 16 &&
  260. (bChar1 = GetHexSkipCRLF()) < 16)
  261. {
  262. *pbBuffer++ = bChar0 << 4 | bChar1;
  263. cbLeft--;
  264. }
  265. return cbBuffer - cbLeft ;
  266. }
  267. /*
  268. * CRTFRead::ReadBinaryData(pbBuffer, cbBuffer)
  269. *
  270. * @mfunc
  271. * Read cbBuffer bytes into pbBuffer
  272. *
  273. * @rdesc
  274. * Count of bytes read in
  275. */
  276. LONG CRTFRead::ReadBinaryData(
  277. BYTE * pbBuffer, //@parm Ptr to buffer where to put data
  278. LONG cbBuffer) //@parm How many bytes to read in
  279. {
  280. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::ReadBinaryData");
  281. LONG cbLeft = min(_cbBinLeft, cbBuffer);
  282. cbBuffer = cbLeft;
  283. for (; cbLeft > 0 ; cbLeft--)
  284. {
  285. *pbBuffer++ = GetChar();
  286. }
  287. _cbBinLeft -= cbBuffer;
  288. return cbBuffer ;
  289. }
  290. /*
  291. * CRTFRead::SkipBinaryData(cbSkip)
  292. *
  293. * @mfunc
  294. * Skip cbSkip bytes in input streamd
  295. *
  296. * @rdesc
  297. * LONG count of bytes skipped
  298. */
  299. LONG CRTFRead::SkipBinaryData(
  300. LONG cbSkip) //@parm Count of bytes to skip
  301. {
  302. BYTE rgb[1024];
  303. _cbBinLeft = cbSkip;
  304. while(ReadBinaryData(rgb, sizeof(rgb)) > 0)
  305. ;
  306. return cbSkip;
  307. }
  308. /*
  309. * CRTFRead::ReadRawText(pszRawText)
  310. *
  311. * @mfunc
  312. * Read in raw text until }. A buffer is allocated to save the text.
  313. * The caller is responsible to free the buffer later.
  314. *
  315. * @rdesc
  316. * LONG count of bytes read
  317. */
  318. LONG CRTFRead::ReadRawText(
  319. char **pszRawText) //@parm Address of the buffer containing the raw text
  320. {
  321. LONG cch=0;
  322. char *szRawTextStart = NULL;
  323. char *szRawText = NULL;
  324. char chLast=0;
  325. char ch;
  326. short cRBrace=0;
  327. LONG cchBuffer = 0;
  328. bool fNeedBuffer = (pszRawText != NULL);
  329. if (fNeedBuffer)
  330. {
  331. *pszRawText = NULL;
  332. cchBuffer = 128;
  333. szRawText = szRawTextStart = (char *)PvAlloc(128, GMEM_ZEROINIT);
  334. if(!szRawTextStart)
  335. {
  336. _ecParseError = ecNoMemory;
  337. return 0;
  338. }
  339. }
  340. while (_ecParseError == ecNoError)
  341. {
  342. ch = GetChar();
  343. if (ch == 0)
  344. break; // error case
  345. if (ch == LF || ch == CR)
  346. continue; // ignore noice characters
  347. if (ch == '}' && chLast != '\\')
  348. {
  349. if (!cRBrace)
  350. {
  351. // Done
  352. UngetChar();
  353. if (fNeedBuffer)
  354. *szRawText = '\0';
  355. break;
  356. }
  357. cRBrace--; // count the RBrace so we will ignore the matching pair of LBrace
  358. }
  359. if (ch == '{' && chLast != '\\')
  360. cRBrace++;
  361. chLast = ch;
  362. cch++;
  363. if (fNeedBuffer)
  364. {
  365. *szRawText = ch;
  366. if (cch == cchBuffer)
  367. {
  368. // Re-alloc a bigger buffer
  369. char *pNewBuff = (char *)PvReAlloc(szRawTextStart, cchBuffer + 64);
  370. if (!pNewBuff)
  371. {
  372. _ecParseError = ecNoMemory;
  373. break;
  374. }
  375. cchBuffer += 64;
  376. szRawTextStart = pNewBuff;
  377. szRawText = szRawTextStart + cch;
  378. }
  379. else
  380. szRawText++;
  381. }
  382. }
  383. if (fNeedBuffer)
  384. {
  385. if (_ecParseError == ecNoError)
  386. *pszRawText = szRawTextStart;
  387. else
  388. FreePv(szRawTextStart);
  389. }
  390. return cch;
  391. }
  392. /*
  393. * CRTFRead::StrAlloc(ppsz, sz)
  394. *
  395. * @mfunc
  396. * Set up a pointer to a newly allocated space to hold a string
  397. *
  398. * @rdesc
  399. * EC The error code
  400. */
  401. EC CRTFRead::StrAlloc(
  402. TCHAR ** ppsz, //@parm Ptr to ptr to string that needs allocation
  403. BYTE * sz) //@parm String to be copied into allocated space
  404. {
  405. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::StrAlloc");
  406. int Length = strlen((CHAR *)sz)+1 ;
  407. *ppsz = (TCHAR *) PvAlloc((Length + 1)*sizeof(TCHAR), GMEM_ZEROINIT);
  408. if (!*ppsz)
  409. {
  410. _ped->GetCallMgr()->SetOutOfMemory();
  411. _ecParseError = ecNoMemory;
  412. goto Quit;
  413. }
  414. MultiByteToWideChar(CP_ACP,0,(char *)sz,-1,*ppsz,Length) ;
  415. Quit:
  416. return _ecParseError;
  417. }
  418. /*
  419. * CRTFRead::FreeRtfObject()
  420. *
  421. * @mfunc
  422. * Cleans up memory used by prtfobject
  423. */
  424. void CRTFRead::FreeRtfObject()
  425. {
  426. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CRTFRead::FreeRtfObject");
  427. if (_prtfObject)
  428. {
  429. FreePv(_prtfObject->szClass);
  430. FreePv(_prtfObject->szName);
  431. FreePv(_prtfObject);
  432. _prtfObject = NULL;
  433. }
  434. }
  435. /*
  436. * CRTFRead::ObjectReadSiteFlags(preobj)
  437. *
  438. * @mfunc
  439. * Read dwFlags and dwUser bytes from a container specific stream
  440. *
  441. * @rdesc
  442. * BOOL TRUE if successfully read the bytes
  443. */
  444. BOOL CRTFRead::ObjectReadSiteFlags(
  445. REOBJECT * preobj) //@parm REOBJ from where to copy flags. This preobj is
  446. // then later put out in a site
  447. {
  448. return (::ObjectReadSiteFlags(preobj) == NOERROR);
  449. }
  450. /*
  451. * CRTFRead::ObjectReadFromStream()
  452. *
  453. * @mfunc
  454. * Reads an OLE object from the RTF output stream.
  455. *
  456. * @rdesc
  457. * BOOL TRUE on success, FALSE on failure.
  458. */
  459. BOOL CRTFRead::ObjectReadFromEditStream()
  460. {
  461. WCHAR ch = WCH_EMBEDDING;
  462. BOOL fGotClsid = TRUE;
  463. BOOL fRet = FALSE;
  464. HRESULT hr;
  465. CObjectMgr * pObjectMgr = _ped->GetObjectMgr();
  466. LPOLECACHE polecache = NULL;
  467. LPRICHEDITOLECALLBACK precall=NULL;
  468. LPENUMSTATDATA penumstatdata = NULL;
  469. REOBJECT reobj = { 0 };
  470. STATDATA statdata;
  471. if(!pObjectMgr)
  472. goto Cleanup;
  473. precall = pObjectMgr->GetRECallback();
  474. // If no IRichEditOleCallback exists, then fail
  475. if (!precall)
  476. goto Cleanup;
  477. // AssertSz(_prtfObject->szClass,"ObFReadFromEditstream: reading unknown class");
  478. //$ REVIEW: MAC This call is incorrect for the Mac. It may not matter though
  479. // if ole support in RichEdit is not needed for the Mac.
  480. if (!(_prtfObject->szClass &&
  481. CLSIDFromProgID(_prtfObject->szClass, &reobj.clsid) == NOERROR))
  482. {
  483. fGotClsid = FALSE;
  484. }
  485. // Get storage for the object from the application
  486. if (precall->GetNewStorage(&reobj.pstg))
  487. goto Cleanup;
  488. hr = OleConvertOLESTREAMToIStorage((LPOLESTREAM) &RTFReadOLEStream, reobj.pstg, NULL);
  489. if (FAILED(hr))
  490. goto Cleanup;
  491. // Create another object site for the new object
  492. _ped->GetClientSite(&reobj.polesite) ;
  493. if (!reobj.polesite ||
  494. OleLoad(reobj.pstg, IID_IOleObject, reobj.polesite,
  495. (LPVOID *) &reobj.poleobj))
  496. {
  497. goto Cleanup;
  498. }
  499. if(!fGotClsid)
  500. {
  501. // We weren't able to obtain a clsid from the progid
  502. // in the \objclass RTF tag
  503. reobj.poleobj->GetUserClassID(&reobj.clsid);
  504. }
  505. reobj.cbStruct = sizeof(REOBJECT);
  506. reobj.cp = _prg->GetCp();
  507. reobj.sizel.cx = HimetricFromTwips(_prtfObject->xExt)
  508. * _prtfObject->xScale / 100;
  509. reobj.sizel.cy = HimetricFromTwips(_prtfObject->yExt)
  510. * _prtfObject->yScale / 100;
  511. // Read any container flags which may have been previously saved
  512. if (!ObjectReadSiteFlags(&reobj))
  513. reobj.dwFlags = REO_RESIZABLE; // If no flags, make best guess
  514. reobj.dvaspect = DVASPECT_CONTENT; // OLE 1 forces DVASPECT_CONTENT
  515. // Ask the cache if it knows what to display
  516. if (!reobj.poleobj->QueryInterface(IID_IOleCache, (void**)&polecache) &&
  517. !polecache->EnumCache(&penumstatdata))
  518. {
  519. // Go look for the best cached presentation CF_METAFILEPICT
  520. while (penumstatdata->Next(1, &statdata, NULL) == S_OK)
  521. {
  522. if (statdata.formatetc.cfFormat == CF_METAFILEPICT)
  523. {
  524. LPDATAOBJECT pdataobj = NULL;
  525. STGMEDIUM med;
  526. BOOL fUpdate;
  527. ZeroMemory(&med, sizeof(STGMEDIUM));
  528. if (!polecache->QueryInterface(IID_IDataObject, (void**)&pdataobj) &&
  529. !pdataobj->GetData(&statdata.formatetc, &med))
  530. {
  531. HANDLE hGlobal = med.hGlobal;
  532. if( FIsIconMetafilePict(hGlobal) )
  533. {
  534. OleStdSwitchDisplayAspect(reobj.poleobj, &reobj.dvaspect,
  535. DVASPECT_ICON, med.hGlobal, TRUE, FALSE, NULL, &fUpdate);
  536. }
  537. }
  538. ReleaseStgMedium(&med);
  539. if (pdataobj)
  540. pdataobj->Release();
  541. break;
  542. }
  543. }
  544. polecache->Release();
  545. penumstatdata->Release();
  546. }
  547. // EVIL HACK ALERT. This code is borrowed from RichEdit1.0; Word generates
  548. // bogus objects, so we need to compensate.
  549. if( reobj.dvaspect == DVASPECT_CONTENT )
  550. {
  551. IStream *pstm = NULL;
  552. BYTE bT;
  553. BOOL fUpdate;
  554. if (!reobj.pstg->OpenStream(OLESTR("\3ObjInfo"), 0, STGM_READ |
  555. STGM_SHARE_EXCLUSIVE, 0, &pstm) &&
  556. !pstm->Read(&bT, sizeof(BYTE), NULL) &&
  557. (bT & 0x40))
  558. {
  559. _fNeedIcon = TRUE;
  560. _fNeedPres = TRUE;
  561. _pobj = (COleObject *)reobj.polesite;
  562. OleStdSwitchDisplayAspect(reobj.poleobj, &reobj.dvaspect, DVASPECT_ICON,
  563. NULL, TRUE, FALSE, NULL, &fUpdate);
  564. }
  565. if( pstm )
  566. pstm->Release();
  567. }
  568. // Since we are loading an object, it shouldn't be blank
  569. reobj.dwFlags &= ~REO_BLANK;
  570. _prg->Set_iCF(-1);
  571. _prg->ReplaceRange(1, &ch, NULL, SELRR_IGNORE);
  572. hr = pObjectMgr->InsertObject(reobj.cp, &reobj, NULL);
  573. if(hr)
  574. goto Cleanup;
  575. // EVIL HACK ALERT!! Word doesn't give us objects with presenation
  576. // caches; as a result, we can't draw them! In order to get around this,
  577. // we check to see if there is a presentation cache (via the same way
  578. // RE1.0 did) using a GetExtent call. If that fails, we'll just use
  579. // the presentation stored in the RTF.
  580. //
  581. // COMPATIBILITY ISSUE: RE1.0, instead of using the presenation stored
  582. // in RTF, would instead call IOleObject::Update. There are two _big_
  583. // drawbacks to this approach: 1. it's incredibly expensive (potentially,
  584. // MANY SECONDS per object), and 2. it doesn't work if the object server
  585. // is not installed on the machine.
  586. SIZE sizeltemp;
  587. if( reobj.poleobj->GetExtent(reobj.dvaspect, &sizeltemp) != NOERROR )
  588. {
  589. _fNeedPres = TRUE;
  590. _pobj = (COleObject *)reobj.polesite;
  591. }
  592. fRet = TRUE;
  593. Cleanup:
  594. if (reobj.pstg) reobj.pstg->Release();
  595. if (reobj.polesite) reobj.polesite->Release();
  596. if (reobj.poleobj) reobj.poleobj->Release();
  597. return fRet;
  598. }
  599. /*
  600. * ObHBuildMetafilePict(prtfobject, hBits)
  601. *
  602. * @func
  603. * Build a METAFILEPICT from RTFOBJECT and the raw data.
  604. *
  605. * @rdesc
  606. * HGLOBAL Handle to a METAFILEPICT
  607. */
  608. HGLOBAL ObHBuildMetafilePict(
  609. RTFOBJECT * prtfobject, //@parm Details we picked up from RTF
  610. HGLOBAL hBits) //@parm Handle to the raw data
  611. {
  612. #ifndef NOMETAFILES
  613. ULONG cbBits;
  614. HGLOBAL hmfp = NULL;
  615. LPBYTE pbBits;
  616. LPMETAFILEPICT pmfp = NULL;
  617. SCODE sc = E_OUTOFMEMORY;
  618. // Allocate the METAFILEPICT structure
  619. hmfp = GlobalAlloc(GHND, sizeof(METAFILEPICT));
  620. if (!hmfp)
  621. goto Cleanup;
  622. // Lock it down
  623. pmfp = (LPMETAFILEPICT) GlobalLock(hmfp);
  624. if (!pmfp)
  625. goto Cleanup;
  626. // Put in the header information
  627. pmfp->mm = prtfobject->sPictureType;
  628. pmfp->xExt = prtfobject->xExt;
  629. pmfp->yExt = prtfobject->yExt;
  630. // Set the metafile bits
  631. pbBits = (LPBYTE) GlobalLock(hBits);
  632. cbBits = GlobalSize(hBits);
  633. pmfp->hMF = SetMetaFileBitsEx(cbBits, pbBits);
  634. // We can throw away the data now since we don't need it anymore
  635. GlobalUnlock(hBits);
  636. GlobalFree(hBits);
  637. if (!pmfp->hMF)
  638. goto Cleanup;
  639. GlobalUnlock(hmfp);
  640. sc = S_OK;
  641. Cleanup:
  642. if (sc && hmfp)
  643. {
  644. if (pmfp)
  645. {
  646. if (pmfp->hMF)
  647. ::DeleteMetaFile(pmfp->hMF);
  648. GlobalUnlock(hmfp);
  649. }
  650. GlobalFree(hmfp);
  651. hmfp = NULL;
  652. }
  653. TRACEERRSZSC("ObHBuildMetafilePict", sc);
  654. return hmfp;
  655. #else
  656. return NULL;
  657. #endif
  658. }
  659. /*
  660. * ObHBuildBitmap(prtfobject, hBits)
  661. *
  662. * @func
  663. * Build a BITMAP from RTFOBJECT and the raw data
  664. *
  665. * @rdesc
  666. * HGLOBAL Handle to a BITMAP
  667. */
  668. HGLOBAL ObHBuildBitmap(
  669. RTFOBJECT * prtfobject, //@parm Details we picked up from RTF
  670. HGLOBAL hBits) //@parm Handle to the raw data
  671. {
  672. HBITMAP hbm = NULL;
  673. LPVOID pvBits = GlobalLock(hBits);
  674. if(pvBits)
  675. {
  676. hbm = CreateBitmap(prtfobject->xExt, prtfobject->yExt,
  677. prtfobject->cColorPlanes, prtfobject->cBitsPerPixel,
  678. pvBits);
  679. }
  680. GlobalUnlock(hBits);
  681. GlobalFree(hBits);
  682. return hbm;
  683. }
  684. /*
  685. * ObHBuildDib(prtfobject, hBits)
  686. *
  687. * @func
  688. * Build a DIB from RTFOBJECT and the raw data
  689. *
  690. * @rdesc
  691. * HGLOBAL Handle to a DIB
  692. */
  693. HGLOBAL ObHBuildDib(
  694. RTFOBJECT * prtfobject, //@parm Details we picked up from RTF
  695. HGLOBAL hBits) //@parm Handle to the raw data
  696. {
  697. // Apparently DIB's are just a binary dump
  698. return hBits;
  699. }
  700. /*
  701. * CRTFRead::StaticObjectReadFromEditstream(cb)
  702. *
  703. * @mfunc
  704. * Reads a picture from the RTF output stream.
  705. *
  706. * @rdesc
  707. * BOOL TRUE on success, FALSE on failure.
  708. */
  709. #define cbBufferMax 16384
  710. #define cbBufferStep 1024
  711. #define cbBufferMin 1024
  712. BOOL CRTFRead::StaticObjectReadFromEditStream(
  713. int cb) //@parm Count of bytes to read
  714. {
  715. LONG cbBuffer;
  716. LONG cbRead;
  717. WCHAR ch = WCH_EMBEDDING;
  718. DWORD dwAdvf;
  719. DWORD dwConn;
  720. FORMATETC formatetc;
  721. BOOL fRet = FALSE;
  722. HGLOBAL hBits = NULL;
  723. HRESULT hr;
  724. CObjectMgr *pObjectMgr = _ped->GetObjectMgr();
  725. LPPERSISTSTORAGE pperstg = NULL;
  726. LPOLECACHE polecache = NULL;
  727. REOBJECT reobj = { 0 };
  728. LPBYTE pbBuffer = NULL;
  729. LPSTREAM pstm = NULL;
  730. STGMEDIUM stgmedium;
  731. HGLOBAL (*pfnBuildPict)(RTFOBJECT *, HGLOBAL) = NULL;
  732. LPRICHEDITOLECALLBACK precall ;
  733. if(!pObjectMgr)
  734. goto Cleanup;
  735. // precall may end up being null (e.g. Windows CE).
  736. precall = pObjectMgr->GetRECallback();
  737. // Initialize various data structures
  738. formatetc.ptd = NULL;
  739. formatetc.dwAspect = DVASPECT_CONTENT;
  740. formatetc.lindex = -1;
  741. formatetc.tymed = TYMED_NULL;
  742. switch (_prtfObject->sType)
  743. {
  744. case ROT_Metafile:
  745. reobj.clsid = CLSID_StaticMetafile;
  746. formatetc.cfFormat = CF_METAFILEPICT;
  747. formatetc.tymed = TYMED_MFPICT;
  748. pfnBuildPict = ObHBuildMetafilePict;
  749. break;
  750. case ROT_Bitmap:
  751. reobj.clsid = CLSID_StaticDib;
  752. formatetc.cfFormat = CF_BITMAP;
  753. formatetc.tymed = TYMED_GDI;
  754. pfnBuildPict = ObHBuildBitmap;
  755. break;
  756. case ROT_DIB:
  757. reobj.clsid = CLSID_StaticDib;
  758. formatetc.cfFormat = CF_DIB;
  759. formatetc.tymed = TYMED_HGLOBAL;
  760. pfnBuildPict = ObHBuildDib;
  761. break;
  762. }
  763. reobj.sizel.cx = (LONG) HimetricFromTwips(_prtfObject->xExtGoal)
  764. * _prtfObject->xScale / 100;
  765. reobj.sizel.cy = (LONG) HimetricFromTwips(_prtfObject->yExtGoal)
  766. * _prtfObject->yScale / 100;
  767. stgmedium.tymed = formatetc.tymed;
  768. stgmedium.pUnkForRelease = NULL;
  769. if (precall)
  770. {
  771. if( !_fNeedPres )
  772. {
  773. // Get storage for the object from the application
  774. if (precall->GetNewStorage(&reobj.pstg))
  775. goto Cleanup;
  776. }
  777. // Let's create a stream on HGLOBAL
  778. if (hr = CreateStreamOnHGlobal(NULL, FALSE, &pstm))
  779. goto Cleanup;
  780. // Allocate a buffer, preferably a big one
  781. for (cbBuffer = cbBufferMax;
  782. cbBuffer >= cbBufferMin;
  783. cbBuffer -= cbBufferStep)
  784. {
  785. pbBuffer = (unsigned char *)PvAlloc(cbBuffer, 0);
  786. if (pbBuffer)
  787. break;
  788. }
  789. }
  790. else
  791. {
  792. cbBuffer = cb;
  793. if (!cb)
  794. {
  795. // this means we didn't understand the picture type; so just
  796. // skip it without failing.
  797. fRet = TRUE;
  798. goto Cleanup;
  799. }
  800. hBits = GlobalAlloc(GMEM_FIXED, cb);
  801. pbBuffer = (BYTE *) GlobalLock(hBits);
  802. }
  803. if (!pbBuffer)
  804. goto Cleanup;
  805. // Copy the data from RTF into our HGLOBAL
  806. while ((cbRead = RTFReadOLEStream.lpstbl->Get(&RTFReadOLEStream,pbBuffer,cbBuffer)) > 0)
  807. {
  808. if (pstm && (hr = pstm->Write( pbBuffer, cbRead, NULL)))
  809. {
  810. TRACEERRSZSC("ObFReadStaticFromEditstream: Write", GetScode(hr));
  811. goto Cleanup;
  812. }
  813. }
  814. if (hBits)
  815. {
  816. Assert(!precall);
  817. GlobalUnlock(hBits);
  818. pbBuffer = NULL; // To avoid free below
  819. }
  820. if (pstm && (hr = GetHGlobalFromStream(pstm, &hBits)))
  821. {
  822. TRACEERRSZSC("ObFReadStaticFromEditstream: no hglobal from stm", GetScode(hr));
  823. goto Cleanup;
  824. }
  825. // Build the picture
  826. if( pfnBuildPict )
  827. {
  828. stgmedium.hGlobal = pfnBuildPict(_prtfObject, hBits);
  829. }
  830. else
  831. {
  832. // this means we didn't understand the picture type; so just
  833. // skip it without failing.
  834. fRet = TRUE;
  835. goto Cleanup;
  836. }
  837. if( precall && !stgmedium.hGlobal )
  838. goto Cleanup;
  839. if( precall )
  840. {
  841. if( !_fNeedPres )
  842. {
  843. // Create the default handler
  844. hr = OleCreateDefaultHandler(reobj.clsid, NULL, IID_IOleObject,(void **) &reobj.poleobj);
  845. if (hr)
  846. {
  847. TRACEERRSZSC("ObFReadStaticFromEditstream: no def handler", GetScode(hr));
  848. goto Cleanup;
  849. }
  850. // Get the IPersistStorage and initialize it
  851. if ((hr = reobj.poleobj->QueryInterface(IID_IPersistStorage,(void **)&pperstg)) ||
  852. (hr = pperstg->InitNew(reobj.pstg)))
  853. {
  854. TRACEERRSZSC("ObFReadStaticFromEditstream: InitNew", GetScode(hr));
  855. goto Cleanup;
  856. }
  857. dwAdvf = ADVF_PRIMEFIRST;
  858. }
  859. else
  860. {
  861. Assert(_pobj);
  862. _pobj->GetIUnknown()->QueryInterface(IID_IOleObject, (void **)&(reobj.poleobj));
  863. dwAdvf = ADVF_NODATA;
  864. formatetc.dwAspect = _fNeedIcon ? DVASPECT_ICON : DVASPECT_CONTENT;
  865. }
  866. // Get the IOleCache and put the picture data there
  867. if (hr = reobj.poleobj->QueryInterface(IID_IOleCache,(void **)&polecache))
  868. {
  869. TRACEERRSZSC("ObFReadStaticFromEditstream: QI: IOleCache", GetScode(hr));
  870. goto Cleanup;
  871. }
  872. if (FAILED(hr = polecache->Cache(&formatetc, dwAdvf,
  873. &dwConn)))
  874. {
  875. TRACEERRSZSC("ObFReadStaticFromEditstream: Cache", GetScode(hr));
  876. goto Cleanup;
  877. }
  878. if (hr = polecache->SetData(&formatetc, &stgmedium,
  879. TRUE))
  880. {
  881. TRACEERRSZSC("ObFReadStaticFromEditstream: SetData", GetScode(hr));
  882. goto Cleanup;
  883. }
  884. }
  885. if( !_fNeedPres )
  886. {
  887. // Create another object site for the new object
  888. _ped->GetClientSite(&reobj.polesite) ;
  889. if (!reobj.polesite )
  890. goto Cleanup;
  891. // Set the client site
  892. if (reobj.poleobj && (hr = reobj.poleobj->SetClientSite(reobj.polesite)))
  893. {
  894. TRACEERRSZSC("ObFReadStaticFromEditstream: SetClientSite", GetScode(hr));
  895. goto Cleanup;
  896. }
  897. else if (!reobj.poleobj)
  898. {
  899. if(_prtfObject->sType == ROT_DIB)
  900. {
  901. // Windows CE static object Save the data and mark it.
  902. COleObject *pobj = (COleObject *)reobj.polesite;
  903. COleObject::ImageInfo *pimageinfo = new COleObject::ImageInfo;
  904. pobj->SetHdata(hBits);
  905. pimageinfo->xScale = _prtfObject->xScale;
  906. pimageinfo->yScale = _prtfObject->yScale;
  907. pimageinfo->xExtGoal = _prtfObject->xExtGoal;
  908. pimageinfo->yExtGoal = _prtfObject->yExtGoal;
  909. pimageinfo->cBytesPerLine = _prtfObject->cBytesPerLine;
  910. pobj->SetImageInfo(pimageinfo);
  911. }
  912. else
  913. goto Cleanup; // There has been a mistake
  914. }
  915. // Put object into the edit control
  916. reobj.cbStruct = sizeof(REOBJECT);
  917. reobj.cp = _prg->GetCp();
  918. reobj.dvaspect = DVASPECT_CONTENT;
  919. reobj.dwFlags = REO_RESIZABLE;
  920. // Since we are loading an object, it shouldn't be blank
  921. reobj.dwFlags &= ~REO_BLANK;
  922. _prg->Set_iCF(-1);
  923. _prg->ReplaceRange(1, &ch, NULL, SELRR_IGNORE);
  924. hr = pObjectMgr->InsertObject(reobj.cp, &reobj, NULL);
  925. if (hr)
  926. goto Cleanup;
  927. }
  928. else
  929. {
  930. // the new presentation may have a different idea about how big the
  931. // object is supposed to be. Make sure the object stays the correct
  932. // size.
  933. _pobj->ResetSizel(reobj.sizel);
  934. }
  935. fRet = TRUE;
  936. Cleanup:
  937. if (polecache) polecache->Release() ;
  938. if (reobj.pstg) reobj.pstg->Release();
  939. if (reobj.polesite) reobj.polesite->Release();
  940. if (reobj.poleobj) reobj.poleobj->Release();
  941. if (pperstg) pperstg->Release();
  942. if (pstm) pstm->Release();
  943. FreePv(pbBuffer);
  944. _fNeedIcon = FALSE;
  945. _fNeedPres = FALSE;
  946. _pobj = NULL;
  947. return fRet;
  948. }