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