Leaked source code of windows server 2003
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.

763 lines
19 KiB

  1. /*************************************************************************\
  2. * Module Name: mfdc.cxx
  3. *
  4. * This file contains the member functions for metafile DC class defined
  5. * in mfdc.hxx.
  6. *
  7. * Created: 12-June-1991 13:46:00
  8. * Author: Hock San Lee [hockl]
  9. *
  10. * Copyright (c) 1991-1999 Microsoft Corporation
  11. \*************************************************************************/
  12. #define NO_STRICT
  13. extern "C" {
  14. #if defined(_GDIPLUS_)
  15. #include <gpprefix.h>
  16. #endif
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <stddef.h>
  21. #include <windows.h> // GDI function declarations.
  22. #include <winerror.h>
  23. #include "firewall.h"
  24. #define __CPLUSPLUS
  25. #include <winspool.h>
  26. #include <wingdip.h>
  27. #include "ntgdistr.h"
  28. #include "winddi.h"
  29. #include "hmgshare.h"
  30. #include "icm.h"
  31. #include "local.h" // Local object support.
  32. #include "gdiicm.h"
  33. #include "metadef.h" // Metafile record type constants.
  34. }
  35. #include "rectl.hxx"
  36. #include "mfdc.hxx" // Metafile DC class declarations.
  37. extern RECTL rclNull; // METAFILE.CXX
  38. #define MF_CHECK_RECORDMEMORY_LIMIT 0x00010000
  39. VOID METALINK::vInit(ULONG metalink)
  40. {
  41. imhe = ((METALINK *) &metalink)->imhe;
  42. ihdc = ((METALINK *) &metalink)->ihdc;
  43. }
  44. /******************************Public*Routine******************************\
  45. * void * MDC::pvNewRecord(nSize)
  46. *
  47. * Allocate a metafile record from memory buffer.
  48. * Also set the size field in the metafile record. If a fatal error
  49. * has occurred, do not allocate new record.
  50. *
  51. * History:
  52. * Thu Jul 18 11:19:20 1991 -by- Hock San Lee [hockl]
  53. * Wrote it.
  54. \**************************************************************************/
  55. void * MDC::pvNewRecord(DWORD nSize)
  56. {
  57. #if DBG
  58. static DWORD cRcd = 0;
  59. PUTSX("MDC::pvNewRecord %ld \n", cRcd++);
  60. #endif
  61. // If a fatal error has occurred, do not allocate any more.
  62. if (fl & MDC_FATALERROR)
  63. return((void *) 0);
  64. // Before we allocate a new record, commit the previous bounds record
  65. // if necessary.
  66. if (fl & MDC_DELAYCOMMIT)
  67. {
  68. // Clear the flag.
  69. fl &= ~MDC_DELAYCOMMIT;
  70. PENHMETABOUNDRECORD pmrb = (PENHMETABOUNDRECORD) GetNextRecordPtr(sizeof(ENHMETABOUNDRECORD));
  71. if(pmrb)
  72. {
  73. // Get and reset bounds.
  74. // See also MDC::vFlushBounds.
  75. if (GetBoundsRectAlt(hdcRef, (LPRECT) &pmrb->rclBounds, (UINT) (DCB_RESET | DCB_WINDOWMGR))
  76. == DCB_SET)
  77. {
  78. // Need to intersect bounds with current clipping region first
  79. *((PERECTL) &pmrb->rclBounds) *= *perclMetaBoundsGet();
  80. *((PERECTL) &pmrb->rclBounds) *= *perclClipBoundsGet();
  81. // Make it inclusive-inclusive.
  82. pmrb->rclBounds.right--;
  83. pmrb->rclBounds.bottom--;
  84. // Accumulate bounds to the metafile header.
  85. if (!((PERECTL) &pmrb->rclBounds)->bEmpty())
  86. *((PERECTL) &mrmf.rclBounds) += pmrb->rclBounds;
  87. else
  88. pmrb->rclBounds = rclNull;
  89. }
  90. else
  91. {
  92. pmrb->rclBounds = rclNull;
  93. }
  94. vCommit(*(PENHMETARECORD) pmrb);
  95. ASSERTGDI(!(fl & MDC_FATALERROR),
  96. "MDC::pvNewRecord: Fatal error has occurred");
  97. ReleasePtr(pmrb);
  98. }
  99. else
  100. {
  101. WARNING("MDC::pvNewRecord() failed to get new record\n");
  102. return(NULL);
  103. }
  104. }
  105. // If there is enough free buffer space, use it.
  106. if (iMem + nSize > nMem)
  107. {
  108. // Not enough free buffer space. Flush the filled buffer if it is
  109. // a disk metafile.
  110. if (bIsDiskFile())
  111. if (!bFlush())
  112. return((void *) 0);
  113. // Realloc memory buffer if the free buffer is still too small.
  114. if (iMem + nSize > nMem)
  115. {
  116. ULONG nMemNew, sizeNeeded, sizeExtra;
  117. sizeNeeded = (nSize + MF_BUFSIZE_INC - 1) / MF_BUFSIZE_INC * MF_BUFSIZE_INC;
  118. if (!bIsEMFSpool())
  119. {
  120. //
  121. // When not EMF spooling, use the following heuristics:
  122. // If current size <= 64K, enlarge the buffer by extra 16K
  123. // Else, enlarge the buffer by extra 25%
  124. //
  125. sizeExtra = (nMem > 0x10000) ? (nMem >> 2) : MF_BUFSIZE_INC;
  126. nMemNew = nMem + sizeExtra + sizeNeeded;
  127. }
  128. else
  129. {
  130. //
  131. // When EMF spooling, use the more aggressive heuristics:
  132. // If current size <= 1MB, double the buffer
  133. // Else, enlarge the buffer by 50% with a cap of 4MB
  134. if (nMem > 0x100000)
  135. {
  136. sizeExtra = nMem >> 1;
  137. if (sizeExtra > 0x400000)
  138. sizeExtra = 0x400000;
  139. }
  140. else
  141. sizeExtra = nMem;
  142. nMemNew = nMem + max(sizeNeeded, sizeExtra);
  143. }
  144. if (!ReallocMem(nMemNew))
  145. {
  146. ERROR_ASSERT(FALSE, "ReallocMem failed\n");
  147. return NULL;
  148. }
  149. }
  150. }
  151. // Zero the last dword. If the record does not use up all bytes in the
  152. // last dword, the unused bytes will be zeros.
  153. PVOID pvRecord = GetNextRecordPtr(nSize);
  154. if(pvRecord)
  155. {
  156. ((PDWORD) pvRecord)[nSize / 4 - 1] = 0;
  157. // Set the size field and return the pointer to the new record.
  158. ((PENHMETARECORD) pvRecord)->nSize = nSize;
  159. // WINBUG 365051 4-10-2001 pravins Need to modify usage of pvNewRecord() to release ptr
  160. // We should not be doing the release here. We should have users of pvNewRecord()
  161. // call ReleasePtr when they are done. This requires a bunch of edits in metarec.cxx
  162. // and mestsup.cxx.
  163. ReleasePtr(pvRecord);
  164. }
  165. else
  166. {
  167. WARNING("MDC::pvNewRecord() failed to get next record ptr\n");
  168. }
  169. return pvRecord;
  170. }
  171. BOOL
  172. MDC::ReallocMem(
  173. ULONG newsize
  174. )
  175. /*++
  176. Routine Description:
  177. Resize the memory buffer used to hold EMF data
  178. Arguments:
  179. newsize - new size of EMF memory buffer
  180. Return Value:
  181. TRUE if successful, FALSE if there is an error
  182. --*/
  183. {
  184. if (bIsEMFSpool())
  185. {
  186. ENHMETAHEADER *pNewHeader;
  187. if(!((EMFSpoolData *) hData)->ResizeEMFData(newsize))
  188. return FALSE;
  189. }
  190. else
  191. {
  192. HANDLE hMemNew;
  193. if ((hMemNew = LocalReAlloc(hData, newsize, LMEM_MOVEABLE)) == NULL)
  194. {
  195. ERROR_ASSERT(FALSE, "LocalReAlloc failed");
  196. return FALSE;
  197. }
  198. hData = hMemNew;
  199. }
  200. nMem = newsize;
  201. return TRUE;
  202. }
  203. /******************************Public*Routine******************************\
  204. * BOOL MDC::bFlush()
  205. *
  206. * Flush the filled memory buffer to disk.
  207. *
  208. * History:
  209. * Thu Jul 18 11:19:20 1991 -by- Hock San Lee [hockl]
  210. * Wrote it.
  211. \**************************************************************************/
  212. BOOL MDC::bFlush()
  213. {
  214. ULONG nWritten ;
  215. PUTS("MDC::bFlush\n");
  216. PUTSX("\tnFlushSize = %ld\n", (ULONG)iMem);
  217. PUTSX("\tnBufferSize = %ld\n", (ULONG)nMem);
  218. ASSERTGDI(bIsDiskFile(), "MDC::bFlush: Not a disk metafile");
  219. ASSERTGDI(!(fl & MDC_FATALERROR), "MDC::bFlush: Fatal error has occurred");
  220. // WriteFile handles a null write correctly.
  221. if (!WriteFile(hFile, hData, iMem, &nWritten, (LPOVERLAPPED) NULL)
  222. || nWritten != iMem)
  223. {
  224. // The write error here is fatal since we are doing record buffering and
  225. // have no way of recovering to a previous state.
  226. ERROR_ASSERT(FALSE, "MDC::bFlush failed");
  227. fl |= MDC_FATALERROR;
  228. return(FALSE);
  229. }
  230. iMem = 0L;
  231. return(TRUE);
  232. }
  233. /******************************Public*Routine******************************\
  234. * VOID MDC::vAddToMetaFilePalette(cEntries, pPalEntriesNew)
  235. *
  236. * Add new palette entries to the metafile palette.
  237. *
  238. * When new palette entries are added to a metafile in CreatePalette or
  239. * SetPaletteEntries, they are also accumulated to the metafile palette.
  240. * The palette is later returned in GetEnhMetaFilePaletteEntries when an
  241. * application queries it. It assumes that the peFlags of the palette entries
  242. * are zeroes.
  243. *
  244. * A palette color is added to the metafile palette only if it is not a
  245. * duplicate. It uses a simple linear search algorithm to determine if
  246. * a duplicate palette exists.
  247. *
  248. * History:
  249. * Mon Sep 23 14:27:25 1991 -by- Hock San Lee [hockl]
  250. * Wrote it.
  251. \**************************************************************************/
  252. VOID MDC::vAddToMetaFilePalette(UINT cEntries, PPALETTEENTRY pPalEntriesNew)
  253. {
  254. UINT ii;
  255. PUTS("vAddToMetaFilePalette\n");
  256. while (cEntries--)
  257. {
  258. ASSERTGDI(pPalEntriesNew->peFlags == 0,
  259. "MDC::vAddToMetaFilePalette: peFlags not zero");
  260. // Look for duplicate.
  261. for (ii = 0; ii < iPalEntries; ii++)
  262. {
  263. ASSERTGDI(sizeof(PALETTEENTRY) == sizeof(DWORD),
  264. "MDC::vAddToMetaFilePalette: Bad size");
  265. if (*(PDWORD) &pPalEntries[ii] == *(PDWORD) pPalEntriesNew)
  266. break;
  267. }
  268. // Add to the metafile palette if not a duplicate.
  269. if (ii >= iPalEntries)
  270. {
  271. pPalEntries[iPalEntries] = *pPalEntriesNew;
  272. iPalEntries++; // Advance iPalEntries for next loop!
  273. }
  274. pPalEntriesNew++;
  275. }
  276. }
  277. /******************************Public*Routine******************************\
  278. * VOID METALINK::vNext()
  279. *
  280. * Update *this to the next metalink.
  281. *
  282. * History:
  283. * Wed Aug 07 09:28:54 1991 -by- Hock San Lee [hockl]
  284. * Wrote it.
  285. \**************************************************************************/
  286. VOID METALINK::vNext()
  287. {
  288. PUTS("METALINK::vNext\n");
  289. ASSERTGDI(bValid(), "METALINK::vNext: Invalid metalink");
  290. PMDC pmdc = pmdcGetFromIhdc(ihdc);
  291. ASSERTGDI(pmdc,"METALINK::vNext - invalid pmdc\n");
  292. if (pmdc == NULL)
  293. ZeroMemory(this,sizeof(*this)); // Make it invalid so bValid will fail
  294. else
  295. *this = pmdc->pmhe[imhe].metalink;
  296. }
  297. /******************************Public*Routine******************************\
  298. * METALINK * METALINK::pmetalinkNext()
  299. *
  300. * Return the pointer to the next metalink.
  301. *
  302. * History:
  303. * Wed Aug 07 09:28:54 1991 -by- Hock San Lee [hockl]
  304. * Wrote it.
  305. \**************************************************************************/
  306. METALINK * METALINK::pmetalinkNext()
  307. {
  308. PUTS("METALINK::pmetalinkNext\n");
  309. ASSERTGDI(bValid(), "METALINK::pmetalinkNext: Invalid metalink");
  310. PMDC pmdc = pmdcGetFromIhdc(ihdc);
  311. ASSERTGDI(pmdc,"METALINK::vNext - invalid pmdc\n");
  312. return(&pmdc->pmhe[imhe].metalink);
  313. }
  314. VOID EMFContainer::Init(ENHMETAHEADER * inHdr, UINT32 dataSize)
  315. {
  316. dwRefCount = 0;
  317. pemfhdr = inHdr;
  318. dwHdrSize = dataSize;
  319. pvWindow = NULL;
  320. dwWindowOffset = 0;
  321. dwWindowSize = 0;
  322. hFile = NULL;
  323. }
  324. BOOL EMFContainer::Init(HANDLE inFile, UINT64 inHdrOffset, UINT64 inFileSize)
  325. {
  326. BOOL bResult = FALSE;
  327. dwRefCount = 0;
  328. pemfhdr = NULL;
  329. dwHdrSize = 0;
  330. pvWindow = NULL;
  331. dwWindowOffset = 0;
  332. dwWindowSize = 0;
  333. hFile = inFile;
  334. hFileMapping = NULL;
  335. pvHdr = NULL;
  336. qwHdrOffset = inHdrOffset;
  337. qwFileSize = inFileSize;
  338. if(qwFileSize != 0 || GetFileSizeEx(hFile, (LARGE_INTEGER *) &qwFileSize))
  339. {
  340. hFileMapping = CreateFileMappingW(hFile,
  341. NULL,
  342. PAGE_READWRITE,
  343. HIDWORD(qwFileSize),
  344. LODWORD(qwFileSize),
  345. NULL);
  346. if(hFileMapping != NULL)
  347. {
  348. UINT64 qwOffset = qwHdrOffset;
  349. UINT32 dwSize = sizeof(ENHMETAHEADER);
  350. pvHdr = pvMapView(&qwOffset, &dwSize);
  351. if(pvHdr)
  352. {
  353. UINT32 dwViewOffset = (UINT32) (qwHdrOffset - qwOffset);
  354. pemfhdr = (PENHMETAHEADER) ((PBYTE) pvHdr + dwViewOffset);
  355. dwHdrSize = dwSize - dwViewOffset;
  356. bResult = TRUE;
  357. }
  358. }
  359. }
  360. if(!bResult)
  361. Term();
  362. return bResult;
  363. }
  364. VOID EMFContainer::Term()
  365. {
  366. // Free any locally allocated resources
  367. if(hFile)
  368. {
  369. // We were using mapped views of the file
  370. if(hFileMapping)
  371. {
  372. if(!CloseHandle(hFileMapping))
  373. {
  374. WARNING("EMFContainer::Term() failed to close file mapping\n");
  375. }
  376. hFileMapping = NULL;
  377. }
  378. if(pvHdr != NULL)
  379. {
  380. if(!UnmapViewOfFile(pvHdr))
  381. {
  382. WARNING("EMFContainer::Term() Failed to unmap header view\n");
  383. }
  384. pvHdr = NULL;
  385. }
  386. if(pvWindow != NULL)
  387. {
  388. if(!UnmapViewOfFile(pvWindow))
  389. {
  390. WARNING("EMFContainer::Term() Failed to unmap window view\n");
  391. }
  392. pvWindow = NULL;
  393. }
  394. hFile = NULL;
  395. }
  396. pemfhdr = NULL;
  397. dwHdrSize = 0;
  398. }
  399. BOOL bProbeAndPageInAddressRange(BYTE *pb, UINT inSize)
  400. {
  401. BOOL bRet = TRUE;
  402. if (inSize == 0)
  403. return bRet;
  404. __try
  405. {
  406. DWORD dwPagesize = GetSystemPageSize( );
  407. BYTE bData;
  408. BYTE *pbLoc = pb;
  409. BYTE *pbEnd = pbLoc + ( (inSize < MF_CHECK_RECORDMEMORY_LIMIT) ? inSize : MF_CHECK_RECORDMEMORY_LIMIT );
  410. while (pbLoc < pbEnd)
  411. {
  412. bData = *pbLoc;
  413. pbLoc += dwPagesize;
  414. }
  415. pbEnd--;
  416. bData = *pbEnd;
  417. }
  418. __except( GetExceptionCode() == STATUS_IN_PAGE_ERROR ||
  419. GetExceptionCode() == STATUS_ACCESS_VIOLATION)
  420. {
  421. EMFVALFAIL(("bProbeAndPageInAddressRange: (%p) [%08x] Failed\n", pb, inSize));
  422. bRet = FALSE;
  423. }
  424. return bRet;
  425. }
  426. PVOID EMFContainer::ObtainPtr(UINT inOffset, UINT inSize)
  427. {
  428. if(dwRefCount > 1)
  429. {
  430. WARNING("Obtaining record with non-zero ref count\n");
  431. return NULL;
  432. }
  433. dwRefCount++;
  434. if(inOffset < dwHdrSize && inSize <= (dwHdrSize - inOffset))
  435. {
  436. if (bProbeAndPageInAddressRange((PBYTE) pemfhdr + inOffset, inSize))
  437. return (PVOID) ((PBYTE) pemfhdr + inOffset);
  438. else
  439. {
  440. --dwRefCount;
  441. return NULL;
  442. }
  443. }
  444. if(!hFile)
  445. {
  446. WARNING("EMFContainer::ObtainPtr() Attempt to obtain ptr past end of memory EMF\n");
  447. dwRefCount--;
  448. return NULL;
  449. }
  450. if(inOffset < dwWindowOffset ||
  451. (inOffset + inSize) > (dwWindowOffset + dwWindowSize))
  452. {
  453. if(pvWindow && !UnmapViewOfFile(pvWindow))
  454. {
  455. WARNING("EMFContainer::ObtainPtr() failed to unmap window view\n");
  456. }
  457. UINT64 qwOffset = qwHdrOffset + inOffset;
  458. dwWindowSize = inSize;
  459. pvWindow = pvMapView(&qwOffset, &dwWindowSize);
  460. if(!pvWindow)
  461. {
  462. WARNING("EMFContainer::ObtainPtr() failed to map window view\n");
  463. dwRefCount--;
  464. return NULL;
  465. }
  466. if(qwOffset < qwHdrOffset)
  467. {
  468. dwWindowUnusable = (UINT32) (qwHdrOffset - qwOffset);
  469. ASSERTGDI(dwWindowUnusable < dwWindowSize, "EMFContainer::ObtainPtr() Unexpected dwUnusable value\n");
  470. dwWindowSize -= dwWindowUnusable;
  471. dwWindowOffset = 0;
  472. }
  473. else
  474. {
  475. dwWindowUnusable = 0;
  476. dwWindowOffset = (UINT32) (qwOffset - qwHdrOffset);
  477. }
  478. if(inOffset < dwWindowOffset ||
  479. (inOffset + inSize) > (dwWindowOffset + dwWindowSize))
  480. {
  481. WARNING("EMFContainer::ObtainPtr() something went really wrong\n");
  482. dwRefCount--;
  483. return NULL;
  484. }
  485. }
  486. BYTE *pbRet = (BYTE *)pvWindow + inOffset - dwWindowOffset + dwWindowUnusable;
  487. if (bProbeAndPageInAddressRange(pbRet, inSize))
  488. return (PVOID)pbRet;
  489. else
  490. return NULL;
  491. }
  492. PENHMETARECORD EMFContainer::ObtainRecordPtr(UINT inOffset)
  493. {
  494. ENHMETARECORD *pemr = NULL;
  495. ENHMETARECORD *pemrTemp = (ENHMETARECORD *) ObtainPtr(inOffset, sizeof(ENHMETARECORD));
  496. if (pemrTemp != NULL)
  497. {
  498. UINT size = pemrTemp->nSize;
  499. ReleasePtr(pemrTemp);
  500. pemrTemp = (ENHMETARECORD *) ObtainPtr(inOffset, size);
  501. if (pemrTemp != NULL)
  502. {
  503. pemr = pemrTemp;
  504. }
  505. }
  506. return pemr;
  507. }
  508. PEMREOF EMFContainer::ObtainEOFRecordPtr()
  509. {
  510. PEMREOF pmreof = NULL;
  511. ENHMETAHEADER * pmrmf = GetEMFHeader();
  512. if(pmrmf)
  513. {
  514. PDWORD pdw = (PDWORD) ObtainPtr(pmrmf->nBytes - sizeof(DWORD),
  515. sizeof(DWORD));
  516. if(pdw)
  517. {
  518. DWORD dwOffset = pmrmf->nBytes - *pdw;
  519. ReleasePtr(pdw);
  520. pmreof = (PEMREOF) ObtainRecordPtr(dwOffset);
  521. }
  522. }
  523. return pmreof;
  524. }
  525. PVOID EMFContainer::pvMapView(UINT64 * ioOffset, UINT32 * ioSize)
  526. {
  527. UINT64 qwMappingAlignment = GetFileMappingAlignment();
  528. UINT64 qwMappingMask = ~(qwMappingAlignment - 1);
  529. UINT64 qwRecordStart = *ioOffset;
  530. UINT64 qwRecordEnd = qwRecordStart + *ioSize;
  531. UINT64 qwViewStart;
  532. UINT64 qwViewEnd;
  533. PVOID pvView;
  534. qwViewStart = qwRecordStart & qwMappingMask;
  535. qwViewEnd = qwViewStart + qwMappingAlignment;
  536. if(qwViewEnd < qwRecordEnd)
  537. {
  538. qwViewEnd = qwRecordEnd;
  539. }
  540. qwViewEnd = (qwViewEnd + (qwMappingAlignment - 1)) & qwMappingMask;
  541. if(qwViewEnd > qwFileSize)
  542. {
  543. qwViewEnd = qwFileSize;
  544. }
  545. DWORD dwViewSize = (DWORD) (qwViewEnd - qwViewStart);
  546. pvView = MapViewOfFile(hFileMapping,
  547. FILE_MAP_WRITE,
  548. HIDWORD(qwViewStart),
  549. LODWORD(qwViewStart),
  550. dwViewSize);
  551. if(pvView)
  552. {
  553. *ioOffset = qwViewStart;
  554. *ioSize = dwViewSize;
  555. }
  556. else
  557. {
  558. ioOffset = 0;
  559. ioSize = 0;
  560. }
  561. return pvView;
  562. }
  563. BOOL EMFContainer::bBounded(BYTE *p, DWORD dwSize)
  564. {
  565. BYTE *pBh = 0, *pEh = 0;
  566. BYTE *pBw = 0, *pEw = 0;
  567. BYTE *pBt = 0, *pEt = 0;
  568. if (pvWindow)
  569. {
  570. pBw = (PBYTE)pvWindow;
  571. pEw = pBw + dwWindowSize;
  572. }
  573. if (pemfhdr)
  574. {
  575. pBh = (PBYTE)pemfhdr;
  576. pEh = pBh + dwHdrSize;
  577. }
  578. pBt = p;
  579. pEt = p + dwSize - 1;
  580. // The pointer/extent is bounded if the address range they represent are
  581. // bounded between the address ranges represented by the header range or
  582. // the window range.
  583. if (((pBt >= pBw && pBt < pEw) && (pEt >= pBw && pEt < pEw)) ||
  584. ((pBt >= pBh && pBt < pEh) && (pEt >= pBh && pEt < pEh)))
  585. return TRUE;
  586. return FALSE;
  587. }