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.

1194 lines
19 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation 1999
  3. Module Name:
  4. buffers
  5. Abstract:
  6. This module provides the implementation for the high-performance buffer
  7. management class.
  8. Author:
  9. Doug Barlow (dbarlow) 9/2/1999
  10. Notes:
  11. ?Notes?
  12. --*/
  13. #ifndef WIN32_LEAN_AND_MEAN
  14. #define WIN32_LEAN_AND_MEAN
  15. #endif
  16. #include <windows.h>
  17. #include <stdlib.h>
  18. #include "cspUtils.h"
  19. #define DALC_STATIC 0
  20. #define DALC_HEAP 1
  21. //
  22. //==============================================================================
  23. //
  24. // CBufferReference
  25. //
  26. class CBufferReference
  27. {
  28. protected:
  29. typedef void (__cdecl *deallocator)(LPBYTE pbBuffer);
  30. static const deallocator Static; // The data was statically referenced.
  31. static const deallocator Heap; // The data came from the process heap.
  32. // Constructors & Destructor
  33. CBufferReference(void);
  34. virtual ~CBufferReference();
  35. // Properties
  36. ULONG m_nReferenceCount;
  37. ULONG m_cbBufferLength;
  38. LPBYTE m_pbBuffer;
  39. deallocator m_pfDeallocator;
  40. // Methods
  41. ULONG AddRef(void);
  42. ULONG Release(void);
  43. void Clear(void);
  44. void Set(LPCBYTE pbData, ULONG cbLength, deallocator pfDealloc = Static);
  45. LPCBYTE Value(void) const
  46. { return m_pbBuffer; };
  47. LPBYTE Access(void) const
  48. { return m_pbBuffer; };
  49. ULONG Space(void) const
  50. { return m_cbBufferLength; };
  51. LPBYTE Preallocate(ULONG cbLength);
  52. LPBYTE Reallocate(ULONG cbLength);
  53. // Operators
  54. // Friends
  55. friend class CBuffer;
  56. };
  57. //
  58. //==============================================================================
  59. //
  60. // Static definitions
  61. //
  62. const CBufferReference::deallocator
  63. CBufferReference::Static = (CBufferReference::deallocator)DALC_STATIC,
  64. CBufferReference::Heap = (CBufferReference::deallocator)DALC_HEAP;
  65. /*++
  66. NoMemory:
  67. This routine controls the action to be taken when no memory can be
  68. allocated for use.
  69. Arguments:
  70. None
  71. Return Value:
  72. None
  73. Throws:
  74. Throws a DWORD or raises an exception.
  75. Remarks:
  76. ?Remarks?
  77. Author:
  78. Doug Barlow (dbarlow) 9/2/1999
  79. --*/
  80. #undef __SUBROUTINE__
  81. #define __SUBROUTINE__ TEXT("NoMemory")
  82. static void
  83. NoMemory(
  84. void)
  85. {
  86. throw (DWORD)ERROR_OUTOFMEMORY;
  87. }
  88. //
  89. //==============================================================================
  90. //
  91. // CBufferReference
  92. //
  93. // This class is hidden from normal use. It actually mantains the buffer
  94. // and it's reference count. It knows how to release the buffer when there
  95. // is noone referring to it.
  96. //
  97. /*++
  98. CBufferReference::CBufferReference:
  99. This is the default constructor for the CBufferReference object.
  100. Arguments:
  101. None
  102. Return Value:
  103. None
  104. Throws:
  105. None
  106. Remarks:
  107. Note that the object is not automatically referenced upon creation!
  108. Delete it using the Release method.
  109. Author:
  110. Doug Barlow (dbarlow) 9/2/1999
  111. --*/
  112. #undef __SUBROUTINE__
  113. #define __SUBROUTINE__ TEXT("CBufferReference::CBufferReference")
  114. CBufferReference::CBufferReference(
  115. void)
  116. {
  117. m_nReferenceCount = 0;
  118. m_cbBufferLength = 0;
  119. m_pbBuffer = NULL;
  120. m_pfDeallocator = CBufferReference::Static;
  121. }
  122. /*++
  123. CBufferReference::~CBufferReference:
  124. This is the destructor for the CBufferReference object. It is called only
  125. by the Release method.
  126. Arguments:
  127. None
  128. Return Value:
  129. None
  130. Throws:
  131. None
  132. Remarks:
  133. ?Remarks?
  134. Author:
  135. Doug Barlow (dbarlow) 9/2/1999
  136. --*/
  137. #undef __SUBROUTINE__
  138. #define __SUBROUTINE__ TEXT("CBufferReference::~CBufferReference")
  139. CBufferReference::~CBufferReference()
  140. {
  141. Clear();
  142. }
  143. /*++
  144. CBufferReference::AddRef:
  145. This method increments the reference count of the object.
  146. Arguments:
  147. None
  148. Return Value:
  149. The new number of outstanding references.
  150. Throws:
  151. None
  152. Remarks:
  153. ?Remarks?
  154. Author:
  155. Doug Barlow (dbarlow) 9/2/1999
  156. --*/
  157. #undef __SUBROUTINE__
  158. #define __SUBROUTINE__ TEXT("CBufferReference::AddRef")
  159. ULONG
  160. CBufferReference::AddRef(
  161. void)
  162. {
  163. m_nReferenceCount += 1;
  164. return m_nReferenceCount;
  165. }
  166. /*++
  167. CBufferReference::Release:
  168. This method decrements the object's reference count, and if it reaches zero,
  169. the object is automatically deleted.
  170. Arguments:
  171. None
  172. Return Value:
  173. The new reference count. A Return code of zero imples the object was
  174. deleted.
  175. Throws:
  176. None
  177. Remarks:
  178. ?Remarks?
  179. Author:
  180. Doug Barlow (dbarlow) 9/2/1999
  181. --*/
  182. #undef __SUBROUTINE__
  183. #define __SUBROUTINE__ TEXT("CBufferReference::Release")
  184. ULONG
  185. CBufferReference::Release(
  186. void)
  187. {
  188. ULONG nReturn;
  189. ASSERT(0 < m_nReferenceCount);
  190. m_nReferenceCount -= 1;
  191. nReturn = m_nReferenceCount;
  192. if (0 == m_nReferenceCount)
  193. delete this;
  194. return nReturn;
  195. }
  196. /*++
  197. CBufferReference::Clear:
  198. This method clears out any existing buffer in preparation for adding a new
  199. one, or to delete the object.
  200. Arguments:
  201. None
  202. Return Value:
  203. None
  204. Throws:
  205. None
  206. Remarks:
  207. ?Remarks?
  208. Author:
  209. Doug Barlow (dbarlow) 9/2/1999
  210. --*/
  211. #undef __SUBROUTINE__
  212. #define __SUBROUTINE__ TEXT("CBufferReference::Clear")
  213. void
  214. CBufferReference::Clear(
  215. void)
  216. {
  217. if (NULL != m_pbBuffer)
  218. {
  219. switch ((ULONG_PTR)m_pfDeallocator)
  220. {
  221. case DALC_STATIC:
  222. break;
  223. case DALC_HEAP:
  224. HeapFree(GetProcessHeap(), 0, m_pbBuffer);
  225. break;
  226. default:
  227. ASSERT(NULL != m_pfDeallocator);
  228. (*m_pfDeallocator)(m_pbBuffer);
  229. }
  230. }
  231. m_pbBuffer = NULL;
  232. m_cbBufferLength = 0;
  233. m_pfDeallocator = Static;
  234. }
  235. /*++
  236. CBufferReference::Set:
  237. This method establishes the contents of the buffer.
  238. Arguments:
  239. pbData supplies the new data to be loaded.
  240. cbLength supplies the length of the data, in bytes.
  241. pfDealloc supplies the deallocator to be called when the data is no longer
  242. needed.
  243. Return Value:
  244. None
  245. Throws:
  246. None
  247. Remarks:
  248. The value is changed for all referencers of the buffer.
  249. Author:
  250. Doug Barlow (dbarlow) 9/2/1999
  251. --*/
  252. #undef __SUBROUTINE__
  253. #define __SUBROUTINE__ TEXT("CBufferReference::Set")
  254. void
  255. CBufferReference::Set(
  256. LPCBYTE pbData,
  257. ULONG cbLength,
  258. deallocator pfDealloc)
  259. {
  260. Clear();
  261. m_cbBufferLength = cbLength;
  262. m_pbBuffer = const_cast<LPBYTE>(pbData);
  263. m_pfDeallocator = pfDealloc;
  264. }
  265. /*++
  266. CBufferReference::Preallocate:
  267. This method prepares an empty buffer to be managed.
  268. Arguments:
  269. cbLength supplies the length of the requested buffer, in bytes.
  270. Return Value:
  271. The address of the allocated buffer.
  272. Throws:
  273. ?exceptions?
  274. Remarks:
  275. The value is changed for all referencers of the buffer.
  276. Author:
  277. Doug Barlow (dbarlow) 9/2/1999
  278. --*/
  279. #undef __SUBROUTINE__
  280. #define __SUBROUTINE__ TEXT("CBufferReference::Preallocate")
  281. LPBYTE
  282. CBufferReference::Preallocate(
  283. ULONG cbLength)
  284. {
  285. LPBYTE pbBuf = (LPBYTE)HeapAlloc(
  286. GetProcessHeap(),
  287. HEAP_ZERO_MEMORY,
  288. cbLength);
  289. if (NULL == pbBuf)
  290. NoMemory();
  291. Set(pbBuf, cbLength, Heap);
  292. return pbBuf;
  293. }
  294. /*++
  295. CBufferReference::Reallocate:
  296. This method changes the size of the allocated buffer. No data is lost.
  297. Arguments:
  298. cbLength supplies the length of the buffer.
  299. Return Value:
  300. The address of the buffer.
  301. Throws:
  302. ?exceptions?
  303. Remarks:
  304. The value is changed for all referencers of the buffer.
  305. Author:
  306. Doug Barlow (dbarlow) 9/2/1999
  307. --*/
  308. #undef __SUBROUTINE__
  309. #define __SUBROUTINE__ TEXT("CBufferReference::Reallocate")
  310. LPBYTE
  311. CBufferReference::Reallocate(
  312. ULONG cbLength)
  313. {
  314. LPBYTE pbBuf;
  315. if (NULL == m_pbBuffer)
  316. pbBuf = Preallocate(cbLength);
  317. else
  318. {
  319. switch ((ULONG_PTR)m_pfDeallocator)
  320. {
  321. case DALC_HEAP:
  322. pbBuf = (LPBYTE)HeapReAlloc(
  323. GetProcessHeap(),
  324. HEAP_ZERO_MEMORY,
  325. m_pbBuffer,
  326. cbLength);
  327. if (NULL == pbBuf)
  328. NoMemory();
  329. m_pbBuffer = pbBuf;
  330. m_cbBufferLength = cbLength;
  331. m_pfDeallocator = Heap;
  332. case DALC_STATIC:
  333. m_pfDeallocator = NULL;
  334. // Fall through to default case
  335. default:
  336. pbBuf = (LPBYTE)HeapAlloc(
  337. GetProcessHeap(),
  338. HEAP_ZERO_MEMORY,
  339. cbLength);
  340. if (NULL == pbBuf)
  341. NoMemory();
  342. CopyMemory(pbBuf, m_pbBuffer, __min(cbLength, m_cbBufferLength));
  343. Set(pbBuf, cbLength, Heap);
  344. }
  345. }
  346. return pbBuf;
  347. }
  348. //
  349. //==============================================================================
  350. //
  351. // CBuffer
  352. //
  353. // This class exposes access to the CBufferReference class.
  354. //
  355. /*++
  356. CBuffer::CBuffer:
  357. These methods are the constructors of the CBuffer object.
  358. Arguments:
  359. pbData supplies static data with which to initialize the object.
  360. cbLength supplies the length of the initialization data.
  361. Return Value:
  362. None
  363. Throws:
  364. ?exceptions?
  365. Remarks:
  366. ?Remarks?
  367. Author:
  368. Doug Barlow (dbarlow) 9/2/1999
  369. --*/
  370. #undef __SUBROUTINE__
  371. #define __SUBROUTINE__ TEXT("CBuffer::CBuffer")
  372. CBuffer::CBuffer(
  373. void)
  374. {
  375. Init();
  376. }
  377. CBuffer::CBuffer(
  378. ULONG cbLength)
  379. {
  380. Init();
  381. Space(cbLength);
  382. }
  383. CBuffer::CBuffer(
  384. LPCBYTE pbData,
  385. ULONG cbLength)
  386. {
  387. Init();
  388. Set(pbData, cbLength);
  389. }
  390. /*++
  391. CBuffer::~CBuffer:
  392. This is the destructor for the CBuffer object.
  393. Arguments:
  394. None
  395. Return Value:
  396. None
  397. Throws:
  398. None
  399. Remarks:
  400. ?Remarks?
  401. Author:
  402. Doug Barlow (dbarlow) 9/2/1999
  403. --*/
  404. #undef __SUBROUTINE__
  405. #define __SUBROUTINE__ TEXT("CBuffer::~CBuffer")
  406. CBuffer::~CBuffer()
  407. {
  408. if (NULL != m_pbfr)
  409. m_pbfr->Release();
  410. }
  411. /*++
  412. CBuffer::Init:
  413. This is a common routine shared between all the constructors. It does
  414. all the preliminary initialization. It should only be called by
  415. constructors.
  416. Arguments:
  417. None
  418. Return Value:
  419. None
  420. Throws:
  421. None
  422. Remarks:
  423. ?Remarks?
  424. Author:
  425. Doug Barlow (dbarlow) 9/2/1999
  426. --*/
  427. #undef __SUBROUTINE__
  428. #define __SUBROUTINE__ TEXT("CBuffer::Init")
  429. void
  430. CBuffer::Init(
  431. void)
  432. {
  433. m_pbfr = NULL;
  434. m_cbDataLength = 0;
  435. }
  436. /*++
  437. CBuffer::Empty:
  438. This routine sets the buffer to an empty state.
  439. Arguments:
  440. None
  441. Return Value:
  442. None
  443. Throws:
  444. None
  445. Remarks:
  446. ?Remarks?
  447. Author:
  448. Doug Barlow (dbarlow) 9/2/1999
  449. --*/
  450. #undef __SUBROUTINE__
  451. #define __SUBROUTINE__ TEXT("CBuffer::Empty")
  452. void
  453. CBuffer::Empty(
  454. void)
  455. {
  456. if (NULL != m_pbfr)
  457. {
  458. m_pbfr->Release();
  459. m_pbfr = NULL;
  460. }
  461. m_cbDataLength = 0;
  462. }
  463. /*++
  464. CBuffer::Set:
  465. This method sets the object to the specified value.
  466. Arguments:
  467. pbData supplies the value to be set, as static data.
  468. cbLength supplies the length of the pbData buffer, in bytes.
  469. pbfr supplies a buffer reference object to use.
  470. Return Value:
  471. None
  472. Throws:
  473. ?exceptions?
  474. Remarks:
  475. ?Remarks?
  476. Author:
  477. Doug Barlow (dbarlow) 9/2/1999
  478. --*/
  479. #undef __SUBROUTINE__
  480. #define __SUBROUTINE__ TEXT("CBuffer::Set")
  481. void
  482. CBuffer::Set(
  483. LPCBYTE pbData,
  484. ULONG cbLength)
  485. {
  486. CBufferReference *pbfr = new CBufferReference;
  487. if (NULL == pbfr)
  488. NoMemory();
  489. pbfr->Set(pbData, cbLength);
  490. Set(pbfr); // That will AddRef it.
  491. m_cbDataLength = cbLength;
  492. }
  493. void
  494. CBuffer::Set(
  495. CBufferReference *pbfr)
  496. {
  497. if (NULL != m_pbfr)
  498. m_pbfr->Release();
  499. m_cbDataLength = 0;
  500. m_pbfr = pbfr;
  501. m_pbfr->AddRef();
  502. }
  503. /*++
  504. CBuffer::Copy:
  505. This method forces the object to make a private copy of the specified
  506. value.
  507. Arguments:
  508. pbData supplies the value to be set, as static data.
  509. cbLength supplies the length of the pbData buffer, in bytes.
  510. Return Value:
  511. None
  512. Throws:
  513. ?exceptions?
  514. Remarks:
  515. ?Remarks?
  516. Author:
  517. Doug Barlow (dbarlow) 9/2/1999
  518. --*/
  519. #undef __SUBROUTINE__
  520. #define __SUBROUTINE__ TEXT("CBuffer::Copy")
  521. void
  522. CBuffer::Copy(
  523. LPCBYTE pbData,
  524. ULONG cbLength)
  525. {
  526. CBufferReference *pbfr = new CBufferReference;
  527. if (NULL == pbfr)
  528. NoMemory();
  529. pbfr->Preallocate(cbLength);
  530. CopyMemory(pbfr->Access(), pbData, cbLength);
  531. Set(pbfr); // That will AddRef it.
  532. m_cbDataLength = cbLength;
  533. }
  534. /*++
  535. CBuffer::Append:
  536. This method appends additional data onto existing data, creating a new
  537. CBufferReference if necessary.
  538. Arguments:
  539. pbData supplies the data to be appended onto the existing buffer.
  540. cbLength supplies the length of that data, in bytes.
  541. Return Value:
  542. None
  543. Throws:
  544. ?exceptions?
  545. Remarks:
  546. ?Remarks?
  547. Author:
  548. Doug Barlow (dbarlow) 9/2/1999
  549. --*/
  550. #undef __SUBROUTINE__
  551. #define __SUBROUTINE__ TEXT("CBuffer::Append")
  552. void
  553. CBuffer::Append(
  554. LPCBYTE pbData,
  555. ULONG cbLength)
  556. {
  557. ULONG cbDesired = Length() + cbLength;
  558. if (NULL == m_pbfr)
  559. Set(pbData, cbLength);
  560. else if (cbDesired < m_pbfr->Space())
  561. {
  562. CopyMemory(m_pbfr->Access() + Length(), pbData, cbLength);
  563. m_cbDataLength = cbDesired;
  564. }
  565. else
  566. {
  567. m_pbfr->Reallocate(cbDesired);
  568. CopyMemory(m_pbfr->Access() + Length(), pbData, cbLength);
  569. m_cbDataLength = cbDesired;
  570. }
  571. }
  572. /*++
  573. CBuffer::Space:
  574. This method returns the size of the existing buffer, in bytes. This is the
  575. length of the actual buffer, not the length of any data stored within the
  576. buffer. Note that it is possible for the stored data to be shorter than
  577. the buffer.
  578. Arguments:
  579. None
  580. Return Value:
  581. The length of the buffer, in bytes.
  582. Throws:
  583. None
  584. Remarks:
  585. ?Remarks?
  586. Author:
  587. Doug Barlow (dbarlow) 9/2/1999
  588. --*/
  589. #undef __SUBROUTINE__
  590. #define __SUBROUTINE__ TEXT("CBuffer::Space")
  591. ULONG
  592. CBuffer::Space(
  593. void)
  594. const
  595. {
  596. ULONG cbLen = 0;
  597. if (NULL != m_pbfr)
  598. cbLen = m_pbfr->Space();
  599. return cbLen;
  600. }
  601. /*++
  602. CBuffer::Space:
  603. This method forces the referenced buffer to be at least as long as the
  604. length supplied. Data will be lost.
  605. Arguments:
  606. cbLength supplies the requested minimum length of the buffer.
  607. Return Value:
  608. The address of the allocated buffer.
  609. Throws:
  610. ?exceptions?
  611. Remarks:
  612. ?Remarks?
  613. Author:
  614. Doug Barlow (dbarlow) 9/2/1999
  615. --*/
  616. #undef __SUBROUTINE__
  617. #define __SUBROUTINE__ TEXT("CBuffer::Space")
  618. LPBYTE
  619. CBuffer::Space(
  620. ULONG cbLength)
  621. {
  622. CBufferReference *pbfr = new CBufferReference;
  623. if (NULL == pbfr)
  624. NoMemory();
  625. pbfr->Preallocate(cbLength);
  626. Set(pbfr);
  627. return Access();
  628. }
  629. /*++
  630. CBuffer::Extend:
  631. This method provides more space in the buffer without losing the data
  632. that's already there.
  633. Arguments:
  634. cbLength supplies the required buffer length, in bytes.
  635. Return Value:
  636. None
  637. Throws:
  638. ?exceptions?
  639. Remarks:
  640. ?Remarks?
  641. Author:
  642. Doug Barlow (dbarlow) 9/3/1999
  643. --*/
  644. #undef __SUBROUTINE__
  645. #define __SUBROUTINE__ TEXT("CBuffer::Extend")
  646. LPBYTE
  647. CBuffer::Extend(
  648. ULONG cbLength)
  649. {
  650. ULONG cbLen = m_cbDataLength;
  651. CBufferReference *pbfr = new CBufferReference;
  652. if (NULL == pbfr)
  653. NoMemory();
  654. pbfr->Preallocate(cbLength);
  655. CopyMemory(pbfr->Access(), Value(), cbLen);
  656. Set(pbfr);
  657. m_cbDataLength = cbLen;
  658. return Access();
  659. }
  660. /*++
  661. CBuffer::Length:
  662. This method returns the number of bytes of actual data stored within the
  663. internal buffer.
  664. Arguments:
  665. None
  666. Return Value:
  667. The length of the data in the buffer, in bytes.
  668. Throws:
  669. None
  670. Remarks:
  671. ?Remarks?
  672. Author:
  673. Doug Barlow (dbarlow) 9/2/1999
  674. --*/
  675. #undef __SUBROUTINE__
  676. #define __SUBROUTINE__ TEXT("CBuffer::Length")
  677. ULONG
  678. CBuffer::Length(
  679. void)
  680. const
  681. {
  682. return m_cbDataLength;
  683. }
  684. /*++
  685. CBuffer::Length:
  686. This method resizes the length of the data stored in the buffer. It does
  687. not attempt to resize the buffer itself. The purpose of this routine is to
  688. declare the size of data written into a the buffer by an outside source.
  689. Arguments:
  690. cbLength supplies the actual length of useful data currently in the buffer.
  691. Return Value:
  692. The address of the buffer.
  693. Throws:
  694. None
  695. Remarks:
  696. The data length is set to at most the length of the underlying buffer.
  697. Use Extend if the buffer needs to be longer.
  698. Author:
  699. Doug Barlow (dbarlow) 9/2/1999
  700. --*/
  701. #undef __SUBROUTINE__
  702. #define __SUBROUTINE__ TEXT("CBuffer::Length")
  703. LPCBYTE
  704. CBuffer::Length(
  705. ULONG cbLength)
  706. {
  707. ULONG cbActLen = cbLength;
  708. if (NULL != m_pbfr)
  709. {
  710. if (cbActLen > m_pbfr->Space())
  711. cbActLen = m_pbfr->Space();
  712. }
  713. else
  714. cbActLen = 0;
  715. m_cbDataLength = cbActLen;
  716. ASSERT(cbLength == cbActLen); // Catch mistakes
  717. return Value();
  718. }
  719. /*++
  720. CBuffer::Value:
  721. This method returns the contents of the buffer as a Read Only Byte Array.
  722. Arguments:
  723. nOffset supplies an offset into the data, in bytes.
  724. Return Value:
  725. The address of the data, offset by the supplied parameter.
  726. Throws:
  727. None
  728. Remarks:
  729. If no buffer exists, or the offset exceeds the data, then a temporary
  730. value is supplied.
  731. Author:
  732. Doug Barlow (dbarlow) 9/2/1999
  733. --*/
  734. #undef __SUBROUTINE__
  735. #define __SUBROUTINE__ TEXT("CBuffer::Value")
  736. LPCBYTE
  737. CBuffer::Value(
  738. ULONG nOffset)
  739. const
  740. {
  741. static const LPVOID pvDefault = NULL;
  742. LPCBYTE pbRet = (LPCBYTE)&pvDefault;
  743. if (NULL != m_pbfr)
  744. {
  745. if (nOffset < Length())
  746. pbRet = m_pbfr->Value() + nOffset;
  747. }
  748. return pbRet;
  749. }
  750. /*++
  751. CBuffer::Access:
  752. This method supplies the the buffer as a writable space. The expected
  753. length must have been preset.
  754. Arguments:
  755. nOffset supplies an offset into the buffer, in bytes.
  756. Return Value:
  757. The address of the buffer, offset by the supplied parameter.
  758. Throws:
  759. ?exceptions?
  760. Remarks:
  761. ?Remarks?
  762. Author:
  763. Doug Barlow (dbarlow) 9/2/1999
  764. --*/
  765. #undef __SUBROUTINE__
  766. #define __SUBROUTINE__ TEXT("CBuffer::Access")
  767. LPBYTE
  768. CBuffer::Access(
  769. ULONG nOffset)
  770. const
  771. {
  772. LPBYTE pbRet = NULL;
  773. if (NULL != m_pbfr)
  774. {
  775. if (nOffset <= m_pbfr->Space())
  776. pbRet = m_pbfr->Access() + nOffset;
  777. else
  778. pbRet = NULL;
  779. }
  780. return pbRet;
  781. }