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.

636 lines
17 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: serial.cxx
  4. //
  5. // Contents: serialization support
  6. //
  7. // Classes: Serializer
  8. //
  9. // Functions: Helper class for serialization which holds
  10. // serialization state like MES handles, position
  11. // in buffer, stream etc. Provides a virtual
  12. // buffer for operation but is created from and
  13. // commited back to an IStream object.
  14. //
  15. // History: 24-Jan-98 vinaykr Created
  16. // 17-Aug-98 vinaykr Made every method inline
  17. // and non-COM class.
  18. //
  19. //--------------------------------------------------------------------
  20. #ifndef __SERIAL_HXX
  21. #define __SERIAL_HXX
  22. #include <rpc.h>
  23. #include <midles.h>
  24. #include <actstrm.hxx>
  25. #include <buffer.h>
  26. #include <serializ.h>
  27. #include <ole2int.h>
  28. #ifdef _WIN64
  29. // Flag used to signal the in-proc case for Serialization header marshalling
  30. #define INTERNAL_SERIALIZATION_FLAG 0x487fabc
  31. // Struct used to optimize calls to IStream::Write
  32. typedef struct _SSerializationHeader64 {
  33. DWORD dwSize;
  34. DWORD dwFlag;
  35. void *pvMarshalPtr;
  36. } SerializationHeader64;
  37. #endif
  38. typedef struct _SSerializationHeader {
  39. DWORD dwSize;
  40. void *pvMarshalPtr;
  41. } SerializationHeader;
  42. class Serializer
  43. {
  44. public:
  45. enum
  46. {
  47. DIRECTION_READ = 0x1,
  48. DIRECTION_WRITE = 0x2
  49. };
  50. inline ~Serializer()
  51. {
  52. // Free MES handle
  53. if (_handle!=0)
  54. MesHandleFree(_handle);
  55. // If we have a stream free it
  56. if (_pStream)
  57. {
  58. _pIBuff->Release();
  59. _pStream->Release();
  60. }
  61. // If original stream is different free it
  62. if ((_pOriginalStream) && (_pOriginalStream != _pStream))
  63. _pOriginalStream->Release();
  64. }
  65. inline Serializer()
  66. {
  67. _bufSize=0;
  68. _operationSize=0;
  69. _buffer = 0;
  70. _nWritten = 0;
  71. _position = 0;
  72. _start = 0;
  73. _pStream = NULL;
  74. _pOriginalStream = NULL;
  75. _pIBuff = NULL;
  76. _handle = 0;
  77. _clRefs = 1;
  78. }
  79. inline Serializer(DWORD dwMaxDestCtx, DWORD dwCurrCtx, DWORD dwMarshalFlags)
  80. {
  81. this->Serializer::Serializer();
  82. _dwMaxDestCtx = dwMaxDestCtx;
  83. _dwCurrentDestCtx = dwCurrCtx;
  84. _dwMarshalFlags = dwMarshalFlags;
  85. }
  86. inline ULONG Serializer::Release(void)
  87. {
  88. Win4Assert((_clRefs != 0) && "Serializer::Release");
  89. if (InterlockedDecrement(&_clRefs) == 0)
  90. {
  91. delete this;
  92. return 0;
  93. }
  94. return _clRefs;
  95. }
  96. /***************************************************************************/
  97. /** Initializes state based on stream for serialization **/
  98. /** Assumes that we know the limits of our operation before hand if we **/
  99. /** writing out to the stream. **/
  100. /** Note that it is the responsibility of the caller to ensure that the **/
  101. /** variable pMarshalPtr is only passed during in process marshalling **/
  102. /** otherwise undefined errors may result. **/
  103. /** Note that when writing pMarshalPtr and dwSize are input parameters **/
  104. /** and while reading they are output.
  105. /***************************************************************************/
  106. inline HRESULT InitStream(IStream *pStream,DWORD &dwSize,
  107. DWORD direction, void* &pMarshalPtr)
  108. {
  109. HRESULT hr;
  110. DWORD nRead;
  111. _direction = direction;
  112. _pOriginalStream = pStream;
  113. _pOriginalStream->AddRef();
  114. // Either read or write initial protocol header
  115. if (direction == DIRECTION_READ)
  116. {
  117. SerializationHeader hdr;
  118. #ifdef _WIN64
  119. // To maintain compatibility with 32 bit DCOM, we need to maintain the
  120. // illusion that SerializationHeader's are 8 bytes in size
  121. //
  122. // For the in proc case, there will be a DWORD after the dwSize field
  123. // that tells us if we are in proc or out of proc. If the DWORD is our
  124. // special flag, then we are in-proc and there's an 8 byte pointer that
  125. // we need to read from the stream.
  126. // For the out of proc case, the DWORD will be zero and we can just ignore
  127. // it and set the pvMarshalPtr field to NULL
  128. //
  129. // -mfeingol, 10/15/1999
  130. // Read eight bytes from the stream
  131. DWORD dwData[2];
  132. if ((hr = _pOriginalStream->Read(dwData, 2 * sizeof (DWORD), &nRead)) != S_OK)
  133. return hr;
  134. // Assign the dwSize field
  135. hdr.dwSize = dwData[0];
  136. // Determine if we're in proc or out of proc
  137. if (dwData[1] == INTERNAL_SERIALIZATION_FLAG) {
  138. // In proc case: there's a pointer in the stream
  139. if ((hr = _pOriginalStream->Read(&hdr.pvMarshalPtr, sizeof (void*), &nRead)) != S_OK)
  140. return hr;
  141. }
  142. else
  143. {
  144. // Out of proc case; the DWORD we read is just a NULL
  145. hdr.pvMarshalPtr = NULL;
  146. }
  147. #else
  148. if ((hr = _pOriginalStream->Read(&hdr, GetSize(), &nRead)) != S_OK)
  149. return hr;
  150. #endif
  151. pMarshalPtr = hdr.pvMarshalPtr;
  152. if (hdr.pvMarshalPtr)
  153. {
  154. _operationSize = hdr.dwSize;
  155. }
  156. else
  157. {
  158. BYTE *pSrc = (BYTE*) &hdr.dwSize;
  159. _operationSize = 0;
  160. for (int i = 0; i<(sizeof(DWORD)/sizeof(BYTE)); i++)
  161. {
  162. _operationSize |= ((((DWORD)(*pSrc++)) & 0xFF) << (i*8));
  163. }
  164. }
  165. dwSize = _operationSize;
  166. }
  167. else
  168. {
  169. _operationSize = dwSize;
  170. SerializationHeader hdr;
  171. hdr.pvMarshalPtr = pMarshalPtr;
  172. if (pMarshalPtr)
  173. {
  174. hdr.dwSize = dwSize;
  175. }
  176. else
  177. {
  178. BYTE *pDst = (BYTE*) &hdr.dwSize;
  179. for (int i = 0; i<(sizeof(DWORD)/sizeof(BYTE)); i++)
  180. {
  181. *pDst++ = (BYTE)((dwSize>>(i*8)) & 0xFF);
  182. }
  183. }
  184. #ifdef _WIN64
  185. // To maintain compatibility with 32 bit DCOM, we need to maintain the
  186. // illusion that SerializationHeader's are 8 bytes in size
  187. //
  188. // For the in proc case, we write a DWORD after the dwSize field
  189. // that tells the reader of the stream that we are in proc. Then we serialize
  190. // our 8 byte pointer into the stream.
  191. // For the out of proc case, we just write a zero'd DWORD after the dwSize field
  192. //
  193. // -mfeingol, 10/15/1999
  194. if (pMarshalPtr)
  195. {
  196. // Inproc: write the DWORD, a flag, then the ptr
  197. SerializationHeader64 sh64Data =
  198. {
  199. hdr.dwSize,
  200. INTERNAL_SERIALIZATION_FLAG,
  201. pMarshalPtr
  202. };
  203. if ((hr = _pOriginalStream->Write(&sh64Data, sizeof (SerializationHeader64), &_nWritten)) != S_OK)
  204. return hr;
  205. }
  206. else
  207. {
  208. DWORD dwData[2] =
  209. {
  210. hdr.dwSize,
  211. 0
  212. };
  213. // Out of proc: write the DWORD and blank DWORD
  214. if ((hr = _pOriginalStream->Write(&dwData, 2 * sizeof (DWORD), &_nWritten)) != S_OK)
  215. return hr;
  216. }
  217. #else
  218. if ((hr = _pOriginalStream->Write(&hdr, GetSize(), &_nWritten)) != S_OK)
  219. return hr;
  220. #endif
  221. }
  222. if (!_operationSize)
  223. {
  224. if (!pMarshalPtr)
  225. return E_UNEXPECTED;
  226. return S_OK;
  227. }
  228. // See if given stream supports IBuffer otherwise create one that does
  229. IBuffer *pibuff;
  230. if (_pOriginalStream->QueryInterface(IID_IBuffer, (void**)&pibuff)!=S_OK)
  231. {
  232. // allocate more in case alignment needed
  233. _bufSize = _operationSize + 8;
  234. _pStream = new ActivationStream(_bufSize);
  235. if (_pStream==NULL)
  236. return E_OUTOFMEMORY;
  237. hr = _pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff);
  238. ASSERT(hr==S_OK);
  239. pibuff = _pIBuff;
  240. }
  241. do // Loop until we get right buffer
  242. {
  243. // Invariant is that pibuff must exist by the time we get here
  244. ASSERT(pibuff != 0);
  245. // Set up our buffer appropriately
  246. if (direction == DIRECTION_READ)
  247. {
  248. if (pibuff->GetBuffer(&_bufSize, &_buffer)!=S_OK)
  249. return E_FAIL;
  250. if (_bufSize < _operationSize)
  251. return E_FAIL;
  252. }
  253. else
  254. if (direction == DIRECTION_WRITE)
  255. {
  256. if (pibuff->GetOrCreateBuffer(_operationSize+GetSize(),
  257. &_bufSize, &_buffer)!=S_OK)
  258. return E_FAIL;
  259. }
  260. if(((LONG_PTR)_buffer)&0x7)
  261. {
  262. // If buffer is not 8 byte aligned, do it
  263. if (pibuff != _pIBuff)
  264. {
  265. // Only get here if we are still using original
  266. ASSERT(_pIBuff == 0);
  267. // So release it and create a new aligned one
  268. pibuff->Release();
  269. _bufSize = _operationSize + 8;
  270. _pStream = new ActivationStream(_bufSize);
  271. if (_pStream==NULL)
  272. return E_OUTOFMEMORY;
  273. hr = _pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff);
  274. ASSERT(hr==S_OK);
  275. pibuff = _pIBuff; //Continue loop
  276. }
  277. else
  278. {
  279. // Got a buffer which we can align
  280. ASSERT(_pIBuff != 0);
  281. pibuff = 0; //Signal end of loop
  282. // Align buffer
  283. _start = (DWORD)(8-(((DWORD_PTR)_buffer)&7));
  284. }
  285. }
  286. else
  287. {
  288. // We have an original good one
  289. _pIBuff = pibuff;
  290. pibuff = 0;
  291. }
  292. }
  293. while (pibuff);
  294. ASSERT(_pIBuff!=0);
  295. // Set position for next operations and set up
  296. // internal state correctly
  297. hr = _pIBuff->SetPosition(_bufSize, _start);
  298. ASSERT(hr == S_OK);
  299. _bufSize -= _start;
  300. _buffer += _start;
  301. _position = 0;
  302. if (direction==DIRECTION_READ)
  303. {
  304. if ((_pStream) && (_pOriginalStream != _pStream))
  305. {
  306. //If what we have is not the original one then we
  307. //need to copy data into aligned address from original
  308. DWORD nOver=0;
  309. do {
  310. if ((hr=_pOriginalStream->Read(_buffer+nOver,
  311. _operationSize-nOver, &nRead))!= S_OK)
  312. return hr;
  313. nOver += nRead;
  314. }
  315. while (nOver<_operationSize);
  316. _pOriginalStream->Release();
  317. _pOriginalStream = 0; // Don't need original any longer
  318. }
  319. else
  320. _pStream = _pOriginalStream; // Set operating to original
  321. ASSERT(_pStream!=0);
  322. // Create decoding handle for MES operations
  323. MesDecodeBufferHandleCreate((char*)_buffer, _bufSize, &_handle);
  324. if (_handle == NULL)
  325. return E_OUTOFMEMORY;
  326. }
  327. else
  328. {
  329. _nWritten = 0;
  330. // Check if we are still using the orignal stream
  331. if (_pStream == 0)
  332. _pStream = _pOriginalStream;
  333. // Create encoding handle for MES operations
  334. MesEncodeFixedBufferHandleCreate((char*)_buffer,
  335. _bufSize, &_nWritten, &_handle);
  336. if (_handle == NULL)
  337. return E_OUTOFMEMORY;
  338. }
  339. return S_OK;
  340. }
  341. /***************************************************************************/
  342. /** Sets stream and state for further serialization operations **/
  343. /** Assumes that a stream supporting IBuffer is provided. **/
  344. /***************************************************************************/
  345. inline HRESULT SetStream(IStream *pStream,DWORD dwOpSize,
  346. DWORD direction)
  347. {
  348. // Set up internal state
  349. _direction = direction;
  350. _pOriginalStream = 0;
  351. _pStream = pStream;
  352. _operationSize = dwOpSize;
  353. _pStream->AddRef();
  354. // Assume IBuffer exists otherwise fail
  355. if (_pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff)!=S_OK)
  356. return E_FAIL;
  357. if (_pIBuff->GetBuffer(&_bufSize, &_buffer)!=S_OK)
  358. return E_FAIL;
  359. if (_bufSize < _operationSize)
  360. return E_FAIL;
  361. // Set up MES handles
  362. if (direction==DIRECTION_READ)
  363. MesDecodeBufferHandleCreate((char*)_buffer, _bufSize, &_handle);
  364. else
  365. MesEncodeFixedBufferHandleCreate((char*)_buffer,
  366. _bufSize, &_nWritten, &_handle);
  367. if (_handle == NULL)
  368. return E_OUTOFMEMORY;
  369. return S_OK;
  370. }
  371. // Gets MES handle
  372. inline HRESULT GetSerializationHandle(void *pHandle)
  373. {
  374. *((handle_t*) pHandle) = _handle;
  375. return S_OK;
  376. }
  377. // Gets MES handle for sizing operations
  378. inline HRESULT GetSizingHandle(void *pHandle)
  379. {
  380. char dummy[30], *dummybuff;
  381. unsigned long encodedSize;
  382. handle_t handle;
  383. dummybuff = (char*)(((LONG_PTR)(&dummy[7])) & ~7);
  384. MesEncodeFixedBufferHandleCreate(dummybuff, 100, &encodedSize, (handle_t*)pHandle);
  385. if ( (*(handle_t*)pHandle) == NULL)
  386. return E_OUTOFMEMORY;
  387. return S_OK;
  388. }
  389. //Signals end of operations on this object and commits
  390. //operations to stream
  391. inline HRESULT Commit()
  392. {
  393. // If we are not using original and we are writing,
  394. // then we need to copy
  395. if ((_pOriginalStream) && (_pOriginalStream != _pStream))
  396. {
  397. ASSERT(_direction==DIRECTION_WRITE);
  398. HRESULT hr;
  399. do
  400. {
  401. _nWritten = 0;
  402. hr = _pOriginalStream->Write(_buffer,
  403. _operationSize, &_nWritten);
  404. if (hr != S_OK)
  405. break;
  406. _operationSize -= _nWritten;
  407. _buffer += _nWritten;
  408. }
  409. while (_operationSize);
  410. return hr;
  411. }
  412. else
  413. return _pIBuff->SetPosition(_bufSize, _operationSize);
  414. }
  415. inline HRESULT SetPosition(DWORD dwPos)
  416. {
  417. // Sets position in buffer and creates appropriate MES handle
  418. HRESULT hr = _pIBuff->SetPosition(_bufSize, dwPos);
  419. if (hr!=S_OK)
  420. return hr;
  421. MesHandleFree(_handle);
  422. if (_direction == DIRECTION_READ)
  423. MesDecodeBufferHandleCreate((char*)(_buffer+dwPos), _bufSize, &_handle);
  424. else
  425. {
  426. _nWritten = 0;
  427. MesEncodeFixedBufferHandleCreate((char*)(_buffer+dwPos), _bufSize, &_nWritten, &_handle);
  428. }
  429. if (_handle == NULL)
  430. return E_OUTOFMEMORY;
  431. _position = dwPos;
  432. return S_OK;
  433. }
  434. // Gets current position in buffer
  435. inline HRESULT GetPosition(DWORD *pdwPos)
  436. {
  437. *pdwPos = _position;
  438. return S_OK;
  439. }
  440. // Increment current position by specified amount in buffer
  441. inline HRESULT IncrementPosition(DWORD dwInc)
  442. {
  443. return SetPosition(_position+dwInc);
  444. }
  445. // Get buffers underlying stream object
  446. inline HRESULT GetStream(IStream **ppStream)
  447. {
  448. _pStream->AddRef();
  449. *ppStream = _pStream;
  450. return S_OK;
  451. }
  452. // Get a copy of this object
  453. inline HRESULT GetCopy(Serializer **ppSer)
  454. {
  455. HRESULT hr=E_FAIL;
  456. IStream *pNewStream;
  457. if (_pStream)
  458. {
  459. ASSERT(_direction==DIRECTION_READ); //No need for any other case right now
  460. hr = _pIBuff->SetPosition(_bufSize, 0);
  461. ASSERT(hr==S_OK);
  462. if (_pOriginalStream) // Still using original so clone
  463. {
  464. ASSERT(_start==0);
  465. ASSERT(_pStream==_pOriginalStream);
  466. hr = _pIBuff->SetCopyAlignment(8);
  467. ASSERT(hr==S_OK);
  468. hr = _pStream->Clone(&pNewStream);
  469. if (hr != S_OK)
  470. return hr;
  471. }
  472. else
  473. {
  474. pNewStream = _pStream;
  475. }
  476. Serializer *ser = new Serializer(_dwMaxDestCtx, _dwCurrentDestCtx, _dwMarshalFlags);
  477. if (ser==NULL)
  478. return E_OUTOFMEMORY;
  479. hr = ser->SetStream(pNewStream, _operationSize, _direction);
  480. if (FAILED(hr))
  481. goto exit_point;
  482. hr = ser->SetPosition(_position);
  483. if (FAILED(hr))
  484. goto exit_point;
  485. hr = _pIBuff->SetPosition(_bufSize, _position);
  486. if (FAILED(hr))
  487. goto exit_point;
  488. *ppSer = ser;
  489. exit_point:
  490. if (pNewStream != _pStream)
  491. pNewStream->Release();
  492. if (FAILED(hr))
  493. {
  494. ser->Release();
  495. *ppSer = NULL;
  496. }
  497. }
  498. return hr;
  499. }
  500. // Write provided buffer into our buffer at current position
  501. // and advance position
  502. inline HRESULT Write(BYTE *buff, DWORD nBytes)
  503. {
  504. ASSERT(nBytes<=(_bufSize-_position));
  505. memcpy(_buffer+_position,buff, (size_t) nBytes);
  506. IncrementPosition(nBytes);
  507. return S_OK;
  508. }
  509. // Copy into provided Serializer our data at given position and length
  510. inline HRESULT CopyTo(Serializer *pSer, DWORD dwPos, DWORD nBytes)
  511. {
  512. ASSERT(nBytes<=(_bufSize-dwPos));
  513. return pSer->Write(_buffer+dwPos, nBytes);
  514. }
  515. // return buffer starting at current position
  516. inline HRESULT GetBufferAtCurrent(BYTE **ppBuff)
  517. {
  518. *ppBuff = _buffer+_position;
  519. return S_OK;
  520. }
  521. inline void GetMaxDestCtx(OUT DWORD *pdwDestCtx)
  522. {
  523. *pdwDestCtx = _dwMaxDestCtx;
  524. }
  525. inline void GetCurrDestCtx(OUT DWORD *pdwDestCtx)
  526. {
  527. *pdwDestCtx = _dwCurrentDestCtx;
  528. }
  529. inline void GetMarshalFlags(OUT DWORD *pdwMarshalFlags)
  530. {
  531. *pdwMarshalFlags = _dwMarshalFlags;
  532. }
  533. static inline DWORD GetSize()
  534. {
  535. // fixed initialization length
  536. return sizeof(SerializationHeader);
  537. }
  538. private:
  539. IStream *_pStream;
  540. IStream *_pOriginalStream;
  541. IBuffer *_pIBuff;
  542. BYTE *_buffer;
  543. DWORD _nWritten;
  544. DWORD _bufSize;
  545. DWORD _operationSize;
  546. handle_t _handle;
  547. LONG _clRefs;
  548. DWORD _direction;
  549. DWORD _position;
  550. DWORD _start;
  551. DWORD _dwMaxDestCtx;
  552. DWORD _dwCurrentDestCtx;
  553. DWORD _dwMarshalFlags;
  554. };
  555. #endif //__SERIAL_HXX__