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.

715 lines
19 KiB

  1. #include "precomp.h"
  2. //
  3. // RBC.CPP
  4. // Received Bitmap Cache
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. // RBC_ViewStarting()
  11. //
  12. // For 3.0 nodes, we create the cache each time they start hosting.
  13. // For 2.x nodes, we create the cache once and use it until they leave the
  14. // share.
  15. //
  16. BOOL ASShare::RBC_ViewStarting(ASPerson * pasPerson)
  17. {
  18. BOOL rc = FALSE;
  19. DebugEntry(ASShare::RBC_ViewStarting);
  20. ValidatePerson(pasPerson);
  21. //
  22. // Allocate the INCOMING cache data for this host.
  23. //
  24. pasPerson->prbcHost = new RBC_HOST_INFO;
  25. if (!pasPerson->prbcHost)
  26. {
  27. ERROR_OUT(( "Failed to get memory for prbcHost info"));
  28. DC_QUIT;
  29. }
  30. ZeroMemory(pasPerson->prbcHost, sizeof(*(pasPerson->prbcHost)));
  31. SET_STAMP(pasPerson->prbcHost, RBCHOST);
  32. TRACE_OUT(( "Allocated RBC root for host [%d] at 0x%08x",
  33. pasPerson->mcsID, pasPerson->prbcHost));
  34. //
  35. // Create the bitmap caches for the sender
  36. //
  37. // SMALL
  38. if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsSmallCacheNumEntries,
  39. pasPerson->cpcCaps.bitmaps.sender.capsSmallCacheCellSize,
  40. ID_SMALL_BMP_CACHE,
  41. &(pasPerson->prbcHost->bitmapCache[ID_SMALL_BMP_CACHE])))
  42. {
  43. DC_QUIT;
  44. }
  45. // MEDIUM
  46. if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsMediumCacheNumEntries,
  47. pasPerson->cpcCaps.bitmaps.sender.capsMediumCacheCellSize,
  48. ID_MEDIUM_BMP_CACHE,
  49. &(pasPerson->prbcHost->bitmapCache[ID_MEDIUM_BMP_CACHE])))
  50. {
  51. DC_QUIT;
  52. }
  53. // LARGE
  54. if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsLargeCacheNumEntries,
  55. pasPerson->cpcCaps.bitmaps.sender.capsLargeCacheCellSize,
  56. ID_LARGE_BMP_CACHE,
  57. &(pasPerson->prbcHost->bitmapCache[ID_LARGE_BMP_CACHE])))
  58. {
  59. DC_QUIT;
  60. }
  61. //
  62. // The host can join the share.
  63. //
  64. rc = TRUE;
  65. DC_EXIT_POINT:
  66. DebugExitBOOL(ASShare::RBC_ViewStarting, rc);
  67. return(rc);
  68. }
  69. //
  70. // RBC_ViewEnded()
  71. //
  72. void ASShare::RBC_ViewEnded(ASPerson * pasPerson)
  73. {
  74. DebugEntry(ASShare::RBC_ViewEnded);
  75. ValidatePerson(pasPerson);
  76. RBCFreeIncoming(pasPerson);
  77. DebugExitVOID(ASShare::RBC_ViewEnded);
  78. }
  79. //
  80. // RBC_PartyLeftShare()
  81. // For 2.x nodes, frees the incoming RBC data
  82. //
  83. void ASShare::RBC_PartyLeftShare(ASPerson * pasPerson)
  84. {
  85. DebugEntry(ASShare::RBC_PartyLeftShare);
  86. ValidatePerson(pasPerson);
  87. // This should be gone!
  88. ASSERT(pasPerson->prbcHost == NULL);
  89. DebugExitVOID(ASShare::RBC_PartyLeftShare);
  90. }
  91. //
  92. // RBCFreeIncoming()
  93. // Frees the party RBC incoming structures. This happens
  94. // * For 3.0 nodes when they stop hosting
  95. // * For 2.x nodes when leave the share
  96. //
  97. void ASShare::RBCFreeIncoming(ASPerson * pasPerson)
  98. {
  99. DebugEntry(ASShare::RBCFreeIncoming);
  100. //
  101. // Free this host's cache bitmaps.
  102. //
  103. if (pasPerson->prbcHost != NULL)
  104. {
  105. UINT i;
  106. //
  107. // Delete all of this host's cache bitmaps.
  108. //
  109. for (i = 0; i < NUM_BMP_CACHES; i++)
  110. {
  111. BMCFreeCacheData(&(pasPerson->prbcHost->bitmapCache[i]));
  112. }
  113. delete pasPerson->prbcHost;
  114. pasPerson->prbcHost = NULL;
  115. }
  116. DebugExitVOID(ASShare::RBCFreeIncoming);
  117. }
  118. //
  119. // RBC_ProcessCacheOrder(..)
  120. //
  121. void ASShare::RBC_ProcessCacheOrder
  122. (
  123. ASPerson * pasPerson,
  124. LPCOM_ORDER_UA pOrder
  125. )
  126. {
  127. PBMC_ORDER_HDR pBmcOrderHdr;
  128. PBMC_COLOR_TABLE_ORDER_UA pColorOrder;
  129. PBMC_BITMAP_BITS_ORDER_R2_UA pBitsOrderR2;
  130. BOOL fCompressed = FALSE;
  131. UINT cxFixedBitmapWidth;
  132. UINT iCacheEntry;
  133. LPBYTE pBitmapBits;
  134. UINT cbBitmapBits;
  135. DebugEntry(ASShare::RBC_ProcessCacheOrder);
  136. ValidatePerson(pasPerson);
  137. //
  138. // The rectangle is not included in the header for private order data
  139. // (see SBC_CopyPrivateOrderData) so we must take this into account
  140. // when working out the address of the order data.
  141. //
  142. pBmcOrderHdr = (PBMC_ORDER_HDR)
  143. (pOrder->abOrderData - sizeof(pOrder->OrderHeader.rcsDst));
  144. switch (pBmcOrderHdr->bmcPacketType)
  145. {
  146. case BMC_PT_COLOR_TABLE:
  147. //
  148. // This is a new color table. Simply cache the RGB values for
  149. // use when we come to process a memblt order
  150. // For backlevel calls the color table is always stored at
  151. // index 0 because the index field in the order reuses a
  152. // zero initialized "padding" field in the old structure.
  153. //
  154. TRACE_OUT(("Person [%d] Caching color table", pasPerson->mcsID));
  155. pColorOrder = (PBMC_COLOR_TABLE_ORDER_UA)pBmcOrderHdr;
  156. PM_CacheRxColorTable(pasPerson, pColorOrder->index,
  157. EXTRACT_TSHR_UINT16_UA(&(pColorOrder->colorTableSize)),
  158. (LPTSHR_RGBQUAD)&pColorOrder->data[0]);
  159. break;
  160. case BMC_PT_BITMAP_BITS_COMPRESSED:
  161. fCompressed = TRUE;
  162. TRACE_OUT(( "Compressed BMP"));
  163. case BMC_PT_BITMAP_BITS_UNCOMPRESSED:
  164. //
  165. // This is some cached bitmap data. We have to store it in the
  166. // specified slot in the specified cache.
  167. //
  168. //
  169. // The width of the bitmaps we use are actually fixed as
  170. // multiples of 16 pels wide. Work out the width that
  171. // corresponds to the sub-bitmap width of data we are caching.
  172. //
  173. pBitsOrderR2 = (PBMC_BITMAP_BITS_ORDER_R2_UA)pBmcOrderHdr;
  174. cbBitmapBits = EXTRACT_TSHR_UINT16_UA(
  175. &(pBitsOrderR2->header.cbBitmapBits));
  176. cxFixedBitmapWidth =
  177. ((pBitsOrderR2->header.cxSubBitmapWidth +15)/16)*16;
  178. //
  179. // The location of cache entry field depends on the R1/R2
  180. // protocol
  181. //
  182. iCacheEntry = EXTRACT_TSHR_UINT16_UA(&(pBitsOrderR2->iCacheEntryR2));
  183. pBitmapBits = pBitsOrderR2->data;
  184. TRACE_OUT(("Person [%d] Rx bmp: id(%d) entry(%d) size(%dx%d) " \
  185. "fixed(%d) bpp(%d) bytes(%d) compressed(%d)",
  186. pasPerson->mcsID,
  187. pBitsOrderR2->header.cacheID,
  188. iCacheEntry,
  189. pBitsOrderR2->header.cxSubBitmapWidth,
  190. pBitsOrderR2->header.cySubBitmapHeight,
  191. cxFixedBitmapWidth,
  192. pBitsOrderR2->header.bpp,
  193. cbBitmapBits,
  194. fCompressed));
  195. //
  196. // Pass the BMC data to the caching code. When calculating the
  197. // pointer to the bitmap bits remember that we did not send the
  198. // pBitmapBits field of the BMC_BITMAP_BITS_ORDER_Rx structure
  199. // (see SBC_CopyPrivateOrderData).
  200. //
  201. RBCStoreBitsInCacheBitmap(pasPerson,
  202. pBitsOrderR2->header.cacheID,
  203. iCacheEntry,
  204. pBitsOrderR2->header.cxSubBitmapWidth,
  205. cxFixedBitmapWidth,
  206. pBitsOrderR2->header.cySubBitmapHeight,
  207. pBitsOrderR2->header.bpp,
  208. pBitmapBits,
  209. cbBitmapBits,
  210. fCompressed);
  211. break;
  212. default:
  213. ERROR_OUT(( "[%u]Invalid packet type(%d)",
  214. pasPerson,
  215. (UINT)pBmcOrderHdr->bmcPacketType));
  216. break;
  217. }
  218. DebugExitVOID(ASShare::RBC_ProcessCacheOrder);
  219. }
  220. //
  221. // RBC_MapCacheIDToBitmapHandle(..)
  222. //
  223. HBITMAP ASShare::RBC_MapCacheIDToBitmapHandle
  224. (
  225. ASPerson * pasPerson,
  226. UINT cache,
  227. UINT cacheEntry,
  228. UINT colorIndex
  229. )
  230. {
  231. PBMC_DIB_CACHE pDIBCache;
  232. PBMC_DIB_ENTRY pDIBEntry;
  233. BITMAPINFO_ours bitmapInfo;
  234. UINT cColors;
  235. HBITMAP hWorkBitmap = NULL;
  236. HPALETTE hpalOldDIB = NULL;
  237. LPBYTE pBits;
  238. UINT cacheOffset;
  239. DebugEntry(ASShare::RBC_MapCacheIDToBitmapHandle);
  240. ValidateView(pasPerson);
  241. //
  242. // Check that the supplied cache ID is valid.
  243. //
  244. if (cache >= NUM_BMP_CACHES)
  245. {
  246. ERROR_OUT(( "[%u]Invalid cache ID (%d)", pasPerson, cache));
  247. cache = 0;
  248. }
  249. //
  250. // Get a pointer to the bitmap data
  251. //
  252. // Note that there are two indexes floating around. From the host's
  253. // perspective this index is a Cache Handler token and it must be
  254. // translated in order to address the associated data. However we
  255. // use it as the direct index into our receive cache and so the
  256. // slots used on host and remote will be diferent.
  257. //
  258. // There is no reason why the slots should be the same. This is just
  259. // to warn you that if you try correlating cache offsets between
  260. // host and remote you will get confused as soon as the cache fills
  261. // up and entries are reallocated in different positions.
  262. //
  263. //
  264. pDIBCache = &(pasPerson->prbcHost->bitmapCache[cache]);
  265. TRACE_OUT(( "Local person [%d] cache id %d pointer %lx",
  266. pasPerson->mcsID, cache, pDIBCache));
  267. cacheOffset = cacheEntry * pDIBCache->cSize;
  268. pDIBEntry = (PBMC_DIB_ENTRY)(pDIBCache->data + cacheOffset);
  269. TRACE_OUT(( "Bits for index %u are at offset %ld, pointer 0x%08x",
  270. cacheEntry, (cacheEntry * pDIBCache->cSize), pDIBEntry));
  271. //
  272. // Set up the BitmapInfo structure.
  273. //
  274. USR_InitDIBitmapHeader((BITMAPINFOHEADER *)&bitmapInfo, pDIBEntry->bpp);
  275. bitmapInfo.bmiHeader.biWidth = pDIBEntry->cxFixed;
  276. bitmapInfo.bmiHeader.biHeight = pDIBEntry->cy;
  277. //
  278. // Copy the Rx color table into the bitmap header.
  279. //
  280. if ( (pDIBEntry->bpp == 1) ||
  281. (pDIBEntry->bpp == 4) ||
  282. (pDIBEntry->bpp == 8) )
  283. {
  284. cColors = COLORS_FOR_BPP(pDIBEntry->bpp);
  285. PM_GetColorTable( pasPerson,
  286. colorIndex,
  287. &cColors,
  288. (LPTSHR_RGBQUAD)(&bitmapInfo.bmiColors) );
  289. TRACE_OUT(( "Got %u colors from table",cColors));
  290. bitmapInfo.bmiHeader.biClrUsed = cColors;
  291. }
  292. else if (pDIBEntry->bpp == 24)
  293. {
  294. ASSERT(colorIndex == COLORCACHEINDEX_NONE);
  295. }
  296. else
  297. {
  298. ERROR_OUT(("RBC: Unexpected bpp %d from [%d]", pDIBEntry->bpp, pasPerson->mcsID));
  299. DC_QUIT;
  300. }
  301. //
  302. // Select which fixed width bitmap we are going to use to store the
  303. // incoming DIB bits.
  304. //
  305. switch (pDIBEntry->cxFixed)
  306. {
  307. case 16:
  308. hWorkBitmap = m_usrBmp16;
  309. break;
  310. case 32:
  311. hWorkBitmap = m_usrBmp32;
  312. break;
  313. case 48:
  314. hWorkBitmap = m_usrBmp48;
  315. break;
  316. case 64:
  317. hWorkBitmap = m_usrBmp64;
  318. break;
  319. case 80:
  320. hWorkBitmap = m_usrBmp80;
  321. break;
  322. case 96:
  323. hWorkBitmap = m_usrBmp96;
  324. break;
  325. case 112:
  326. hWorkBitmap = m_usrBmp112;
  327. break;
  328. case 128:
  329. hWorkBitmap = m_usrBmp128;
  330. break;
  331. case 256:
  332. hWorkBitmap = m_usrBmp256;
  333. break;
  334. default:
  335. ERROR_OUT(("RBC_MapCacheIDToBitmapHandle: invalid size from [%d]",
  336. pDIBEntry->cxFixed, pasPerson->mcsID));
  337. hWorkBitmap = m_usrBmp256;
  338. break;
  339. }
  340. ASSERT(hWorkBitmap != NULL);
  341. //
  342. // If the cached bitmap bits are compressed, we first have to
  343. // decompress them.
  344. //
  345. if (pDIBEntry->bCompressed)
  346. {
  347. ASSERT(pDIBEntry->bpp <= 8);
  348. //
  349. // Use the decompression buffer to decompress the bitmap data.
  350. //
  351. if (!BD_DecompressBitmap(pDIBEntry->bits, m_usrPBitmapBuffer,
  352. pDIBEntry->cCompressed,
  353. pDIBEntry->cxFixed,
  354. pDIBEntry->cy,
  355. pDIBEntry->bpp))
  356. {
  357. ERROR_OUT((
  358. "Failed to decompress bitmap pBits(%lx)"
  359. " pBuf(%lx) cb(%x) cx(%d) cy(%d) bpp(%d)",
  360. pDIBEntry->bits,
  361. m_usrPBitmapBuffer,
  362. pDIBEntry->cCompressed,
  363. pDIBEntry->cxFixed,
  364. pDIBEntry->cy,
  365. pDIBEntry->bpp));
  366. DC_QUIT;
  367. }
  368. pBits = m_usrPBitmapBuffer;
  369. }
  370. else
  371. {
  372. //
  373. // For uncompressed data just use direct from the cache
  374. //
  375. TRACE_OUT(( "Bitmap bits are uncompressed"));
  376. pBits = pDIBEntry->bits;
  377. }
  378. //
  379. // Set the bits into the bitmap we are about to return to the caller
  380. //
  381. hpalOldDIB = SelectPalette(pasPerson->m_pView->m_usrWorkDC,
  382. pasPerson->pmPalette, FALSE);
  383. RealizePalette(pasPerson->m_pView->m_usrWorkDC);
  384. if (!SetDIBits(pasPerson->m_pView->m_usrWorkDC,
  385. hWorkBitmap,
  386. 0,
  387. pDIBEntry->cy,
  388. pBits,
  389. (BITMAPINFO *)&bitmapInfo,
  390. DIB_RGB_COLORS))
  391. {
  392. ERROR_OUT(("SetDIBits failed in RBC_MapCacheIDToBitmapHandle"));
  393. }
  394. SelectPalette(pasPerson->m_pView->m_usrWorkDC, hpalOldDIB, FALSE );
  395. TRACE_OUT(( "Returning bitmap for person [%d] cache %u index %u color %u",
  396. pasPerson->mcsID, cache, cacheEntry, colorIndex));
  397. DC_EXIT_POINT:
  398. DebugExitVOID(ASShare::RBC_MapCacheIDToBitmapHandle);
  399. return(hWorkBitmap);
  400. }
  401. //
  402. // FUNCTION: RBCStoreBitsInCacheBitmap(..)
  403. //
  404. // DESCRIPTION:
  405. //
  406. // Stores received bitmap bits into one of the receiver's cache bitmaps.
  407. //
  408. // PARAMETERS:
  409. //
  410. // pasPerson - pasPerson of host the bits came from.
  411. //
  412. // cache - the id of the cache bitmap to store the bits in.
  413. //
  414. // iCacheEntry - the cache entry number (index).
  415. //
  416. // cxSubBitmapWidth - the width in pels of the actual sub-bitmap (ie.
  417. // excluding padding)
  418. //
  419. // cxFixedWidth - the fixed width in pels of the supplied bits (ie.
  420. // including padding)
  421. //
  422. // cySubBitmapHeight - the height in pels of the sub-bitmap.
  423. //
  424. // pBitmapBits - a pointer to the actual bitmap bits. These may or may
  425. // not be compressed (determined by the value of the fCompressed
  426. // flag).
  427. //
  428. // cbBitmapBits - the size of the bitmap bits pointed to by pBitmapBits.
  429. //
  430. // fCompressed - a flag specifying whether the supplied bitmap
  431. // bits are compressed.
  432. //
  433. // RETURNS:
  434. //
  435. // Nothing.
  436. //
  437. //
  438. void ASShare::RBCStoreBitsInCacheBitmap
  439. (
  440. ASPerson * pasPerson,
  441. UINT cache,
  442. UINT iCacheEntry,
  443. UINT cxSubBitmapWidth,
  444. UINT cxFixedWidth,
  445. UINT cySubBitmapHeight,
  446. UINT bpp,
  447. LPBYTE pBitmapBits,
  448. UINT cbBitmapBits,
  449. BOOL fCompressed
  450. )
  451. {
  452. PBMC_DIB_ENTRY pDIBEntry;
  453. DebugEntry(ASShare::RBCStoreBitsInCacheBitmap);
  454. ValidatePerson(pasPerson);
  455. //
  456. // Do some error checking.
  457. //
  458. if (cache >= NUM_BMP_CACHES)
  459. {
  460. ERROR_OUT(("Invalid cache ID %d from [%d]", cache, pasPerson->mcsID));
  461. DC_QUIT;
  462. }
  463. //
  464. // Now store the bits in the cache
  465. // The cache is a huge chunk of memory comprising cache slots of cSize
  466. // bytes each. cSize is rounded to a power of 2 to ensure the array
  467. // spans segment boundaries cleanly for segmented architecture OSs.
  468. //
  469. pDIBEntry = (PBMC_DIB_ENTRY)
  470. (((LPBYTE)(pasPerson->prbcHost->bitmapCache[cache].data) +
  471. (iCacheEntry * pasPerson->prbcHost->bitmapCache[cache].cSize)));
  472. TRACE_OUT(( "Selected cache entry 0x%08x",pDIBEntry));
  473. pDIBEntry->inUse = TRUE;
  474. pDIBEntry->cx = (TSHR_UINT16)cxSubBitmapWidth;
  475. pDIBEntry->cxFixed = (TSHR_UINT16)cxFixedWidth;
  476. pDIBEntry->cy = (TSHR_UINT16)cySubBitmapHeight;
  477. pDIBEntry->bpp = (TSHR_UINT16)bpp;
  478. pDIBEntry->bCompressed = (fCompressed != FALSE);
  479. pDIBEntry->cCompressed = cbBitmapBits;
  480. //
  481. // Now copy the bits into the cache entry
  482. //
  483. memcpy(pDIBEntry->bits, pBitmapBits, cbBitmapBits);
  484. //
  485. // THIS FIELD IS NEVER ACCESSED.
  486. //
  487. pDIBEntry->cBits = BYTES_IN_BITMAP(cxFixedWidth, cySubBitmapHeight,
  488. pDIBEntry->bpp);
  489. DC_EXIT_POINT:
  490. DebugExitVOID(ASShare::RBCStoreBitsInCacheBitmap);
  491. }
  492. //
  493. // BMCAllocateCacheData()
  494. //
  495. // DESCRIPTION:
  496. //
  497. // Allocates memory for a bitmap cache
  498. //
  499. // PARAMETERS:
  500. //
  501. // cellSize
  502. //
  503. // RETURNS:
  504. //
  505. // Area needed
  506. //
  507. //
  508. BOOL BMCAllocateCacheData
  509. (
  510. UINT numEntries,
  511. UINT cellSize,
  512. UINT cacheID,
  513. PBMC_DIB_CACHE pCache
  514. )
  515. {
  516. BOOL rc = TRUE;
  517. UINT memoryNeeded;
  518. UINT workSize;
  519. PBMC_DIB_ENTRY pCacheEntry;
  520. UINT i;
  521. DebugEntry(BMCAllocateCacheData);
  522. //
  523. // First we must free up any data, if it has been allocated
  524. //
  525. BMCFreeCacheData(pCache);
  526. //
  527. // For 2.x compat, we have SEND caps of 1 entry, 1 byte since 2.x
  528. // remotes fail for zero entries. But we don't want a small cache
  529. // at all, and for W95 nodes that don't have a cache at all, we don't
  530. // want viewers to alloc memory which will never be used.
  531. //
  532. if ((cellSize > 1) && (numEntries > 1))
  533. {
  534. //
  535. // Calculate the cell area
  536. //
  537. workSize = cellSize + sizeof(BMC_DIB_ENTRY) - 1;
  538. memoryNeeded = numEntries * workSize;
  539. TRACE_OUT(("Need 0x%08x bytes for cache %d, %d cells of size 0x%08x",
  540. memoryNeeded, cacheID, numEntries, cellSize));
  541. //
  542. // Malloc the huge space
  543. //
  544. pCache->data = new BYTE[memoryNeeded];
  545. if (pCache->data == NULL)
  546. {
  547. ERROR_OUT(( "Failed to alloc bitmap cache %d", cacheID));
  548. rc = FALSE;
  549. DC_QUIT;
  550. }
  551. pCache->cCellSize = cellSize;
  552. pCache->cEntries = numEntries;
  553. pCache->cSize = workSize;
  554. pCache->freeEntry = NULL;
  555. pCacheEntry = (PBMC_DIB_ENTRY)(pCache->data);
  556. for (i = 0; i < numEntries; i++)
  557. {
  558. pCacheEntry->inUse = FALSE;
  559. pCacheEntry = (PBMC_DIB_ENTRY)(((LPBYTE)pCacheEntry) + workSize);
  560. }
  561. TRACE_OUT(( "Allocated cache %d size %d, pointer 0x%08x stored at 0x%08x",
  562. cacheID,
  563. memoryNeeded,
  564. pCache->data,
  565. &pCache->data));
  566. }
  567. DC_EXIT_POINT:
  568. DebugExitBOOL(BMCAllocateCacheData, rc);
  569. return(rc);
  570. }
  571. //
  572. // FUNCTION: BMCFreeCacheData()
  573. //
  574. // DESCRIPTION:
  575. //
  576. // Deletes selected cache's memory
  577. //
  578. // PARAMETERS:
  579. //
  580. // cacheID - id of cache for free
  581. // pCache - pointer to memory to be freed
  582. //
  583. //
  584. // RETURNS:
  585. //
  586. // Nothing.
  587. //
  588. //
  589. void BMCFreeCacheData(PBMC_DIB_CACHE pCache)
  590. {
  591. DebugEntry(BMCFreeCacheData);
  592. if (pCache->data)
  593. {
  594. delete[] pCache->data;
  595. pCache->data = NULL;
  596. }
  597. pCache->cCellSize = 0;
  598. pCache->cEntries = 0;
  599. DebugExitVOID(BMCFreeCacheData);
  600. }
  601.