source: trunk/src/ole32/stg_stream.c

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 22.6 KB
RevLine 
[5026]1/*
2 * Compound Storage (32 bit version)
3 * Stream implementation
4 *
5 * This file contains the implementation of the stream interface
6 * for streams contained in a compound storage.
7 *
8 * Copyright 1999 Francis Beaudet
9 * Copyright 1999 Thuy Nguyen
[8441]10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
[5026]24 */
25#include <assert.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29
30#include "winbase.h"
31#include "winerror.h"
[9400]32#include "winternl.h"
[8441]33#include "wine/debug.h"
[5026]34
35#include "storage32.h"
36
[8441]37WINE_DEFAULT_DEBUG_CHANNEL(storage);
[5026]38
39
40/*
41 * Virtual function table for the StgStreamImpl class.
42 */
43static ICOM_VTABLE(IStream) StgStreamImpl_Vtbl =
44{
45 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
46 StgStreamImpl_QueryInterface,
47 StgStreamImpl_AddRef,
48 StgStreamImpl_Release,
49 StgStreamImpl_Read,
50 StgStreamImpl_Write,
51 StgStreamImpl_Seek,
52 StgStreamImpl_SetSize,
53 StgStreamImpl_CopyTo,
54 StgStreamImpl_Commit,
55 StgStreamImpl_Revert,
56 StgStreamImpl_LockRegion,
57 StgStreamImpl_UnlockRegion,
58 StgStreamImpl_Stat,
59 StgStreamImpl_Clone
60};
61
62/******************************************************************************
63** StgStreamImpl implementation
64*/
65
66/***
67 * This is the constructor for the StgStreamImpl class.
68 *
69 * Params:
70 * parentStorage - Pointer to the storage that contains the stream to open
71 * ownerProperty - Index of the property that points to this stream.
72 */
73StgStreamImpl* StgStreamImpl_Construct(
[6711]74 StorageBaseImpl* parentStorage,
[5026]75 DWORD grfMode,
76 ULONG ownerProperty)
77{
78 StgStreamImpl* newStream;
79
80 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
[8620]81
[5026]82 if (newStream!=0)
83 {
84 /*
85 * Set-up the virtual function table and reference count.
86 */
87 ICOM_VTBL(newStream) = &StgStreamImpl_Vtbl;
88 newStream->ref = 0;
[8620]89
[5026]90 /*
91 * We want to nail-down the reference to the storage in case the
92 * stream out-lives the storage in the client application.
93 */
94 newStream->parentStorage = parentStorage;
95 IStorage_AddRef((IStorage*)newStream->parentStorage);
96
[8620]97 newStream->grfMode = grfMode;
[5026]98 newStream->ownerProperty = ownerProperty;
[8620]99
[5026]100 /*
[7926]101 * Start the stream at the beginning.
[5026]102 */
[21916]103 newStream->currentPosition.DUMMYSTRUCTNAME_DOT HighPart = 0;
104 newStream->currentPosition.DUMMYSTRUCTNAME_DOT LowPart = 0;
[8620]105
[5026]106 /*
107 * Initialize the rest of the data.
108 */
[21916]109 newStream->streamSize.DUMMYSTRUCTNAME_DOT HighPart = 0;
110 newStream->streamSize.DUMMYSTRUCTNAME_DOT LowPart = 0;
[5026]111 newStream->bigBlockChain = 0;
112 newStream->smallBlockChain = 0;
[8620]113
[5026]114 /*
115 * Read the size from the property and determine if the blocks forming
116 * this stream are large or small.
117 */
118 StgStreamImpl_OpenBlockChain(newStream);
119 }
[8620]120
[5026]121 return newStream;
122}
123
124/***
125 * This is the destructor of the StgStreamImpl class.
126 *
[8620]127 * This method will clean-up all the resources used-up by the given StgStreamImpl
[5026]128 * class. The pointer passed-in to this function will be freed and will not
129 * be valid anymore.
130 */
131void StgStreamImpl_Destroy(StgStreamImpl* This)
132{
133 TRACE("(%p)\n", This);
134
135 /*
136 * Release the reference we are holding on the parent storage.
137 */
138 IStorage_Release((IStorage*)This->parentStorage);
139 This->parentStorage = 0;
140
141 /*
142 * Make sure we clean-up the block chain stream objects that we were using.
143 */
144 if (This->bigBlockChain != 0)
145 {
146 BlockChainStream_Destroy(This->bigBlockChain);
147 This->bigBlockChain = 0;
148 }
149
150 if (This->smallBlockChain != 0)
151 {
152 SmallBlockChainStream_Destroy(This->smallBlockChain);
153 This->smallBlockChain = 0;
154 }
155
156 /*
157 * Finally, free the memory used-up by the class.
158 */
[8620]159 HeapFree(GetProcessHeap(), 0, This);
[5026]160}
161
162/***
163 * This implements the IUnknown method QueryInterface for this
164 * class
165 */
166HRESULT WINAPI StgStreamImpl_QueryInterface(
[6711]167 IStream* iface,
[8620]168 REFIID riid, /* [in] */
169 void** ppvObject) /* [iid_is][out] */
[5026]170{
171 StgStreamImpl* const This=(StgStreamImpl*)iface;
172
173 /*
174 * Perform a sanity check on the parameters.
175 */
176 if (ppvObject==0)
177 return E_INVALIDARG;
[8620]178
[5026]179 /*
180 * Initialize the return parameter.
181 */
182 *ppvObject = 0;
[8620]183
[5026]184 /*
185 * Compare the riid with the interface IDs implemented by this object.
186 */
[8620]187 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
[5026]188 {
189 *ppvObject = (IStream*)This;
190 }
[8620]191 else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
[5026]192 {
193 *ppvObject = (IStream*)This;
194 }
[8620]195
[5026]196 /*
197 * Check that we obtained an interface.
198 */
199 if ((*ppvObject)==0)
200 return E_NOINTERFACE;
[8620]201
[5026]202 /*
203 * Query Interface always increases the reference count by one when it is
204 * successful
205 */
206 StgStreamImpl_AddRef(iface);
[8620]207
208 return S_OK;
[5026]209}
210
211/***
212 * This implements the IUnknown method AddRef for this
213 * class
214 */
215ULONG WINAPI StgStreamImpl_AddRef(
[6711]216 IStream* iface)
[5026]217{
218 StgStreamImpl* const This=(StgStreamImpl*)iface;
219
220 This->ref++;
[8620]221
[5026]222 return This->ref;
223}
224
225/***
226 * This implements the IUnknown method Release for this
227 * class
228 */
229ULONG WINAPI StgStreamImpl_Release(
[6711]230 IStream* iface)
[5026]231{
232 StgStreamImpl* const This=(StgStreamImpl*)iface;
233
234 ULONG newRef;
[8620]235
[5026]236 This->ref--;
[8620]237
[5026]238 newRef = This->ref;
[8620]239
[5026]240 /*
241 * If the reference count goes down to 0, perform suicide.
242 */
243 if (newRef==0)
244 {
245 StgStreamImpl_Destroy(This);
246 }
[8620]247
[5026]248 return newRef;
249}
250
251/***
252 * This method will open the block chain pointed by the property
253 * that describes the stream.
254 * If the stream's size is null, no chain is opened.
255 */
256void StgStreamImpl_OpenBlockChain(
257 StgStreamImpl* This)
258{
259 StgProperty curProperty;
260 BOOL readSucessful;
261
262 /*
[7926]263 * Make sure no old object is left over.
[5026]264 */
265 if (This->smallBlockChain != 0)
266 {
267 SmallBlockChainStream_Destroy(This->smallBlockChain);
268 This->smallBlockChain = 0;
269 }
270
271 if (This->bigBlockChain != 0)
272 {
273 BlockChainStream_Destroy(This->bigBlockChain);
274 This->bigBlockChain = 0;
275 }
276
277 /*
278 * Read the information from the property.
279 */
280 readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
[6711]281 This->ownerProperty,
282 &curProperty);
[8620]283
[5026]284 if (readSucessful)
285 {
286 This->streamSize = curProperty.size;
[8620]287
[5026]288 /*
289 * This code supports only streams that are <32 bits in size.
290 */
[21916]291 assert(This->streamSize.DUMMYSTRUCTNAME_DOT HighPart == 0);
[8620]292
[5026]293 if(curProperty.startingBlock == BLOCK_END_OF_CHAIN)
294 {
[21916]295 assert( (This->streamSize.DUMMYSTRUCTNAME_DOT HighPart == 0) && (This->streamSize.DUMMYSTRUCTNAME_DOT LowPart == 0) );
[5026]296 }
297 else
298 {
[21916]299 if ( (This->streamSize.DUMMYSTRUCTNAME_DOT HighPart == 0) &&
300 (This->streamSize.DUMMYSTRUCTNAME_DOT LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
[5026]301 {
[6711]302 This->smallBlockChain = SmallBlockChainStream_Construct(
[8620]303 This->parentStorage->ancestorStorage,
[6711]304 This->ownerProperty);
[5026]305 }
306 else
307 {
[6711]308 This->bigBlockChain = BlockChainStream_Construct(
309 This->parentStorage->ancestorStorage,
310 NULL,
311 This->ownerProperty);
[5026]312 }
313 }
314 }
315}
316
317/***
318 * This method is part of the ISequentialStream interface.
319 *
[7926]320 * It reads a block of information from the stream at the current
[5026]321 * position. It then moves the current position at the end of the
322 * read block
323 *
324 * See the documentation of ISequentialStream for more info.
325 */
[8620]326HRESULT WINAPI StgStreamImpl_Read(
[6711]327 IStream* iface,
328 void* pv, /* [length_is][size_is][out] */
[8620]329 ULONG cb, /* [in] */
330 ULONG* pcbRead) /* [out] */
[5026]331{
332 StgStreamImpl* const This=(StgStreamImpl*)iface;
333
334 ULONG bytesReadBuffer;
335 ULONG bytesToReadFromBuffer;
[7926]336 HRESULT res = S_FALSE;
[5026]337
338 TRACE("(%p, %p, %ld, %p)\n",
[6711]339 iface, pv, cb, pcbRead);
[5026]340
[8620]341 /*
[7926]342 * If the caller is not interested in the number of bytes read,
[5026]343 * we use another buffer to avoid "if" statements in the code.
344 */
345 if (pcbRead==0)
346 pcbRead = &bytesReadBuffer;
[8620]347
[5026]348 /*
349 * Using the known size of the stream, calculate the number of bytes
350 * to read from the block chain
351 */
[21916]352 bytesToReadFromBuffer = min( This->streamSize.DUMMYSTRUCTNAME_DOT LowPart - This->currentPosition.DUMMYSTRUCTNAME_DOT LowPart, cb);
[8620]353
[5026]354 /*
355 * Depending on the type of chain that was opened when the stream was constructed,
[7926]356 * we delegate the work to the method that reads the block chains.
[5026]357 */
358 if (This->smallBlockChain!=0)
359 {
360 SmallBlockChainStream_ReadAt(This->smallBlockChain,
[6711]361 This->currentPosition,
362 bytesToReadFromBuffer,
363 pv,
364 pcbRead);
[8620]365
[5026]366 }
367 else if (This->bigBlockChain!=0)
368 {
369 BlockChainStream_ReadAt(This->bigBlockChain,
[6711]370 This->currentPosition,
371 bytesToReadFromBuffer,
372 pv,
373 pcbRead);
[5026]374 }
375 else
376 {
377 /*
378 * Small and big block chains are both NULL. This case will happen
379 * when a stream starts with BLOCK_END_OF_CHAIN and has size zero.
380 */
381
382 *pcbRead = 0;
[7926]383 res = S_OK;
384 goto end;
[5026]385 }
386
387 /*
388 * We should always be able to read the proper amount of data from the
389 * chain.
390 */
391 assert(bytesToReadFromBuffer == *pcbRead);
392
393 /*
394 * Advance the pointer for the number of positions read.
395 */
[21916]396 This->currentPosition.DUMMYSTRUCTNAME_DOT LowPart += *pcbRead;
[8620]397
[7926]398 if(*pcbRead != cb)
399 {
400 WARN("read %ld instead of the required %ld bytes !\n", *pcbRead, cb);
401 /*
402 * this used to return S_FALSE, however MSDN docu says that an app should
403 * be prepared to handle error in case of stream end reached, as *some*
404 * implementations *might* return an error (IOW: most do *not*).
405 * As some program fails on returning S_FALSE, I better use S_OK here.
406 */
407 res = S_OK;
408 }
409 else
410 res = S_OK;
[8620]411
[7926]412end:
413 TRACE("<-- %08lx\n", res);
414 return res;
[5026]415}
[8620]416
[5026]417/***
418 * This method is part of the ISequentialStream interface.
419 *
420 * It writes a block of information to the stream at the current
421 * position. It then moves the current position at the end of the
422 * written block. If the stream is too small to fit the block,
423 * the stream is grown to fit.
424 *
425 * See the documentation of ISequentialStream for more info.
426 */
427HRESULT WINAPI StgStreamImpl_Write(
[6711]428 IStream* iface,
[8620]429 const void* pv, /* [size_is][in] */
430 ULONG cb, /* [in] */
431 ULONG* pcbWritten) /* [out] */
[5026]432{
433 StgStreamImpl* const This=(StgStreamImpl*)iface;
434
435 ULARGE_INTEGER newSize;
436 ULONG bytesWritten = 0;
437
438 TRACE("(%p, %p, %ld, %p)\n",
[6711]439 iface, pv, cb, pcbWritten);
[8620]440
[5026]441 /*
442 * Do we have permission to write to this stream?
443 */
444 if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE))) {
445 return STG_E_ACCESSDENIED;
446 }
447
448 /*
449 * If the caller is not interested in the number of bytes written,
450 * we use another buffer to avoid "if" statements in the code.
451 */
452 if (pcbWritten == 0)
453 pcbWritten = &bytesWritten;
[8620]454
[5026]455 /*
456 * Initialize the out parameter
457 */
458 *pcbWritten = 0;
459
460 if (cb == 0)
461 {
462 return S_OK;
463 }
464 else
465 {
[21916]466 newSize.DUMMYSTRUCTNAME_DOT HighPart = 0;
467 newSize.DUMMYSTRUCTNAME_DOT LowPart = This->currentPosition.DUMMYSTRUCTNAME_DOT LowPart + cb;
[5026]468 }
[8620]469
[5026]470 /*
471 * Verify if we need to grow the stream
472 */
[21916]473 if (newSize.DUMMYSTRUCTNAME_DOT LowPart > This->streamSize.DUMMYSTRUCTNAME_DOT LowPart)
[5026]474 {
475 /* grow stream */
476 IStream_SetSize(iface, newSize);
477 }
[8620]478
[5026]479 /*
480 * Depending on the type of chain that was opened when the stream was constructed,
481 * we delegate the work to the method that readwrites to the block chains.
482 */
483 if (This->smallBlockChain!=0)
484 {
485 SmallBlockChainStream_WriteAt(This->smallBlockChain,
[6711]486 This->currentPosition,
487 cb,
488 pv,
489 pcbWritten);
[8620]490
[5026]491 }
492 else if (This->bigBlockChain!=0)
493 {
494 BlockChainStream_WriteAt(This->bigBlockChain,
[6711]495 This->currentPosition,
496 cb,
497 pv,
498 pcbWritten);
[5026]499 }
500 else
501 assert(FALSE);
[8620]502
[5026]503 /*
504 * Advance the position pointer for the number of positions written.
505 */
[21916]506 This->currentPosition.DUMMYSTRUCTNAME_DOT LowPart += *pcbWritten;
[8620]507
[5026]508 return S_OK;
509}
510
511/***
512 * This method is part of the IStream interface.
513 *
514 * It will move the current stream pointer according to the parameters
515 * given.
516 *
517 * See the documentation of IStream for more info.
[8620]518 */
519HRESULT WINAPI StgStreamImpl_Seek(
[6711]520 IStream* iface,
[8620]521 LARGE_INTEGER dlibMove, /* [in] */
522 DWORD dwOrigin, /* [in] */
[6711]523 ULARGE_INTEGER* plibNewPosition) /* [out] */
[5026]524{
525 StgStreamImpl* const This=(StgStreamImpl*)iface;
526
527 ULARGE_INTEGER newPosition;
528
529 TRACE("(%p, %ld, %ld, %p)\n",
[21916]530 iface, dlibMove.DUMMYSTRUCTNAME_DOT LowPart, dwOrigin, plibNewPosition);
[5026]531
[8620]532 /*
[5026]533 * The caller is allowed to pass in NULL as the new position return value.
534 * If it happens, we assign it to a dynamic variable to avoid special cases
535 * in the code below.
536 */
537 if (plibNewPosition == 0)
538 {
539 plibNewPosition = &newPosition;
540 }
541
542 /*
543 * The file pointer is moved depending on the given "function"
544 * parameter.
545 */
546 switch (dwOrigin)
547 {
548 case STREAM_SEEK_SET:
[21916]549 plibNewPosition->DUMMYSTRUCTNAME_DOT HighPart = 0;
550 plibNewPosition->DUMMYSTRUCTNAME_DOT LowPart = 0;
[5026]551 break;
552 case STREAM_SEEK_CUR:
553 *plibNewPosition = This->currentPosition;
554 break;
555 case STREAM_SEEK_END:
556 *plibNewPosition = This->streamSize;
557 break;
558 default:
559 return STG_E_INVALIDFUNCTION;
560 }
[7926]561
[21916]562#ifdef __WIN32OS2__
[8636]563 *((LARGE_INTEGER*)plibNewPosition )= RtlpLargeIntegerAdd( (LARGE_INTEGER *)plibNewPosition, &dlibMove );
[5026]564#else
565 plibNewPosition->QuadPart = RtlLargeIntegerAdd( plibNewPosition->QuadPart, dlibMove.QuadPart );
566#endif
567 /*
568 * tell the caller what we calculated
569 */
570 This->currentPosition = *plibNewPosition;
[8620]571
[5026]572 return S_OK;
573}
574
575/***
576 * This method is part of the IStream interface.
577 *
578 * It will change the size of a stream.
579 *
580 * TODO: Switch from small blocks to big blocks and vice versa.
581 *
582 * See the documentation of IStream for more info.
583 */
[8620]584HRESULT WINAPI StgStreamImpl_SetSize(
[6711]585 IStream* iface,
[8620]586 ULARGE_INTEGER libNewSize) /* [in] */
[5026]587{
588 StgStreamImpl* const This=(StgStreamImpl*)iface;
589
590 StgProperty curProperty;
591 BOOL Success;
592
[21916]593 TRACE("(%p, %ld)\n", iface, libNewSize.DUMMYSTRUCTNAME_DOT LowPart);
[5026]594
595 /*
596 * As documented.
597 */
[21916]598 if (libNewSize.DUMMYSTRUCTNAME_DOT HighPart != 0)
[5026]599 return STG_E_INVALIDFUNCTION;
600
601 /*
602 * Do we have permission?
603 */
604 if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
605 return STG_E_ACCESSDENIED;
606
[21916]607 if (This->streamSize.DUMMYSTRUCTNAME_DOT LowPart == libNewSize.DUMMYSTRUCTNAME_DOT LowPart)
[5026]608 return S_OK;
609
610 /*
611 * This will happen if we're creating a stream
612 */
613 if ((This->smallBlockChain == 0) && (This->bigBlockChain == 0))
614 {
[21916]615 if (libNewSize.DUMMYSTRUCTNAME_DOT LowPart < LIMIT_TO_USE_SMALL_BLOCK)
[5026]616 {
617 This->smallBlockChain = SmallBlockChainStream_Construct(
618 This->parentStorage->ancestorStorage,
619 This->ownerProperty);
620 }
621 else
622 {
623 This->bigBlockChain = BlockChainStream_Construct(
624 This->parentStorage->ancestorStorage,
625 NULL,
626 This->ownerProperty);
627 }
628 }
629
630 /*
631 * Read this stream's property to see if it's small blocks or big blocks
632 */
633 Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
634 This->ownerProperty,
[8620]635 &curProperty);
[5026]636 /*
637 * Determine if we have to switch from small to big blocks or vice versa
[8620]638 */
639 if ( (This->smallBlockChain!=0) &&
[21916]640 (curProperty.size.DUMMYSTRUCTNAME_DOT LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
[5026]641 {
[21916]642 if (libNewSize.DUMMYSTRUCTNAME_DOT LowPart >= LIMIT_TO_USE_SMALL_BLOCK)
[5026]643 {
644 /*
645 * Transform the small block chain into a big block chain
646 */
647 This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks(
648 This->parentStorage->ancestorStorage,
649 &This->smallBlockChain);
650 }
651 }
652
653 if (This->smallBlockChain!=0)
654 {
655 Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize);
656 }
657 else
658 {
659 Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize);
660 }
661
662 /*
[7926]663 * Write the new information about this stream to the property
[5026]664 */
665 Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
666 This->ownerProperty,
667 &curProperty);
668
[21916]669 curProperty.size.DUMMYSTRUCTNAME_DOT HighPart = libNewSize.DUMMYSTRUCTNAME_DOT HighPart;
670 curProperty.size.DUMMYSTRUCTNAME_DOT LowPart = libNewSize.DUMMYSTRUCTNAME_DOT LowPart;
[8620]671
[5026]672 if (Success)
673 {
674 StorageImpl_WriteProperty(This->parentStorage->ancestorStorage,
[6711]675 This->ownerProperty,
676 &curProperty);
[5026]677 }
[8620]678
[5026]679 This->streamSize = libNewSize;
[8620]680
[5026]681 return S_OK;
682}
[8620]683
[5026]684/***
685 * This method is part of the IStream interface.
686 *
687 * It will copy the 'cb' Bytes to 'pstm' IStream.
688 *
689 * See the documentation of IStream for more info.
690 */
[8620]691HRESULT WINAPI StgStreamImpl_CopyTo(
[6711]692 IStream* iface,
[8620]693 IStream* pstm, /* [unique][in] */
694 ULARGE_INTEGER cb, /* [in] */
695 ULARGE_INTEGER* pcbRead, /* [out] */
696 ULARGE_INTEGER* pcbWritten) /* [out] */
[5026]697{
698 HRESULT hr = S_OK;
699 BYTE tmpBuffer[128];
700 ULONG bytesRead, bytesWritten, copySize;
701 ULARGE_INTEGER totalBytesRead;
702 ULARGE_INTEGER totalBytesWritten;
703
[8620]704 TRACE("(%p, %p, %ld, %p, %p)\n",
[21916]705 iface, pstm, cb.DUMMYSTRUCTNAME_DOT LowPart, pcbRead, pcbWritten);
[5026]706
707 /*
708 * Sanity check
709 */
710 if ( pstm == 0 )
711 return STG_E_INVALIDPOINTER;
712
[21916]713 totalBytesRead.DUMMYSTRUCTNAME_DOT LowPart = totalBytesRead.DUMMYSTRUCTNAME_DOT HighPart = 0;
714 totalBytesWritten.DUMMYSTRUCTNAME_DOT LowPart = totalBytesWritten.DUMMYSTRUCTNAME_DOT HighPart = 0;
[5026]715
716 /*
[7926]717 * use stack to store data temporarily
718 * there is surely a more performant way of doing it, for now this basic
[5026]719 * implementation will do the job
720 */
[21916]721 while ( cb.DUMMYSTRUCTNAME_DOT LowPart > 0 )
[5026]722 {
[21916]723 if ( cb.DUMMYSTRUCTNAME_DOT LowPart >= 128 )
[5026]724 copySize = 128;
725 else
[21916]726 copySize = cb.DUMMYSTRUCTNAME_DOT LowPart;
[8620]727
[5026]728 IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
729
[21916]730 totalBytesRead.DUMMYSTRUCTNAME_DOT LowPart += bytesRead;
[8620]731
[5026]732 IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
733
[21916]734 totalBytesWritten.DUMMYSTRUCTNAME_DOT LowPart += bytesWritten;
[5026]735
736 /*
[7926]737 * Check that read & write operations were successful
[5026]738 */
739 if (bytesRead != bytesWritten)
740 {
741 hr = STG_E_MEDIUMFULL;
742 break;
743 }
[8620]744
[5026]745 if (bytesRead!=copySize)
[21916]746 cb.DUMMYSTRUCTNAME_DOT LowPart = 0;
[5026]747 else
[21916]748 cb.DUMMYSTRUCTNAME_DOT LowPart -= bytesRead;
[5026]749 }
750
751 /*
752 * Update number of bytes read and written
753 */
754 if (pcbRead)
755 {
[21916]756 pcbRead->DUMMYSTRUCTNAME_DOT LowPart = totalBytesRead.DUMMYSTRUCTNAME_DOT LowPart;
757 pcbRead->DUMMYSTRUCTNAME_DOT HighPart = totalBytesRead.DUMMYSTRUCTNAME_DOT HighPart;
[5026]758 }
759
760 if (pcbWritten)
761 {
[21916]762 pcbWritten->DUMMYSTRUCTNAME_DOT LowPart = totalBytesWritten.DUMMYSTRUCTNAME_DOT LowPart;
763 pcbWritten->DUMMYSTRUCTNAME_DOT HighPart = totalBytesWritten.DUMMYSTRUCTNAME_DOT HighPart;
[5026]764 }
765 return hr;
766}
767
768/***
769 * This method is part of the IStream interface.
770 *
771 * For streams contained in structured storages, this method
772 * does nothing. This is what the documentation tells us.
773 *
774 * See the documentation of IStream for more info.
[8620]775 */
776HRESULT WINAPI StgStreamImpl_Commit(
[6711]777 IStream* iface,
[8620]778 DWORD grfCommitFlags) /* [in] */
[5026]779{
780 return S_OK;
781}
782
783/***
784 * This method is part of the IStream interface.
785 *
786 * For streams contained in structured storages, this method
787 * does nothing. This is what the documentation tells us.
788 *
789 * See the documentation of IStream for more info.
[8620]790 */
791HRESULT WINAPI StgStreamImpl_Revert(
[6711]792 IStream* iface)
[5026]793{
794 return S_OK;
795}
796
[8620]797HRESULT WINAPI StgStreamImpl_LockRegion(
[6711]798 IStream* iface,
[8620]799 ULARGE_INTEGER libOffset, /* [in] */
800 ULARGE_INTEGER cb, /* [in] */
801 DWORD dwLockType) /* [in] */
[5026]802{
803 FIXME("not implemented!\n");
804 return E_NOTIMPL;
805}
806
[8620]807HRESULT WINAPI StgStreamImpl_UnlockRegion(
[6711]808 IStream* iface,
[8620]809 ULARGE_INTEGER libOffset, /* [in] */
810 ULARGE_INTEGER cb, /* [in] */
811 DWORD dwLockType) /* [in] */
[5026]812{
813 FIXME("not implemented!\n");
814 return E_NOTIMPL;
815}
816
817/***
818 * This method is part of the IStream interface.
819 *
820 * This method returns information about the current
821 * stream.
822 *
823 * See the documentation of IStream for more info.
[8620]824 */
825HRESULT WINAPI StgStreamImpl_Stat(
[6711]826 IStream* iface,
827 STATSTG* pstatstg, /* [out] */
[8620]828 DWORD grfStatFlag) /* [in] */
[5026]829{
830 StgStreamImpl* const This=(StgStreamImpl*)iface;
831
832 StgProperty curProperty;
833 BOOL readSucessful;
[8620]834
[5026]835 /*
836 * Read the information from the property.
837 */
838 readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
[6711]839 This->ownerProperty,
840 &curProperty);
[8620]841
[5026]842 if (readSucessful)
843 {
[8620]844 StorageUtl_CopyPropertyToSTATSTG(pstatstg,
845 &curProperty,
[6711]846 grfStatFlag);
[5026]847
848 pstatstg->grfMode = This->grfMode;
[8620]849
[5026]850 return S_OK;
851 }
[8620]852
[5026]853 return E_FAIL;
854}
[8620]855
[6711]856/***
857 * This method is part of the IStream interface.
858 *
859 * This method returns a clone of the interface that allows for
860 * another seek pointer
861 *
862 * See the documentation of IStream for more info.
863 *
864 * I am not totally sure what I am doing here but I presume that this
865 * should be basically as simple as creating a new stream with the same
866 * parent etc and positioning its seek cursor.
[8620]867 */
868HRESULT WINAPI StgStreamImpl_Clone(
[6711]869 IStream* iface,
[8620]870 IStream** ppstm) /* [out] */
[6711]871{
872 StgStreamImpl* const This=(StgStreamImpl*)iface;
873 HRESULT hres;
874 StgStreamImpl* new_stream;
875 LARGE_INTEGER seek_pos;
[6648]876
[6711]877 /*
878 * Sanity check
879 */
880 if ( ppstm == 0 )
881 return STG_E_INVALIDPOINTER;
882
883 new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->ownerProperty);
884
885 if (!new_stream)
886 return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */
887
888 *ppstm = (IStream*) new_stream;
889 seek_pos.QuadPart = This->currentPosition.QuadPart;
[8620]890
[6711]891 hres=StgStreamImpl_Seek (*ppstm, seek_pos, STREAM_SEEK_SET, NULL);
[8620]892
[6711]893 assert (SUCCEEDED(hres));
894
895 return S_OK;
[5026]896}
Note: See TracBrowser for help on using the repository browser.