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