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.

473 lines
13 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 in serial.hxx
  18. // This file no longer used
  19. //
  20. //
  21. //--------------------------------------------------------------------
  22. #include <ole2int.h>
  23. #include "serial.hxx"
  24. #include "buffer.h"
  25. Serializer::~Serializer()
  26. {
  27. // Free MES handle
  28. if (_handle!=0)
  29. MesHandleFree(_handle);
  30. // If we have a stream free it
  31. if (_pStream)
  32. {
  33. _pIBuff->Release();
  34. _pStream->Release();
  35. }
  36. // If original stream is different free it
  37. if ((_pOriginalStream) && (_pOriginalStream != _pStream))
  38. _pOriginalStream->Release();
  39. }
  40. Serializer::Serializer()
  41. {
  42. _bufSize=0;
  43. _operationSize=0;
  44. _buffer = 0;
  45. _nWritten = 0;
  46. _position = 0;
  47. _start = 0;
  48. _pStream = NULL;
  49. _pOriginalStream = NULL;
  50. _pIBuff = NULL;
  51. _handle = 0;
  52. _clRefs = 1;
  53. }
  54. HRESULT Serializer::QueryInterface(REFIID iidInterface,
  55. void **ppvObj)
  56. {
  57. HRESULT hresult = S_OK;
  58. // We only support IUnknown and ISerializer
  59. if (IsEqualIID(iidInterface, IID_IUnknown) ||
  60. IsEqualIID(iidInterface, IID_ISerializer))
  61. {
  62. *ppvObj = (void*)this;
  63. AddRef();
  64. }
  65. else
  66. {
  67. *ppvObj = NULL;
  68. hresult = E_NOINTERFACE;
  69. }
  70. return hresult;
  71. }
  72. STDMETHODIMP_(ULONG) Serializer::AddRef(void)
  73. {
  74. Win4Assert((_clRefs != 0) && "Serializer::AddRef");
  75. InterlockedIncrement(&_clRefs);
  76. return _clRefs;
  77. }
  78. STDMETHODIMP_(ULONG) Serializer::Release(void)
  79. {
  80. Win4Assert((_clRefs != 0) && "Serializer::Release");
  81. if (InterlockedDecrement(&_clRefs) == 0)
  82. {
  83. delete this;
  84. return 0;
  85. }
  86. return _clRefs;
  87. }
  88. /***************************************************************************/
  89. /** Initializes state based on stream for serialization **/
  90. /** Assumes that we know the limits of our operation before hand if we **/
  91. /** writing out to the stream. **/
  92. /***************************************************************************/
  93. STDMETHODIMP Serializer::InitStream(IStream *pStream,DWORD dwSize,
  94. DWORD direction, DWORD dwDestCtx,
  95. DWORD dwMarshalCtx)
  96. {
  97. HRESULT hr;
  98. DWORD nRead;
  99. _direction = direction;
  100. _destCtx = dwDestCtx;
  101. _marshalCtx = dwMarshalCtx;
  102. _pOriginalStream = pStream;
  103. _pOriginalStream->AddRef();
  104. // Either read or write initial protocol header
  105. if (direction == DIRECTION_IN)
  106. {
  107. DWORD x[2];
  108. if ((hr = _pOriginalStream->Read(x, 8, &nRead)) != S_OK)
  109. return hr;
  110. _operationSize = x[0];
  111. }
  112. else
  113. {
  114. DWORD x[2];
  115. x[0] = dwSize;
  116. if ((hr = _pOriginalStream->Write(x, 8, &_nWritten)) != S_OK)
  117. return hr;
  118. _operationSize = dwSize;
  119. }
  120. // See if given stream supports IBuffer otherwise create one that does
  121. IBuffer *pibuff;
  122. if (_pOriginalStream->QueryInterface(IID_IBuffer, (void**)&pibuff)!=S_OK)
  123. {
  124. // allocate more in case alignment needed
  125. _bufSize = _operationSize + 8;
  126. _pStream = new ActivationStream(_bufSize);
  127. if (_pStream==NULL)
  128. return E_OUTOFMEMORY;
  129. hr = _pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff);
  130. ASSERT(hr==S_OK);
  131. pibuff = _pIBuff;
  132. }
  133. do // Loop until we get right buffer
  134. {
  135. // Invariant is that pibuff must exist by the time we get here
  136. ASSERT(pibuff != 0);
  137. // Set up our buffer appropriately
  138. if (direction == DIRECTION_IN)
  139. {
  140. if (pibuff->GetBuffer(&_bufSize, &_buffer)!=S_OK)
  141. return E_FAIL;
  142. if (_bufSize < _operationSize)
  143. return E_FAIL;
  144. }
  145. else
  146. if (direction == DIRECTION_OUT)
  147. {
  148. if (pibuff->GetOrCreateBuffer(_operationSize+GetSize(),
  149. &_bufSize, &_buffer)!=S_OK)
  150. return E_FAIL;
  151. }
  152. if(((INT_PTR)_buffer)&0x7)
  153. {
  154. // If buffer is not 8 byte aligned, do it
  155. if (pibuff != _pIBuff)
  156. {
  157. // Only get here if we are still using original
  158. ASSERT(_pIBuff == 0);
  159. // So release it and create a new aligned one
  160. pibuff->Release();
  161. _bufSize = _operationSize + 8;
  162. _pStream = new ActivationStream(_bufSize);
  163. if (_pStream==NULL)
  164. return E_OUTOFMEMORY;
  165. hr = _pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff);
  166. ASSERT(hr==S_OK);
  167. pibuff = _pIBuff; //Continue loop
  168. }
  169. else
  170. {
  171. // Got a buffer which we can align
  172. ASSERT(_pIBuff != 0);
  173. pibuff = 0; //Signal end of loop
  174. // Align buffer
  175. _start = 8-(PtrToUlong(_buffer)&7);
  176. }
  177. }
  178. else
  179. {
  180. // We have an original good one
  181. _pIBuff = pibuff;
  182. pibuff = 0;
  183. }
  184. }
  185. while (pibuff);
  186. ASSERT(_pIBuff!=0);
  187. // Set position for next operations and set up
  188. // internal state correctly
  189. hr = _pIBuff->SetPosition(_bufSize, _start);
  190. ASSERT(hr == S_OK);
  191. _bufSize -= _start;
  192. _buffer += _start;
  193. _position = 0;
  194. if (direction==DIRECTION_IN)
  195. {
  196. if ((_pStream) && (_pOriginalStream != _pStream))
  197. {
  198. //If what we have is not the original one then we
  199. //need to copy data into aligned address from original
  200. DWORD nOver=0;
  201. do {
  202. if ((hr=_pOriginalStream->Read(_buffer+nOver,
  203. _operationSize-nOver, &nRead))!= S_OK)
  204. return hr;
  205. nOver += nRead;
  206. }
  207. while (nOver<_operationSize);
  208. _pOriginalStream->Release();
  209. _pOriginalStream = 0; // Don't need original any longer
  210. }
  211. else
  212. _pStream = _pOriginalStream; // Set operating to original
  213. ASSERT(_pStream!=0);
  214. // Create decoding handle for MES operations
  215. MesDecodeBufferHandleCreate((char*)_buffer, _bufSize, &_handle);
  216. if (_handle == NULL)
  217. return E_OUTOFMEMORY;
  218. }
  219. else
  220. {
  221. _nWritten = 0;
  222. // Check if we are still using the orignal stream
  223. if (_pStream == 0)
  224. _pStream = _pOriginalStream;
  225. // Create encoding handle for MES operations
  226. MesEncodeFixedBufferHandleCreate((char*)_buffer,
  227. _bufSize, &_nWritten, &_handle);
  228. if (_handle == NULL)
  229. return E_OUTOFMEMORY;
  230. }
  231. return S_OK;
  232. }
  233. /***************************************************************************/
  234. /** Sets stream and state for further serialization operations **/
  235. /** Assumes that a stream supporting IBuffer is provided. **/
  236. /***************************************************************************/
  237. STDMETHODIMP Serializer::SetStream(IStream *pStream,DWORD dwOpSize,
  238. DWORD direction,DWORD dwDestCtx,
  239. DWORD dwMarshalCtx)
  240. {
  241. // Set up internal state
  242. _destCtx = dwDestCtx;
  243. _marshalCtx = dwMarshalCtx;
  244. _direction = direction;
  245. _pOriginalStream = 0;
  246. _pStream = pStream;
  247. _operationSize = dwOpSize;
  248. _pStream->AddRef();
  249. // Assume IBuffer exists otherwise fail
  250. if (_pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff)!=S_OK)
  251. return E_FAIL;
  252. if (_pIBuff->GetBuffer(&_bufSize, &_buffer)!=S_OK)
  253. return E_FAIL;
  254. if (_bufSize < _operationSize)
  255. return E_FAIL;
  256. // Set up MES handles
  257. if (direction==DIRECTION_IN)
  258. MesDecodeBufferHandleCreate((char*)_buffer, _bufSize, &_handle);
  259. else
  260. MesEncodeFixedBufferHandleCreate((char*)_buffer,
  261. _bufSize, &_nWritten, &_handle);
  262. if (_handle == NULL)
  263. return E_OUTOFMEMORY;
  264. return S_OK;
  265. }
  266. // Gets MES handle
  267. STDMETHODIMP Serializer::GetSerializationHandle(void *pHandle)
  268. {
  269. *((handle_t*) pHandle) = _handle;
  270. Win4Assert(_handle);
  271. return S_OK;
  272. }
  273. // Gets MES handle for sizing operations
  274. STDMETHODIMP Serializer::GetSizingHandle(void *pHandle)
  275. {
  276. char dummy[30], *dummybuff;
  277. unsigned long encodedSize;
  278. handle_t handle;
  279. dummybuff = (char*)(((INT_PTR)(&dummy[7])) & ~7);
  280. MesEncodeFixedBufferHandleCreate(dummybuff, 100, &encodedSize, (handle_t*)pHandle);
  281. if (pHandle == NULL)
  282. return E_OUTOFMEMORY;
  283. return S_OK;
  284. }
  285. //Signals end of operations on this object and commits
  286. //operations to stream
  287. STDMETHODIMP Serializer::Commit()
  288. {
  289. // If we are not using original and we are writing,
  290. // then we need to copy
  291. if ((_pOriginalStream) && (_pOriginalStream != _pStream))
  292. {
  293. ASSERT(_direction==DIRECTION_OUT);
  294. HRESULT hr;
  295. do
  296. {
  297. _nWritten = 0;
  298. hr = _pOriginalStream->Write(_buffer,
  299. _operationSize, &_nWritten);
  300. if (hr != S_OK)
  301. break;
  302. _operationSize -= _nWritten;
  303. _buffer += _nWritten;
  304. }
  305. while (_operationSize);
  306. return hr;
  307. }
  308. else
  309. return _pIBuff->SetPosition(_bufSize, _operationSize);
  310. }
  311. STDMETHODIMP Serializer::SetPosition(DWORD dwPos)
  312. {
  313. // Sets position in buffer and creates appropriate MES handle
  314. HRESULT hr = _pIBuff->SetPosition(_bufSize, dwPos);
  315. if (hr!=S_OK)
  316. return hr;
  317. MesHandleFree(_handle);
  318. if (_direction == DIRECTION_IN)
  319. MesDecodeBufferHandleCreate((char*)(_buffer+dwPos), _bufSize, &_handle);
  320. else
  321. {
  322. _nWritten = 0;
  323. MesEncodeFixedBufferHandleCreate((char*)(_buffer+dwPos), _bufSize, &_nWritten, &_handle);
  324. }
  325. if (_handle == NULL)
  326. return E_OUTOFMEMORY;
  327. _position = dwPos;
  328. return S_OK;
  329. }
  330. // Gets current position in buffer
  331. STDMETHODIMP Serializer::GetPosition(DWORD *pdwPos)
  332. {
  333. *pdwPos = _position;
  334. return S_OK;
  335. }
  336. // Increment current position by specified amount in buffer
  337. STDMETHODIMP Serializer::IncrementPosition(DWORD dwInc)
  338. {
  339. return SetPosition(_position+dwInc);
  340. }
  341. // Get buffers underlying stream object
  342. STDMETHODIMP Serializer::GetStream(IStream **ppStream)
  343. {
  344. _pStream->AddRef();
  345. *ppStream = _pStream;
  346. return S_OK;
  347. }
  348. // Get a copy of this object
  349. STDMETHODIMP Serializer::GetCopy(ISerializer **ppSer)
  350. {
  351. HRESULT hr;
  352. IStream *pNewStream;
  353. if (_pStream)
  354. {
  355. ASSERT(_direction==DIRECTION_IN); //No need for any other case right now
  356. hr = _pIBuff->SetPosition(_bufSize, 0);
  357. ASSERT(hr==S_OK);
  358. Serializer *ser = new Serializer();
  359. if (ser==NULL)
  360. return E_OUTOFMEMORY;
  361. if (_pOriginalStream) // Still using original so clone
  362. {
  363. ASSERT(_start==0);
  364. ASSERT(_pStream==_pOriginalStream);
  365. hr = _pIBuff->SetCopyAlignment(8);
  366. ASSERT(hr==S_OK);
  367. hr = _pStream->Clone(&pNewStream);
  368. if (hr != S_OK)
  369. {
  370. delete ser;
  371. return hr;
  372. }
  373. }
  374. else
  375. {
  376. pNewStream = _pStream;
  377. }
  378. hr = ser->SetStream(pNewStream, _operationSize,
  379. _direction, _destCtx, _marshalCtx);
  380. if (FAILED(hr))
  381. {
  382. if (pNewStream != _pStream)
  383. pNewStream->Release();
  384. delete ser;
  385. return hr;
  386. }
  387. hr = ser->SetPosition(_position);
  388. if (FAILED(hr))
  389. {
  390. if (pNewStream != _pStream)
  391. pNewStream->Release();
  392. delete ser;
  393. return hr;
  394. }
  395. hr = _pIBuff->SetPosition(_bufSize, _position);
  396. ASSERT(hr==S_OK);
  397. *ppSer = ser;
  398. if (pNewStream != _pStream)
  399. pNewStream->Release();
  400. return S_OK;
  401. }
  402. return E_FAIL;
  403. }
  404. // Write provided buffer into our buffer at current position
  405. // and advance position
  406. STDMETHODIMP Serializer::Write(BYTE *buff, DWORD nBytes)
  407. {
  408. ASSERT(nBytes<=(_bufSize-_position));
  409. memcpy(_buffer+_position,buff, (size_t) nBytes);
  410. IncrementPosition(nBytes);
  411. return S_OK;
  412. }
  413. // Copy into provided Serializer our data at given position and length
  414. STDMETHODIMP Serializer::CopyTo(ISerializer *pSer, DWORD dwPos, DWORD nBytes)
  415. {
  416. ASSERT(nBytes<=(_bufSize-dwPos));
  417. return pSer->Write(_buffer+dwPos, nBytes);
  418. }
  419. // return buffer starting at current position
  420. STDMETHODIMP Serializer::GetBufferAtCurrent(BYTE **ppBuff)
  421. {
  422. *ppBuff = _buffer+_position;
  423. return S_OK;
  424. }