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.

709 lines
15 KiB

  1. /*++
  2. Microsoft Windows
  3. Copyright (c) 1994 Microsoft Corporation. All rights reserved.
  4. Module Name:
  5. stream.cxx
  6. Abstract:
  7. Implements the IStream interface on a memory buffer.
  8. Author:
  9. ShannonC 09-Mar-1994
  10. Environment:
  11. Windows NT and Windows 95. We do not support DOS and Win16.
  12. Revision History:
  13. 12-Oct-94 ShannonC Reformat for code review.
  14. --*/
  15. #include <ndrp.h>
  16. #include <ndrole.h>
  17. class CNdrStream : public IStream
  18. {
  19. public:
  20. virtual HRESULT STDMETHODCALLTYPE
  21. QueryInterface(
  22. IN REFIID riid,
  23. OUT void **ppvObj);
  24. virtual ULONG STDMETHODCALLTYPE
  25. AddRef();
  26. virtual ULONG STDMETHODCALLTYPE
  27. Release();
  28. virtual HRESULT STDMETHODCALLTYPE
  29. Read(
  30. IN void * pv,
  31. IN ULONG cb,
  32. OUT ULONG * pcbRead);
  33. virtual HRESULT STDMETHODCALLTYPE
  34. Write(
  35. IN void const *pv,
  36. IN ULONG cb,
  37. OUT ULONG * pcbWritten);
  38. virtual HRESULT STDMETHODCALLTYPE
  39. Seek(
  40. IN LARGE_INTEGER dlibMove,
  41. IN DWORD dwOrigin,
  42. OUT ULARGE_INTEGER *plibNewPosition);
  43. virtual HRESULT STDMETHODCALLTYPE
  44. SetSize(
  45. IN ULARGE_INTEGER libNewSize);
  46. virtual HRESULT STDMETHODCALLTYPE
  47. CopyTo(
  48. IN IStream * pstm,
  49. IN ULARGE_INTEGER cb,
  50. OUT ULARGE_INTEGER *pcbRead,
  51. OUT ULARGE_INTEGER *pcbWritten);
  52. virtual HRESULT STDMETHODCALLTYPE
  53. Commit(
  54. IN DWORD grfCommitFlags);
  55. virtual HRESULT STDMETHODCALLTYPE
  56. Revert();
  57. virtual HRESULT STDMETHODCALLTYPE
  58. LockRegion(
  59. IN ULARGE_INTEGER libOffset,
  60. IN ULARGE_INTEGER cb,
  61. IN DWORD dwLockType);
  62. virtual HRESULT STDMETHODCALLTYPE
  63. UnlockRegion(
  64. IN ULARGE_INTEGER libOffset,
  65. IN ULARGE_INTEGER cb,
  66. IN DWORD dwLockType);
  67. virtual HRESULT STDMETHODCALLTYPE
  68. Stat(
  69. OUT STATSTG * pstatstg,
  70. IN DWORD grfStatFlag);
  71. virtual HRESULT STDMETHODCALLTYPE
  72. Clone(
  73. OUT IStream **ppstm);
  74. CNdrStream(
  75. IN unsigned char * pData,
  76. IN unsigned long cbMax);
  77. private:
  78. long RefCount;
  79. unsigned char * pBuffer;
  80. unsigned long cbBufferLength;
  81. unsigned long position;
  82. };
  83. EXTERN_C IStream *STDAPICALLTYPE
  84. NdrpCreateStreamOnMemory(
  85. IN unsigned char * pData,
  86. IN unsigned long cbSize)
  87. /*++
  88. Routine Description:
  89. This function creates a stream on the specified memory buffer.
  90. Arguments:
  91. pData - Supplies pointer to memory buffer.
  92. cbSize - Supplies size of memory buffer.
  93. Return Value:
  94. This function returns a pointer to the newly created stream.
  95. --*/
  96. {
  97. CNdrStream *pStream = new CNdrStream(pData, cbSize);
  98. return (IStream *)pStream;
  99. }
  100. CNdrStream::CNdrStream(
  101. IN unsigned char * pData,
  102. IN unsigned long cbMax)
  103. : pBuffer(pData), cbBufferLength(cbMax)
  104. /*++
  105. Routine Description:
  106. This function creates a stream on the specified memory buffer.
  107. Arguments:
  108. pData - Supplies pointer to memory buffer.
  109. cbMax - Supplies size of memory buffer.
  110. Return Value:
  111. None.
  112. --*/
  113. {
  114. RefCount = 1;
  115. position = 0;
  116. }
  117. ULONG STDMETHODCALLTYPE
  118. CNdrStream::AddRef()
  119. /*++
  120. Routine Description:
  121. Increment the reference count.
  122. Arguments:
  123. Return Value:
  124. Reference count.
  125. --*/
  126. {
  127. InterlockedIncrement(&RefCount);
  128. return (ULONG) RefCount;
  129. }
  130. HRESULT STDMETHODCALLTYPE
  131. CNdrStream::Clone(
  132. OUT IStream **ppstm)
  133. /*++
  134. Routine Description:
  135. Create a new IStream object. The new IStream gets an
  136. independent seek pointer but it shares the underlying
  137. data buffer with the original IStream object.
  138. Arguments:
  139. ppstm - Pointer to the new stream.
  140. Return Value:
  141. S_OK - The stream was successfully copied.
  142. E_OUTOFMEMORY - The stream could not be copied due to lack of memory.
  143. --*/
  144. {
  145. HRESULT hr;
  146. CNdrStream *pStream = new CNdrStream(pBuffer, cbBufferLength);
  147. if(pStream != 0)
  148. {
  149. pStream->position = position;
  150. hr = S_OK;
  151. }
  152. else
  153. {
  154. hr = E_OUTOFMEMORY;
  155. }
  156. *ppstm = (IStream *) pStream;
  157. return hr;
  158. }
  159. HRESULT STDMETHODCALLTYPE
  160. CNdrStream::Commit(
  161. IN DWORD grfCommitFlags)
  162. /*++
  163. Routine Description:
  164. This stream does not support transacted mode. This function does nothing.
  165. Arguments:
  166. grfCommitFlags
  167. Return Value:
  168. S_OK
  169. --*/
  170. {
  171. return S_OK;
  172. }
  173. HRESULT STDMETHODCALLTYPE
  174. CNdrStream::CopyTo(
  175. IN IStream * pstm,
  176. IN ULARGE_INTEGER cb,
  177. OUT ULARGE_INTEGER *pcbRead,
  178. OUT ULARGE_INTEGER *pcbWritten)
  179. /*++
  180. Routine Description:
  181. Copies data from one stream to another stream.
  182. Arguments:
  183. pstm - Specifies the destination stream.
  184. cb - Specifies the number of bytes to be copied to the destination stream.
  185. pcbRead - Returns the number of bytes read from the source stream.
  186. pcbWritten - Returns the number of bytes written to the destination stream.
  187. Return Value:
  188. S_OK - The data was successfully copied.
  189. Other errors from IStream::Write.
  190. --*/
  191. {
  192. HRESULT hr;
  193. unsigned char * pSource;
  194. unsigned long cbRead;
  195. unsigned long cbWritten;
  196. unsigned long cbRemaining;
  197. //Check if we are going off the end of the buffer.
  198. if(position < cbBufferLength)
  199. cbRemaining = cbBufferLength - position;
  200. else
  201. cbRemaining = 0;
  202. if((cb.HighPart == 0) && (cb.LowPart <= cbRemaining))
  203. cbRead = cb.LowPart;
  204. else
  205. cbRead = cbRemaining;
  206. pSource = pBuffer + position;
  207. //copy the data
  208. hr = pstm->Write(pSource, cbRead, &cbWritten);
  209. //advance the current position
  210. position += cbRead;
  211. if (pcbRead != 0)
  212. {
  213. pcbRead->LowPart = cbRead;
  214. pcbRead->HighPart = 0;
  215. }
  216. if (pcbWritten != 0)
  217. {
  218. pcbWritten->LowPart = cbWritten;
  219. pcbWritten->HighPart = 0;
  220. }
  221. return hr;
  222. }
  223. HRESULT STDMETHODCALLTYPE
  224. CNdrStream::LockRegion(
  225. IN ULARGE_INTEGER libOffset,
  226. IN ULARGE_INTEGER cb,
  227. IN DWORD dwLockType)
  228. /*++
  229. Routine Description:
  230. Range locking is not supported by this stream.
  231. Return Value:
  232. STG_E_INVALIDFUNCTION.
  233. --*/
  234. {
  235. return STG_E_INVALIDFUNCTION;
  236. }
  237. HRESULT STDMETHODCALLTYPE
  238. CNdrStream::QueryInterface(
  239. REFIID riid,
  240. void **ppvObj)
  241. /*++
  242. Routine Description:
  243. Query for an interface on the stream. The stream supports
  244. the IUnknown and IStream interfaces.
  245. Arguments:
  246. riid - Supplies the IID of the interface being requested.
  247. ppvObject - Returns a pointer to the requested interface.
  248. Return Value:
  249. S_OK
  250. E_NOINTERFACE
  251. --*/
  252. {
  253. HRESULT hr;
  254. if ((memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) ||
  255. (memcmp(&riid, &IID_IStream, sizeof(IID)) == 0))
  256. {
  257. this->AddRef();
  258. *ppvObj = (IStream *) this;
  259. hr = S_OK;
  260. }
  261. else
  262. {
  263. *ppvObj = 0;
  264. hr = E_NOINTERFACE;
  265. }
  266. return hr;
  267. }
  268. HRESULT STDMETHODCALLTYPE
  269. CNdrStream::Read(
  270. OUT void * pv,
  271. IN ULONG cb,
  272. OUT ULONG *pcbRead)
  273. /*++
  274. Routine Description:
  275. Reads data from the stream starting at the current seek pointer.
  276. Arguments:
  277. pv - Returns the data read from the stream.
  278. cb - Supplies the number of bytes to read from the stream.
  279. pcbRead - Returns the number of bytes actually read from the stream.
  280. Return Value:
  281. S_OK - The data was successfully read from the stream.
  282. S_FALSE - The number of bytes read was smaller than the number requested.
  283. --*/
  284. {
  285. HRESULT hr;
  286. unsigned long cbRead;
  287. unsigned long cbRemaining;
  288. //Check if we are reading past the end of the buffer.
  289. if(position < cbBufferLength)
  290. cbRemaining = cbBufferLength - position;
  291. else
  292. cbRemaining = 0;
  293. if(cb <= cbRemaining)
  294. {
  295. cbRead = cb;
  296. hr = S_OK;
  297. }
  298. else
  299. {
  300. cbRead = cbRemaining;
  301. hr = S_FALSE;
  302. }
  303. //copy the data
  304. RpcpMemoryCopy(pv, pBuffer + position, cbRead);
  305. //advance the current position
  306. position += cbRead;
  307. if(pcbRead != 0)
  308. *pcbRead = cbRead;
  309. return hr;
  310. }
  311. ULONG STDMETHODCALLTYPE
  312. CNdrStream::Release()
  313. /*++
  314. Routine Description:
  315. Decrement the reference count. When the reference count
  316. reaches zero, the stream is deleted.
  317. Arguments:
  318. Return Value:
  319. Reference count.
  320. --*/
  321. {
  322. unsigned long count;
  323. count = RefCount - 1;
  324. if(InterlockedDecrement(&RefCount) == 0)
  325. {
  326. count = 0;
  327. delete this;
  328. }
  329. return count;
  330. }
  331. HRESULT STDMETHODCALLTYPE
  332. CNdrStream::Revert()
  333. /*++
  334. Routine Description:
  335. This stream does not support transacted mode. This function does nothing.
  336. Arguments:
  337. None.
  338. Return Value:
  339. S_OK.
  340. --*/
  341. {
  342. return S_OK;
  343. }
  344. HRESULT STDMETHODCALLTYPE
  345. CNdrStream::Seek(
  346. IN LARGE_INTEGER dlibMove,
  347. IN DWORD dwOrigin,
  348. OUT ULARGE_INTEGER *plibNewPosition)
  349. /*++
  350. Routine Description:
  351. Sets the position of the seek pointer. It is an error to seek
  352. before the beginning of the stream or past the end of the stream.
  353. Arguments:
  354. dlibMove - Supplies the offset from the position specified in dwOrigin.
  355. dwOrigin - Supplies the seek mode.
  356. plibNewPosition - Returns the new position of the seek pointer.
  357. Return Value:
  358. S_OK - The seek pointer was successfully adjusted.
  359. STG_E_INVALIDFUNCTION - dwOrigin contains invalid value.
  360. STG_E_SEEKERROR - The seek pointer cannot be positioned before the
  361. beginning of the stream or past the
  362. end of the stream.
  363. --*/
  364. {
  365. HRESULT hr;
  366. long high;
  367. long low;
  368. unsigned long offset;
  369. unsigned long cbRemaining;
  370. switch (dwOrigin)
  371. {
  372. case STREAM_SEEK_SET:
  373. //Set the seek position relative to the beginning of the stream.
  374. if((dlibMove.HighPart == 0) && (dlibMove.LowPart <= cbBufferLength))
  375. {
  376. position = dlibMove.LowPart;
  377. hr = S_OK;
  378. }
  379. else
  380. {
  381. //It is an error to seek past the end of the stream.
  382. hr = STG_E_SEEKERROR;
  383. }
  384. break;
  385. case STREAM_SEEK_CUR:
  386. //Set the seek position relative to the current position of the stream.
  387. high = (long) dlibMove.HighPart;
  388. if(high < 0)
  389. {
  390. //Negative offset
  391. low = (long) dlibMove.LowPart;
  392. offset = -low;
  393. if((high == -1) && (offset <= position))
  394. {
  395. position -= offset;
  396. hr = S_OK;
  397. }
  398. else
  399. {
  400. //It is an error to seek before the beginning of the stream.
  401. hr = STG_E_SEEKERROR;
  402. }
  403. }
  404. else
  405. {
  406. //Positive offset
  407. if(position < cbBufferLength)
  408. cbRemaining = cbBufferLength - position;
  409. else
  410. cbRemaining = 0;
  411. if((dlibMove.HighPart == 0) && (dlibMove.LowPart <= cbRemaining))
  412. {
  413. position += dlibMove.LowPart;
  414. hr = S_OK;
  415. }
  416. else
  417. {
  418. //It is an error to seek past the end of the stream.
  419. hr = STG_E_SEEKERROR;
  420. }
  421. }
  422. break;
  423. case STREAM_SEEK_END:
  424. //Set the seek position relative to the end of the stream.
  425. high = (long) dlibMove.HighPart;
  426. if(high < 0)
  427. {
  428. //Negative offset
  429. low = (long) dlibMove.LowPart;
  430. offset = -low;
  431. if((high == -1) && (offset <= cbBufferLength))
  432. {
  433. position = cbBufferLength - offset;
  434. hr = S_OK;
  435. }
  436. else
  437. {
  438. //It is an error to seek before the beginning of the stream.
  439. hr = STG_E_SEEKERROR;
  440. }
  441. }
  442. else if(dlibMove.QuadPart == 0)
  443. {
  444. position = cbBufferLength;
  445. hr = S_OK;
  446. }
  447. else
  448. {
  449. //Positive offset
  450. //It is an error to seek past the end of the stream.
  451. hr = STG_E_SEEKERROR;
  452. }
  453. break;
  454. default:
  455. //dwOrigin contains an invalid value.
  456. hr = STG_E_INVALIDFUNCTION;
  457. }
  458. if (plibNewPosition != 0)
  459. {
  460. plibNewPosition->LowPart = position;
  461. plibNewPosition->HighPart = 0;
  462. }
  463. return hr;
  464. }
  465. HRESULT STDMETHODCALLTYPE
  466. CNdrStream::SetSize(
  467. IN ULARGE_INTEGER libNewSize)
  468. /*++
  469. Routine Description:
  470. Changes the size of the stream.
  471. Arguments:
  472. libNewSize - Supplies the new size of the stream.
  473. Return Value:
  474. S_OK - The stream size was successfully changed.
  475. STG_E_MEDIUMFULL - The stream size could not be changed.
  476. --*/
  477. {
  478. HRESULT hr;
  479. if((libNewSize.HighPart == 0) && (libNewSize.LowPart <= cbBufferLength))
  480. {
  481. cbBufferLength = libNewSize.LowPart;
  482. hr = S_OK;
  483. }
  484. else
  485. {
  486. hr = STG_E_MEDIUMFULL;
  487. }
  488. return hr;
  489. }
  490. HRESULT STDMETHODCALLTYPE
  491. CNdrStream::Stat(
  492. OUT STATSTG * pstatstg,
  493. IN DWORD grfStatFlag)
  494. /*++
  495. Routine Description:
  496. This function gets information about this stream.
  497. Arguments:
  498. pstatstg - Returns information about this stream.
  499. grfStatFlg - Specifies the information to be returned in pstatstg.
  500. Return Value:
  501. S_OK.
  502. --*/
  503. {
  504. memset(pstatstg, 0, sizeof(STATSTG));
  505. pstatstg->type = STGTY_STREAM;
  506. pstatstg->cbSize.LowPart = cbBufferLength;
  507. pstatstg->cbSize.HighPart = 0;
  508. return S_OK;
  509. }
  510. HRESULT STDMETHODCALLTYPE
  511. CNdrStream::UnlockRegion(
  512. IN ULARGE_INTEGER libOffset,
  513. IN ULARGE_INTEGER cb,
  514. IN DWORD dwLockType)
  515. /*++
  516. Routine Description:
  517. Range locking is not supported by this stream.
  518. Return Value:
  519. STG_E_INVALIDFUNCTION.
  520. --*/
  521. {
  522. return STG_E_INVALIDFUNCTION;
  523. }
  524. HRESULT STDMETHODCALLTYPE
  525. CNdrStream::Write(
  526. IN void const *pv,
  527. IN ULONG cb,
  528. OUT ULONG * pcbWritten)
  529. /*++
  530. Routine Description:
  531. Write data to the stream starting at the current seek pointer.
  532. Arguments:
  533. pv - Supplies the data to be written to the stream.
  534. cb - Specifies the number of bytes to be written to the stream.
  535. pcbWritten - Returns the number of bytes actually written to the stream.
  536. Return Value:
  537. S_OK - The data was successfully written to the stream.
  538. STG_E_MEDIUMFULL - Data cannot be written past the end of the stream.
  539. --*/
  540. {
  541. HRESULT hr;
  542. unsigned long cbRemaining;
  543. unsigned long cbWritten;
  544. //Check if we are writing past the end of the buffer.
  545. if(position < cbBufferLength)
  546. cbRemaining = cbBufferLength - position;
  547. else
  548. cbRemaining = 0;
  549. if(cb <= cbRemaining)
  550. {
  551. cbWritten = cb;
  552. hr = S_OK;
  553. }
  554. else
  555. {
  556. cbWritten = cbRemaining;
  557. hr = STG_E_MEDIUMFULL;
  558. }
  559. // Write the data.
  560. RpcpMemoryCopy(pBuffer + position, pv, cbWritten);
  561. //Advance the current position
  562. position += cbWritten;
  563. //update pcbWritten
  564. if (pcbWritten != 0)
  565. *pcbWritten = cbWritten;
  566. return hr;
  567. }
  568.