source: trunk/src/ole32/stg_stream.c@ 7788

Last change on this file since 7788 was 6711, checked in by sandervl, 24 years ago

restored old version + wine update

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