wined3d: IWineD3DBuffer_Unmap() can't fail.
[wine] / dlls / ole32 / storage32.c
1 /*
2  * Compound Storage (32 bit version)
3  * Storage implementation
4  *
5  * This file contains the compound file implementation
6  * of the storage interface.
7  *
8  * Copyright 1999 Francis Beaudet
9  * Copyright 1999 Sylvain St-Germain
10  * Copyright 1999 Thuy Nguyen
11  * Copyright 2005 Mike McCormack
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26  *
27  * NOTES
28  *  The compound file implementation of IStorage used for create
29  *  and manage substorages and streams within a storage object
30  *  residing in a compound file object.
31  */
32
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #define COBJMACROS
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winnls.h"
46 #include "winuser.h"
47 #include "wine/unicode.h"
48 #include "wine/debug.h"
49
50 #include "storage32.h"
51 #include "ole2.h"      /* For Write/ReadClassStm */
52
53 #include "winreg.h"
54 #include "wine/wingdi16.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(storage);
57
58 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
59 #define OLESTREAM_ID 0x501
60 #define OLESTREAM_MAX_STR_LEN 255
61
62 /*
63  * These are signatures to detect the type of Document file.
64  */
65 static const BYTE STORAGE_magic[8]    ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
66 static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
67
68 static const char rootEntryName[] = "Root Entry";
69
70 /****************************************************************************
71  * Storage32InternalImpl definitions.
72  *
73  * Definition of the implementation structure for the IStorage32 interface.
74  * This one implements the IStorage32 interface for storage that are
75  * inside another storage.
76  */
77 struct StorageInternalImpl
78 {
79   struct StorageBaseImpl base;
80
81   /*
82    * Entry in the parent's stream tracking list
83    */
84   struct list ParentListEntry;
85
86   StorageBaseImpl *parentStorage;
87 };
88 typedef struct StorageInternalImpl StorageInternalImpl;
89
90 /* Method definitions for the Storage32InternalImpl class. */
91 static StorageInternalImpl* StorageInternalImpl_Construct(StorageBaseImpl* parentStorage,
92                                                           DWORD openFlags, DirRef storageDirEntry);
93 static void StorageImpl_Destroy(StorageBaseImpl* iface);
94 static void StorageImpl_Invalidate(StorageBaseImpl* iface);
95 static HRESULT StorageImpl_Flush(StorageBaseImpl* iface);
96 static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
97 static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, const void* buffer);
98 static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock);
99 static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This);
100 static void StorageImpl_SaveFileHeader(StorageImpl* This);
101
102 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex);
103 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
104 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex);
105 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex);
106 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex);
107
108 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This);
109 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This);
110 static ULONG BlockChainStream_GetCount(BlockChainStream* This);
111
112 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This);
113 static ULONG SmallBlockChainStream_GetHeadOfChain(SmallBlockChainStream* This);
114 static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This,
115     ULONG blockIndex, ULONG offset, DWORD value);
116 static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl*  This,
117     ULONG blockIndex, ULONG offset, DWORD* value);
118
119 static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry);
120 static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry);
121
122 typedef struct TransactedDirEntry
123 {
124   /* If applicable, a reference to the original DirEntry in the transacted
125    * parent. If this is a newly-created entry, DIRENTRY_NULL. */
126   DirRef transactedParentEntry;
127
128   /* True if this entry is being used. */
129   int inuse;
130
131   /* True if data is up to date. */
132   int read;
133
134   /* True if this entry has been modified. */
135   int dirty;
136
137   /* True if this entry's stream has been modified. */
138   int stream_dirty;
139
140   /* True if this entry has been deleted in the transacted storage, but the
141    * delete has not yet been committed. */
142   int deleted;
143
144   /* If this entry's stream has been modified, a reference to where the stream
145    * is stored in the snapshot file. */
146   DirRef stream_entry;
147
148   /* This directory entry's data, including any changes that have been made. */
149   DirEntry data;
150
151   /* A reference to the parent of this node. This is only valid while we are
152    * committing changes. */
153   DirRef parent;
154
155   /* A reference to a newly-created entry in the transacted parent. This is
156    * always equal to transactedParentEntry except when committing changes. */
157   DirRef newTransactedParentEntry;
158 } TransactedDirEntry;
159
160 /****************************************************************************
161  * Transacted storage object.
162  */
163 typedef struct TransactedSnapshotImpl
164 {
165   struct StorageBaseImpl base;
166
167   /*
168    * Modified streams are temporarily saved to the scratch file.
169    */
170   StorageBaseImpl *scratch;
171
172   /* The directory structure is kept here, so that we can track how these
173    * entries relate to those in the parent storage. */
174   TransactedDirEntry *entries;
175   ULONG entries_size;
176   ULONG firstFreeEntry;
177
178   /*
179    * Changes are committed to the transacted parent.
180    */
181   StorageBaseImpl *transactedParent;
182 } TransactedSnapshotImpl;
183
184 /* Generic function to create a transacted wrapper for a direct storage object. */
185 static HRESULT Storage_ConstructTransacted(StorageBaseImpl* parent, StorageBaseImpl** result);
186
187 /* OLESTREAM memory structure to use for Get and Put Routines */
188 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
189 typedef struct
190 {
191     DWORD dwOleID;
192     DWORD dwTypeID;
193     DWORD dwOleTypeNameLength;
194     CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];
195     CHAR  *pstrOleObjFileName;
196     DWORD dwOleObjFileNameLength;
197     DWORD dwMetaFileWidth;
198     DWORD dwMetaFileHeight;
199     CHAR  strUnknown[8]; /* don't know what this 8 byte information in OLE stream is. */
200     DWORD dwDataLength;
201     BYTE *pData;
202 }OLECONVERT_OLESTREAM_DATA;
203
204 /* CompObj Stream structure */
205 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
206 typedef struct
207 {
208     BYTE byUnknown1[12];
209     CLSID clsid;
210     DWORD dwCLSIDNameLength;
211     CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
212     DWORD dwOleTypeNameLength;
213     CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
214     DWORD dwProgIDNameLength;
215     CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
216     BYTE byUnknown2[16];
217 }OLECONVERT_ISTORAGE_COMPOBJ;
218
219
220 /* Ole Presentation Stream structure */
221 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
222 typedef struct
223 {
224     BYTE byUnknown1[28];
225     DWORD dwExtentX;
226     DWORD dwExtentY;
227     DWORD dwSize;
228     BYTE *pData;
229 }OLECONVERT_ISTORAGE_OLEPRES;
230
231
232
233 /***********************************************************************
234  * Forward declaration of internal functions used by the method DestroyElement
235  */
236 static HRESULT deleteStorageContents(
237   StorageBaseImpl *parentStorage,
238   DirRef       indexToDelete,
239   DirEntry     entryDataToDelete);
240
241 static HRESULT deleteStreamContents(
242   StorageBaseImpl *parentStorage,
243   DirRef        indexToDelete,
244   DirEntry      entryDataToDelete);
245
246 static HRESULT removeFromTree(
247   StorageBaseImpl *This,
248   DirRef        parentStorageIndex,
249   DirRef        deletedIndex);
250
251 /***********************************************************************
252  * Declaration of the functions used to manipulate DirEntry
253  */
254
255 static HRESULT insertIntoTree(
256   StorageBaseImpl *This,
257   DirRef        parentStorageIndex,
258   DirRef        newEntryIndex);
259
260 static LONG entryNameCmp(
261     const OLECHAR *name1,
262     const OLECHAR *name2);
263
264 static DirRef findElement(
265     StorageBaseImpl *storage,
266     DirRef storageEntry,
267     const OLECHAR *name,
268     DirEntry *data);
269
270 static HRESULT findTreeParent(
271     StorageBaseImpl *storage,
272     DirRef storageEntry,
273     const OLECHAR *childName,
274     DirEntry *parentData,
275     DirRef *parentEntry,
276     ULONG *relation);
277
278 /***********************************************************************
279  * Declaration of miscellaneous functions...
280  */
281 static HRESULT validateSTGM(DWORD stgmValue);
282
283 static DWORD GetShareModeFromSTGM(DWORD stgm);
284 static DWORD GetAccessModeFromSTGM(DWORD stgm);
285 static DWORD GetCreationModeFromSTGM(DWORD stgm);
286
287 extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
288
289
290 /****************************************************************************
291  * IEnumSTATSTGImpl definitions.
292  *
293  * Definition of the implementation structure for the IEnumSTATSTGImpl interface.
294  * This class allows iterating through the content of a storage and to find
295  * specific items inside it.
296  */
297 struct IEnumSTATSTGImpl
298 {
299   const IEnumSTATSTGVtbl *lpVtbl;    /* Needs to be the first item in the struct
300                                 * since we want to cast this in an IEnumSTATSTG pointer */
301
302   LONG           ref;                   /* Reference count */
303   StorageBaseImpl* parentStorage;         /* Reference to the parent storage */
304   DirRef         storageDirEntry;     /* Directory entry of the storage to enumerate */
305
306   WCHAR          name[DIRENTRY_NAME_MAX_LEN]; /* The most recent name visited */
307 };
308
309
310 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageBaseImpl* This, DirRef storageDirEntry);
311 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This);
312
313 /************************************************************************
314 ** Block Functions
315 */
316
317 static ULONG StorageImpl_GetBigBlockOffset(StorageImpl* This, ULONG index)
318 {
319     return (index+1) * This->bigBlockSize;
320 }
321
322 /************************************************************************
323 ** Storage32BaseImpl implementation
324 */
325 static HRESULT StorageImpl_ReadAt(StorageImpl* This,
326   ULARGE_INTEGER offset,
327   void*          buffer,
328   ULONG          size,
329   ULONG*         bytesRead)
330 {
331     return ILockBytes_ReadAt(This->lockBytes,offset,buffer,size,bytesRead);
332 }
333
334 static HRESULT StorageImpl_WriteAt(StorageImpl* This,
335   ULARGE_INTEGER offset,
336   const void*    buffer,
337   const ULONG    size,
338   ULONG*         bytesWritten)
339 {
340     return ILockBytes_WriteAt(This->lockBytes,offset,buffer,size,bytesWritten);
341 }
342
343 /************************************************************************
344  * Storage32BaseImpl_QueryInterface (IUnknown)
345  *
346  * This method implements the common QueryInterface for all IStorage32
347  * implementations contained in this file.
348  *
349  * See Windows documentation for more details on IUnknown methods.
350  */
351 static HRESULT WINAPI StorageBaseImpl_QueryInterface(
352   IStorage*        iface,
353   REFIID             riid,
354   void**             ppvObject)
355 {
356   StorageBaseImpl *This = (StorageBaseImpl *)iface;
357
358   if ( (This==0) || (ppvObject==0) )
359     return E_INVALIDARG;
360
361   *ppvObject = 0;
362
363   if (IsEqualGUID(&IID_IUnknown, riid) ||
364       IsEqualGUID(&IID_IStorage, riid))
365   {
366     *ppvObject = This;
367   }
368   else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
369   {
370     *ppvObject = &This->pssVtbl;
371   }
372
373   if ((*ppvObject)==0)
374     return E_NOINTERFACE;
375
376   IStorage_AddRef(iface);
377
378   return S_OK;
379 }
380
381 /************************************************************************
382  * Storage32BaseImpl_AddRef (IUnknown)
383  *
384  * This method implements the common AddRef for all IStorage32
385  * implementations contained in this file.
386  *
387  * See Windows documentation for more details on IUnknown methods.
388  */
389 static ULONG WINAPI StorageBaseImpl_AddRef(
390             IStorage* iface)
391 {
392   StorageBaseImpl *This = (StorageBaseImpl *)iface;
393   ULONG ref = InterlockedIncrement(&This->ref);
394
395   TRACE("(%p) AddRef to %d\n", This, ref);
396
397   return ref;
398 }
399
400 /************************************************************************
401  * Storage32BaseImpl_Release (IUnknown)
402  *
403  * This method implements the common Release for all IStorage32
404  * implementations contained in this file.
405  *
406  * See Windows documentation for more details on IUnknown methods.
407  */
408 static ULONG WINAPI StorageBaseImpl_Release(
409       IStorage* iface)
410 {
411   StorageBaseImpl *This = (StorageBaseImpl *)iface;
412
413   ULONG ref = InterlockedDecrement(&This->ref);
414
415   TRACE("(%p) ReleaseRef to %d\n", This, ref);
416
417   if (ref == 0)
418   {
419     /*
420      * Since we are using a system of base-classes, we want to call the
421      * destructor of the appropriate derived class. To do this, we are
422      * using virtual functions to implement the destructor.
423      */
424     StorageBaseImpl_Destroy(This);
425   }
426
427   return ref;
428 }
429
430 /************************************************************************
431  * Storage32BaseImpl_OpenStream (IStorage)
432  *
433  * This method will open the specified stream object from the current storage.
434  *
435  * See Windows documentation for more details on IStorage methods.
436  */
437 static HRESULT WINAPI StorageBaseImpl_OpenStream(
438   IStorage*        iface,
439   const OLECHAR*   pwcsName,  /* [string][in] */
440   void*            reserved1, /* [unique][in] */
441   DWORD            grfMode,   /* [in]  */
442   DWORD            reserved2, /* [in]  */
443   IStream**        ppstm)     /* [out] */
444 {
445   StorageBaseImpl *This = (StorageBaseImpl *)iface;
446   StgStreamImpl*    newStream;
447   DirEntry          currentEntry;
448   DirRef            streamEntryRef;
449   HRESULT           res = STG_E_UNKNOWN;
450
451   TRACE("(%p, %s, %p, %x, %d, %p)\n",
452         iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
453
454   if ( (pwcsName==NULL) || (ppstm==0) )
455   {
456     res = E_INVALIDARG;
457     goto end;
458   }
459
460   *ppstm = NULL;
461
462   if ( FAILED( validateSTGM(grfMode) ) ||
463        STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
464   {
465     res = STG_E_INVALIDFLAG;
466     goto end;
467   }
468
469   /*
470    * As documented.
471    */
472   if ( (grfMode & STGM_DELETEONRELEASE) || (grfMode & STGM_TRANSACTED) )
473   {
474     res = STG_E_INVALIDFUNCTION;
475     goto end;
476   }
477
478   if (This->reverted)
479   {
480     res = STG_E_REVERTED;
481     goto end;
482   }
483
484   /*
485    * Check that we're compatible with the parent's storage mode, but
486    * only if we are not in transacted mode
487    */
488   if(!(This->openFlags & STGM_TRANSACTED)) {
489     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
490     {
491       res = STG_E_INVALIDFLAG;
492       goto end;
493     }
494   }
495
496   /*
497    * Search for the element with the given name
498    */
499   streamEntryRef = findElement(
500     This,
501     This->storageDirEntry,
502     pwcsName,
503     &currentEntry);
504
505   /*
506    * If it was found, construct the stream object and return a pointer to it.
507    */
508   if ( (streamEntryRef!=DIRENTRY_NULL) &&
509        (currentEntry.stgType==STGTY_STREAM) )
510   {
511     if (StorageBaseImpl_IsStreamOpen(This, streamEntryRef))
512     {
513       /* A single stream cannot be opened a second time. */
514       res = STG_E_ACCESSDENIED;
515       goto end;
516     }
517
518     newStream = StgStreamImpl_Construct(This, grfMode, streamEntryRef);
519
520     if (newStream!=0)
521     {
522       newStream->grfMode = grfMode;
523       *ppstm = (IStream*)newStream;
524
525       IStream_AddRef(*ppstm);
526
527       res = S_OK;
528       goto end;
529     }
530
531     res = E_OUTOFMEMORY;
532     goto end;
533   }
534
535   res = STG_E_FILENOTFOUND;
536
537 end:
538   if (res == S_OK)
539     TRACE("<-- IStream %p\n", *ppstm);
540   TRACE("<-- %08x\n", res);
541   return res;
542 }
543
544 /************************************************************************
545  * Storage32BaseImpl_OpenStorage (IStorage)
546  *
547  * This method will open a new storage object from the current storage.
548  *
549  * See Windows documentation for more details on IStorage methods.
550  */
551 static HRESULT WINAPI StorageBaseImpl_OpenStorage(
552   IStorage*        iface,
553   const OLECHAR*   pwcsName,      /* [string][unique][in] */
554   IStorage*        pstgPriority,  /* [unique][in] */
555   DWORD            grfMode,       /* [in] */
556   SNB              snbExclude,    /* [unique][in] */
557   DWORD            reserved,      /* [in] */
558   IStorage**       ppstg)         /* [out] */
559 {
560   StorageBaseImpl *This = (StorageBaseImpl *)iface;
561   StorageInternalImpl*   newStorage;
562   StorageBaseImpl*       newTransactedStorage;
563   DirEntry               currentEntry;
564   DirRef                 storageEntryRef;
565   HRESULT                res = STG_E_UNKNOWN;
566
567   TRACE("(%p, %s, %p, %x, %p, %d, %p)\n",
568         iface, debugstr_w(pwcsName), pstgPriority,
569         grfMode, snbExclude, reserved, ppstg);
570
571   if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
572   {
573     res = E_INVALIDARG;
574     goto end;
575   }
576
577   if (This->openFlags & STGM_SIMPLE)
578   {
579     res = STG_E_INVALIDFUNCTION;
580     goto end;
581   }
582
583   /* as documented */
584   if (snbExclude != NULL)
585   {
586     res = STG_E_INVALIDPARAMETER;
587     goto end;
588   }
589
590   if ( FAILED( validateSTGM(grfMode) ))
591   {
592     res = STG_E_INVALIDFLAG;
593     goto end;
594   }
595
596   /*
597    * As documented.
598    */
599   if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
600         (grfMode & STGM_DELETEONRELEASE) ||
601         (grfMode & STGM_PRIORITY) )
602   {
603     res = STG_E_INVALIDFUNCTION;
604     goto end;
605   }
606
607   if (This->reverted)
608     return STG_E_REVERTED;
609
610   /*
611    * Check that we're compatible with the parent's storage mode,
612    * but only if we are not transacted
613    */
614   if(!(This->openFlags & STGM_TRANSACTED)) {
615     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
616     {
617       res = STG_E_ACCESSDENIED;
618       goto end;
619     }
620   }
621
622   *ppstg = NULL;
623
624   storageEntryRef = findElement(
625                          This,
626                          This->storageDirEntry,
627                          pwcsName,
628                          &currentEntry);
629
630   if ( (storageEntryRef!=DIRENTRY_NULL) &&
631        (currentEntry.stgType==STGTY_STORAGE) )
632   {
633     if (StorageBaseImpl_IsStorageOpen(This, storageEntryRef))
634     {
635       /* A single storage cannot be opened a second time. */
636       res = STG_E_ACCESSDENIED;
637       goto end;
638     }
639
640     newStorage = StorageInternalImpl_Construct(
641                    This,
642                    grfMode,
643                    storageEntryRef);
644
645     if (newStorage != 0)
646     {
647       if (grfMode & STGM_TRANSACTED)
648       {
649         res = Storage_ConstructTransacted(&newStorage->base, &newTransactedStorage);
650
651         if (FAILED(res))
652         {
653           HeapFree(GetProcessHeap(), 0, newStorage);
654           goto end;
655         }
656
657         *ppstg = (IStorage*)newTransactedStorage;
658       }
659       else
660       {
661         *ppstg = (IStorage*)newStorage;
662       }
663
664       list_add_tail(&This->storageHead, &newStorage->ParentListEntry);
665
666       res = S_OK;
667       goto end;
668     }
669
670     res = STG_E_INSUFFICIENTMEMORY;
671     goto end;
672   }
673
674   res = STG_E_FILENOTFOUND;
675
676 end:
677   TRACE("<-- %08x\n", res);
678   return res;
679 }
680
681 /************************************************************************
682  * Storage32BaseImpl_EnumElements (IStorage)
683  *
684  * This method will create an enumerator object that can be used to
685  * retrieve information about all the elements in the storage object.
686  *
687  * See Windows documentation for more details on IStorage methods.
688  */
689 static HRESULT WINAPI StorageBaseImpl_EnumElements(
690   IStorage*       iface,
691   DWORD           reserved1, /* [in] */
692   void*           reserved2, /* [size_is][unique][in] */
693   DWORD           reserved3, /* [in] */
694   IEnumSTATSTG**  ppenum)    /* [out] */
695 {
696   StorageBaseImpl *This = (StorageBaseImpl *)iface;
697   IEnumSTATSTGImpl* newEnum;
698
699   TRACE("(%p, %d, %p, %d, %p)\n",
700         iface, reserved1, reserved2, reserved3, ppenum);
701
702   if ( (This==0) || (ppenum==0))
703     return E_INVALIDARG;
704
705   if (This->reverted)
706     return STG_E_REVERTED;
707
708   newEnum = IEnumSTATSTGImpl_Construct(
709               This,
710               This->storageDirEntry);
711
712   if (newEnum!=0)
713   {
714     *ppenum = (IEnumSTATSTG*)newEnum;
715
716     IEnumSTATSTG_AddRef(*ppenum);
717
718     return S_OK;
719   }
720
721   return E_OUTOFMEMORY;
722 }
723
724 /************************************************************************
725  * Storage32BaseImpl_Stat (IStorage)
726  *
727  * This method will retrieve information about this storage object.
728  *
729  * See Windows documentation for more details on IStorage methods.
730  */
731 static HRESULT WINAPI StorageBaseImpl_Stat(
732   IStorage*        iface,
733   STATSTG*         pstatstg,     /* [out] */
734   DWORD            grfStatFlag)  /* [in] */
735 {
736   StorageBaseImpl *This = (StorageBaseImpl *)iface;
737   DirEntry       currentEntry;
738   HRESULT        res = STG_E_UNKNOWN;
739
740   TRACE("(%p, %p, %x)\n",
741         iface, pstatstg, grfStatFlag);
742
743   if ( (This==0) || (pstatstg==0))
744   {
745     res = E_INVALIDARG;
746     goto end;
747   }
748
749   if (This->reverted)
750   {
751     res = STG_E_REVERTED;
752     goto end;
753   }
754
755   res = StorageBaseImpl_ReadDirEntry(
756                     This,
757                     This->storageDirEntry,
758                     &currentEntry);
759
760   if (SUCCEEDED(res))
761   {
762     StorageUtl_CopyDirEntryToSTATSTG(
763       This,
764       pstatstg,
765       &currentEntry,
766       grfStatFlag);
767
768     pstatstg->grfMode = This->openFlags;
769     pstatstg->grfStateBits = This->stateBits;
770   }
771
772 end:
773   if (res == S_OK)
774   {
775     TRACE("<-- STATSTG: pwcsName: %s, type: %d, cbSize.Low/High: %d/%d, grfMode: %08x, grfLocksSupported: %d, grfStateBits: %08x\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
776   }
777   TRACE("<-- %08x\n", res);
778   return res;
779 }
780
781 /************************************************************************
782  * Storage32BaseImpl_RenameElement (IStorage)
783  *
784  * This method will rename the specified element.
785  *
786  * See Windows documentation for more details on IStorage methods.
787  */
788 static HRESULT WINAPI StorageBaseImpl_RenameElement(
789             IStorage*        iface,
790             const OLECHAR*   pwcsOldName,  /* [in] */
791             const OLECHAR*   pwcsNewName)  /* [in] */
792 {
793   StorageBaseImpl *This = (StorageBaseImpl *)iface;
794   DirEntry          currentEntry;
795   DirRef            currentEntryRef;
796
797   TRACE("(%p, %s, %s)\n",
798         iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
799
800   if (This->reverted)
801     return STG_E_REVERTED;
802
803   currentEntryRef = findElement(This,
804                                    This->storageDirEntry,
805                                    pwcsNewName,
806                                    &currentEntry);
807
808   if (currentEntryRef != DIRENTRY_NULL)
809   {
810     /*
811      * There is already an element with the new name
812      */
813     return STG_E_FILEALREADYEXISTS;
814   }
815
816   /*
817    * Search for the old element name
818    */
819   currentEntryRef = findElement(This,
820                                    This->storageDirEntry,
821                                    pwcsOldName,
822                                    &currentEntry);
823
824   if (currentEntryRef != DIRENTRY_NULL)
825   {
826     if (StorageBaseImpl_IsStreamOpen(This, currentEntryRef) ||
827         StorageBaseImpl_IsStorageOpen(This, currentEntryRef))
828     {
829       WARN("Element is already open; cannot rename.\n");
830       return STG_E_ACCESSDENIED;
831     }
832
833     /* Remove the element from its current position in the tree */
834     removeFromTree(This, This->storageDirEntry,
835         currentEntryRef);
836
837     /* Change the name of the element */
838     strcpyW(currentEntry.name, pwcsNewName);
839
840     /* Delete any sibling links */
841     currentEntry.leftChild = DIRENTRY_NULL;
842     currentEntry.rightChild = DIRENTRY_NULL;
843
844     StorageBaseImpl_WriteDirEntry(This, currentEntryRef,
845         &currentEntry);
846
847     /* Insert the element in a new position in the tree */
848     insertIntoTree(This, This->storageDirEntry,
849         currentEntryRef);
850   }
851   else
852   {
853     /*
854      * There is no element with the old name
855      */
856     return STG_E_FILENOTFOUND;
857   }
858
859   return StorageBaseImpl_Flush(This);
860 }
861
862 /************************************************************************
863  * Storage32BaseImpl_CreateStream (IStorage)
864  *
865  * This method will create a stream object within this storage
866  *
867  * See Windows documentation for more details on IStorage methods.
868  */
869 static HRESULT WINAPI StorageBaseImpl_CreateStream(
870             IStorage*        iface,
871             const OLECHAR*   pwcsName,  /* [string][in] */
872             DWORD            grfMode,   /* [in] */
873             DWORD            reserved1, /* [in] */
874             DWORD            reserved2, /* [in] */
875             IStream**        ppstm)     /* [out] */
876 {
877   StorageBaseImpl *This = (StorageBaseImpl *)iface;
878   StgStreamImpl*    newStream;
879   DirEntry          currentEntry, newStreamEntry;
880   DirRef            currentEntryRef, newStreamEntryRef;
881   HRESULT hr;
882
883   TRACE("(%p, %s, %x, %d, %d, %p)\n",
884         iface, debugstr_w(pwcsName), grfMode,
885         reserved1, reserved2, ppstm);
886
887   if (ppstm == 0)
888     return STG_E_INVALIDPOINTER;
889
890   if (pwcsName == 0)
891     return STG_E_INVALIDNAME;
892
893   if (reserved1 || reserved2)
894     return STG_E_INVALIDPARAMETER;
895
896   if ( FAILED( validateSTGM(grfMode) ))
897     return STG_E_INVALIDFLAG;
898
899   if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) 
900     return STG_E_INVALIDFLAG;
901
902   if (This->reverted)
903     return STG_E_REVERTED;
904
905   /*
906    * As documented.
907    */
908   if ((grfMode & STGM_DELETEONRELEASE) ||
909       (grfMode & STGM_TRANSACTED))
910     return STG_E_INVALIDFUNCTION;
911
912   /*
913    * Don't worry about permissions in transacted mode, as we can always write
914    * changes; we just can't always commit them.
915    */
916   if(!(This->openFlags & STGM_TRANSACTED)) {
917     /* Can't create a stream on read-only storage */
918     if ( STGM_ACCESS_MODE( This->openFlags ) == STGM_READ )
919       return STG_E_ACCESSDENIED;
920
921     /* Can't create a stream with greater access than the parent. */
922     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
923       return STG_E_ACCESSDENIED;
924   }
925
926   if(This->openFlags & STGM_SIMPLE)
927     if(grfMode & STGM_CREATE) return STG_E_INVALIDFLAG;
928
929   *ppstm = 0;
930
931   currentEntryRef = findElement(This,
932                                    This->storageDirEntry,
933                                    pwcsName,
934                                    &currentEntry);
935
936   if (currentEntryRef != DIRENTRY_NULL)
937   {
938     /*
939      * An element with this name already exists
940      */
941     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
942     {
943       IStorage_DestroyElement(iface, pwcsName);
944     }
945     else
946       return STG_E_FILEALREADYEXISTS;
947   }
948
949   /*
950    * memset the empty entry
951    */
952   memset(&newStreamEntry, 0, sizeof(DirEntry));
953
954   newStreamEntry.sizeOfNameString =
955       ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
956
957   if (newStreamEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN)
958     return STG_E_INVALIDNAME;
959
960   strcpyW(newStreamEntry.name, pwcsName);
961
962   newStreamEntry.stgType       = STGTY_STREAM;
963   newStreamEntry.startingBlock = BLOCK_END_OF_CHAIN;
964   newStreamEntry.size.u.LowPart  = 0;
965   newStreamEntry.size.u.HighPart = 0;
966
967   newStreamEntry.leftChild        = DIRENTRY_NULL;
968   newStreamEntry.rightChild       = DIRENTRY_NULL;
969   newStreamEntry.dirRootEntry     = DIRENTRY_NULL;
970
971   /* call CoFileTime to get the current time
972   newStreamEntry.ctime
973   newStreamEntry.mtime
974   */
975
976   /*  newStreamEntry.clsid */
977
978   /*
979    * Create an entry with the new data
980    */
981   hr = StorageBaseImpl_CreateDirEntry(This, &newStreamEntry, &newStreamEntryRef);
982   if (FAILED(hr))
983     return hr;
984
985   /*
986    * Insert the new entry in the parent storage's tree.
987    */
988   hr = insertIntoTree(
989     This,
990     This->storageDirEntry,
991     newStreamEntryRef);
992   if (FAILED(hr))
993   {
994     StorageBaseImpl_DestroyDirEntry(This, newStreamEntryRef);
995     return hr;
996   }
997
998   /*
999    * Open the stream to return it.
1000    */
1001   newStream = StgStreamImpl_Construct(This, grfMode, newStreamEntryRef);
1002
1003   if (newStream != 0)
1004   {
1005     *ppstm = (IStream*)newStream;
1006
1007     IStream_AddRef(*ppstm);
1008   }
1009   else
1010   {
1011     return STG_E_INSUFFICIENTMEMORY;
1012   }
1013
1014   return StorageBaseImpl_Flush(This);
1015 }
1016
1017 /************************************************************************
1018  * Storage32BaseImpl_SetClass (IStorage)
1019  *
1020  * This method will write the specified CLSID in the directory entry of this
1021  * storage.
1022  *
1023  * See Windows documentation for more details on IStorage methods.
1024  */
1025 static HRESULT WINAPI StorageBaseImpl_SetClass(
1026   IStorage*        iface,
1027   REFCLSID         clsid) /* [in] */
1028 {
1029   StorageBaseImpl *This = (StorageBaseImpl *)iface;
1030   HRESULT hRes;
1031   DirEntry currentEntry;
1032
1033   TRACE("(%p, %p)\n", iface, clsid);
1034
1035   if (This->reverted)
1036     return STG_E_REVERTED;
1037
1038   hRes = StorageBaseImpl_ReadDirEntry(This,
1039                                       This->storageDirEntry,
1040                                       &currentEntry);
1041   if (SUCCEEDED(hRes))
1042   {
1043     currentEntry.clsid = *clsid;
1044
1045     hRes = StorageBaseImpl_WriteDirEntry(This,
1046                                          This->storageDirEntry,
1047                                          &currentEntry);
1048   }
1049
1050   if (SUCCEEDED(hRes))
1051     hRes = StorageBaseImpl_Flush(This);
1052
1053   return hRes;
1054 }
1055
1056 /************************************************************************
1057 ** Storage32Impl implementation
1058 */
1059
1060 /************************************************************************
1061  * Storage32BaseImpl_CreateStorage (IStorage)
1062  *
1063  * This method will create the storage object within the provided storage.
1064  *
1065  * See Windows documentation for more details on IStorage methods.
1066  */
1067 static HRESULT WINAPI StorageBaseImpl_CreateStorage(
1068   IStorage*      iface,
1069   const OLECHAR  *pwcsName, /* [string][in] */
1070   DWORD            grfMode,   /* [in] */
1071   DWORD            reserved1, /* [in] */
1072   DWORD            reserved2, /* [in] */
1073   IStorage       **ppstg)   /* [out] */
1074 {
1075   StorageBaseImpl* const This=(StorageBaseImpl*)iface;
1076
1077   DirEntry         currentEntry;
1078   DirEntry         newEntry;
1079   DirRef           currentEntryRef;
1080   DirRef           newEntryRef;
1081   HRESULT          hr;
1082
1083   TRACE("(%p, %s, %x, %d, %d, %p)\n",
1084         iface, debugstr_w(pwcsName), grfMode,
1085         reserved1, reserved2, ppstg);
1086
1087   if (ppstg == 0)
1088     return STG_E_INVALIDPOINTER;
1089
1090   if (This->openFlags & STGM_SIMPLE)
1091   {
1092     return STG_E_INVALIDFUNCTION;
1093   }
1094
1095   if (pwcsName == 0)
1096     return STG_E_INVALIDNAME;
1097
1098   *ppstg = NULL;
1099
1100   if ( FAILED( validateSTGM(grfMode) ) ||
1101        (grfMode & STGM_DELETEONRELEASE) )
1102   {
1103     WARN("bad grfMode: 0x%x\n", grfMode);
1104     return STG_E_INVALIDFLAG;
1105   }
1106
1107   if (This->reverted)
1108     return STG_E_REVERTED;
1109
1110   /*
1111    * Check that we're compatible with the parent's storage mode
1112    */
1113   if ( !(This->openFlags & STGM_TRANSACTED) &&
1114        STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
1115   {
1116     WARN("access denied\n");
1117     return STG_E_ACCESSDENIED;
1118   }
1119
1120   currentEntryRef = findElement(This,
1121                                    This->storageDirEntry,
1122                                    pwcsName,
1123                                    &currentEntry);
1124
1125   if (currentEntryRef != DIRENTRY_NULL)
1126   {
1127     /*
1128      * An element with this name already exists
1129      */
1130     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE &&
1131         ((This->openFlags & STGM_TRANSACTED) ||
1132          STGM_ACCESS_MODE(This->openFlags) != STGM_READ))
1133     {
1134       hr = IStorage_DestroyElement(iface, pwcsName);
1135       if (FAILED(hr))
1136         return hr;
1137     }
1138     else
1139     {
1140       WARN("file already exists\n");
1141       return STG_E_FILEALREADYEXISTS;
1142     }
1143   }
1144   else if (!(This->openFlags & STGM_TRANSACTED) &&
1145            STGM_ACCESS_MODE(This->openFlags) == STGM_READ)
1146   {
1147     WARN("read-only storage\n");
1148     return STG_E_ACCESSDENIED;
1149   }
1150
1151   memset(&newEntry, 0, sizeof(DirEntry));
1152
1153   newEntry.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
1154
1155   if (newEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN)
1156   {
1157     FIXME("name too long\n");
1158     return STG_E_INVALIDNAME;
1159   }
1160
1161   strcpyW(newEntry.name, pwcsName);
1162
1163   newEntry.stgType       = STGTY_STORAGE;
1164   newEntry.startingBlock = BLOCK_END_OF_CHAIN;
1165   newEntry.size.u.LowPart  = 0;
1166   newEntry.size.u.HighPart = 0;
1167
1168   newEntry.leftChild        = DIRENTRY_NULL;
1169   newEntry.rightChild       = DIRENTRY_NULL;
1170   newEntry.dirRootEntry     = DIRENTRY_NULL;
1171
1172   /* call CoFileTime to get the current time
1173   newEntry.ctime
1174   newEntry.mtime
1175   */
1176
1177   /*  newEntry.clsid */
1178
1179   /*
1180    * Create a new directory entry for the storage
1181    */
1182   hr = StorageBaseImpl_CreateDirEntry(This, &newEntry, &newEntryRef);
1183   if (FAILED(hr))
1184     return hr;
1185
1186   /*
1187    * Insert the new directory entry into the parent storage's tree
1188    */
1189   hr = insertIntoTree(
1190     This,
1191     This->storageDirEntry,
1192     newEntryRef);
1193   if (FAILED(hr))
1194   {
1195     StorageBaseImpl_DestroyDirEntry(This, newEntryRef);
1196     return hr;
1197   }
1198
1199   /*
1200    * Open it to get a pointer to return.
1201    */
1202   hr = IStorage_OpenStorage(iface, pwcsName, 0, grfMode, 0, 0, ppstg);
1203
1204   if( (hr != S_OK) || (*ppstg == NULL))
1205   {
1206     return hr;
1207   }
1208
1209   if (SUCCEEDED(hr))
1210     hr = StorageBaseImpl_Flush(This);
1211
1212   return S_OK;
1213 }
1214
1215
1216 /***************************************************************************
1217  *
1218  * Internal Method
1219  *
1220  * Reserve a directory entry in the file and initialize it.
1221  */
1222 static HRESULT StorageImpl_CreateDirEntry(
1223   StorageBaseImpl *base,
1224   const DirEntry *newData,
1225   DirRef *index)
1226 {
1227   StorageImpl *storage = (StorageImpl*)base;
1228   ULONG       currentEntryIndex    = 0;
1229   ULONG       newEntryIndex        = DIRENTRY_NULL;
1230   HRESULT hr = S_OK;
1231   BYTE currentData[RAW_DIRENTRY_SIZE];
1232   WORD sizeOfNameString;
1233
1234   do
1235   {
1236     hr = StorageImpl_ReadRawDirEntry(storage,
1237                                      currentEntryIndex,
1238                                      currentData);
1239
1240     if (SUCCEEDED(hr))
1241     {
1242       StorageUtl_ReadWord(
1243         currentData,
1244         OFFSET_PS_NAMELENGTH,
1245         &sizeOfNameString);
1246
1247       if (sizeOfNameString == 0)
1248       {
1249         /*
1250          * The entry exists and is available, we found it.
1251          */
1252         newEntryIndex = currentEntryIndex;
1253       }
1254     }
1255     else
1256     {
1257       /*
1258        * We exhausted the directory entries, we will create more space below
1259        */
1260       newEntryIndex = currentEntryIndex;
1261     }
1262     currentEntryIndex++;
1263
1264   } while (newEntryIndex == DIRENTRY_NULL);
1265
1266   /*
1267    * grow the directory stream
1268    */
1269   if (FAILED(hr))
1270   {
1271     BYTE           emptyData[RAW_DIRENTRY_SIZE];
1272     ULARGE_INTEGER newSize;
1273     ULONG          entryIndex;
1274     ULONG          lastEntry     = 0;
1275     ULONG          blockCount    = 0;
1276
1277     /*
1278      * obtain the new count of blocks in the directory stream
1279      */
1280     blockCount = BlockChainStream_GetCount(
1281                    storage->rootBlockChain)+1;
1282
1283     /*
1284      * initialize the size used by the directory stream
1285      */
1286     newSize.u.HighPart = 0;
1287     newSize.u.LowPart  = storage->bigBlockSize * blockCount;
1288
1289     /*
1290      * add a block to the directory stream
1291      */
1292     BlockChainStream_SetSize(storage->rootBlockChain, newSize);
1293
1294     /*
1295      * memset the empty entry in order to initialize the unused newly
1296      * created entries
1297      */
1298     memset(&emptyData, 0, RAW_DIRENTRY_SIZE);
1299
1300     /*
1301      * initialize them
1302      */
1303     lastEntry = storage->bigBlockSize / RAW_DIRENTRY_SIZE * blockCount;
1304
1305     for(
1306       entryIndex = newEntryIndex + 1;
1307       entryIndex < lastEntry;
1308       entryIndex++)
1309     {
1310       StorageImpl_WriteRawDirEntry(
1311         storage,
1312         entryIndex,
1313         emptyData);
1314     }
1315
1316     StorageImpl_SaveFileHeader(storage);
1317   }
1318
1319   UpdateRawDirEntry(currentData, newData);
1320
1321   hr = StorageImpl_WriteRawDirEntry(storage, newEntryIndex, currentData);
1322
1323   if (SUCCEEDED(hr))
1324     *index = newEntryIndex;
1325
1326   return hr;
1327 }
1328
1329 /***************************************************************************
1330  *
1331  * Internal Method
1332  *
1333  * Mark a directory entry in the file as free.
1334  */
1335 static HRESULT StorageImpl_DestroyDirEntry(
1336   StorageBaseImpl *base,
1337   DirRef index)
1338 {
1339   HRESULT hr;
1340   BYTE emptyData[RAW_DIRENTRY_SIZE];
1341   StorageImpl *storage = (StorageImpl*)base;
1342
1343   memset(&emptyData, 0, RAW_DIRENTRY_SIZE);
1344
1345   hr = StorageImpl_WriteRawDirEntry(storage, index, emptyData);
1346
1347   return hr;
1348 }
1349
1350
1351 /****************************************************************************
1352  *
1353  * Internal Method
1354  *
1355  * Case insensitive comparison of DirEntry.name by first considering
1356  * their size.
1357  *
1358  * Returns <0 when name1 < name2
1359  *         >0 when name1 > name2
1360  *          0 when name1 == name2
1361  */
1362 static LONG entryNameCmp(
1363     const OLECHAR *name1,
1364     const OLECHAR *name2)
1365 {
1366   LONG diff      = lstrlenW(name1) - lstrlenW(name2);
1367
1368   while (diff == 0 && *name1 != 0)
1369   {
1370     /*
1371      * We compare the string themselves only when they are of the same length
1372      */
1373     diff = toupperW(*name1++) - toupperW(*name2++);
1374   }
1375
1376   return diff;
1377 }
1378
1379 /****************************************************************************
1380  *
1381  * Internal Method
1382  *
1383  * Add a directory entry to a storage
1384  */
1385 static HRESULT insertIntoTree(
1386   StorageBaseImpl *This,
1387   DirRef        parentStorageIndex,
1388   DirRef        newEntryIndex)
1389 {
1390   DirEntry currentEntry;
1391   DirEntry newEntry;
1392
1393   /*
1394    * Read the inserted entry
1395    */
1396   StorageBaseImpl_ReadDirEntry(This,
1397                                newEntryIndex,
1398                                &newEntry);
1399
1400   /*
1401    * Read the storage entry
1402    */
1403   StorageBaseImpl_ReadDirEntry(This,
1404                                parentStorageIndex,
1405                                &currentEntry);
1406
1407   if (currentEntry.dirRootEntry != DIRENTRY_NULL)
1408   {
1409     /*
1410      * The root storage contains some element, therefore, start the research
1411      * for the appropriate location.
1412      */
1413     BOOL found = 0;
1414     DirRef current, next, previous, currentEntryId;
1415
1416     /*
1417      * Keep a reference to the root of the storage's element tree
1418      */
1419     currentEntryId = currentEntry.dirRootEntry;
1420
1421     /*
1422      * Read
1423      */
1424     StorageBaseImpl_ReadDirEntry(This,
1425                                  currentEntry.dirRootEntry,
1426                                  &currentEntry);
1427
1428     previous = currentEntry.leftChild;
1429     next     = currentEntry.rightChild;
1430     current  = currentEntryId;
1431
1432     while (found == 0)
1433     {
1434       LONG diff = entryNameCmp( newEntry.name, currentEntry.name);
1435
1436       if (diff < 0)
1437       {
1438         if (previous != DIRENTRY_NULL)
1439         {
1440           StorageBaseImpl_ReadDirEntry(This,
1441                                        previous,
1442                                        &currentEntry);
1443           current = previous;
1444         }
1445         else
1446         {
1447           currentEntry.leftChild = newEntryIndex;
1448           StorageBaseImpl_WriteDirEntry(This,
1449                                         current,
1450                                         &currentEntry);
1451           found = 1;
1452         }
1453       }
1454       else if (diff > 0)
1455       {
1456         if (next != DIRENTRY_NULL)
1457         {
1458           StorageBaseImpl_ReadDirEntry(This,
1459                                        next,
1460                                        &currentEntry);
1461           current = next;
1462         }
1463         else
1464         {
1465           currentEntry.rightChild = newEntryIndex;
1466           StorageBaseImpl_WriteDirEntry(This,
1467                                         current,
1468                                         &currentEntry);
1469           found = 1;
1470         }
1471       }
1472       else
1473       {
1474         /*
1475          * Trying to insert an item with the same name in the
1476          * subtree structure.
1477          */
1478         return STG_E_FILEALREADYEXISTS;
1479       }
1480
1481       previous = currentEntry.leftChild;
1482       next     = currentEntry.rightChild;
1483     }
1484   }
1485   else
1486   {
1487     /*
1488      * The storage is empty, make the new entry the root of its element tree
1489      */
1490     currentEntry.dirRootEntry = newEntryIndex;
1491     StorageBaseImpl_WriteDirEntry(This,
1492                                   parentStorageIndex,
1493                                   &currentEntry);
1494   }
1495
1496   return S_OK;
1497 }
1498
1499 /****************************************************************************
1500  *
1501  * Internal Method
1502  *
1503  * Find and read the element of a storage with the given name.
1504  */
1505 static DirRef findElement(StorageBaseImpl *storage, DirRef storageEntry,
1506     const OLECHAR *name, DirEntry *data)
1507 {
1508   DirRef currentEntry;
1509
1510   /* Read the storage entry to find the root of the tree. */
1511   StorageBaseImpl_ReadDirEntry(storage, storageEntry, data);
1512
1513   currentEntry = data->dirRootEntry;
1514
1515   while (currentEntry != DIRENTRY_NULL)
1516   {
1517     LONG cmp;
1518
1519     StorageBaseImpl_ReadDirEntry(storage, currentEntry, data);
1520
1521     cmp = entryNameCmp(name, data->name);
1522
1523     if (cmp == 0)
1524       /* found it */
1525       break;
1526
1527     else if (cmp < 0)
1528       currentEntry = data->leftChild;
1529
1530     else if (cmp > 0)
1531       currentEntry = data->rightChild;
1532   }
1533
1534   return currentEntry;
1535 }
1536
1537 /****************************************************************************
1538  *
1539  * Internal Method
1540  *
1541  * Find and read the binary tree parent of the element with the given name.
1542  *
1543  * If there is no such element, find a place where it could be inserted and
1544  * return STG_E_FILENOTFOUND.
1545  */
1546 static HRESULT findTreeParent(StorageBaseImpl *storage, DirRef storageEntry,
1547     const OLECHAR *childName, DirEntry *parentData, DirRef *parentEntry,
1548     ULONG *relation)
1549 {
1550   DirRef childEntry;
1551   DirEntry childData;
1552
1553   /* Read the storage entry to find the root of the tree. */
1554   StorageBaseImpl_ReadDirEntry(storage, storageEntry, parentData);
1555
1556   *parentEntry = storageEntry;
1557   *relation = DIRENTRY_RELATION_DIR;
1558
1559   childEntry = parentData->dirRootEntry;
1560
1561   while (childEntry != DIRENTRY_NULL)
1562   {
1563     LONG cmp;
1564
1565     StorageBaseImpl_ReadDirEntry(storage, childEntry, &childData);
1566
1567     cmp = entryNameCmp(childName, childData.name);
1568
1569     if (cmp == 0)
1570       /* found it */
1571       break;
1572
1573     else if (cmp < 0)
1574     {
1575       *parentData = childData;
1576       *parentEntry = childEntry;
1577       *relation = DIRENTRY_RELATION_PREVIOUS;
1578
1579       childEntry = parentData->leftChild;
1580     }
1581
1582     else if (cmp > 0)
1583     {
1584       *parentData = childData;
1585       *parentEntry = childEntry;
1586       *relation = DIRENTRY_RELATION_NEXT;
1587
1588       childEntry = parentData->rightChild;
1589     }
1590   }
1591
1592   if (childEntry == DIRENTRY_NULL)
1593     return STG_E_FILENOTFOUND;
1594   else
1595     return S_OK;
1596 }
1597
1598
1599 /*************************************************************************
1600  * CopyTo (IStorage)
1601  */
1602 static HRESULT WINAPI StorageBaseImpl_CopyTo(
1603   IStorage*   iface,
1604   DWORD       ciidExclude,  /* [in] */
1605   const IID*  rgiidExclude, /* [size_is][unique][in] */
1606   SNB         snbExclude,   /* [unique][in] */
1607   IStorage*   pstgDest)     /* [unique][in] */
1608 {
1609   StorageBaseImpl* const This=(StorageBaseImpl*)iface;
1610
1611   IEnumSTATSTG *elements     = 0;
1612   STATSTG      curElement, strStat;
1613   HRESULT      hr;
1614   IStorage     *pstgTmp, *pstgChild;
1615   IStream      *pstrTmp, *pstrChild;
1616   DirRef       srcEntryRef;
1617   DirEntry     srcEntry;
1618   BOOL         skip = FALSE, skip_storage = FALSE, skip_stream = FALSE;
1619   int          i;
1620
1621   TRACE("(%p, %d, %p, %p, %p)\n",
1622         iface, ciidExclude, rgiidExclude,
1623         snbExclude, pstgDest);
1624
1625   if ( pstgDest == 0 )
1626     return STG_E_INVALIDPOINTER;
1627
1628   /*
1629    * Enumerate the elements
1630    */
1631   hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
1632
1633   if ( hr != S_OK )
1634     return hr;
1635
1636   /*
1637    * set the class ID
1638    */
1639   IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
1640   IStorage_SetClass( pstgDest, &curElement.clsid );
1641
1642   for(i = 0; i < ciidExclude; ++i)
1643   {
1644     if(IsEqualGUID(&IID_IStorage, &rgiidExclude[i]))
1645         skip_storage = TRUE;
1646     else if(IsEqualGUID(&IID_IStream, &rgiidExclude[i]))
1647         skip_stream = TRUE;
1648     else
1649         WARN("Unknown excluded GUID: %s\n", debugstr_guid(&rgiidExclude[i]));
1650   }
1651
1652   do
1653   {
1654     /*
1655      * Obtain the next element
1656      */
1657     hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
1658
1659     if ( hr == S_FALSE )
1660     {
1661       hr = S_OK;   /* done, every element has been copied */
1662       break;
1663     }
1664
1665     if ( snbExclude )
1666     {
1667       WCHAR **snb = snbExclude;
1668       skip = FALSE;
1669       while ( *snb != NULL && !skip )
1670       {
1671         if ( lstrcmpW(curElement.pwcsName, *snb) == 0 )
1672           skip = TRUE;
1673         ++snb;
1674       }
1675     }
1676
1677     if ( skip )
1678       goto cleanup;
1679
1680     if (curElement.type == STGTY_STORAGE)
1681     {
1682       if(skip_storage)
1683         goto cleanup;
1684
1685       /*
1686        * open child source storage
1687        */
1688       hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
1689                                  STGM_READ|STGM_SHARE_EXCLUSIVE,
1690                                  NULL, 0, &pstgChild );
1691
1692       if (hr != S_OK)
1693         goto cleanup;
1694
1695       /*
1696        * create a new storage in destination storage
1697        */
1698       hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
1699                                    STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1700                                    0, 0,
1701                                    &pstgTmp );
1702       /*
1703        * if it already exist, don't create a new one use this one
1704        */
1705       if (hr == STG_E_FILEALREADYEXISTS)
1706       {
1707         hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
1708                                    STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1709                                    NULL, 0, &pstgTmp );
1710       }
1711
1712       if (hr == S_OK)
1713       {
1714         /*
1715          * do the copy recursively
1716          */
1717         hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
1718                                  NULL, pstgTmp );
1719
1720         IStorage_Release( pstgTmp );
1721       }
1722
1723       IStorage_Release( pstgChild );
1724     }
1725     else if (curElement.type == STGTY_STREAM)
1726     {
1727       if(skip_stream)
1728         goto cleanup;
1729
1730       /*
1731        * create a new stream in destination storage. If the stream already
1732        * exist, it will be deleted and a new one will be created.
1733        */
1734       hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
1735                                   STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1736                                   0, 0, &pstrTmp );
1737
1738       if (hr != S_OK)
1739         goto cleanup;
1740
1741       /*
1742        * open child stream storage. This operation must succeed even if the
1743        * stream is already open, so we use internal functions to do it.
1744        */
1745       srcEntryRef = findElement( This, This->storageDirEntry, curElement.pwcsName,
1746         &srcEntry);
1747       if (!srcEntryRef)
1748       {
1749         ERR("source stream not found\n");
1750         hr = STG_E_DOCFILECORRUPT;
1751       }
1752
1753       if (hr == S_OK)
1754       {
1755         pstrChild = (IStream*)StgStreamImpl_Construct(This, STGM_READ|STGM_SHARE_EXCLUSIVE, srcEntryRef);
1756         if (pstrChild)
1757           IStream_AddRef(pstrChild);
1758         else
1759           hr = E_OUTOFMEMORY;
1760       }
1761
1762       if (hr == S_OK)
1763       {
1764         /*
1765          * Get the size of the source stream
1766          */
1767         IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1768
1769         /*
1770          * Set the size of the destination stream.
1771          */
1772         IStream_SetSize(pstrTmp, strStat.cbSize);
1773
1774         /*
1775          * do the copy
1776          */
1777         hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1778                              NULL, NULL );
1779
1780         IStream_Release( pstrChild );
1781       }
1782
1783       IStream_Release( pstrTmp );
1784     }
1785     else
1786     {
1787       WARN("unknown element type: %d\n", curElement.type);
1788     }
1789
1790 cleanup:
1791     CoTaskMemFree(curElement.pwcsName);
1792   } while (hr == S_OK);
1793
1794   /*
1795    * Clean-up
1796    */
1797   IEnumSTATSTG_Release(elements);
1798
1799   return hr;
1800 }
1801
1802 /*************************************************************************
1803  * MoveElementTo (IStorage)
1804  */
1805 static HRESULT WINAPI StorageBaseImpl_MoveElementTo(
1806   IStorage*     iface,
1807   const OLECHAR *pwcsName,   /* [string][in] */
1808   IStorage      *pstgDest,   /* [unique][in] */
1809   const OLECHAR *pwcsNewName,/* [string][in] */
1810   DWORD           grfFlags)    /* [in] */
1811 {
1812   FIXME("(%p %s %p %s %u): stub\n", iface,
1813          debugstr_w(pwcsName), pstgDest,
1814          debugstr_w(pwcsNewName), grfFlags);
1815   return E_NOTIMPL;
1816 }
1817
1818 /*************************************************************************
1819  * Commit (IStorage)
1820  *
1821  * Ensures that any changes made to a storage object open in transacted mode
1822  * are reflected in the parent storage
1823  *
1824  * In a non-transacted mode, this ensures all cached writes are completed.
1825  */
1826 static HRESULT WINAPI StorageImpl_Commit(
1827   IStorage*   iface,
1828   DWORD         grfCommitFlags)/* [in] */
1829 {
1830   StorageBaseImpl* const base=(StorageBaseImpl*)iface;
1831   TRACE("(%p %d)\n", iface, grfCommitFlags);
1832   return StorageBaseImpl_Flush(base);
1833 }
1834
1835 /*************************************************************************
1836  * Revert (IStorage)
1837  *
1838  * Discard all changes that have been made since the last commit operation
1839  */
1840 static HRESULT WINAPI StorageImpl_Revert(
1841   IStorage* iface)
1842 {
1843   TRACE("(%p)\n", iface);
1844   return S_OK;
1845 }
1846
1847 /*************************************************************************
1848  * DestroyElement (IStorage)
1849  *
1850  * Strategy: This implementation is built this way for simplicity not for speed.
1851  *          I always delete the topmost element of the enumeration and adjust
1852  *          the deleted element pointer all the time.  This takes longer to
1853  *          do but allow to reinvoke DestroyElement whenever we encounter a
1854  *          storage object.  The optimisation resides in the usage of another
1855  *          enumeration strategy that would give all the leaves of a storage
1856  *          first. (postfix order)
1857  */
1858 static HRESULT WINAPI StorageBaseImpl_DestroyElement(
1859   IStorage*     iface,
1860   const OLECHAR *pwcsName)/* [string][in] */
1861 {
1862   StorageBaseImpl* const This=(StorageBaseImpl*)iface;
1863
1864   HRESULT           hr = S_OK;
1865   DirEntry          entryToDelete;
1866   DirRef            entryToDeleteRef;
1867
1868   TRACE("(%p, %s)\n",
1869         iface, debugstr_w(pwcsName));
1870
1871   if (pwcsName==NULL)
1872     return STG_E_INVALIDPOINTER;
1873
1874   if (This->reverted)
1875     return STG_E_REVERTED;
1876
1877   if ( !(This->openFlags & STGM_TRANSACTED) &&
1878        STGM_ACCESS_MODE( This->openFlags ) == STGM_READ )
1879     return STG_E_ACCESSDENIED;
1880
1881   entryToDeleteRef = findElement(
1882     This,
1883     This->storageDirEntry,
1884     pwcsName,
1885     &entryToDelete);
1886
1887   if ( entryToDeleteRef == DIRENTRY_NULL )
1888   {
1889     return STG_E_FILENOTFOUND;
1890   }
1891
1892   if ( entryToDelete.stgType == STGTY_STORAGE )
1893   {
1894     hr = deleteStorageContents(
1895            This,
1896            entryToDeleteRef,
1897            entryToDelete);
1898   }
1899   else if ( entryToDelete.stgType == STGTY_STREAM )
1900   {
1901     hr = deleteStreamContents(
1902            This,
1903            entryToDeleteRef,
1904            entryToDelete);
1905   }
1906
1907   if (hr!=S_OK)
1908     return hr;
1909
1910   /*
1911    * Remove the entry from its parent storage
1912    */
1913   hr = removeFromTree(
1914         This,
1915         This->storageDirEntry,
1916         entryToDeleteRef);
1917
1918   /*
1919    * Invalidate the entry
1920    */
1921   if (SUCCEEDED(hr))
1922     StorageBaseImpl_DestroyDirEntry(This, entryToDeleteRef);
1923
1924   if (SUCCEEDED(hr))
1925     hr = StorageBaseImpl_Flush(This);
1926
1927   return hr;
1928 }
1929
1930
1931 /******************************************************************************
1932  * Internal stream list handlers
1933  */
1934
1935 void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm)
1936 {
1937   TRACE("Stream added (stg=%p strm=%p)\n", stg, strm);
1938   list_add_tail(&stg->strmHead,&strm->StrmListEntry);
1939 }
1940
1941 void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm)
1942 {
1943   TRACE("Stream removed (stg=%p strm=%p)\n", stg,strm);
1944   list_remove(&(strm->StrmListEntry));
1945 }
1946
1947 static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry)
1948 {
1949   StgStreamImpl *strm;
1950
1951   LIST_FOR_EACH_ENTRY(strm, &stg->strmHead, StgStreamImpl, StrmListEntry)
1952   {
1953     if (strm->dirEntry == streamEntry)
1954     {
1955       return TRUE;
1956     }
1957   }
1958
1959   return FALSE;
1960 }
1961
1962 static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry)
1963 {
1964   StorageInternalImpl *childstg;
1965
1966   LIST_FOR_EACH_ENTRY(childstg, &stg->storageHead, StorageInternalImpl, ParentListEntry)
1967   {
1968     if (childstg->base.storageDirEntry == storageEntry)
1969     {
1970       return TRUE;
1971     }
1972   }
1973
1974   return FALSE;
1975 }
1976
1977 static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg)
1978 {
1979   struct list *cur, *cur2;
1980   StgStreamImpl *strm=NULL;
1981   StorageInternalImpl *childstg=NULL;
1982
1983   LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) {
1984     strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry);
1985     TRACE("Streams invalidated (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev);
1986     strm->parentStorage = NULL;
1987     list_remove(cur);
1988   }
1989
1990   LIST_FOR_EACH_SAFE(cur, cur2, &stg->storageHead) {
1991     childstg = LIST_ENTRY(cur,StorageInternalImpl,ParentListEntry);
1992     StorageBaseImpl_Invalidate( &childstg->base );
1993   }
1994
1995   if (stg->transactedChild)
1996   {
1997     StorageBaseImpl_Invalidate(stg->transactedChild);
1998
1999     stg->transactedChild = NULL;
2000   }
2001 }
2002
2003
2004 /*********************************************************************
2005  *
2006  * Internal Method
2007  *
2008  * Delete the contents of a storage entry.
2009  *
2010  */
2011 static HRESULT deleteStorageContents(
2012   StorageBaseImpl *parentStorage,
2013   DirRef       indexToDelete,
2014   DirEntry     entryDataToDelete)
2015 {
2016   IEnumSTATSTG *elements     = 0;
2017   IStorage   *childStorage = 0;
2018   STATSTG      currentElement;
2019   HRESULT      hr;
2020   HRESULT      destroyHr = S_OK;
2021   StorageInternalImpl *stg, *stg2;
2022
2023   /* Invalidate any open storage objects. */
2024   LIST_FOR_EACH_ENTRY_SAFE(stg, stg2, &parentStorage->storageHead, StorageInternalImpl, ParentListEntry)
2025   {
2026     if (stg->base.storageDirEntry == indexToDelete)
2027     {
2028       StorageBaseImpl_Invalidate(&stg->base);
2029     }
2030   }
2031
2032   /*
2033    * Open the storage and enumerate it
2034    */
2035   hr = StorageBaseImpl_OpenStorage(
2036         (IStorage*)parentStorage,
2037         entryDataToDelete.name,
2038         0,
2039         STGM_WRITE | STGM_SHARE_EXCLUSIVE,
2040         0,
2041         0,
2042         &childStorage);
2043
2044   if (hr != S_OK)
2045   {
2046     return hr;
2047   }
2048
2049   /*
2050    * Enumerate the elements
2051    */
2052   IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
2053
2054   do
2055   {
2056     /*
2057      * Obtain the next element
2058      */
2059     hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
2060     if (hr==S_OK)
2061     {
2062       destroyHr = IStorage_DestroyElement(childStorage, currentElement.pwcsName);
2063
2064       CoTaskMemFree(currentElement.pwcsName);
2065     }
2066
2067     /*
2068      * We need to Reset the enumeration every time because we delete elements
2069      * and the enumeration could be invalid
2070      */
2071     IEnumSTATSTG_Reset(elements);
2072
2073   } while ((hr == S_OK) && (destroyHr == S_OK));
2074
2075   IStorage_Release(childStorage);
2076   IEnumSTATSTG_Release(elements);
2077
2078   return destroyHr;
2079 }
2080
2081 /*********************************************************************
2082  *
2083  * Internal Method
2084  *
2085  * Perform the deletion of a stream's data
2086  *
2087  */
2088 static HRESULT deleteStreamContents(
2089   StorageBaseImpl *parentStorage,
2090   DirRef        indexToDelete,
2091   DirEntry      entryDataToDelete)
2092 {
2093   IStream      *pis;
2094   HRESULT        hr;
2095   ULARGE_INTEGER size;
2096   StgStreamImpl *strm, *strm2;
2097
2098   /* Invalidate any open stream objects. */
2099   LIST_FOR_EACH_ENTRY_SAFE(strm, strm2, &parentStorage->strmHead, StgStreamImpl, StrmListEntry)
2100   {
2101     if (strm->dirEntry == indexToDelete)
2102     {
2103       TRACE("Stream deleted %p\n", strm);
2104       strm->parentStorage = NULL;
2105       list_remove(&strm->StrmListEntry);
2106     }
2107   }
2108
2109   size.u.HighPart = 0;
2110   size.u.LowPart = 0;
2111
2112   hr = StorageBaseImpl_OpenStream((IStorage*)parentStorage,
2113         entryDataToDelete.name, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pis);
2114
2115   if (hr!=S_OK)
2116   {
2117     return(hr);
2118   }
2119
2120   /*
2121    * Zap the stream
2122    */
2123   hr = IStream_SetSize(pis, size);
2124
2125   if(hr != S_OK)
2126   {
2127     return hr;
2128   }
2129
2130   /*
2131    * Release the stream object.
2132    */
2133   IStream_Release(pis);
2134
2135   return S_OK;
2136 }
2137
2138 static void setEntryLink(DirEntry *entry, ULONG relation, DirRef new_target)
2139 {
2140   switch (relation)
2141   {
2142     case DIRENTRY_RELATION_PREVIOUS:
2143       entry->leftChild = new_target;
2144       break;
2145     case DIRENTRY_RELATION_NEXT:
2146       entry->rightChild = new_target;
2147       break;
2148     case DIRENTRY_RELATION_DIR:
2149       entry->dirRootEntry = new_target;
2150       break;
2151     default:
2152       assert(0);
2153   }
2154 }
2155
2156 /*************************************************************************
2157  *
2158  * Internal Method
2159  *
2160  * This method removes a directory entry from its parent storage tree without
2161  * freeing any resources attached to it.
2162  */
2163 static HRESULT removeFromTree(
2164   StorageBaseImpl *This,
2165   DirRef        parentStorageIndex,
2166   DirRef        deletedIndex)
2167 {
2168   HRESULT hr                     = S_OK;
2169   DirEntry   entryToDelete;
2170   DirEntry   parentEntry;
2171   DirRef parentEntryRef;
2172   ULONG typeOfRelation;
2173
2174   hr = StorageBaseImpl_ReadDirEntry(This, deletedIndex, &entryToDelete);
2175
2176   if (hr != S_OK)
2177     return hr;
2178
2179   /*
2180    * Find the element that links to the one we want to delete.
2181    */
2182   hr = findTreeParent(This, parentStorageIndex, entryToDelete.name,
2183     &parentEntry, &parentEntryRef, &typeOfRelation);
2184
2185   if (hr != S_OK)
2186     return hr;
2187
2188   if (entryToDelete.leftChild != DIRENTRY_NULL)
2189   {
2190     /*
2191      * Replace the deleted entry with its left child
2192      */
2193     setEntryLink(&parentEntry, typeOfRelation, entryToDelete.leftChild);
2194
2195     hr = StorageBaseImpl_WriteDirEntry(
2196             This,
2197             parentEntryRef,
2198             &parentEntry);
2199     if(FAILED(hr))
2200     {
2201       return hr;
2202     }
2203
2204     if (entryToDelete.rightChild != DIRENTRY_NULL)
2205     {
2206       /*
2207        * We need to reinsert the right child somewhere. We already know it and
2208        * its children are greater than everything in the left tree, so we
2209        * insert it at the rightmost point in the left tree.
2210        */
2211       DirRef newRightChildParent = entryToDelete.leftChild;
2212       DirEntry newRightChildParentEntry;
2213
2214       do
2215       {
2216         hr = StorageBaseImpl_ReadDirEntry(
2217                 This,
2218                 newRightChildParent,
2219                 &newRightChildParentEntry);
2220         if (FAILED(hr))
2221         {
2222           return hr;
2223         }
2224
2225         if (newRightChildParentEntry.rightChild != DIRENTRY_NULL)
2226           newRightChildParent = newRightChildParentEntry.rightChild;
2227       } while (newRightChildParentEntry.rightChild != DIRENTRY_NULL);
2228
2229       newRightChildParentEntry.rightChild = entryToDelete.rightChild;
2230
2231       hr = StorageBaseImpl_WriteDirEntry(
2232               This,
2233               newRightChildParent,
2234               &newRightChildParentEntry);
2235       if (FAILED(hr))
2236       {
2237         return hr;
2238       }
2239     }
2240   }
2241   else
2242   {
2243     /*
2244      * Replace the deleted entry with its right child
2245      */
2246     setEntryLink(&parentEntry, typeOfRelation, entryToDelete.rightChild);
2247
2248     hr = StorageBaseImpl_WriteDirEntry(
2249             This,
2250             parentEntryRef,
2251             &parentEntry);
2252     if(FAILED(hr))
2253     {
2254       return hr;
2255     }
2256   }
2257
2258   return hr;
2259 }
2260
2261
2262 /******************************************************************************
2263  * SetElementTimes (IStorage)
2264  */
2265 static HRESULT WINAPI StorageBaseImpl_SetElementTimes(
2266   IStorage*     iface,
2267   const OLECHAR *pwcsName,/* [string][in] */
2268   const FILETIME  *pctime,  /* [in] */
2269   const FILETIME  *patime,  /* [in] */
2270   const FILETIME  *pmtime)  /* [in] */
2271 {
2272   FIXME("(%s,...), stub!\n",debugstr_w(pwcsName));
2273   return S_OK;
2274 }
2275
2276 /******************************************************************************
2277  * SetStateBits (IStorage)
2278  */
2279 static HRESULT WINAPI StorageBaseImpl_SetStateBits(
2280   IStorage*   iface,
2281   DWORD         grfStateBits,/* [in] */
2282   DWORD         grfMask)     /* [in] */
2283 {
2284   StorageBaseImpl* const This = (StorageBaseImpl*)iface;
2285
2286   if (This->reverted)
2287     return STG_E_REVERTED;
2288
2289   This->stateBits = (This->stateBits & ~grfMask) | (grfStateBits & grfMask);
2290   return S_OK;
2291 }
2292
2293 static HRESULT StorageImpl_BaseWriteDirEntry(StorageBaseImpl *base,
2294   DirRef index, const DirEntry *data)
2295 {
2296   StorageImpl *This = (StorageImpl*)base;
2297   return StorageImpl_WriteDirEntry(This, index, data);
2298 }
2299
2300 static HRESULT StorageImpl_BaseReadDirEntry(StorageBaseImpl *base,
2301   DirRef index, DirEntry *data)
2302 {
2303   StorageImpl *This = (StorageImpl*)base;
2304   return StorageImpl_ReadDirEntry(This, index, data);
2305 }
2306
2307 static BlockChainStream **StorageImpl_GetFreeBlockChainCacheEntry(StorageImpl* This)
2308 {
2309   int i;
2310
2311   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
2312   {
2313     if (!This->blockChainCache[i])
2314     {
2315       return &This->blockChainCache[i];
2316     }
2317   }
2318
2319   i = This->blockChainToEvict;
2320
2321   BlockChainStream_Destroy(This->blockChainCache[i]);
2322   This->blockChainCache[i] = NULL;
2323
2324   This->blockChainToEvict++;
2325   if (This->blockChainToEvict == BLOCKCHAIN_CACHE_SIZE)
2326     This->blockChainToEvict = 0;
2327
2328   return &This->blockChainCache[i];
2329 }
2330
2331 static BlockChainStream **StorageImpl_GetCachedBlockChainStream(StorageImpl *This,
2332     DirRef index)
2333 {
2334   int i, free_index=-1;
2335
2336   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
2337   {
2338     if (!This->blockChainCache[i])
2339     {
2340       if (free_index == -1) free_index = i;
2341     }
2342     else if (This->blockChainCache[i]->ownerDirEntry == index)
2343     {
2344       return &This->blockChainCache[i];
2345     }
2346   }
2347
2348   if (free_index == -1)
2349   {
2350     free_index = This->blockChainToEvict;
2351
2352     BlockChainStream_Destroy(This->blockChainCache[free_index]);
2353     This->blockChainCache[free_index] = NULL;
2354
2355     This->blockChainToEvict++;
2356     if (This->blockChainToEvict == BLOCKCHAIN_CACHE_SIZE)
2357       This->blockChainToEvict = 0;
2358   }
2359
2360   This->blockChainCache[free_index] = BlockChainStream_Construct(This, NULL, index);
2361   return &This->blockChainCache[free_index];
2362 }
2363
2364 static void StorageImpl_DeleteCachedBlockChainStream(StorageImpl *This, DirRef index)
2365 {
2366   int i;
2367
2368   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
2369   {
2370     if (This->blockChainCache[i] && This->blockChainCache[i]->ownerDirEntry == index)
2371     {
2372       BlockChainStream_Destroy(This->blockChainCache[i]);
2373       This->blockChainCache[i] = NULL;
2374       return;
2375     }
2376   }
2377 }
2378
2379 static HRESULT StorageImpl_StreamReadAt(StorageBaseImpl *base, DirRef index,
2380   ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
2381 {
2382   StorageImpl *This = (StorageImpl*)base;
2383   DirEntry data;
2384   HRESULT hr;
2385   ULONG bytesToRead;
2386
2387   hr = StorageImpl_ReadDirEntry(This, index, &data);
2388   if (FAILED(hr)) return hr;
2389
2390   if (data.size.QuadPart == 0)
2391   {
2392     *bytesRead = 0;
2393     return S_OK;
2394   }
2395
2396   if (offset.QuadPart + size > data.size.QuadPart)
2397   {
2398     bytesToRead = data.size.QuadPart - offset.QuadPart;
2399   }
2400   else
2401   {
2402     bytesToRead = size;
2403   }
2404
2405   if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
2406   {
2407     SmallBlockChainStream *stream;
2408
2409     stream = SmallBlockChainStream_Construct(This, NULL, index);
2410     if (!stream) return E_OUTOFMEMORY;
2411
2412     hr = SmallBlockChainStream_ReadAt(stream, offset, bytesToRead, buffer, bytesRead);
2413
2414     SmallBlockChainStream_Destroy(stream);
2415
2416     return hr;
2417   }
2418   else
2419   {
2420     BlockChainStream *stream = NULL;
2421
2422     stream = *StorageImpl_GetCachedBlockChainStream(This, index);
2423     if (!stream) return E_OUTOFMEMORY;
2424
2425     hr = BlockChainStream_ReadAt(stream, offset, bytesToRead, buffer, bytesRead);
2426
2427     return hr;
2428   }
2429 }
2430
2431 static HRESULT StorageImpl_StreamSetSize(StorageBaseImpl *base, DirRef index,
2432   ULARGE_INTEGER newsize)
2433 {
2434   StorageImpl *This = (StorageImpl*)base;
2435   DirEntry data;
2436   HRESULT hr;
2437   SmallBlockChainStream *smallblock=NULL;
2438   BlockChainStream **pbigblock=NULL, *bigblock=NULL;
2439
2440   hr = StorageImpl_ReadDirEntry(This, index, &data);
2441   if (FAILED(hr)) return hr;
2442
2443   /* In simple mode keep the stream size above the small block limit */
2444   if (This->base.openFlags & STGM_SIMPLE)
2445     newsize.QuadPart = max(newsize.QuadPart, LIMIT_TO_USE_SMALL_BLOCK);
2446
2447   if (data.size.QuadPart == newsize.QuadPart)
2448     return S_OK;
2449
2450   /* Create a block chain object of the appropriate type */
2451   if (data.size.QuadPart == 0)
2452   {
2453     if (newsize.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
2454     {
2455       smallblock = SmallBlockChainStream_Construct(This, NULL, index);
2456       if (!smallblock) return E_OUTOFMEMORY;
2457     }
2458     else
2459     {
2460       pbigblock = StorageImpl_GetCachedBlockChainStream(This, index);
2461       bigblock = *pbigblock;
2462       if (!bigblock) return E_OUTOFMEMORY;
2463     }
2464   }
2465   else if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
2466   {
2467     smallblock = SmallBlockChainStream_Construct(This, NULL, index);
2468     if (!smallblock) return E_OUTOFMEMORY;
2469   }
2470   else
2471   {
2472     pbigblock = StorageImpl_GetCachedBlockChainStream(This, index);
2473     bigblock = *pbigblock;
2474     if (!bigblock) return E_OUTOFMEMORY;
2475   }
2476
2477   /* Change the block chain type if necessary. */
2478   if (smallblock && newsize.QuadPart >= LIMIT_TO_USE_SMALL_BLOCK)
2479   {
2480     bigblock = Storage32Impl_SmallBlocksToBigBlocks(This, &smallblock);
2481     if (!bigblock)
2482     {
2483       SmallBlockChainStream_Destroy(smallblock);
2484       return E_FAIL;
2485     }
2486
2487     pbigblock = StorageImpl_GetFreeBlockChainCacheEntry(This);
2488     *pbigblock = bigblock;
2489   }
2490   else if (bigblock && newsize.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
2491   {
2492     smallblock = Storage32Impl_BigBlocksToSmallBlocks(This, pbigblock);
2493     if (!smallblock)
2494       return E_FAIL;
2495   }
2496
2497   /* Set the size of the block chain. */
2498   if (smallblock)
2499   {
2500     SmallBlockChainStream_SetSize(smallblock, newsize);
2501     SmallBlockChainStream_Destroy(smallblock);
2502   }
2503   else
2504   {
2505     BlockChainStream_SetSize(bigblock, newsize);
2506   }
2507
2508   /* Set the size in the directory entry. */
2509   hr = StorageImpl_ReadDirEntry(This, index, &data);
2510   if (SUCCEEDED(hr))
2511   {
2512     data.size = newsize;
2513
2514     hr = StorageImpl_WriteDirEntry(This, index, &data);
2515   }
2516   return hr;
2517 }
2518
2519 static HRESULT StorageImpl_StreamWriteAt(StorageBaseImpl *base, DirRef index,
2520   ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
2521 {
2522   StorageImpl *This = (StorageImpl*)base;
2523   DirEntry data;
2524   HRESULT hr;
2525   ULARGE_INTEGER newSize;
2526
2527   hr = StorageImpl_ReadDirEntry(This, index, &data);
2528   if (FAILED(hr)) return hr;
2529
2530   /* Grow the stream if necessary */
2531   newSize.QuadPart = 0;
2532   newSize.QuadPart = offset.QuadPart + size;
2533
2534   if (newSize.QuadPart > data.size.QuadPart)
2535   {
2536     hr = StorageImpl_StreamSetSize(base, index, newSize);
2537     if (FAILED(hr))
2538       return hr;
2539
2540     hr = StorageImpl_ReadDirEntry(This, index, &data);
2541     if (FAILED(hr)) return hr;
2542   }
2543
2544   if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
2545   {
2546     SmallBlockChainStream *stream;
2547
2548     stream = SmallBlockChainStream_Construct(This, NULL, index);
2549     if (!stream) return E_OUTOFMEMORY;
2550
2551     hr = SmallBlockChainStream_WriteAt(stream, offset, size, buffer, bytesWritten);
2552
2553     SmallBlockChainStream_Destroy(stream);
2554
2555     return hr;
2556   }
2557   else
2558   {
2559     BlockChainStream *stream;
2560
2561     stream = *StorageImpl_GetCachedBlockChainStream(This, index);
2562     if (!stream) return E_OUTOFMEMORY;
2563
2564     hr = BlockChainStream_WriteAt(stream, offset, size, buffer, bytesWritten);
2565
2566     return hr;
2567   }
2568 }
2569
2570 static HRESULT StorageImpl_StreamLink(StorageBaseImpl *base, DirRef dst,
2571   DirRef src)
2572 {
2573   StorageImpl *This = (StorageImpl*)base;
2574   DirEntry dst_data, src_data;
2575   HRESULT hr;
2576
2577   hr = StorageImpl_ReadDirEntry(This, dst, &dst_data);
2578
2579   if (SUCCEEDED(hr))
2580     hr = StorageImpl_ReadDirEntry(This, src, &src_data);
2581
2582   if (SUCCEEDED(hr))
2583   {
2584     StorageImpl_DeleteCachedBlockChainStream(This, src);
2585     dst_data.startingBlock = src_data.startingBlock;
2586     dst_data.size = src_data.size;
2587
2588     hr = StorageImpl_WriteDirEntry(This, dst, &dst_data);
2589   }
2590
2591   return hr;
2592 }
2593
2594 static HRESULT StorageImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
2595 {
2596   StorageImpl *This = (StorageImpl*) iface;
2597   STATSTG statstg;
2598   HRESULT hr;
2599
2600   hr = ILockBytes_Stat(This->lockBytes, &statstg, 0);
2601
2602   *result = statstg.pwcsName;
2603
2604   return hr;
2605 }
2606
2607 /*
2608  * Virtual function table for the IStorage32Impl class.
2609  */
2610 static const IStorageVtbl Storage32Impl_Vtbl =
2611 {
2612     StorageBaseImpl_QueryInterface,
2613     StorageBaseImpl_AddRef,
2614     StorageBaseImpl_Release,
2615     StorageBaseImpl_CreateStream,
2616     StorageBaseImpl_OpenStream,
2617     StorageBaseImpl_CreateStorage,
2618     StorageBaseImpl_OpenStorage,
2619     StorageBaseImpl_CopyTo,
2620     StorageBaseImpl_MoveElementTo,
2621     StorageImpl_Commit,
2622     StorageImpl_Revert,
2623     StorageBaseImpl_EnumElements,
2624     StorageBaseImpl_DestroyElement,
2625     StorageBaseImpl_RenameElement,
2626     StorageBaseImpl_SetElementTimes,
2627     StorageBaseImpl_SetClass,
2628     StorageBaseImpl_SetStateBits,
2629     StorageBaseImpl_Stat
2630 };
2631
2632 static const StorageBaseImplVtbl StorageImpl_BaseVtbl =
2633 {
2634   StorageImpl_Destroy,
2635   StorageImpl_Invalidate,
2636   StorageImpl_Flush,
2637   StorageImpl_GetFilename,
2638   StorageImpl_CreateDirEntry,
2639   StorageImpl_BaseWriteDirEntry,
2640   StorageImpl_BaseReadDirEntry,
2641   StorageImpl_DestroyDirEntry,
2642   StorageImpl_StreamReadAt,
2643   StorageImpl_StreamWriteAt,
2644   StorageImpl_StreamSetSize,
2645   StorageImpl_StreamLink
2646 };
2647
2648 static HRESULT StorageImpl_Construct(
2649   HANDLE       hFile,
2650   LPCOLESTR    pwcsName,
2651   ILockBytes*  pLkbyt,
2652   DWORD        openFlags,
2653   BOOL         fileBased,
2654   BOOL         create,
2655   ULONG        sector_size,
2656   StorageImpl** result)
2657 {
2658   StorageImpl* This;
2659   HRESULT     hr = S_OK;
2660   DirEntry currentEntry;
2661   DirRef      currentEntryRef;
2662
2663   if ( FAILED( validateSTGM(openFlags) ))
2664     return STG_E_INVALIDFLAG;
2665
2666   This = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
2667   if (!This)
2668     return E_OUTOFMEMORY;
2669
2670   memset(This, 0, sizeof(StorageImpl));
2671
2672   list_init(&This->base.strmHead);
2673
2674   list_init(&This->base.storageHead);
2675
2676   This->base.lpVtbl = &Storage32Impl_Vtbl;
2677   This->base.pssVtbl = &IPropertySetStorage_Vtbl;
2678   This->base.baseVtbl = &StorageImpl_BaseVtbl;
2679   This->base.openFlags = (openFlags & ~STGM_CREATE);
2680   This->base.ref = 1;
2681   This->base.create = create;
2682
2683   This->base.reverted = 0;
2684
2685   /*
2686    * Initialize the big block cache.
2687    */
2688   This->bigBlockSize   = sector_size;
2689   This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
2690   if (hFile)
2691     hr = FileLockBytesImpl_Construct(hFile, openFlags, pwcsName, &This->lockBytes);
2692   else
2693   {
2694     This->lockBytes = pLkbyt;
2695     ILockBytes_AddRef(pLkbyt);
2696   }
2697
2698   if (FAILED(hr))
2699     goto end;
2700
2701   if (create)
2702   {
2703     ULARGE_INTEGER size;
2704     BYTE bigBlockBuffer[MAX_BIG_BLOCK_SIZE];
2705
2706     /*
2707      * Initialize all header variables:
2708      * - The big block depot consists of one block and it is at block 0
2709      * - The directory table starts at block 1
2710      * - There is no small block depot
2711      */
2712     memset( This->bigBlockDepotStart,
2713             BLOCK_UNUSED,
2714             sizeof(This->bigBlockDepotStart));
2715
2716     This->bigBlockDepotCount    = 1;
2717     This->bigBlockDepotStart[0] = 0;
2718     This->rootStartBlock        = 1;
2719     This->smallBlockLimit       = LIMIT_TO_USE_SMALL_BLOCK;
2720     This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
2721     if (sector_size == 4096)
2722       This->bigBlockSizeBits      = MAX_BIG_BLOCK_SIZE_BITS;
2723     else
2724       This->bigBlockSizeBits      = MIN_BIG_BLOCK_SIZE_BITS;
2725     This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
2726     This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
2727     This->extBigBlockDepotCount = 0;
2728
2729     StorageImpl_SaveFileHeader(This);
2730
2731     /*
2732      * Add one block for the big block depot and one block for the directory table
2733      */
2734     size.u.HighPart = 0;
2735     size.u.LowPart  = This->bigBlockSize * 3;
2736     ILockBytes_SetSize(This->lockBytes, size);
2737
2738     /*
2739      * Initialize the big block depot
2740      */
2741     memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2742     StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
2743     StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
2744     StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
2745   }
2746   else
2747   {
2748     /*
2749      * Load the header for the file.
2750      */
2751     hr = StorageImpl_LoadFileHeader(This);
2752
2753     if (FAILED(hr))
2754     {
2755       goto end;
2756     }
2757   }
2758
2759   /*
2760    * There is no block depot cached yet.
2761    */
2762   This->indexBlockDepotCached = 0xFFFFFFFF;
2763
2764   /*
2765    * Start searching for free blocks with block 0.
2766    */
2767   This->prevFreeBlock = 0;
2768
2769   This->firstFreeSmallBlock = 0;
2770
2771   /*
2772    * Create the block chain abstractions.
2773    */
2774   if(!(This->rootBlockChain =
2775        BlockChainStream_Construct(This, &This->rootStartBlock, DIRENTRY_NULL)))
2776   {
2777     hr = STG_E_READFAULT;
2778     goto end;
2779   }
2780
2781   if(!(This->smallBlockDepotChain =
2782        BlockChainStream_Construct(This, &This->smallBlockDepotStart,
2783                                   DIRENTRY_NULL)))
2784   {
2785     hr = STG_E_READFAULT;
2786     goto end;
2787   }
2788
2789   /*
2790    * Write the root storage entry (memory only)
2791    */
2792   if (create)
2793   {
2794     DirEntry rootEntry;
2795     /*
2796      * Initialize the directory table
2797      */
2798     memset(&rootEntry, 0, sizeof(rootEntry));
2799     MultiByteToWideChar( CP_ACP, 0, rootEntryName, -1, rootEntry.name,
2800                          sizeof(rootEntry.name)/sizeof(WCHAR) );
2801     rootEntry.sizeOfNameString = (strlenW(rootEntry.name)+1) * sizeof(WCHAR);
2802     rootEntry.stgType          = STGTY_ROOT;
2803     rootEntry.leftChild = DIRENTRY_NULL;
2804     rootEntry.rightChild     = DIRENTRY_NULL;
2805     rootEntry.dirRootEntry     = DIRENTRY_NULL;
2806     rootEntry.startingBlock    = BLOCK_END_OF_CHAIN;
2807     rootEntry.size.u.HighPart    = 0;
2808     rootEntry.size.u.LowPart     = 0;
2809
2810     StorageImpl_WriteDirEntry(This, 0, &rootEntry);
2811   }
2812
2813   /*
2814    * Find the ID of the root storage.
2815    */
2816   currentEntryRef = 0;
2817
2818   do
2819   {
2820     hr = StorageImpl_ReadDirEntry(
2821                       This,
2822                       currentEntryRef,
2823                       &currentEntry);
2824
2825     if (SUCCEEDED(hr))
2826     {
2827       if ( (currentEntry.sizeOfNameString != 0 ) &&
2828            (currentEntry.stgType          == STGTY_ROOT) )
2829       {
2830         This->base.storageDirEntry = currentEntryRef;
2831       }
2832     }
2833
2834     currentEntryRef++;
2835
2836   } while (SUCCEEDED(hr) && (This->base.storageDirEntry == DIRENTRY_NULL) );
2837
2838   if (FAILED(hr))
2839   {
2840     hr = STG_E_READFAULT;
2841     goto end;
2842   }
2843
2844   /*
2845    * Create the block chain abstraction for the small block root chain.
2846    */
2847   if(!(This->smallBlockRootChain =
2848        BlockChainStream_Construct(This, NULL, This->base.storageDirEntry)))
2849   {
2850     hr = STG_E_READFAULT;
2851   }
2852
2853 end:
2854   if (FAILED(hr))
2855   {
2856     IStorage_Release((IStorage*)This);
2857     *result = NULL;
2858   }
2859   else
2860   {
2861     StorageImpl_Flush((StorageBaseImpl*)This);
2862     *result = This;
2863   }
2864
2865   return hr;
2866 }
2867
2868 static void StorageImpl_Invalidate(StorageBaseImpl* iface)
2869 {
2870   StorageImpl *This = (StorageImpl*) iface;
2871
2872   StorageBaseImpl_DeleteAll(&This->base);
2873
2874   This->base.reverted = 1;
2875 }
2876
2877 static void StorageImpl_Destroy(StorageBaseImpl* iface)
2878 {
2879   StorageImpl *This = (StorageImpl*) iface;
2880   int i;
2881   TRACE("(%p)\n", This);
2882
2883   StorageImpl_Flush(iface);
2884
2885   StorageImpl_Invalidate(iface);
2886
2887   BlockChainStream_Destroy(This->smallBlockRootChain);
2888   BlockChainStream_Destroy(This->rootBlockChain);
2889   BlockChainStream_Destroy(This->smallBlockDepotChain);
2890
2891   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
2892     BlockChainStream_Destroy(This->blockChainCache[i]);
2893
2894   if (This->lockBytes)
2895     ILockBytes_Release(This->lockBytes);
2896   HeapFree(GetProcessHeap(), 0, This);
2897 }
2898
2899 static HRESULT StorageImpl_Flush(StorageBaseImpl* iface)
2900 {
2901   StorageImpl *This = (StorageImpl*) iface;
2902   int i;
2903   HRESULT hr;
2904   TRACE("(%p)\n", This);
2905
2906   hr = BlockChainStream_Flush(This->smallBlockRootChain);
2907
2908   if (SUCCEEDED(hr))
2909     hr = BlockChainStream_Flush(This->rootBlockChain);
2910
2911   if (SUCCEEDED(hr))
2912     hr = BlockChainStream_Flush(This->smallBlockDepotChain);
2913
2914   for (i=0; SUCCEEDED(hr) && i<BLOCKCHAIN_CACHE_SIZE; i++)
2915     if (This->blockChainCache[i])
2916       hr = BlockChainStream_Flush(This->blockChainCache[i]);
2917
2918   if (SUCCEEDED(hr))
2919     hr = ILockBytes_Flush(This->lockBytes);
2920
2921   return hr;
2922 }
2923
2924 /******************************************************************************
2925  *      Storage32Impl_GetNextFreeBigBlock
2926  *
2927  * Returns the index of the next free big block.
2928  * If the big block depot is filled, this method will enlarge it.
2929  *
2930  */
2931 static ULONG StorageImpl_GetNextFreeBigBlock(
2932   StorageImpl* This)
2933 {
2934   ULONG depotBlockIndexPos;
2935   BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
2936   BOOL success;
2937   ULONG depotBlockOffset;
2938   ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
2939   ULONG nextBlockIndex    = BLOCK_SPECIAL;
2940   int   depotIndex        = 0;
2941   ULONG freeBlock         = BLOCK_UNUSED;
2942   ULARGE_INTEGER neededSize;
2943   STATSTG statstg;
2944
2945   depotIndex = This->prevFreeBlock / blocksPerDepot;
2946   depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2947
2948   /*
2949    * Scan the entire big block depot until we find a block marked free
2950    */
2951   while (nextBlockIndex != BLOCK_UNUSED)
2952   {
2953     if (depotIndex < COUNT_BBDEPOTINHEADER)
2954     {
2955       depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2956
2957       /*
2958        * Grow the primary depot.
2959        */
2960       if (depotBlockIndexPos == BLOCK_UNUSED)
2961       {
2962         depotBlockIndexPos = depotIndex*blocksPerDepot;
2963
2964         /*
2965          * Add a block depot.
2966          */
2967         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2968         This->bigBlockDepotCount++;
2969         This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2970
2971         /*
2972          * Flag it as a block depot.
2973          */
2974         StorageImpl_SetNextBlockInChain(This,
2975                                           depotBlockIndexPos,
2976                                           BLOCK_SPECIAL);
2977
2978         /* Save new header information.
2979          */
2980         StorageImpl_SaveFileHeader(This);
2981       }
2982     }
2983     else
2984     {
2985       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2986
2987       if (depotBlockIndexPos == BLOCK_UNUSED)
2988       {
2989         /*
2990          * Grow the extended depot.
2991          */
2992         ULONG extIndex       = BLOCK_UNUSED;
2993         ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
2994         ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2995
2996         if (extBlockOffset == 0)
2997         {
2998           /* We need an extended block.
2999            */
3000           extIndex = Storage32Impl_AddExtBlockDepot(This);
3001           This->extBigBlockDepotCount++;
3002           depotBlockIndexPos = extIndex + 1;
3003         }
3004         else
3005           depotBlockIndexPos = depotIndex * blocksPerDepot;
3006
3007         /*
3008          * Add a block depot and mark it in the extended block.
3009          */
3010         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
3011         This->bigBlockDepotCount++;
3012         Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
3013
3014         /* Flag the block depot.
3015          */
3016         StorageImpl_SetNextBlockInChain(This,
3017                                           depotBlockIndexPos,
3018                                           BLOCK_SPECIAL);
3019
3020         /* If necessary, flag the extended depot block.
3021          */
3022         if (extIndex != BLOCK_UNUSED)
3023           StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
3024
3025         /* Save header information.
3026          */
3027         StorageImpl_SaveFileHeader(This);
3028       }
3029     }
3030
3031     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
3032
3033     if (success)
3034     {
3035       while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
3036               ( nextBlockIndex != BLOCK_UNUSED))
3037       {
3038         StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
3039
3040         if (nextBlockIndex == BLOCK_UNUSED)
3041         {
3042           freeBlock = (depotIndex * blocksPerDepot) +
3043                       (depotBlockOffset/sizeof(ULONG));
3044         }
3045
3046         depotBlockOffset += sizeof(ULONG);
3047       }
3048     }
3049
3050     depotIndex++;
3051     depotBlockOffset = 0;
3052   }
3053
3054   /*
3055    * make sure that the block physically exists before using it
3056    */
3057   neededSize.QuadPart = StorageImpl_GetBigBlockOffset(This, freeBlock)+This->bigBlockSize;
3058
3059   ILockBytes_Stat(This->lockBytes, &statstg, STATFLAG_NONAME);
3060
3061   if (neededSize.QuadPart > statstg.cbSize.QuadPart)
3062     ILockBytes_SetSize(This->lockBytes, neededSize);
3063
3064   This->prevFreeBlock = freeBlock;
3065
3066   return freeBlock;
3067 }
3068
3069 /******************************************************************************
3070  *      Storage32Impl_AddBlockDepot
3071  *
3072  * This will create a depot block, essentially it is a block initialized
3073  * to BLOCK_UNUSEDs.
3074  */
3075 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
3076 {
3077   BYTE blockBuffer[MAX_BIG_BLOCK_SIZE];
3078
3079   /*
3080    * Initialize blocks as free
3081    */
3082   memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
3083   StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
3084 }
3085
3086 /******************************************************************************
3087  *      Storage32Impl_GetExtDepotBlock
3088  *
3089  * Returns the index of the block that corresponds to the specified depot
3090  * index. This method is only for depot indexes equal or greater than
3091  * COUNT_BBDEPOTINHEADER.
3092  */
3093 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
3094 {
3095   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
3096   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
3097   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
3098   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
3099   ULONG blockIndex             = BLOCK_UNUSED;
3100   ULONG extBlockIndex          = This->extBigBlockDepotStart;
3101
3102   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
3103
3104   if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
3105     return BLOCK_UNUSED;
3106
3107   while (extBlockCount > 0)
3108   {
3109     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
3110     extBlockCount--;
3111   }
3112
3113   if (extBlockIndex != BLOCK_UNUSED)
3114     StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex,
3115                         extBlockOffset * sizeof(ULONG), &blockIndex);
3116
3117   return blockIndex;
3118 }
3119
3120 /******************************************************************************
3121  *      Storage32Impl_SetExtDepotBlock
3122  *
3123  * Associates the specified block index to the specified depot index.
3124  * This method is only for depot indexes equal or greater than
3125  * COUNT_BBDEPOTINHEADER.
3126  */
3127 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
3128 {
3129   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
3130   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
3131   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
3132   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
3133   ULONG extBlockIndex          = This->extBigBlockDepotStart;
3134
3135   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
3136
3137   while (extBlockCount > 0)
3138   {
3139     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
3140     extBlockCount--;
3141   }
3142
3143   if (extBlockIndex != BLOCK_UNUSED)
3144   {
3145     StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
3146                         extBlockOffset * sizeof(ULONG),
3147                         blockIndex);
3148   }
3149 }
3150
3151 /******************************************************************************
3152  *      Storage32Impl_AddExtBlockDepot
3153  *
3154  * Creates an extended depot block.
3155  */
3156 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
3157 {
3158   ULONG numExtBlocks           = This->extBigBlockDepotCount;
3159   ULONG nextExtBlock           = This->extBigBlockDepotStart;
3160   BYTE  depotBuffer[MAX_BIG_BLOCK_SIZE];
3161   ULONG index                  = BLOCK_UNUSED;
3162   ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
3163   ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
3164   ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
3165
3166   index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
3167           blocksPerDepotBlock;
3168
3169   if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
3170   {
3171     /*
3172      * The first extended block.
3173      */
3174     This->extBigBlockDepotStart = index;
3175   }
3176   else
3177   {
3178     unsigned int i;
3179     /*
3180      * Follow the chain to the last one.
3181      */
3182     for (i = 0; i < (numExtBlocks - 1); i++)
3183     {
3184       nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
3185     }
3186
3187     /*
3188      * Add the new extended block to the chain.
3189      */
3190     StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
3191                                      index);
3192   }
3193
3194   /*
3195    * Initialize this block.
3196    */
3197   memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
3198   StorageImpl_WriteBigBlock(This, index, depotBuffer);
3199
3200   return index;
3201 }
3202
3203 /******************************************************************************
3204  *      Storage32Impl_FreeBigBlock
3205  *
3206  * This method will flag the specified block as free in the big block depot.
3207  */
3208 static void StorageImpl_FreeBigBlock(
3209   StorageImpl* This,
3210   ULONG          blockIndex)
3211 {
3212   StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
3213
3214   if (blockIndex < This->prevFreeBlock)
3215     This->prevFreeBlock = blockIndex;
3216 }
3217
3218 /************************************************************************
3219  * Storage32Impl_GetNextBlockInChain
3220  *
3221  * This method will retrieve the block index of the next big block in
3222  * in the chain.
3223  *
3224  * Params:  This       - Pointer to the Storage object.
3225  *          blockIndex - Index of the block to retrieve the chain
3226  *                       for.
3227  *          nextBlockIndex - receives the return value.
3228  *
3229  * Returns: This method returns the index of the next block in the chain.
3230  *          It will return the constants:
3231  *              BLOCK_SPECIAL - If the block given was not part of a
3232  *                              chain.
3233  *              BLOCK_END_OF_CHAIN - If the block given was the last in
3234  *                                   a chain.
3235  *              BLOCK_UNUSED - If the block given was not past of a chain
3236  *                             and is available.
3237  *              BLOCK_EXTBBDEPOT - This block is part of the extended
3238  *                                 big block depot.
3239  *
3240  * See Windows documentation for more details on IStorage methods.
3241  */
3242 static HRESULT StorageImpl_GetNextBlockInChain(
3243   StorageImpl* This,
3244   ULONG        blockIndex,
3245   ULONG*       nextBlockIndex)
3246 {
3247   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
3248   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
3249   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
3250   BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
3251   BOOL success;
3252   ULONG depotBlockIndexPos;
3253   int index, num_blocks;
3254
3255   *nextBlockIndex   = BLOCK_SPECIAL;
3256
3257   if(depotBlockCount >= This->bigBlockDepotCount)
3258   {
3259     WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount,
3260          This->bigBlockDepotCount);
3261     return STG_E_READFAULT;
3262   }
3263
3264   /*
3265    * Cache the currently accessed depot block.
3266    */
3267   if (depotBlockCount != This->indexBlockDepotCached)
3268   {
3269     This->indexBlockDepotCached = depotBlockCount;
3270
3271     if (depotBlockCount < COUNT_BBDEPOTINHEADER)
3272     {
3273       depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
3274     }
3275     else
3276     {
3277       /*
3278        * We have to look in the extended depot.
3279        */
3280       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
3281     }
3282
3283     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
3284
3285     if (!success)
3286       return STG_E_READFAULT;
3287
3288     num_blocks = This->bigBlockSize / 4;
3289
3290     for (index = 0; index < num_blocks; index++)
3291     {
3292       StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
3293       This->blockDepotCached[index] = *nextBlockIndex;
3294     }
3295   }
3296
3297   *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
3298
3299   return S_OK;
3300 }
3301
3302 /******************************************************************************
3303  *      Storage32Impl_GetNextExtendedBlock
3304  *
3305  * Given an extended block this method will return the next extended block.
3306  *
3307  * NOTES:
3308  * The last ULONG of an extended block is the block index of the next
3309  * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
3310  * depot.
3311  *
3312  * Return values:
3313  *    - The index of the next extended block
3314  *    - BLOCK_UNUSED: there is no next extended block.
3315  *    - Any other return values denotes failure.
3316  */
3317 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
3318 {
3319   ULONG nextBlockIndex   = BLOCK_SPECIAL;
3320   ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
3321
3322   StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
3323                         &nextBlockIndex);
3324
3325   return nextBlockIndex;
3326 }
3327
3328 /******************************************************************************
3329  *      Storage32Impl_SetNextBlockInChain
3330  *
3331  * This method will write the index of the specified block's next block
3332  * in the big block depot.
3333  *
3334  * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
3335  *              do the following
3336  *
3337  * Storage32Impl_SetNextBlockInChain(This, 3, 1);
3338  * Storage32Impl_SetNextBlockInChain(This, 1, 7);
3339  * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
3340  *
3341  */
3342 static void StorageImpl_SetNextBlockInChain(
3343           StorageImpl* This,
3344           ULONG          blockIndex,
3345           ULONG          nextBlock)
3346 {
3347   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
3348   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
3349   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
3350   ULONG depotBlockIndexPos;
3351
3352   assert(depotBlockCount < This->bigBlockDepotCount);
3353   assert(blockIndex != nextBlock);
3354
3355   if (depotBlockCount < COUNT_BBDEPOTINHEADER)
3356   {
3357     depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
3358   }
3359   else
3360   {
3361     /*
3362      * We have to look in the extended depot.
3363      */
3364     depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
3365   }
3366
3367   StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
3368                         nextBlock);
3369   /*
3370    * Update the cached block depot, if necessary.
3371    */
3372   if (depotBlockCount == This->indexBlockDepotCached)
3373   {
3374     This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
3375   }
3376 }
3377
3378 /******************************************************************************
3379  *      Storage32Impl_LoadFileHeader
3380  *
3381  * This method will read in the file header
3382  */
3383 static HRESULT StorageImpl_LoadFileHeader(
3384           StorageImpl* This)
3385 {
3386   HRESULT hr;
3387   BYTE    headerBigBlock[HEADER_SIZE];
3388   int     index;
3389   ULARGE_INTEGER offset;
3390   DWORD bytes_read;
3391
3392   TRACE("\n");
3393   /*
3394    * Get a pointer to the big block of data containing the header.
3395    */
3396   offset.u.HighPart = 0;
3397   offset.u.LowPart = 0;
3398   hr = StorageImpl_ReadAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_read);
3399   if (SUCCEEDED(hr) && bytes_read != HEADER_SIZE)
3400     hr = STG_E_FILENOTFOUND;
3401
3402   /*
3403    * Extract the information from the header.
3404    */
3405   if (SUCCEEDED(hr))
3406   {
3407     /*
3408      * Check for the "magic number" signature and return an error if it is not
3409      * found.
3410      */
3411     if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
3412     {
3413       return STG_E_OLDFORMAT;
3414     }
3415
3416     if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
3417     {
3418       return STG_E_INVALIDHEADER;
3419     }
3420
3421     StorageUtl_ReadWord(
3422       headerBigBlock,
3423       OFFSET_BIGBLOCKSIZEBITS,
3424       &This->bigBlockSizeBits);
3425
3426     StorageUtl_ReadWord(
3427       headerBigBlock,
3428       OFFSET_SMALLBLOCKSIZEBITS,
3429       &This->smallBlockSizeBits);
3430
3431     StorageUtl_ReadDWord(
3432       headerBigBlock,
3433       OFFSET_BBDEPOTCOUNT,
3434       &This->bigBlockDepotCount);
3435
3436     StorageUtl_ReadDWord(
3437       headerBigBlock,
3438       OFFSET_ROOTSTARTBLOCK,
3439       &This->rootStartBlock);
3440
3441     StorageUtl_ReadDWord(
3442       headerBigBlock,
3443       OFFSET_SMALLBLOCKLIMIT,
3444       &This->smallBlockLimit);
3445
3446     StorageUtl_ReadDWord(
3447       headerBigBlock,
3448       OFFSET_SBDEPOTSTART,
3449       &This->smallBlockDepotStart);
3450
3451     StorageUtl_ReadDWord(
3452       headerBigBlock,
3453       OFFSET_EXTBBDEPOTSTART,
3454       &This->extBigBlockDepotStart);
3455
3456     StorageUtl_ReadDWord(
3457       headerBigBlock,
3458       OFFSET_EXTBBDEPOTCOUNT,
3459       &This->extBigBlockDepotCount);
3460
3461     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3462     {
3463       StorageUtl_ReadDWord(
3464         headerBigBlock,
3465         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3466         &(This->bigBlockDepotStart[index]));
3467     }
3468
3469     /*
3470      * Make the bitwise arithmetic to get the size of the blocks in bytes.
3471      */
3472     This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
3473     This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
3474
3475     /*
3476      * Right now, the code is making some assumptions about the size of the
3477      * blocks, just make sure they are what we're expecting.
3478      */
3479     if ((This->bigBlockSize != MIN_BIG_BLOCK_SIZE && This->bigBlockSize != MAX_BIG_BLOCK_SIZE) ||
3480         This->smallBlockSize != DEF_SMALL_BLOCK_SIZE ||
3481         This->smallBlockLimit != LIMIT_TO_USE_SMALL_BLOCK)
3482     {
3483         FIXME("Broken OLE storage file? bigblock=0x%x, smallblock=0x%x, sblimit=0x%x\n",
3484             This->bigBlockSize, This->smallBlockSize, This->smallBlockLimit);
3485         hr = STG_E_INVALIDHEADER;
3486     }
3487     else
3488         hr = S_OK;
3489   }
3490
3491   return hr;
3492 }
3493
3494 /******************************************************************************
3495  *      Storage32Impl_SaveFileHeader
3496  *
3497  * This method will save to the file the header
3498  */
3499 static void StorageImpl_SaveFileHeader(
3500           StorageImpl* This)
3501 {
3502   BYTE   headerBigBlock[HEADER_SIZE];
3503   int    index;
3504   HRESULT hr;
3505   ULARGE_INTEGER offset;
3506   DWORD bytes_read, bytes_written;
3507   DWORD major_version, dirsectorcount;
3508
3509   /*
3510    * Get a pointer to the big block of data containing the header.
3511    */
3512   offset.u.HighPart = 0;
3513   offset.u.LowPart = 0;
3514   hr = StorageImpl_ReadAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_read);
3515   if (SUCCEEDED(hr) && bytes_read != HEADER_SIZE)
3516     hr = STG_E_FILENOTFOUND;
3517
3518   if (This->bigBlockSizeBits == 0x9)
3519     major_version = 3;
3520   else if (This->bigBlockSizeBits == 0xc)
3521     major_version = 4;
3522   else
3523   {
3524     ERR("invalid big block shift 0x%x\n", This->bigBlockSizeBits);
3525     major_version = 4;
3526   }
3527
3528   /*
3529    * If the block read failed, the file is probably new.
3530    */
3531   if (FAILED(hr))
3532   {
3533     /*
3534      * Initialize for all unknown fields.
3535      */
3536     memset(headerBigBlock, 0, HEADER_SIZE);
3537
3538     /*
3539      * Initialize the magic number.
3540      */
3541     memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
3542   }
3543
3544   /*
3545    * Write the information to the header.
3546    */
3547   StorageUtl_WriteWord(
3548     headerBigBlock,
3549     OFFSET_MINORVERSION,
3550     0x3e);
3551
3552   StorageUtl_WriteWord(
3553     headerBigBlock,
3554     OFFSET_MAJORVERSION,
3555     major_version);
3556
3557   StorageUtl_WriteWord(
3558     headerBigBlock,
3559     OFFSET_BYTEORDERMARKER,
3560     (WORD)-2);
3561
3562   StorageUtl_WriteWord(
3563     headerBigBlock,
3564     OFFSET_BIGBLOCKSIZEBITS,
3565     This->bigBlockSizeBits);
3566
3567   StorageUtl_WriteWord(
3568     headerBigBlock,
3569     OFFSET_SMALLBLOCKSIZEBITS,
3570     This->smallBlockSizeBits);
3571
3572   if (major_version >= 4)
3573   {
3574     if (This->rootBlockChain)
3575       dirsectorcount = BlockChainStream_GetCount(This->rootBlockChain);
3576     else
3577       /* This file is being created, and it will start out with one block. */
3578       dirsectorcount = 1;
3579   }
3580   else
3581     /* This field must be 0 in versions older than 4 */
3582     dirsectorcount = 0;
3583
3584   StorageUtl_WriteDWord(
3585     headerBigBlock,
3586     OFFSET_DIRSECTORCOUNT,
3587     dirsectorcount);
3588
3589   StorageUtl_WriteDWord(
3590     headerBigBlock,
3591     OFFSET_BBDEPOTCOUNT,
3592     This->bigBlockDepotCount);
3593
3594   StorageUtl_WriteDWord(
3595     headerBigBlock,
3596     OFFSET_ROOTSTARTBLOCK,
3597     This->rootStartBlock);
3598
3599   StorageUtl_WriteDWord(
3600     headerBigBlock,
3601     OFFSET_SMALLBLOCKLIMIT,
3602     This->smallBlockLimit);
3603
3604   StorageUtl_WriteDWord(
3605     headerBigBlock,
3606     OFFSET_SBDEPOTSTART,
3607     This->smallBlockDepotStart);
3608
3609   StorageUtl_WriteDWord(
3610     headerBigBlock,
3611     OFFSET_SBDEPOTCOUNT,
3612     This->smallBlockDepotChain ?
3613      BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
3614
3615   StorageUtl_WriteDWord(
3616     headerBigBlock,
3617     OFFSET_EXTBBDEPOTSTART,
3618     This->extBigBlockDepotStart);
3619
3620   StorageUtl_WriteDWord(
3621     headerBigBlock,
3622     OFFSET_EXTBBDEPOTCOUNT,
3623     This->extBigBlockDepotCount);
3624
3625   for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3626   {
3627     StorageUtl_WriteDWord(
3628       headerBigBlock,
3629       OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3630       (This->bigBlockDepotStart[index]));
3631   }
3632
3633   /*
3634    * Write the big block back to the file.
3635    */
3636   StorageImpl_WriteAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_written);
3637 }
3638
3639 /******************************************************************************
3640  *      StorageImpl_ReadRawDirEntry
3641  *
3642  * This method will read the raw data from a directory entry in the file.
3643  *
3644  * buffer must be RAW_DIRENTRY_SIZE bytes long.
3645  */
3646 HRESULT StorageImpl_ReadRawDirEntry(StorageImpl *This, ULONG index, BYTE *buffer)
3647 {
3648   ULARGE_INTEGER offset;
3649   HRESULT hr;
3650   ULONG bytesRead;
3651
3652   offset.u.HighPart = 0;
3653   offset.u.LowPart  = index * RAW_DIRENTRY_SIZE;
3654
3655   hr = BlockChainStream_ReadAt(
3656                     This->rootBlockChain,
3657                     offset,
3658                     RAW_DIRENTRY_SIZE,
3659                     buffer,
3660                     &bytesRead);
3661
3662   if (bytesRead != RAW_DIRENTRY_SIZE)
3663     return STG_E_READFAULT;
3664
3665   return hr;
3666 }
3667
3668 /******************************************************************************
3669  *      StorageImpl_WriteRawDirEntry
3670  *
3671  * This method will write the raw data from a directory entry in the file.
3672  *
3673  * buffer must be RAW_DIRENTRY_SIZE bytes long.
3674  */
3675 HRESULT StorageImpl_WriteRawDirEntry(StorageImpl *This, ULONG index, const BYTE *buffer)
3676 {
3677   ULARGE_INTEGER offset;
3678   HRESULT hr;
3679   ULONG bytesRead;
3680
3681   offset.u.HighPart = 0;
3682   offset.u.LowPart  = index * RAW_DIRENTRY_SIZE;
3683
3684   hr = BlockChainStream_WriteAt(
3685                     This->rootBlockChain,
3686                     offset,
3687                     RAW_DIRENTRY_SIZE,
3688                     buffer,
3689                     &bytesRead);
3690
3691   return hr;
3692 }
3693
3694 /******************************************************************************
3695  *      UpdateRawDirEntry
3696  *
3697  * Update raw directory entry data from the fields in newData.
3698  *
3699  * buffer must be RAW_DIRENTRY_SIZE bytes long.
3700  */
3701 void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData)
3702 {
3703   memset(buffer, 0, RAW_DIRENTRY_SIZE);
3704
3705   memcpy(
3706     buffer + OFFSET_PS_NAME,
3707     newData->name,
3708     DIRENTRY_NAME_BUFFER_LEN );
3709
3710   memcpy(buffer + OFFSET_PS_STGTYPE, &newData->stgType, 1);
3711
3712   StorageUtl_WriteWord(
3713     buffer,
3714       OFFSET_PS_NAMELENGTH,
3715       newData->sizeOfNameString);
3716
3717   StorageUtl_WriteDWord(
3718     buffer,
3719       OFFSET_PS_LEFTCHILD,
3720       newData->leftChild);
3721
3722   StorageUtl_WriteDWord(
3723     buffer,
3724       OFFSET_PS_RIGHTCHILD,
3725       newData->rightChild);
3726
3727   StorageUtl_WriteDWord(
3728     buffer,
3729       OFFSET_PS_DIRROOT,
3730       newData->dirRootEntry);
3731
3732   StorageUtl_WriteGUID(
3733     buffer,
3734       OFFSET_PS_GUID,
3735       &newData->clsid);
3736
3737   StorageUtl_WriteDWord(
3738     buffer,
3739       OFFSET_PS_CTIMELOW,
3740       newData->ctime.dwLowDateTime);
3741
3742   StorageUtl_WriteDWord(
3743     buffer,
3744       OFFSET_PS_CTIMEHIGH,
3745       newData->ctime.dwHighDateTime);
3746
3747   StorageUtl_WriteDWord(
3748     buffer,
3749       OFFSET_PS_MTIMELOW,
3750       newData->mtime.dwLowDateTime);
3751
3752   StorageUtl_WriteDWord(
3753     buffer,
3754       OFFSET_PS_MTIMEHIGH,
3755       newData->ctime.dwHighDateTime);
3756
3757   StorageUtl_WriteDWord(
3758     buffer,
3759       OFFSET_PS_STARTBLOCK,
3760       newData->startingBlock);
3761
3762   StorageUtl_WriteDWord(
3763     buffer,
3764       OFFSET_PS_SIZE,
3765       newData->size.u.LowPart);
3766 }
3767
3768 /******************************************************************************
3769  *      Storage32Impl_ReadDirEntry
3770  *
3771  * This method will read the specified directory entry.
3772  */
3773 HRESULT StorageImpl_ReadDirEntry(
3774   StorageImpl* This,
3775   DirRef         index,
3776   DirEntry*      buffer)
3777 {
3778   BYTE           currentEntry[RAW_DIRENTRY_SIZE];
3779   HRESULT        readRes;
3780
3781   readRes = StorageImpl_ReadRawDirEntry(This, index, currentEntry);
3782
3783   if (SUCCEEDED(readRes))
3784   {
3785     memset(buffer->name, 0, sizeof(buffer->name));
3786     memcpy(
3787       buffer->name,
3788       (WCHAR *)currentEntry+OFFSET_PS_NAME,
3789       DIRENTRY_NAME_BUFFER_LEN );
3790     TRACE("storage name: %s\n", debugstr_w(buffer->name));
3791
3792     memcpy(&buffer->stgType, currentEntry + OFFSET_PS_STGTYPE, 1);
3793
3794     StorageUtl_ReadWord(
3795       currentEntry,
3796       OFFSET_PS_NAMELENGTH,
3797       &buffer->sizeOfNameString);
3798
3799     StorageUtl_ReadDWord(
3800       currentEntry,
3801       OFFSET_PS_LEFTCHILD,
3802       &buffer->leftChild);
3803
3804     StorageUtl_ReadDWord(
3805       currentEntry,
3806       OFFSET_PS_RIGHTCHILD,
3807       &buffer->rightChild);
3808
3809     StorageUtl_ReadDWord(
3810       currentEntry,
3811       OFFSET_PS_DIRROOT,
3812       &buffer->dirRootEntry);
3813
3814     StorageUtl_ReadGUID(
3815       currentEntry,
3816       OFFSET_PS_GUID,
3817       &buffer->clsid);
3818
3819     StorageUtl_ReadDWord(
3820       currentEntry,
3821       OFFSET_PS_CTIMELOW,
3822       &buffer->ctime.dwLowDateTime);
3823
3824     StorageUtl_ReadDWord(
3825       currentEntry,
3826       OFFSET_PS_CTIMEHIGH,
3827       &buffer->ctime.dwHighDateTime);
3828
3829     StorageUtl_ReadDWord(
3830       currentEntry,
3831       OFFSET_PS_MTIMELOW,
3832       &buffer->mtime.dwLowDateTime);
3833
3834     StorageUtl_ReadDWord(
3835       currentEntry,
3836       OFFSET_PS_MTIMEHIGH,
3837       &buffer->mtime.dwHighDateTime);
3838
3839     StorageUtl_ReadDWord(
3840       currentEntry,
3841       OFFSET_PS_STARTBLOCK,
3842       &buffer->startingBlock);
3843
3844     StorageUtl_ReadDWord(
3845       currentEntry,
3846       OFFSET_PS_SIZE,
3847       &buffer->size.u.LowPart);
3848
3849     buffer->size.u.HighPart = 0;
3850   }
3851
3852   return readRes;
3853 }
3854
3855 /*********************************************************************
3856  * Write the specified directory entry to the file
3857  */
3858 HRESULT StorageImpl_WriteDirEntry(
3859   StorageImpl*          This,
3860   DirRef                index,
3861   const DirEntry*       buffer)
3862 {
3863   BYTE           currentEntry[RAW_DIRENTRY_SIZE];
3864   HRESULT        writeRes;
3865
3866   UpdateRawDirEntry(currentEntry, buffer);
3867
3868   writeRes = StorageImpl_WriteRawDirEntry(This, index, currentEntry);
3869   return writeRes;
3870 }
3871
3872 static BOOL StorageImpl_ReadBigBlock(
3873   StorageImpl* This,
3874   ULONG          blockIndex,
3875   void*          buffer)
3876 {
3877   ULARGE_INTEGER ulOffset;
3878   DWORD  read=0;
3879
3880   ulOffset.u.HighPart = 0;
3881   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3882
3883   StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
3884
3885   if (read && read < This->bigBlockSize)
3886   {
3887     /* File ends during this block; fill the rest with 0's. */
3888     memset((LPBYTE)buffer+read, 0, This->bigBlockSize-read);
3889   }
3890
3891   return (read != 0);
3892 }
3893
3894 static BOOL StorageImpl_ReadDWordFromBigBlock(
3895   StorageImpl*  This,
3896   ULONG         blockIndex,
3897   ULONG         offset,
3898   DWORD*        value)
3899 {
3900   ULARGE_INTEGER ulOffset;
3901   DWORD  read;
3902   DWORD  tmp;
3903
3904   ulOffset.u.HighPart = 0;
3905   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3906   ulOffset.u.LowPart += offset;
3907
3908   StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
3909   *value = lendian32toh(tmp);
3910   return (read == sizeof(DWORD));
3911 }
3912
3913 static BOOL StorageImpl_WriteBigBlock(
3914   StorageImpl*  This,
3915   ULONG         blockIndex,
3916   const void*   buffer)
3917 {
3918   ULARGE_INTEGER ulOffset;
3919   DWORD  wrote;
3920
3921   ulOffset.u.HighPart = 0;
3922   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3923
3924   StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
3925   return (wrote == This->bigBlockSize);
3926 }
3927
3928 static BOOL StorageImpl_WriteDWordToBigBlock(
3929   StorageImpl* This,
3930   ULONG         blockIndex,
3931   ULONG         offset,
3932   DWORD         value)
3933 {
3934   ULARGE_INTEGER ulOffset;
3935   DWORD  wrote;
3936
3937   ulOffset.u.HighPart = 0;
3938   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3939   ulOffset.u.LowPart += offset;
3940
3941   value = htole32(value);
3942   StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
3943   return (wrote == sizeof(DWORD));
3944 }
3945
3946 /******************************************************************************
3947  *              Storage32Impl_SmallBlocksToBigBlocks
3948  *
3949  * This method will convert a small block chain to a big block chain.
3950  * The small block chain will be destroyed.
3951  */
3952 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3953                       StorageImpl* This,
3954                       SmallBlockChainStream** ppsbChain)
3955 {
3956   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3957   ULARGE_INTEGER size, offset;
3958   ULONG cbRead, cbWritten;
3959   ULARGE_INTEGER cbTotalRead;
3960   DirRef streamEntryRef;
3961   HRESULT resWrite = S_OK;
3962   HRESULT resRead;
3963   DirEntry streamEntry;
3964   BYTE *buffer;
3965   BlockChainStream *bbTempChain = NULL;
3966   BlockChainStream *bigBlockChain = NULL;
3967
3968   /*
3969    * Create a temporary big block chain that doesn't have
3970    * an associated directory entry. This temporary chain will be
3971    * used to copy data from small blocks to big blocks.
3972    */
3973   bbTempChain = BlockChainStream_Construct(This,
3974                                            &bbHeadOfChain,
3975                                            DIRENTRY_NULL);
3976   if(!bbTempChain) return NULL;
3977   /*
3978    * Grow the big block chain.
3979    */
3980   size = SmallBlockChainStream_GetSize(*ppsbChain);
3981   BlockChainStream_SetSize(bbTempChain, size);
3982
3983   /*
3984    * Copy the contents of the small block chain to the big block chain
3985    * by small block size increments.
3986    */
3987   offset.u.LowPart = 0;
3988   offset.u.HighPart = 0;
3989   cbTotalRead.QuadPart = 0;
3990
3991   buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3992   do
3993   {
3994     resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3995                                            offset,
3996                                            min(This->smallBlockSize, size.u.LowPart - offset.u.LowPart),
3997                                            buffer,
3998                                            &cbRead);
3999     if (FAILED(resRead))
4000         break;
4001
4002     if (cbRead > 0)
4003     {
4004         cbTotalRead.QuadPart += cbRead;
4005
4006         resWrite = BlockChainStream_WriteAt(bbTempChain,
4007                                             offset,
4008                                             cbRead,
4009                                             buffer,
4010                                             &cbWritten);
4011
4012         if (FAILED(resWrite))
4013             break;
4014
4015         offset.u.LowPart += cbRead;
4016     }
4017     else
4018     {
4019         resRead = STG_E_READFAULT;
4020         break;
4021     }
4022   } while (cbTotalRead.QuadPart < size.QuadPart);
4023   HeapFree(GetProcessHeap(),0,buffer);
4024
4025   size.u.HighPart = 0;
4026   size.u.LowPart  = 0;
4027
4028   if (FAILED(resRead) || FAILED(resWrite))
4029   {
4030     ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
4031     BlockChainStream_SetSize(bbTempChain, size);
4032     BlockChainStream_Destroy(bbTempChain);
4033     return NULL;
4034   }
4035
4036   /*
4037    * Destroy the small block chain.
4038    */
4039   streamEntryRef = (*ppsbChain)->ownerDirEntry;
4040   SmallBlockChainStream_SetSize(*ppsbChain, size);
4041   SmallBlockChainStream_Destroy(*ppsbChain);
4042   *ppsbChain = 0;
4043
4044   /*
4045    * Change the directory entry. This chain is now a big block chain
4046    * and it doesn't reside in the small blocks chain anymore.
4047    */
4048   StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry);
4049
4050   streamEntry.startingBlock = bbHeadOfChain;
4051
4052   StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry);
4053
4054   /*
4055    * Destroy the temporary entryless big block chain.
4056    * Create a new big block chain associated with this entry.
4057    */
4058   BlockChainStream_Destroy(bbTempChain);
4059   bigBlockChain = BlockChainStream_Construct(This,
4060                                              NULL,
4061                                              streamEntryRef);
4062
4063   return bigBlockChain;
4064 }
4065
4066 /******************************************************************************
4067  *              Storage32Impl_BigBlocksToSmallBlocks
4068  *
4069  * This method will convert a big block chain to a small block chain.
4070  * The big block chain will be destroyed on success.
4071  */
4072 SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks(
4073                            StorageImpl* This,
4074                            BlockChainStream** ppbbChain)
4075 {
4076     ULARGE_INTEGER size, offset, cbTotalRead;
4077     ULONG cbRead, cbWritten, sbHeadOfChain = BLOCK_END_OF_CHAIN;
4078     DirRef streamEntryRef;
4079     HRESULT resWrite = S_OK, resRead;
4080     DirEntry streamEntry;
4081     BYTE* buffer;
4082     SmallBlockChainStream* sbTempChain;
4083
4084     TRACE("%p %p\n", This, ppbbChain);
4085
4086     sbTempChain = SmallBlockChainStream_Construct(This, &sbHeadOfChain,
4087             DIRENTRY_NULL);
4088
4089     if(!sbTempChain)
4090         return NULL;
4091
4092     size = BlockChainStream_GetSize(*ppbbChain);
4093     SmallBlockChainStream_SetSize(sbTempChain, size);
4094
4095     offset.u.HighPart = 0;
4096     offset.u.LowPart = 0;
4097     cbTotalRead.QuadPart = 0;
4098     buffer = HeapAlloc(GetProcessHeap(), 0, This->bigBlockSize);
4099     do
4100     {
4101         resRead = BlockChainStream_ReadAt(*ppbbChain, offset,
4102                 min(This->bigBlockSize, size.u.LowPart - offset.u.LowPart),
4103                 buffer, &cbRead);
4104
4105         if(FAILED(resRead))
4106             break;
4107
4108         if(cbRead > 0)
4109         {
4110             cbTotalRead.QuadPart += cbRead;
4111
4112             resWrite = SmallBlockChainStream_WriteAt(sbTempChain, offset,
4113                     cbRead, buffer, &cbWritten);
4114
4115             if(FAILED(resWrite))
4116                 break;
4117
4118             offset.u.LowPart += cbRead;
4119         }
4120         else
4121         {
4122             resRead = STG_E_READFAULT;
4123             break;
4124         }
4125     }while(cbTotalRead.QuadPart < size.QuadPart);
4126     HeapFree(GetProcessHeap(), 0, buffer);
4127
4128     size.u.HighPart = 0;
4129     size.u.LowPart = 0;
4130
4131     if(FAILED(resRead) || FAILED(resWrite))
4132     {
4133         ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
4134         SmallBlockChainStream_SetSize(sbTempChain, size);
4135         SmallBlockChainStream_Destroy(sbTempChain);
4136         return NULL;
4137     }
4138
4139     /* destroy the original big block chain */
4140     streamEntryRef = (*ppbbChain)->ownerDirEntry;
4141     BlockChainStream_SetSize(*ppbbChain, size);
4142     BlockChainStream_Destroy(*ppbbChain);
4143     *ppbbChain = NULL;
4144
4145     StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry);
4146     streamEntry.startingBlock = sbHeadOfChain;
4147     StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry);
4148
4149     SmallBlockChainStream_Destroy(sbTempChain);
4150     return SmallBlockChainStream_Construct(This, NULL, streamEntryRef);
4151 }
4152
4153 static HRESULT StorageBaseImpl_CopyStream(
4154   StorageBaseImpl *dst, DirRef dst_entry,
4155   StorageBaseImpl *src, DirRef src_entry)
4156 {
4157   HRESULT hr;
4158   BYTE data[4096];
4159   DirEntry srcdata;
4160   ULARGE_INTEGER bytes_copied;
4161   ULONG bytestocopy, bytesread, byteswritten;
4162
4163   hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &srcdata);
4164
4165   if (SUCCEEDED(hr))
4166   {
4167     hr = StorageBaseImpl_StreamSetSize(dst, dst_entry, srcdata.size);
4168
4169     bytes_copied.QuadPart = 0;
4170     while (bytes_copied.QuadPart < srcdata.size.QuadPart && SUCCEEDED(hr))
4171     {
4172       bytestocopy = min(4096, srcdata.size.QuadPart - bytes_copied.QuadPart);
4173
4174       hr = StorageBaseImpl_StreamReadAt(src, src_entry, bytes_copied, bytestocopy,
4175         data, &bytesread);
4176       if (SUCCEEDED(hr) && bytesread != bytestocopy) hr = STG_E_READFAULT;
4177
4178       if (SUCCEEDED(hr))
4179         hr = StorageBaseImpl_StreamWriteAt(dst, dst_entry, bytes_copied, bytestocopy,
4180           data, &byteswritten);
4181       if (SUCCEEDED(hr))
4182       {
4183         if (byteswritten != bytestocopy) hr = STG_E_WRITEFAULT;
4184         bytes_copied.QuadPart += byteswritten;
4185       }
4186     }
4187   }
4188
4189   return hr;
4190 }
4191
4192 static DirRef TransactedSnapshotImpl_FindFreeEntry(TransactedSnapshotImpl *This)
4193 {
4194   DirRef result=This->firstFreeEntry;
4195
4196   while (result < This->entries_size && This->entries[result].inuse)
4197     result++;
4198
4199   if (result == This->entries_size)
4200   {
4201     ULONG new_size = This->entries_size * 2;
4202     TransactedDirEntry *new_entries;
4203
4204     new_entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * new_size);
4205     if (!new_entries) return DIRENTRY_NULL;
4206
4207     memcpy(new_entries, This->entries, sizeof(TransactedDirEntry) * This->entries_size);
4208     HeapFree(GetProcessHeap(), 0, This->entries);
4209
4210     This->entries = new_entries;
4211     This->entries_size = new_size;
4212   }
4213
4214   This->entries[result].inuse = 1;
4215
4216   This->firstFreeEntry = result+1;
4217
4218   return result;
4219 }
4220
4221 static DirRef TransactedSnapshotImpl_CreateStubEntry(
4222   TransactedSnapshotImpl *This, DirRef parentEntryRef)
4223 {
4224   DirRef stubEntryRef;
4225   TransactedDirEntry *entry;
4226
4227   stubEntryRef = TransactedSnapshotImpl_FindFreeEntry(This);
4228
4229   if (stubEntryRef != DIRENTRY_NULL)
4230   {
4231     entry = &This->entries[stubEntryRef];
4232
4233     entry->newTransactedParentEntry = entry->transactedParentEntry = parentEntryRef;
4234
4235     entry->read = 0;
4236   }
4237
4238   return stubEntryRef;
4239 }
4240
4241 static HRESULT TransactedSnapshotImpl_EnsureReadEntry(
4242   TransactedSnapshotImpl *This, DirRef entry)
4243 {
4244   HRESULT hr=S_OK;
4245   DirEntry data;
4246
4247   if (!This->entries[entry].read)
4248   {
4249     hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
4250         This->entries[entry].transactedParentEntry,
4251         &data);
4252
4253     if (SUCCEEDED(hr) && data.leftChild != DIRENTRY_NULL)
4254     {
4255       data.leftChild = TransactedSnapshotImpl_CreateStubEntry(This, data.leftChild);
4256
4257       if (data.leftChild == DIRENTRY_NULL)
4258         hr = E_OUTOFMEMORY;
4259     }
4260
4261     if (SUCCEEDED(hr) && data.rightChild != DIRENTRY_NULL)
4262     {
4263       data.rightChild = TransactedSnapshotImpl_CreateStubEntry(This, data.rightChild);
4264
4265       if (data.rightChild == DIRENTRY_NULL)
4266         hr = E_OUTOFMEMORY;
4267     }
4268
4269     if (SUCCEEDED(hr) && data.dirRootEntry != DIRENTRY_NULL)
4270     {
4271       data.dirRootEntry = TransactedSnapshotImpl_CreateStubEntry(This, data.dirRootEntry);
4272
4273       if (data.dirRootEntry == DIRENTRY_NULL)
4274         hr = E_OUTOFMEMORY;
4275     }
4276
4277     if (SUCCEEDED(hr))
4278     {
4279       memcpy(&This->entries[entry].data, &data, sizeof(DirEntry));
4280       This->entries[entry].read = 1;
4281     }
4282   }
4283
4284   return hr;
4285 }
4286
4287 static HRESULT TransactedSnapshotImpl_MakeStreamDirty(
4288   TransactedSnapshotImpl *This, DirRef entry)
4289 {
4290   HRESULT hr = S_OK;
4291
4292   if (!This->entries[entry].stream_dirty)
4293   {
4294     DirEntry new_entrydata;
4295
4296     memset(&new_entrydata, 0, sizeof(DirEntry));
4297     new_entrydata.name[0] = 'S';
4298     new_entrydata.sizeOfNameString = 1;
4299     new_entrydata.stgType = STGTY_STREAM;
4300     new_entrydata.startingBlock = BLOCK_END_OF_CHAIN;
4301     new_entrydata.leftChild = DIRENTRY_NULL;
4302     new_entrydata.rightChild = DIRENTRY_NULL;
4303     new_entrydata.dirRootEntry = DIRENTRY_NULL;
4304
4305     hr = StorageBaseImpl_CreateDirEntry(This->scratch, &new_entrydata,
4306       &This->entries[entry].stream_entry);
4307
4308     if (SUCCEEDED(hr) && This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
4309     {
4310       hr = StorageBaseImpl_CopyStream(
4311         This->scratch, This->entries[entry].stream_entry,
4312         This->transactedParent, This->entries[entry].transactedParentEntry);
4313
4314       if (FAILED(hr))
4315         StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[entry].stream_entry);
4316     }
4317
4318     if (SUCCEEDED(hr))
4319       This->entries[entry].stream_dirty = 1;
4320
4321     if (This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
4322     {
4323       /* Since this entry is modified, and we aren't using its stream data, we
4324        * no longer care about the original entry. */
4325       DirRef delete_ref;
4326       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[entry].transactedParentEntry);
4327
4328       if (delete_ref != DIRENTRY_NULL)
4329         This->entries[delete_ref].deleted = 1;
4330
4331       This->entries[entry].transactedParentEntry = This->entries[entry].newTransactedParentEntry = DIRENTRY_NULL;
4332     }
4333   }
4334
4335   return hr;
4336 }
4337
4338 /* Find the first entry in a depth-first traversal. */
4339 static DirRef TransactedSnapshotImpl_FindFirstChild(
4340   TransactedSnapshotImpl* This, DirRef parent)
4341 {
4342   DirRef cursor, prev;
4343   TransactedDirEntry *entry;
4344
4345   cursor = parent;
4346   entry = &This->entries[cursor];
4347   while (entry->read)
4348   {
4349     if (entry->data.leftChild != DIRENTRY_NULL)
4350     {
4351       prev = cursor;
4352       cursor = entry->data.leftChild;
4353       entry = &This->entries[cursor];
4354       entry->parent = prev;
4355     }
4356     else if (entry->data.rightChild != DIRENTRY_NULL)
4357     {
4358       prev = cursor;
4359       cursor = entry->data.rightChild;
4360       entry = &This->entries[cursor];
4361       entry->parent = prev;
4362     }
4363     else if (entry->data.dirRootEntry != DIRENTRY_NULL)
4364     {
4365       prev = cursor;
4366       cursor = entry->data.dirRootEntry;
4367       entry = &This->entries[cursor];
4368       entry->parent = prev;
4369     }
4370     else
4371       break;
4372   }
4373
4374   return cursor;
4375 }
4376
4377 /* Find the next entry in a depth-first traversal. */
4378 static DirRef TransactedSnapshotImpl_FindNextChild(
4379   TransactedSnapshotImpl* This, DirRef current)
4380 {
4381   DirRef parent;
4382   TransactedDirEntry *parent_entry;
4383
4384   parent = This->entries[current].parent;
4385   parent_entry = &This->entries[parent];
4386
4387   if (parent != DIRENTRY_NULL && parent_entry->data.dirRootEntry != current)
4388   {
4389     if (parent_entry->data.rightChild != current && parent_entry->data.rightChild != DIRENTRY_NULL)
4390     {
4391       This->entries[parent_entry->data.rightChild].parent = parent;
4392       return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.rightChild);
4393     }
4394
4395     if (parent_entry->data.dirRootEntry != DIRENTRY_NULL)
4396     {
4397       This->entries[parent_entry->data.dirRootEntry].parent = parent;
4398       return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.dirRootEntry);
4399     }
4400   }
4401
4402   return parent;
4403 }
4404
4405 /* Return TRUE if we've made a copy of this entry for committing to the parent. */
4406 static inline BOOL TransactedSnapshotImpl_MadeCopy(
4407   TransactedSnapshotImpl* This, DirRef entry)
4408 {
4409   return entry != DIRENTRY_NULL &&
4410     This->entries[entry].newTransactedParentEntry != This->entries[entry].transactedParentEntry;
4411 }
4412
4413 /* Destroy the entries created by CopyTree. */
4414 static void TransactedSnapshotImpl_DestroyTemporaryCopy(
4415   TransactedSnapshotImpl* This, DirRef stop)
4416 {
4417   DirRef cursor;
4418   TransactedDirEntry *entry;
4419   ULARGE_INTEGER zero;
4420
4421   zero.QuadPart = 0;
4422
4423   if (!This->entries[This->base.storageDirEntry].read)
4424     return;
4425
4426   cursor = This->entries[This->base.storageDirEntry].data.dirRootEntry;
4427
4428   if (cursor == DIRENTRY_NULL)
4429     return;
4430
4431   cursor = TransactedSnapshotImpl_FindFirstChild(This, cursor);
4432
4433   while (cursor != DIRENTRY_NULL && cursor != stop)
4434   {
4435     if (TransactedSnapshotImpl_MadeCopy(This, cursor))
4436     {
4437       entry = &This->entries[cursor];
4438
4439       if (entry->stream_dirty)
4440         StorageBaseImpl_StreamSetSize(This->transactedParent,
4441           entry->newTransactedParentEntry, zero);
4442
4443       StorageBaseImpl_DestroyDirEntry(This->transactedParent,
4444         entry->newTransactedParentEntry);
4445
4446       entry->newTransactedParentEntry = entry->transactedParentEntry;
4447     }
4448
4449     cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
4450   }
4451 }
4452
4453 /* Make a copy of our edited tree that we can use in the parent. */
4454 static HRESULT TransactedSnapshotImpl_CopyTree(TransactedSnapshotImpl* This)
4455 {
4456   DirRef cursor;
4457   TransactedDirEntry *entry;
4458   HRESULT hr = S_OK;
4459
4460   cursor = This->base.storageDirEntry;
4461   entry = &This->entries[cursor];
4462   entry->parent = DIRENTRY_NULL;
4463   entry->newTransactedParentEntry = entry->transactedParentEntry;
4464
4465   if (entry->data.dirRootEntry == DIRENTRY_NULL)
4466     return S_OK;
4467
4468   This->entries[entry->data.dirRootEntry].parent = DIRENTRY_NULL;
4469
4470   cursor = TransactedSnapshotImpl_FindFirstChild(This, entry->data.dirRootEntry);
4471   entry = &This->entries[cursor];
4472
4473   while (cursor != DIRENTRY_NULL)
4474   {
4475     /* Make a copy of this entry in the transacted parent. */
4476     if (!entry->read ||
4477         (!entry->dirty && !entry->stream_dirty &&
4478          !TransactedSnapshotImpl_MadeCopy(This, entry->data.leftChild) &&
4479          !TransactedSnapshotImpl_MadeCopy(This, entry->data.rightChild) &&
4480          !TransactedSnapshotImpl_MadeCopy(This, entry->data.dirRootEntry)))
4481       entry->newTransactedParentEntry = entry->transactedParentEntry;
4482     else
4483     {
4484       DirEntry newData;
4485
4486       memcpy(&newData, &entry->data, sizeof(DirEntry));
4487
4488       newData.size.QuadPart = 0;
4489       newData.startingBlock = BLOCK_END_OF_CHAIN;
4490
4491       if (newData.leftChild != DIRENTRY_NULL)
4492         newData.leftChild = This->entries[newData.leftChild].newTransactedParentEntry;
4493
4494       if (newData.rightChild != DIRENTRY_NULL)
4495         newData.rightChild = This->entries[newData.rightChild].newTransactedParentEntry;
4496
4497       if (newData.dirRootEntry != DIRENTRY_NULL)
4498         newData.dirRootEntry = This->entries[newData.dirRootEntry].newTransactedParentEntry;
4499
4500       hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &newData,
4501         &entry->newTransactedParentEntry);
4502       if (FAILED(hr))
4503       {
4504         TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor);
4505         return hr;
4506       }
4507
4508       if (entry->stream_dirty)
4509       {
4510         hr = StorageBaseImpl_CopyStream(
4511           This->transactedParent, entry->newTransactedParentEntry,
4512           This->scratch, entry->stream_entry);
4513       }
4514       else if (entry->data.size.QuadPart)
4515       {
4516         hr = StorageBaseImpl_StreamLink(
4517           This->transactedParent, entry->newTransactedParentEntry,
4518           entry->transactedParentEntry);
4519       }
4520
4521       if (FAILED(hr))
4522       {
4523         cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
4524         TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor);
4525         return hr;
4526       }
4527     }
4528
4529     cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
4530     entry = &This->entries[cursor];
4531   }
4532
4533   return hr;
4534 }
4535
4536 static HRESULT WINAPI TransactedSnapshotImpl_Commit(
4537   IStorage*            iface,
4538   DWORD                  grfCommitFlags)  /* [in] */
4539 {
4540   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
4541   TransactedDirEntry *root_entry;
4542   DirRef i, dir_root_ref;
4543   DirEntry data;
4544   ULARGE_INTEGER zero;
4545   HRESULT hr;
4546
4547   zero.QuadPart = 0;
4548
4549   TRACE("(%p,%x)\n", iface, grfCommitFlags);
4550
4551   /* Cannot commit a read-only transacted storage */
4552   if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
4553     return STG_E_ACCESSDENIED;
4554
4555   /* To prevent data loss, we create the new structure in the file before we
4556    * delete the old one, so that in case of errors the old data is intact. We
4557    * shouldn't do this if STGC_OVERWRITE is set, but that flag should only be
4558    * needed in the rare situation where we have just enough free disk space to
4559    * overwrite the existing data. */
4560
4561   root_entry = &This->entries[This->base.storageDirEntry];
4562
4563   if (!root_entry->read)
4564     return S_OK;
4565
4566   hr = TransactedSnapshotImpl_CopyTree(This);
4567   if (FAILED(hr)) return hr;
4568
4569   if (root_entry->data.dirRootEntry == DIRENTRY_NULL)
4570     dir_root_ref = DIRENTRY_NULL;
4571   else
4572     dir_root_ref = This->entries[root_entry->data.dirRootEntry].newTransactedParentEntry;
4573
4574   hr = StorageBaseImpl_Flush(This->transactedParent);
4575
4576   /* Update the storage to use the new data in one step. */
4577   if (SUCCEEDED(hr))
4578     hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
4579       root_entry->transactedParentEntry, &data);
4580
4581   if (SUCCEEDED(hr))
4582   {
4583     data.dirRootEntry = dir_root_ref;
4584     data.clsid = root_entry->data.clsid;
4585     data.ctime = root_entry->data.ctime;
4586     data.mtime = root_entry->data.mtime;
4587
4588     hr = StorageBaseImpl_WriteDirEntry(This->transactedParent,
4589       root_entry->transactedParentEntry, &data);
4590   }
4591
4592   /* Try to flush after updating the root storage, but if the flush fails, keep
4593    * going, on the theory that it'll either succeed later or the subsequent
4594    * writes will fail. */
4595   StorageBaseImpl_Flush(This->transactedParent);
4596
4597   if (SUCCEEDED(hr))
4598   {
4599     /* Destroy the old now-orphaned data. */
4600     for (i=0; i<This->entries_size; i++)
4601     {
4602       TransactedDirEntry *entry = &This->entries[i];
4603       if (entry->inuse)
4604       {
4605         if (entry->deleted)
4606         {
4607           StorageBaseImpl_StreamSetSize(This->transactedParent,
4608             entry->transactedParentEntry, zero);
4609           StorageBaseImpl_DestroyDirEntry(This->transactedParent,
4610             entry->transactedParentEntry);
4611           memset(entry, 0, sizeof(TransactedDirEntry));
4612           This->firstFreeEntry = min(i, This->firstFreeEntry);
4613         }
4614         else if (entry->read && entry->transactedParentEntry != entry->newTransactedParentEntry)
4615         {
4616           if (entry->transactedParentEntry != DIRENTRY_NULL)
4617             StorageBaseImpl_DestroyDirEntry(This->transactedParent,
4618               entry->transactedParentEntry);
4619           if (entry->stream_dirty)
4620           {
4621             StorageBaseImpl_StreamSetSize(This->scratch, entry->stream_entry, zero);
4622             StorageBaseImpl_DestroyDirEntry(This->scratch, entry->stream_entry);
4623             entry->stream_dirty = 0;
4624           }
4625           entry->dirty = 0;
4626           entry->transactedParentEntry = entry->newTransactedParentEntry;
4627         }
4628       }
4629     }
4630   }
4631   else
4632   {
4633     TransactedSnapshotImpl_DestroyTemporaryCopy(This, DIRENTRY_NULL);
4634   }
4635
4636   if (SUCCEEDED(hr))
4637     hr = StorageBaseImpl_Flush(This->transactedParent);
4638
4639   return hr;
4640 }
4641
4642 static HRESULT WINAPI TransactedSnapshotImpl_Revert(
4643   IStorage*            iface)
4644 {
4645   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
4646   ULARGE_INTEGER zero;
4647   ULONG i;
4648
4649   TRACE("(%p)\n", iface);
4650
4651   /* Destroy the open objects. */
4652   StorageBaseImpl_DeleteAll(&This->base);
4653
4654   /* Clear out the scratch file. */
4655   zero.QuadPart = 0;
4656   for (i=0; i<This->entries_size; i++)
4657   {
4658     if (This->entries[i].stream_dirty)
4659     {
4660       StorageBaseImpl_StreamSetSize(This->scratch, This->entries[i].stream_entry,
4661         zero);
4662
4663       StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[i].stream_entry);
4664     }
4665   }
4666
4667   memset(This->entries, 0, sizeof(TransactedDirEntry) * This->entries_size);
4668
4669   This->firstFreeEntry = 0;
4670   This->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(This, This->transactedParent->storageDirEntry);
4671
4672   return S_OK;
4673 }
4674
4675 static void TransactedSnapshotImpl_Invalidate(StorageBaseImpl* This)
4676 {
4677   if (!This->reverted)
4678   {
4679     TRACE("Storage invalidated (stg=%p)\n", This);
4680
4681     This->reverted = 1;
4682
4683     StorageBaseImpl_DeleteAll(This);
4684   }
4685 }
4686
4687 static void TransactedSnapshotImpl_Destroy( StorageBaseImpl *iface)
4688 {
4689   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
4690
4691   TransactedSnapshotImpl_Revert((IStorage*)iface);
4692
4693   IStorage_Release((IStorage*)This->transactedParent);
4694
4695   IStorage_Release((IStorage*)This->scratch);
4696
4697   HeapFree(GetProcessHeap(), 0, This->entries);
4698
4699   HeapFree(GetProcessHeap(), 0, This);
4700 }
4701
4702 static HRESULT TransactedSnapshotImpl_Flush(StorageBaseImpl* iface)
4703 {
4704   /* We only need to flush when committing. */
4705   return S_OK;
4706 }
4707
4708 static HRESULT TransactedSnapshotImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
4709 {
4710   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
4711
4712   return StorageBaseImpl_GetFilename(This->transactedParent, result);
4713 }
4714
4715 static HRESULT TransactedSnapshotImpl_CreateDirEntry(StorageBaseImpl *base,
4716   const DirEntry *newData, DirRef *index)
4717 {
4718   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4719   DirRef new_ref;
4720   TransactedDirEntry *new_entry;
4721
4722   new_ref = TransactedSnapshotImpl_FindFreeEntry(This);
4723   if (new_ref == DIRENTRY_NULL)
4724     return E_OUTOFMEMORY;
4725
4726   new_entry = &This->entries[new_ref];
4727
4728   new_entry->newTransactedParentEntry = new_entry->transactedParentEntry = DIRENTRY_NULL;
4729   new_entry->read = 1;
4730   new_entry->dirty = 1;
4731   memcpy(&new_entry->data, newData, sizeof(DirEntry));
4732
4733   *index = new_ref;
4734
4735   TRACE("%s l=%x r=%x d=%x <-- %x\n", debugstr_w(newData->name), newData->leftChild, newData->rightChild, newData->dirRootEntry, *index);
4736
4737   return S_OK;
4738 }
4739
4740 static HRESULT TransactedSnapshotImpl_WriteDirEntry(StorageBaseImpl *base,
4741   DirRef index, const DirEntry *data)
4742 {
4743   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4744   HRESULT hr;
4745
4746   TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
4747
4748   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
4749   if (FAILED(hr)) return hr;
4750
4751   memcpy(&This->entries[index].data, data, sizeof(DirEntry));
4752
4753   if (index != This->base.storageDirEntry)
4754   {
4755     This->entries[index].dirty = 1;
4756
4757     if (data->size.QuadPart == 0 &&
4758         This->entries[index].transactedParentEntry != DIRENTRY_NULL)
4759     {
4760       /* Since this entry is modified, and we aren't using its stream data, we
4761        * no longer care about the original entry. */
4762       DirRef delete_ref;
4763       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
4764
4765       if (delete_ref != DIRENTRY_NULL)
4766         This->entries[delete_ref].deleted = 1;
4767
4768       This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
4769     }
4770   }
4771
4772   return S_OK;
4773 }
4774
4775 static HRESULT TransactedSnapshotImpl_ReadDirEntry(StorageBaseImpl *base,
4776   DirRef index, DirEntry *data)
4777 {
4778   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4779   HRESULT hr;
4780
4781   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
4782   if (FAILED(hr)) return hr;
4783
4784   memcpy(data, &This->entries[index].data, sizeof(DirEntry));
4785
4786   TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
4787
4788   return S_OK;
4789 }
4790
4791 static HRESULT TransactedSnapshotImpl_DestroyDirEntry(StorageBaseImpl *base,
4792   DirRef index)
4793 {
4794   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4795
4796   if (This->entries[index].transactedParentEntry == DIRENTRY_NULL ||
4797       This->entries[index].data.size.QuadPart != 0)
4798   {
4799     /* If we deleted this entry while it has stream data. We must have left the
4800      * data because some other entry is using it, and we need to leave the
4801      * original entry alone. */
4802     memset(&This->entries[index], 0, sizeof(TransactedDirEntry));
4803     This->firstFreeEntry = min(index, This->firstFreeEntry);
4804   }
4805   else
4806   {
4807     This->entries[index].deleted = 1;
4808   }
4809
4810   return S_OK;
4811 }
4812
4813 static HRESULT TransactedSnapshotImpl_StreamReadAt(StorageBaseImpl *base,
4814   DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
4815 {
4816   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4817
4818   if (This->entries[index].stream_dirty)
4819   {
4820     return StorageBaseImpl_StreamReadAt(This->scratch,
4821         This->entries[index].stream_entry, offset, size, buffer, bytesRead);
4822   }
4823   else if (This->entries[index].transactedParentEntry == DIRENTRY_NULL)
4824   {
4825     /* This stream doesn't live in the parent, and we haven't allocated storage
4826      * for it yet */
4827     *bytesRead = 0;
4828     return S_OK;
4829   }
4830   else
4831   {
4832     return StorageBaseImpl_StreamReadAt(This->transactedParent,
4833         This->entries[index].transactedParentEntry, offset, size, buffer, bytesRead);
4834   }
4835 }
4836
4837 static HRESULT TransactedSnapshotImpl_StreamWriteAt(StorageBaseImpl *base,
4838   DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
4839 {
4840   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4841   HRESULT hr;
4842
4843   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
4844   if (FAILED(hr)) return hr;
4845
4846   hr = TransactedSnapshotImpl_MakeStreamDirty(This, index);
4847   if (FAILED(hr)) return hr;
4848
4849   hr = StorageBaseImpl_StreamWriteAt(This->scratch,
4850     This->entries[index].stream_entry, offset, size, buffer, bytesWritten);
4851
4852   if (SUCCEEDED(hr) && size != 0)
4853     This->entries[index].data.size.QuadPart = max(
4854         This->entries[index].data.size.QuadPart,
4855         offset.QuadPart + size);
4856
4857   return hr;
4858 }
4859
4860 static HRESULT TransactedSnapshotImpl_StreamSetSize(StorageBaseImpl *base,
4861   DirRef index, ULARGE_INTEGER newsize)
4862 {
4863   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4864   HRESULT hr;
4865
4866   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
4867   if (FAILED(hr)) return hr;
4868
4869   if (This->entries[index].data.size.QuadPart == newsize.QuadPart)
4870     return S_OK;
4871
4872   if (newsize.QuadPart == 0)
4873   {
4874     /* Destroy any parent references or entries in the scratch file. */
4875     if (This->entries[index].stream_dirty)
4876     {
4877       ULARGE_INTEGER zero;
4878       zero.QuadPart = 0;
4879       StorageBaseImpl_StreamSetSize(This->scratch,
4880         This->entries[index].stream_entry, zero);
4881       StorageBaseImpl_DestroyDirEntry(This->scratch,
4882         This->entries[index].stream_entry);
4883       This->entries[index].stream_dirty = 0;
4884     }
4885     else if (This->entries[index].transactedParentEntry != DIRENTRY_NULL)
4886     {
4887       DirRef delete_ref;
4888       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
4889
4890       if (delete_ref != DIRENTRY_NULL)
4891         This->entries[delete_ref].deleted = 1;
4892
4893       This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
4894     }
4895   }
4896   else
4897   {
4898     hr = TransactedSnapshotImpl_MakeStreamDirty(This, index);
4899     if (FAILED(hr)) return hr;
4900
4901     hr = StorageBaseImpl_StreamSetSize(This->scratch,
4902       This->entries[index].stream_entry, newsize);
4903   }
4904
4905   if (SUCCEEDED(hr))
4906     This->entries[index].data.size = newsize;
4907
4908   return hr;
4909 }
4910
4911 static HRESULT TransactedSnapshotImpl_StreamLink(StorageBaseImpl *base,
4912   DirRef dst, DirRef src)
4913 {
4914   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4915   HRESULT hr;
4916   TransactedDirEntry *dst_entry, *src_entry;
4917
4918   hr = TransactedSnapshotImpl_EnsureReadEntry(This, src);
4919   if (FAILED(hr)) return hr;
4920
4921   hr = TransactedSnapshotImpl_EnsureReadEntry(This, dst);
4922   if (FAILED(hr)) return hr;
4923
4924   dst_entry = &This->entries[dst];
4925   src_entry = &This->entries[src];
4926
4927   dst_entry->stream_dirty = src_entry->stream_dirty;
4928   dst_entry->stream_entry = src_entry->stream_entry;
4929   dst_entry->transactedParentEntry = src_entry->transactedParentEntry;
4930   dst_entry->newTransactedParentEntry = src_entry->newTransactedParentEntry;
4931   dst_entry->data.size = src_entry->data.size;
4932
4933   return S_OK;
4934 }
4935
4936 static const IStorageVtbl TransactedSnapshotImpl_Vtbl =
4937 {
4938     StorageBaseImpl_QueryInterface,
4939     StorageBaseImpl_AddRef,
4940     StorageBaseImpl_Release,
4941     StorageBaseImpl_CreateStream,
4942     StorageBaseImpl_OpenStream,
4943     StorageBaseImpl_CreateStorage,
4944     StorageBaseImpl_OpenStorage,
4945     StorageBaseImpl_CopyTo,
4946     StorageBaseImpl_MoveElementTo,
4947     TransactedSnapshotImpl_Commit,
4948     TransactedSnapshotImpl_Revert,
4949     StorageBaseImpl_EnumElements,
4950     StorageBaseImpl_DestroyElement,
4951     StorageBaseImpl_RenameElement,
4952     StorageBaseImpl_SetElementTimes,
4953     StorageBaseImpl_SetClass,
4954     StorageBaseImpl_SetStateBits,
4955     StorageBaseImpl_Stat
4956 };
4957
4958 static const StorageBaseImplVtbl TransactedSnapshotImpl_BaseVtbl =
4959 {
4960   TransactedSnapshotImpl_Destroy,
4961   TransactedSnapshotImpl_Invalidate,
4962   TransactedSnapshotImpl_Flush,
4963   TransactedSnapshotImpl_GetFilename,
4964   TransactedSnapshotImpl_CreateDirEntry,
4965   TransactedSnapshotImpl_WriteDirEntry,
4966   TransactedSnapshotImpl_ReadDirEntry,
4967   TransactedSnapshotImpl_DestroyDirEntry,
4968   TransactedSnapshotImpl_StreamReadAt,
4969   TransactedSnapshotImpl_StreamWriteAt,
4970   TransactedSnapshotImpl_StreamSetSize,
4971   TransactedSnapshotImpl_StreamLink
4972 };
4973
4974 static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage,
4975   TransactedSnapshotImpl** result)
4976 {
4977   HRESULT hr;
4978
4979   *result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedSnapshotImpl));
4980   if (*result)
4981   {
4982     (*result)->base.lpVtbl = &TransactedSnapshotImpl_Vtbl;
4983
4984     /* This is OK because the property set storage functions use the IStorage functions. */
4985     (*result)->base.pssVtbl = parentStorage->pssVtbl;
4986
4987     (*result)->base.baseVtbl = &TransactedSnapshotImpl_BaseVtbl;
4988
4989     list_init(&(*result)->base.strmHead);
4990
4991     list_init(&(*result)->base.storageHead);
4992
4993     (*result)->base.ref = 1;
4994
4995     (*result)->base.openFlags = parentStorage->openFlags;
4996
4997     /* Create a new temporary storage to act as the scratch file. */
4998     hr = StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
4999         0, (IStorage**)&(*result)->scratch);
5000
5001     if (SUCCEEDED(hr))
5002     {
5003         ULONG num_entries = 20;
5004
5005         (*result)->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * num_entries);
5006
5007         (*result)->entries_size = num_entries;
5008
5009         (*result)->firstFreeEntry = 0;
5010
5011         if ((*result)->entries)
5012         {
5013             /* parentStorage already has 1 reference, which we take over here. */
5014             (*result)->transactedParent = parentStorage;
5015
5016             parentStorage->transactedChild = (StorageBaseImpl*)*result;
5017
5018             (*result)->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(*result, parentStorage->storageDirEntry);
5019         }
5020         else
5021         {
5022             IStorage_Release((IStorage*)(*result)->scratch);
5023
5024             hr = E_OUTOFMEMORY;
5025         }
5026     }
5027
5028     if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, (*result));
5029
5030     return hr;
5031   }
5032   else
5033     return E_OUTOFMEMORY;
5034 }
5035
5036 static HRESULT Storage_ConstructTransacted(StorageBaseImpl *parentStorage,
5037   StorageBaseImpl** result)
5038 {
5039   static int fixme=0;
5040
5041   if (parentStorage->openFlags & (STGM_NOSCRATCH|STGM_NOSNAPSHOT) && !fixme++)
5042   {
5043     FIXME("Unimplemented flags %x\n", parentStorage->openFlags);
5044   }
5045
5046   return TransactedSnapshotImpl_Construct(parentStorage,
5047     (TransactedSnapshotImpl**)result);
5048 }
5049
5050 static HRESULT Storage_Construct(
5051   HANDLE       hFile,
5052   LPCOLESTR    pwcsName,
5053   ILockBytes*  pLkbyt,
5054   DWORD        openFlags,
5055   BOOL         fileBased,
5056   BOOL         create,
5057   ULONG        sector_size,
5058   StorageBaseImpl** result)
5059 {
5060   StorageImpl *newStorage;
5061   StorageBaseImpl *newTransactedStorage;
5062   HRESULT hr;
5063
5064   hr = StorageImpl_Construct(hFile, pwcsName, pLkbyt, openFlags, fileBased, create, sector_size, &newStorage);
5065   if (FAILED(hr)) goto end;
5066
5067   if (openFlags & STGM_TRANSACTED)
5068   {
5069     hr = Storage_ConstructTransacted(&newStorage->base, &newTransactedStorage);
5070     if (FAILED(hr))
5071       IStorage_Release((IStorage*)newStorage);
5072     else
5073       *result = newTransactedStorage;
5074   }
5075   else
5076     *result = &newStorage->base;
5077
5078 end:
5079   return hr;
5080 }
5081
5082 static void StorageInternalImpl_Invalidate( StorageBaseImpl *base )
5083 {
5084   StorageInternalImpl* This = (StorageInternalImpl*) base;
5085
5086   if (!This->base.reverted)
5087   {
5088     TRACE("Storage invalidated (stg=%p)\n", This);
5089
5090     This->base.reverted = 1;
5091
5092     This->parentStorage = NULL;
5093
5094     StorageBaseImpl_DeleteAll(&This->base);
5095
5096     list_remove(&This->ParentListEntry);
5097   }
5098 }
5099
5100 static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
5101 {
5102   StorageInternalImpl* This = (StorageInternalImpl*) iface;
5103
5104   StorageInternalImpl_Invalidate(&This->base);
5105
5106   HeapFree(GetProcessHeap(), 0, This);
5107 }
5108
5109 static HRESULT StorageInternalImpl_Flush(StorageBaseImpl* iface)
5110 {
5111   StorageInternalImpl* This = (StorageInternalImpl*) iface;
5112
5113   return StorageBaseImpl_Flush(This->parentStorage);
5114 }
5115
5116 static HRESULT StorageInternalImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
5117 {
5118   StorageInternalImpl* This = (StorageInternalImpl*) iface;
5119
5120   return StorageBaseImpl_GetFilename(This->parentStorage, result);
5121 }
5122
5123 static HRESULT StorageInternalImpl_CreateDirEntry(StorageBaseImpl *base,
5124   const DirEntry *newData, DirRef *index)
5125 {
5126   StorageInternalImpl* This = (StorageInternalImpl*) base;
5127
5128   return StorageBaseImpl_CreateDirEntry(This->parentStorage,
5129     newData, index);
5130 }
5131
5132 static HRESULT StorageInternalImpl_WriteDirEntry(StorageBaseImpl *base,
5133   DirRef index, const DirEntry *data)
5134 {
5135   StorageInternalImpl* This = (StorageInternalImpl*) base;
5136
5137   return StorageBaseImpl_WriteDirEntry(This->parentStorage,
5138     index, data);
5139 }
5140
5141 static HRESULT StorageInternalImpl_ReadDirEntry(StorageBaseImpl *base,
5142   DirRef index, DirEntry *data)
5143 {
5144   StorageInternalImpl* This = (StorageInternalImpl*) base;
5145
5146   return StorageBaseImpl_ReadDirEntry(This->parentStorage,
5147     index, data);
5148 }
5149
5150 static HRESULT StorageInternalImpl_DestroyDirEntry(StorageBaseImpl *base,
5151   DirRef index)
5152 {
5153   StorageInternalImpl* This = (StorageInternalImpl*) base;
5154
5155   return StorageBaseImpl_DestroyDirEntry(This->parentStorage,
5156     index);
5157 }
5158
5159 static HRESULT StorageInternalImpl_StreamReadAt(StorageBaseImpl *base,
5160   DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
5161 {
5162   StorageInternalImpl* This = (StorageInternalImpl*) base;
5163
5164   return StorageBaseImpl_StreamReadAt(This->parentStorage,
5165     index, offset, size, buffer, bytesRead);
5166 }
5167
5168 static HRESULT StorageInternalImpl_StreamWriteAt(StorageBaseImpl *base,
5169   DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
5170 {
5171   StorageInternalImpl* This = (StorageInternalImpl*) base;
5172
5173   return StorageBaseImpl_StreamWriteAt(This->parentStorage,
5174     index, offset, size, buffer, bytesWritten);
5175 }
5176
5177 static HRESULT StorageInternalImpl_StreamSetSize(StorageBaseImpl *base,
5178   DirRef index, ULARGE_INTEGER newsize)
5179 {
5180   StorageInternalImpl* This = (StorageInternalImpl*) base;
5181
5182   return StorageBaseImpl_StreamSetSize(This->parentStorage,
5183     index, newsize);
5184 }
5185
5186 static HRESULT StorageInternalImpl_StreamLink(StorageBaseImpl *base,
5187   DirRef dst, DirRef src)
5188 {
5189   StorageInternalImpl* This = (StorageInternalImpl*) base;
5190
5191   return StorageBaseImpl_StreamLink(This->parentStorage,
5192     dst, src);
5193 }
5194
5195 /******************************************************************************
5196 **
5197 ** Storage32InternalImpl_Commit
5198 **
5199 */
5200 static HRESULT WINAPI StorageInternalImpl_Commit(
5201   IStorage*            iface,
5202   DWORD                  grfCommitFlags)  /* [in] */
5203 {
5204   StorageBaseImpl* base = (StorageBaseImpl*) iface;
5205   TRACE("(%p,%x)\n", iface, grfCommitFlags);
5206   return StorageBaseImpl_Flush(base);
5207 }
5208
5209 /******************************************************************************
5210 **
5211 ** Storage32InternalImpl_Revert
5212 **
5213 */
5214 static HRESULT WINAPI StorageInternalImpl_Revert(
5215   IStorage*            iface)
5216 {
5217   FIXME("(%p): stub\n", iface);
5218   return S_OK;
5219 }
5220
5221 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
5222 {
5223   IStorage_Release((IStorage*)This->parentStorage);
5224   HeapFree(GetProcessHeap(), 0, This);
5225 }
5226
5227 static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
5228   IEnumSTATSTG*     iface,
5229   REFIID            riid,
5230   void**            ppvObject)
5231 {
5232   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5233
5234   if (ppvObject==0)
5235     return E_INVALIDARG;
5236
5237   *ppvObject = 0;
5238
5239   if (IsEqualGUID(&IID_IUnknown, riid) ||
5240       IsEqualGUID(&IID_IEnumSTATSTG, riid))
5241   {
5242     *ppvObject = This;
5243     IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
5244     return S_OK;
5245   }
5246
5247   return E_NOINTERFACE;
5248 }
5249
5250 static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
5251   IEnumSTATSTG* iface)
5252 {
5253   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5254   return InterlockedIncrement(&This->ref);
5255 }
5256
5257 static ULONG   WINAPI IEnumSTATSTGImpl_Release(
5258   IEnumSTATSTG* iface)
5259 {
5260   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5261
5262   ULONG newRef;
5263
5264   newRef = InterlockedDecrement(&This->ref);
5265
5266   if (newRef==0)
5267   {
5268     IEnumSTATSTGImpl_Destroy(This);
5269   }
5270
5271   return newRef;
5272 }
5273
5274 static HRESULT IEnumSTATSTGImpl_GetNextRef(
5275   IEnumSTATSTGImpl* This,
5276   DirRef *ref)
5277 {
5278   DirRef result = DIRENTRY_NULL;
5279   DirRef searchNode;
5280   DirEntry entry;
5281   HRESULT hr;
5282   WCHAR result_name[DIRENTRY_NAME_MAX_LEN];
5283
5284   hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
5285     This->parentStorage->storageDirEntry, &entry);
5286   searchNode = entry.dirRootEntry;
5287
5288   while (SUCCEEDED(hr) && searchNode != DIRENTRY_NULL)
5289   {
5290     hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, searchNode, &entry);
5291
5292     if (SUCCEEDED(hr))
5293     {
5294       LONG diff = entryNameCmp( entry.name, This->name);
5295
5296       if (diff <= 0)
5297       {
5298         searchNode = entry.rightChild;
5299       }
5300       else
5301       {
5302         result = searchNode;
5303         memcpy(result_name, entry.name, sizeof(result_name));
5304         searchNode = entry.leftChild;
5305       }
5306     }
5307   }
5308
5309   if (SUCCEEDED(hr))
5310   {
5311     *ref = result;
5312     if (result != DIRENTRY_NULL)
5313       memcpy(This->name, result_name, sizeof(result_name));
5314   }
5315
5316   return hr;
5317 }
5318
5319 static HRESULT WINAPI IEnumSTATSTGImpl_Next(
5320   IEnumSTATSTG* iface,
5321   ULONG             celt,
5322   STATSTG*          rgelt,
5323   ULONG*            pceltFetched)
5324 {
5325   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5326
5327   DirEntry    currentEntry;
5328   STATSTG*    currentReturnStruct = rgelt;
5329   ULONG       objectFetched       = 0;
5330   DirRef      currentSearchNode;
5331   HRESULT     hr=S_OK;
5332
5333   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
5334     return E_INVALIDARG;
5335
5336   if (This->parentStorage->reverted)
5337     return STG_E_REVERTED;
5338
5339   /*
5340    * To avoid the special case, get another pointer to a ULONG value if
5341    * the caller didn't supply one.
5342    */
5343   if (pceltFetched==0)
5344     pceltFetched = &objectFetched;
5345
5346   /*
5347    * Start the iteration, we will iterate until we hit the end of the
5348    * linked list or until we hit the number of items to iterate through
5349    */
5350   *pceltFetched = 0;
5351
5352   while ( *pceltFetched < celt )
5353   {
5354     hr = IEnumSTATSTGImpl_GetNextRef(This, &currentSearchNode);
5355
5356     if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL)
5357       break;
5358
5359     /*
5360      * Read the entry from the storage.
5361      */
5362     StorageBaseImpl_ReadDirEntry(This->parentStorage,
5363       currentSearchNode,
5364       &currentEntry);
5365
5366     /*
5367      * Copy the information to the return buffer.
5368      */
5369     StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage,
5370       currentReturnStruct,
5371       &currentEntry,
5372       STATFLAG_DEFAULT);
5373
5374     /*
5375      * Step to the next item in the iteration
5376      */
5377     (*pceltFetched)++;
5378     currentReturnStruct++;
5379   }
5380
5381   if (SUCCEEDED(hr) && *pceltFetched != celt)
5382     hr = S_FALSE;
5383
5384   return hr;
5385 }
5386
5387
5388 static HRESULT WINAPI IEnumSTATSTGImpl_Skip(
5389   IEnumSTATSTG* iface,
5390   ULONG             celt)
5391 {
5392   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5393
5394   ULONG       objectFetched       = 0;
5395   DirRef      currentSearchNode;
5396   HRESULT     hr=S_OK;
5397
5398   if (This->parentStorage->reverted)
5399     return STG_E_REVERTED;
5400
5401   while ( (objectFetched < celt) )
5402   {
5403     hr = IEnumSTATSTGImpl_GetNextRef(This, &currentSearchNode);
5404
5405     if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL)
5406       break;
5407
5408     objectFetched++;
5409   }
5410
5411   if (SUCCEEDED(hr) && objectFetched != celt)
5412     return S_FALSE;
5413
5414   return hr;
5415 }
5416
5417 static HRESULT WINAPI IEnumSTATSTGImpl_Reset(
5418   IEnumSTATSTG* iface)
5419 {
5420   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5421
5422   if (This->parentStorage->reverted)
5423     return STG_E_REVERTED;
5424
5425   This->name[0] = 0;
5426
5427   return S_OK;
5428 }
5429
5430 static HRESULT WINAPI IEnumSTATSTGImpl_Clone(
5431   IEnumSTATSTG* iface,
5432   IEnumSTATSTG**    ppenum)
5433 {
5434   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5435
5436   IEnumSTATSTGImpl* newClone;
5437
5438   if (This->parentStorage->reverted)
5439     return STG_E_REVERTED;
5440
5441   /*
5442    * Perform a sanity check on the parameters.
5443    */
5444   if (ppenum==0)
5445     return E_INVALIDARG;
5446
5447   newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
5448                This->storageDirEntry);
5449
5450
5451   /*
5452    * The new clone enumeration must point to the same current node as
5453    * the ole one.
5454    */
5455   memcpy(newClone->name, This->name, sizeof(newClone->name));
5456
5457   *ppenum = (IEnumSTATSTG*)newClone;
5458
5459   /*
5460    * Don't forget to nail down a reference to the clone before
5461    * returning it.
5462    */
5463   IEnumSTATSTGImpl_AddRef(*ppenum);
5464
5465   return S_OK;
5466 }
5467
5468 /*
5469  * Virtual function table for the IEnumSTATSTGImpl class.
5470  */
5471 static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
5472 {
5473     IEnumSTATSTGImpl_QueryInterface,
5474     IEnumSTATSTGImpl_AddRef,
5475     IEnumSTATSTGImpl_Release,
5476     IEnumSTATSTGImpl_Next,
5477     IEnumSTATSTGImpl_Skip,
5478     IEnumSTATSTGImpl_Reset,
5479     IEnumSTATSTGImpl_Clone
5480 };
5481
5482 /******************************************************************************
5483 ** IEnumSTATSTGImpl implementation
5484 */
5485
5486 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
5487   StorageBaseImpl* parentStorage,
5488   DirRef         storageDirEntry)
5489 {
5490   IEnumSTATSTGImpl* newEnumeration;
5491
5492   newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
5493
5494   if (newEnumeration!=0)
5495   {
5496     /*
5497      * Set-up the virtual function table and reference count.
5498      */
5499     newEnumeration->lpVtbl    = &IEnumSTATSTGImpl_Vtbl;
5500     newEnumeration->ref       = 0;
5501
5502     /*
5503      * We want to nail-down the reference to the storage in case the
5504      * enumeration out-lives the storage in the client application.
5505      */
5506     newEnumeration->parentStorage = parentStorage;
5507     IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
5508
5509     newEnumeration->storageDirEntry   = storageDirEntry;
5510
5511     /*
5512      * Make sure the current node of the iterator is the first one.
5513      */
5514     IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
5515   }
5516
5517   return newEnumeration;
5518 }
5519
5520 /*
5521  * Virtual function table for the Storage32InternalImpl class.
5522  */
5523 static const IStorageVtbl Storage32InternalImpl_Vtbl =
5524 {
5525     StorageBaseImpl_QueryInterface,
5526     StorageBaseImpl_AddRef,
5527     StorageBaseImpl_Release,
5528     StorageBaseImpl_CreateStream,
5529     StorageBaseImpl_OpenStream,
5530     StorageBaseImpl_CreateStorage,
5531     StorageBaseImpl_OpenStorage,
5532     StorageBaseImpl_CopyTo,
5533     StorageBaseImpl_MoveElementTo,
5534     StorageInternalImpl_Commit,
5535     StorageInternalImpl_Revert,
5536     StorageBaseImpl_EnumElements,
5537     StorageBaseImpl_DestroyElement,
5538     StorageBaseImpl_RenameElement,
5539     StorageBaseImpl_SetElementTimes,
5540     StorageBaseImpl_SetClass,
5541     StorageBaseImpl_SetStateBits,
5542     StorageBaseImpl_Stat
5543 };
5544
5545 static const StorageBaseImplVtbl StorageInternalImpl_BaseVtbl =
5546 {
5547   StorageInternalImpl_Destroy,
5548   StorageInternalImpl_Invalidate,
5549   StorageInternalImpl_Flush,
5550   StorageInternalImpl_GetFilename,
5551   StorageInternalImpl_CreateDirEntry,
5552   StorageInternalImpl_WriteDirEntry,
5553   StorageInternalImpl_ReadDirEntry,
5554   StorageInternalImpl_DestroyDirEntry,
5555   StorageInternalImpl_StreamReadAt,
5556   StorageInternalImpl_StreamWriteAt,
5557   StorageInternalImpl_StreamSetSize,
5558   StorageInternalImpl_StreamLink
5559 };
5560
5561 /******************************************************************************
5562 ** Storage32InternalImpl implementation
5563 */
5564
5565 static StorageInternalImpl* StorageInternalImpl_Construct(
5566   StorageBaseImpl* parentStorage,
5567   DWORD        openFlags,
5568   DirRef       storageDirEntry)
5569 {
5570   StorageInternalImpl* newStorage;
5571
5572   newStorage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StorageInternalImpl));
5573
5574   if (newStorage!=0)
5575   {
5576     list_init(&newStorage->base.strmHead);
5577
5578     list_init(&newStorage->base.storageHead);
5579
5580     /*
5581      * Initialize the virtual function table.
5582      */
5583     newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
5584     newStorage->base.pssVtbl = &IPropertySetStorage_Vtbl;
5585     newStorage->base.baseVtbl = &StorageInternalImpl_BaseVtbl;
5586     newStorage->base.openFlags = (openFlags & ~STGM_CREATE);
5587
5588     newStorage->base.reverted = 0;
5589
5590     newStorage->base.ref = 1;
5591
5592     newStorage->parentStorage = parentStorage;
5593
5594     /*
5595      * Keep a reference to the directory entry of this storage
5596      */
5597     newStorage->base.storageDirEntry = storageDirEntry;
5598
5599     newStorage->base.create = 0;
5600
5601     return newStorage;
5602   }
5603
5604   return 0;
5605 }
5606
5607 /******************************************************************************
5608 ** StorageUtl implementation
5609 */
5610
5611 void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
5612 {
5613   WORD tmp;
5614
5615   memcpy(&tmp, buffer+offset, sizeof(WORD));
5616   *value = lendian16toh(tmp);
5617 }
5618
5619 void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
5620 {
5621   value = htole16(value);
5622   memcpy(buffer+offset, &value, sizeof(WORD));
5623 }
5624
5625 void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
5626 {
5627   DWORD tmp;
5628
5629   memcpy(&tmp, buffer+offset, sizeof(DWORD));
5630   *value = lendian32toh(tmp);
5631 }
5632
5633 void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
5634 {
5635   value = htole32(value);
5636   memcpy(buffer+offset, &value, sizeof(DWORD));
5637 }
5638
5639 void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
5640  ULARGE_INTEGER* value)
5641 {
5642 #ifdef WORDS_BIGENDIAN
5643     ULARGE_INTEGER tmp;
5644
5645     memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
5646     value->u.LowPart = htole32(tmp.u.HighPart);
5647     value->u.HighPart = htole32(tmp.u.LowPart);
5648 #else
5649     memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
5650 #endif
5651 }
5652
5653 void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
5654  const ULARGE_INTEGER *value)
5655 {
5656 #ifdef WORDS_BIGENDIAN
5657     ULARGE_INTEGER tmp;
5658
5659     tmp.u.LowPart = htole32(value->u.HighPart);
5660     tmp.u.HighPart = htole32(value->u.LowPart);
5661     memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
5662 #else
5663     memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
5664 #endif
5665 }
5666
5667 void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
5668 {
5669   StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
5670   StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
5671   StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
5672
5673   memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
5674 }
5675
5676 void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
5677 {
5678   StorageUtl_WriteDWord(buffer, offset,   value->Data1);
5679   StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
5680   StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
5681
5682   memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
5683 }
5684
5685 void StorageUtl_CopyDirEntryToSTATSTG(
5686   StorageBaseImpl*      storage,
5687   STATSTG*              destination,
5688   const DirEntry*       source,
5689   int                   statFlags)
5690 {
5691   /*
5692    * The copy of the string occurs only when the flag is not set
5693    */
5694   if (!(statFlags & STATFLAG_NONAME) && source->stgType == STGTY_ROOT)
5695   {
5696     /* Use the filename for the root storage. */
5697     destination->pwcsName = 0;
5698     StorageBaseImpl_GetFilename(storage, &destination->pwcsName);
5699   }
5700   else if( ((statFlags & STATFLAG_NONAME) != 0) ||
5701        (source->name[0] == 0) )
5702   {
5703     destination->pwcsName = 0;
5704   }
5705   else
5706   {
5707     destination->pwcsName =
5708       CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
5709
5710     strcpyW(destination->pwcsName, source->name);
5711   }
5712
5713   switch (source->stgType)
5714   {
5715     case STGTY_STORAGE:
5716     case STGTY_ROOT:
5717       destination->type = STGTY_STORAGE;
5718       break;
5719     case STGTY_STREAM:
5720       destination->type = STGTY_STREAM;
5721       break;
5722     default:
5723       destination->type = STGTY_STREAM;
5724       break;
5725   }
5726
5727   destination->cbSize            = source->size;
5728 /*
5729   currentReturnStruct->mtime     = {0}; TODO
5730   currentReturnStruct->ctime     = {0};
5731   currentReturnStruct->atime     = {0};
5732 */
5733   destination->grfMode           = 0;
5734   destination->grfLocksSupported = 0;
5735   destination->clsid             = source->clsid;
5736   destination->grfStateBits      = 0;
5737   destination->reserved          = 0;
5738 }
5739
5740 /******************************************************************************
5741 ** BlockChainStream implementation
5742 */
5743
5744 /* Read and save the index of all blocks in this stream. */
5745 HRESULT BlockChainStream_UpdateIndexCache(BlockChainStream* This)
5746 {
5747   ULONG  next_sector, next_offset;
5748   HRESULT hr;
5749   struct BlockChainRun *last_run;
5750
5751   if (This->indexCacheLen == 0)
5752   {
5753     last_run = NULL;
5754     next_offset = 0;
5755     next_sector = BlockChainStream_GetHeadOfChain(This);
5756   }
5757   else
5758   {
5759     last_run = &This->indexCache[This->indexCacheLen-1];
5760     next_offset = last_run->lastOffset+1;
5761     hr = StorageImpl_GetNextBlockInChain(This->parentStorage,
5762         last_run->firstSector + last_run->lastOffset - last_run->firstOffset,
5763         &next_sector);
5764     if (FAILED(hr)) return hr;
5765   }
5766
5767   while (next_sector != BLOCK_END_OF_CHAIN)
5768   {
5769     if (!last_run || next_sector != last_run->firstSector + next_offset - last_run->firstOffset)
5770     {
5771       /* Add the current block to the cache. */
5772       if (This->indexCacheSize == 0)
5773       {
5774         This->indexCache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*16);
5775         if (!This->indexCache) return E_OUTOFMEMORY;
5776         This->indexCacheSize = 16;
5777       }
5778       else if (This->indexCacheSize == This->indexCacheLen)
5779       {
5780         struct BlockChainRun *new_cache;
5781         ULONG new_size;
5782
5783         new_size = This->indexCacheSize * 2;
5784         new_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*new_size);
5785         if (!new_cache) return E_OUTOFMEMORY;
5786         memcpy(new_cache, This->indexCache, sizeof(struct BlockChainRun)*This->indexCacheLen);
5787
5788         HeapFree(GetProcessHeap(), 0, This->indexCache);
5789         This->indexCache = new_cache;
5790         This->indexCacheSize = new_size;
5791       }
5792
5793       This->indexCacheLen++;
5794       last_run = &This->indexCache[This->indexCacheLen-1];
5795       last_run->firstSector = next_sector;
5796       last_run->firstOffset = next_offset;
5797     }
5798
5799     last_run->lastOffset = next_offset;
5800
5801     /* Find the next block. */
5802     next_offset++;
5803     hr = StorageImpl_GetNextBlockInChain(This->parentStorage, next_sector, &next_sector);
5804     if (FAILED(hr)) return hr;
5805   }
5806
5807   if (This->indexCacheLen)
5808   {
5809     This->tailIndex = last_run->firstSector + last_run->lastOffset - last_run->firstOffset;
5810     This->numBlocks = last_run->lastOffset+1;
5811   }
5812   else
5813   {
5814     This->tailIndex = BLOCK_END_OF_CHAIN;
5815     This->numBlocks = 0;
5816   }
5817
5818   return S_OK;
5819 }
5820
5821 /* Locate the nth block in this stream. */
5822 ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset)
5823 {
5824   ULONG min_offset = 0, max_offset = This->numBlocks-1;
5825   ULONG min_run = 0, max_run = This->indexCacheLen-1;
5826
5827   if (offset >= This->numBlocks)
5828     return BLOCK_END_OF_CHAIN;
5829
5830   while (min_run < max_run)
5831   {
5832     ULONG run_to_check = min_run + (offset - min_offset) * (max_run - min_run) / (max_offset - min_offset);
5833     if (offset < This->indexCache[run_to_check].firstOffset)
5834     {
5835       max_offset = This->indexCache[run_to_check].firstOffset-1;
5836       max_run = run_to_check-1;
5837     }
5838     else if (offset > This->indexCache[run_to_check].lastOffset)
5839     {
5840       min_offset = This->indexCache[run_to_check].lastOffset+1;
5841       min_run = run_to_check+1;
5842     }
5843     else
5844       /* Block is in this run. */
5845       min_run = max_run = run_to_check;
5846   }
5847
5848   return This->indexCache[min_run].firstSector + offset - This->indexCache[min_run].firstOffset;
5849 }
5850
5851 HRESULT BlockChainStream_GetBlockAtOffset(BlockChainStream *This,
5852     ULONG index, BlockChainBlock **block, ULONG *sector, BOOL create)
5853 {
5854   BlockChainBlock *result=NULL;
5855   int i;
5856
5857   for (i=0; i<2; i++)
5858     if (This->cachedBlocks[i].index == index)
5859     {
5860       *sector = This->cachedBlocks[i].sector;
5861       *block = &This->cachedBlocks[i];
5862       return S_OK;
5863     }
5864
5865   *sector = BlockChainStream_GetSectorOfOffset(This, index);
5866   if (*sector == BLOCK_END_OF_CHAIN)
5867     return STG_E_DOCFILECORRUPT;
5868
5869   if (create)
5870   {
5871     if (This->cachedBlocks[0].index == 0xffffffff)
5872       result = &This->cachedBlocks[0];
5873     else if (This->cachedBlocks[1].index == 0xffffffff)
5874       result = &This->cachedBlocks[1];
5875     else
5876     {
5877       result = &This->cachedBlocks[This->blockToEvict++];
5878       if (This->blockToEvict == 2)
5879         This->blockToEvict = 0;
5880     }
5881
5882     if (result->dirty)
5883     {
5884       if (!StorageImpl_WriteBigBlock(This->parentStorage, result->sector, result->data))
5885         return STG_E_WRITEFAULT;
5886       result->dirty = 0;
5887     }
5888
5889     result->read = 0;
5890     result->index = index;
5891     result->sector = *sector;
5892   }
5893
5894   *block = result;
5895   return S_OK;
5896 }
5897
5898 BlockChainStream* BlockChainStream_Construct(
5899   StorageImpl* parentStorage,
5900   ULONG*         headOfStreamPlaceHolder,
5901   DirRef         dirEntry)
5902 {
5903   BlockChainStream* newStream;
5904
5905   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
5906
5907   newStream->parentStorage           = parentStorage;
5908   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
5909   newStream->ownerDirEntry           = dirEntry;
5910   newStream->indexCache              = NULL;
5911   newStream->indexCacheLen           = 0;
5912   newStream->indexCacheSize          = 0;
5913   newStream->cachedBlocks[0].index = 0xffffffff;
5914   newStream->cachedBlocks[0].dirty = 0;
5915   newStream->cachedBlocks[1].index = 0xffffffff;
5916   newStream->cachedBlocks[1].dirty = 0;
5917   newStream->blockToEvict          = 0;
5918
5919   if (FAILED(BlockChainStream_UpdateIndexCache(newStream)))
5920   {
5921     HeapFree(GetProcessHeap(), 0, newStream->indexCache);
5922     HeapFree(GetProcessHeap(), 0, newStream);
5923     return NULL;
5924   }
5925
5926   return newStream;
5927 }
5928
5929 HRESULT BlockChainStream_Flush(BlockChainStream* This)
5930 {
5931   int i;
5932   if (!This) return S_OK;
5933   for (i=0; i<2; i++)
5934   {
5935     if (This->cachedBlocks[i].dirty)
5936     {
5937       if (StorageImpl_WriteBigBlock(This->parentStorage, This->cachedBlocks[i].sector, This->cachedBlocks[i].data))
5938         This->cachedBlocks[i].dirty = 0;
5939       else
5940         return STG_E_WRITEFAULT;
5941     }
5942   }
5943   return S_OK;
5944 }
5945
5946 void BlockChainStream_Destroy(BlockChainStream* This)
5947 {
5948   if (This)
5949   {
5950     BlockChainStream_Flush(This);
5951     HeapFree(GetProcessHeap(), 0, This->indexCache);
5952   }
5953   HeapFree(GetProcessHeap(), 0, This);
5954 }
5955
5956 /******************************************************************************
5957  *      BlockChainStream_GetHeadOfChain
5958  *
5959  * Returns the head of this stream chain.
5960  * Some special chains don't have directory entries, their heads are kept in
5961  * This->headOfStreamPlaceHolder.
5962  *
5963  */
5964 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
5965 {
5966   DirEntry  chainEntry;
5967   HRESULT   hr;
5968
5969   if (This->headOfStreamPlaceHolder != 0)
5970     return *(This->headOfStreamPlaceHolder);
5971
5972   if (This->ownerDirEntry != DIRENTRY_NULL)
5973   {
5974     hr = StorageImpl_ReadDirEntry(
5975                       This->parentStorage,
5976                       This->ownerDirEntry,
5977                       &chainEntry);
5978
5979     if (SUCCEEDED(hr))
5980     {
5981       return chainEntry.startingBlock;
5982     }
5983   }
5984
5985   return BLOCK_END_OF_CHAIN;
5986 }
5987
5988 /******************************************************************************
5989  *       BlockChainStream_GetCount
5990  *
5991  * Returns the number of blocks that comprises this chain.
5992  * This is not the size of the stream as the last block may not be full!
5993  */
5994 static ULONG BlockChainStream_GetCount(BlockChainStream* This)
5995 {
5996   return This->numBlocks;
5997 }
5998
5999 /******************************************************************************
6000  *      BlockChainStream_ReadAt
6001  *
6002  * Reads a specified number of bytes from this chain at the specified offset.
6003  * bytesRead may be NULL.
6004  * Failure will be returned if the specified number of bytes has not been read.
6005  */
6006 HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
6007   ULARGE_INTEGER offset,
6008   ULONG          size,
6009   void*          buffer,
6010   ULONG*         bytesRead)
6011 {
6012   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
6013   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
6014   ULONG bytesToReadInBuffer;
6015   ULONG blockIndex;
6016   BYTE* bufferWalker;
6017   ULARGE_INTEGER stream_size;
6018   HRESULT hr;
6019   BlockChainBlock *cachedBlock;
6020
6021   TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
6022
6023   /*
6024    * Find the first block in the stream that contains part of the buffer.
6025    */
6026   blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
6027
6028   *bytesRead   = 0;
6029
6030   stream_size = BlockChainStream_GetSize(This);
6031   if (stream_size.QuadPart > offset.QuadPart)
6032     size = min(stream_size.QuadPart - offset.QuadPart, size);
6033   else
6034     return S_OK;
6035
6036   /*
6037    * Start reading the buffer.
6038    */
6039   bufferWalker = buffer;
6040
6041   while (size > 0)
6042   {
6043     ULARGE_INTEGER ulOffset;
6044     DWORD bytesReadAt;
6045
6046     /*
6047      * Calculate how many bytes we can copy from this big block.
6048      */
6049     bytesToReadInBuffer =
6050       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
6051
6052     hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToReadInBuffer);
6053
6054     if (FAILED(hr))
6055       return hr;
6056
6057     if (!cachedBlock)
6058     {
6059       /* Not in cache, and we're going to read past the end of the block. */
6060       ulOffset.u.HighPart = 0;
6061       ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
6062                                offsetInBlock;
6063
6064       StorageImpl_ReadAt(This->parentStorage,
6065            ulOffset,
6066            bufferWalker,
6067            bytesToReadInBuffer,
6068            &bytesReadAt);
6069     }
6070     else
6071     {
6072       if (!cachedBlock->read)
6073       {
6074         if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
6075           return STG_E_READFAULT;
6076
6077         cachedBlock->read = 1;
6078       }
6079
6080       memcpy(bufferWalker, cachedBlock->data+offsetInBlock, bytesToReadInBuffer);
6081       bytesReadAt = bytesToReadInBuffer;
6082     }
6083
6084     blockNoInSequence++;
6085     bufferWalker += bytesReadAt;
6086     size         -= bytesReadAt;
6087     *bytesRead   += bytesReadAt;
6088     offsetInBlock = 0;  /* There is no offset on the next block */
6089
6090     if (bytesToReadInBuffer != bytesReadAt)
6091         break;
6092   }
6093
6094   return S_OK;
6095 }
6096
6097 /******************************************************************************
6098  *      BlockChainStream_WriteAt
6099  *
6100  * Writes the specified number of bytes to this chain at the specified offset.
6101  * Will fail if not all specified number of bytes have been written.
6102  */
6103 HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
6104   ULARGE_INTEGER    offset,
6105   ULONG             size,
6106   const void*       buffer,
6107   ULONG*            bytesWritten)
6108 {
6109   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
6110   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
6111   ULONG bytesToWrite;
6112   ULONG blockIndex;
6113   const BYTE* bufferWalker;
6114   HRESULT hr;
6115   BlockChainBlock *cachedBlock;
6116
6117   *bytesWritten   = 0;
6118   bufferWalker = buffer;
6119
6120   while (size > 0)
6121   {
6122     ULARGE_INTEGER ulOffset;
6123     DWORD bytesWrittenAt;
6124
6125     /*
6126      * Calculate how many bytes we can copy to this big block.
6127      */
6128     bytesToWrite =
6129       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
6130
6131     hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToWrite);
6132
6133     /* BlockChainStream_SetSize should have already been called to ensure we have
6134      * enough blocks in the chain to write into */
6135     if (FAILED(hr))
6136     {
6137       ERR("not enough blocks in chain to write data\n");
6138       return hr;
6139     }
6140
6141     if (!cachedBlock)
6142     {
6143       /* Not in cache, and we're going to write past the end of the block. */
6144       ulOffset.u.HighPart = 0;
6145       ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
6146                                offsetInBlock;
6147
6148       StorageImpl_WriteAt(This->parentStorage,
6149            ulOffset,
6150            bufferWalker,
6151            bytesToWrite,
6152            &bytesWrittenAt);
6153     }
6154     else
6155     {
6156       if (!cachedBlock->read && bytesToWrite != This->parentStorage->bigBlockSize)
6157       {
6158         if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
6159           return STG_E_READFAULT;
6160       }
6161
6162       memcpy(cachedBlock->data+offsetInBlock, bufferWalker, bytesToWrite);
6163       bytesWrittenAt = bytesToWrite;
6164       cachedBlock->read = 1;
6165       cachedBlock->dirty = 1;
6166     }
6167
6168     blockNoInSequence++;
6169     bufferWalker  += bytesWrittenAt;
6170     size          -= bytesWrittenAt;
6171     *bytesWritten += bytesWrittenAt;
6172     offsetInBlock  = 0;      /* There is no offset on the next block */
6173
6174     if (bytesWrittenAt != bytesToWrite)
6175       break;
6176   }
6177
6178   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
6179 }
6180
6181 /******************************************************************************
6182  *      BlockChainStream_Shrink
6183  *
6184  * Shrinks this chain in the big block depot.
6185  */
6186 static BOOL BlockChainStream_Shrink(BlockChainStream* This,
6187                                     ULARGE_INTEGER    newSize)
6188 {
6189   ULONG blockIndex;
6190   ULONG numBlocks;
6191   int i;
6192
6193   /*
6194    * Figure out how many blocks are needed to contain the new size
6195    */
6196   numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
6197
6198   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
6199     numBlocks++;
6200
6201   if (numBlocks)
6202   {
6203     /*
6204      * Go to the new end of chain
6205      */
6206     blockIndex = BlockChainStream_GetSectorOfOffset(This, numBlocks-1);
6207
6208     /* Mark the new end of chain */
6209     StorageImpl_SetNextBlockInChain(
6210       This->parentStorage,
6211       blockIndex,
6212       BLOCK_END_OF_CHAIN);
6213
6214     This->tailIndex = blockIndex;
6215   }
6216   else
6217   {
6218     if (This->headOfStreamPlaceHolder != 0)
6219     {
6220       *This->headOfStreamPlaceHolder = BLOCK_END_OF_CHAIN;
6221     }
6222     else
6223     {
6224       DirEntry chainEntry;
6225       assert(This->ownerDirEntry != DIRENTRY_NULL);
6226
6227       StorageImpl_ReadDirEntry(
6228         This->parentStorage,
6229         This->ownerDirEntry,
6230         &chainEntry);
6231
6232       chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
6233
6234       StorageImpl_WriteDirEntry(
6235         This->parentStorage,
6236         This->ownerDirEntry,
6237         &chainEntry);
6238     }
6239
6240     This->tailIndex = BLOCK_END_OF_CHAIN;
6241   }
6242
6243   This->numBlocks = numBlocks;
6244
6245   /*
6246    * Mark the extra blocks as free
6247    */
6248   while (This->indexCacheLen && This->indexCache[This->indexCacheLen-1].lastOffset >= numBlocks)
6249   {
6250     struct BlockChainRun *last_run = &This->indexCache[This->indexCacheLen-1];
6251     StorageImpl_FreeBigBlock(This->parentStorage,
6252       last_run->firstSector + last_run->lastOffset - last_run->firstOffset);
6253     if (last_run->lastOffset == last_run->firstOffset)
6254       This->indexCacheLen--;
6255     else
6256       last_run->lastOffset--;
6257   }
6258
6259   /*
6260    * Reset the last accessed block cache.
6261    */
6262   for (i=0; i<2; i++)
6263   {
6264     if (This->cachedBlocks[i].index >= numBlocks)
6265     {
6266       This->cachedBlocks[i].index = 0xffffffff;
6267       This->cachedBlocks[i].dirty = 0;
6268     }
6269   }
6270
6271   return TRUE;
6272 }
6273
6274 /******************************************************************************
6275  *      BlockChainStream_Enlarge
6276  *
6277  * Grows this chain in the big block depot.
6278  */
6279 static BOOL BlockChainStream_Enlarge(BlockChainStream* This,
6280                                      ULARGE_INTEGER    newSize)
6281 {
6282   ULONG blockIndex, currentBlock;
6283   ULONG newNumBlocks;
6284   ULONG oldNumBlocks = 0;
6285
6286   blockIndex = BlockChainStream_GetHeadOfChain(This);
6287
6288   /*
6289    * Empty chain. Create the head.
6290    */
6291   if (blockIndex == BLOCK_END_OF_CHAIN)
6292   {
6293     blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
6294     StorageImpl_SetNextBlockInChain(This->parentStorage,
6295                                       blockIndex,
6296                                       BLOCK_END_OF_CHAIN);
6297
6298     if (This->headOfStreamPlaceHolder != 0)
6299     {
6300       *(This->headOfStreamPlaceHolder) = blockIndex;
6301     }
6302     else
6303     {
6304       DirEntry chainEntry;
6305       assert(This->ownerDirEntry != DIRENTRY_NULL);
6306
6307       StorageImpl_ReadDirEntry(
6308         This->parentStorage,
6309         This->ownerDirEntry,
6310         &chainEntry);
6311
6312       chainEntry.startingBlock = blockIndex;
6313
6314       StorageImpl_WriteDirEntry(
6315         This->parentStorage,
6316         This->ownerDirEntry,
6317         &chainEntry);
6318     }
6319
6320     This->tailIndex = blockIndex;
6321     This->numBlocks = 1;
6322   }
6323
6324   /*
6325    * Figure out how many blocks are needed to contain this stream
6326    */
6327   newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
6328
6329   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
6330     newNumBlocks++;
6331
6332   /*
6333    * Go to the current end of chain
6334    */
6335   if (This->tailIndex == BLOCK_END_OF_CHAIN)
6336   {
6337     currentBlock = blockIndex;
6338
6339     while (blockIndex != BLOCK_END_OF_CHAIN)
6340     {
6341       This->numBlocks++;
6342       currentBlock = blockIndex;
6343
6344       if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
6345                                                 &blockIndex)))
6346         return FALSE;
6347     }
6348
6349     This->tailIndex = currentBlock;
6350   }
6351
6352   currentBlock = This->tailIndex;
6353   oldNumBlocks = This->numBlocks;
6354
6355   /*
6356    * Add new blocks to the chain
6357    */
6358   if (oldNumBlocks < newNumBlocks)
6359   {
6360     while (oldNumBlocks < newNumBlocks)
6361     {
6362       blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
6363
6364       StorageImpl_SetNextBlockInChain(
6365         This->parentStorage,
6366         currentBlock,
6367         blockIndex);
6368
6369       StorageImpl_SetNextBlockInChain(
6370         This->parentStorage,
6371         blockIndex,
6372         BLOCK_END_OF_CHAIN);
6373
6374       currentBlock = blockIndex;
6375       oldNumBlocks++;
6376     }
6377
6378     This->tailIndex = blockIndex;
6379     This->numBlocks = newNumBlocks;
6380   }
6381
6382   if (FAILED(BlockChainStream_UpdateIndexCache(This)))
6383     return FALSE;
6384
6385   return TRUE;
6386 }
6387
6388 /******************************************************************************
6389  *      BlockChainStream_SetSize
6390  *
6391  * Sets the size of this stream. The big block depot will be updated.
6392  * The file will grow if we grow the chain.
6393  *
6394  * TODO: Free the actual blocks in the file when we shrink the chain.
6395  *       Currently, the blocks are still in the file. So the file size
6396  *       doesn't shrink even if we shrink streams.
6397  */
6398 BOOL BlockChainStream_SetSize(
6399   BlockChainStream* This,
6400   ULARGE_INTEGER    newSize)
6401 {
6402   ULARGE_INTEGER size = BlockChainStream_GetSize(This);
6403
6404   if (newSize.u.LowPart == size.u.LowPart)
6405     return TRUE;
6406
6407   if (newSize.u.LowPart < size.u.LowPart)
6408   {
6409     BlockChainStream_Shrink(This, newSize);
6410   }
6411   else
6412   {
6413     BlockChainStream_Enlarge(This, newSize);
6414   }
6415
6416   return TRUE;
6417 }
6418
6419 /******************************************************************************
6420  *      BlockChainStream_GetSize
6421  *
6422  * Returns the size of this chain.
6423  * Will return the block count if this chain doesn't have a directory entry.
6424  */
6425 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
6426 {
6427   DirEntry chainEntry;
6428
6429   if(This->headOfStreamPlaceHolder == NULL)
6430   {
6431     /*
6432      * This chain has a directory entry so use the size value from there.
6433      */
6434     StorageImpl_ReadDirEntry(
6435       This->parentStorage,
6436       This->ownerDirEntry,
6437       &chainEntry);
6438
6439     return chainEntry.size;
6440   }
6441   else
6442   {
6443     /*
6444      * this chain is a chain that does not have a directory entry, figure out the
6445      * size by making the product number of used blocks times the
6446      * size of them
6447      */
6448     ULARGE_INTEGER result;
6449     result.u.HighPart = 0;
6450
6451     result.u.LowPart  =
6452       BlockChainStream_GetCount(This) *
6453       This->parentStorage->bigBlockSize;
6454
6455     return result;
6456   }
6457 }
6458
6459 /******************************************************************************
6460 ** SmallBlockChainStream implementation
6461 */
6462
6463 SmallBlockChainStream* SmallBlockChainStream_Construct(
6464   StorageImpl* parentStorage,
6465   ULONG*         headOfStreamPlaceHolder,
6466   DirRef         dirEntry)
6467 {
6468   SmallBlockChainStream* newStream;
6469
6470   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
6471
6472   newStream->parentStorage      = parentStorage;
6473   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
6474   newStream->ownerDirEntry      = dirEntry;
6475
6476   return newStream;
6477 }
6478
6479 void SmallBlockChainStream_Destroy(
6480   SmallBlockChainStream* This)
6481 {
6482   HeapFree(GetProcessHeap(), 0, This);
6483 }
6484
6485 /******************************************************************************
6486  *      SmallBlockChainStream_GetHeadOfChain
6487  *
6488  * Returns the head of this chain of small blocks.
6489  */
6490 static ULONG SmallBlockChainStream_GetHeadOfChain(
6491   SmallBlockChainStream* This)
6492 {
6493   DirEntry  chainEntry;
6494   HRESULT   hr;
6495
6496   if (This->headOfStreamPlaceHolder != NULL)
6497     return *(This->headOfStreamPlaceHolder);
6498
6499   if (This->ownerDirEntry)
6500   {
6501     hr = StorageImpl_ReadDirEntry(
6502                       This->parentStorage,
6503                       This->ownerDirEntry,
6504                       &chainEntry);
6505
6506     if (SUCCEEDED(hr))
6507     {
6508       return chainEntry.startingBlock;
6509     }
6510
6511   }
6512
6513   return BLOCK_END_OF_CHAIN;
6514 }
6515
6516 /******************************************************************************
6517  *      SmallBlockChainStream_GetNextBlockInChain
6518  *
6519  * Returns the index of the next small block in this chain.
6520  *
6521  * Return Values:
6522  *    - BLOCK_END_OF_CHAIN: end of this chain
6523  *    - BLOCK_UNUSED: small block 'blockIndex' is free
6524  */
6525 static HRESULT SmallBlockChainStream_GetNextBlockInChain(
6526   SmallBlockChainStream* This,
6527   ULONG                  blockIndex,
6528   ULONG*                 nextBlockInChain)
6529 {
6530   ULARGE_INTEGER offsetOfBlockInDepot;
6531   DWORD  buffer;
6532   ULONG  bytesRead;
6533   HRESULT res;
6534
6535   *nextBlockInChain = BLOCK_END_OF_CHAIN;
6536
6537   offsetOfBlockInDepot.u.HighPart = 0;
6538   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
6539
6540   /*
6541    * Read those bytes in the buffer from the small block file.
6542    */
6543   res = BlockChainStream_ReadAt(
6544               This->parentStorage->smallBlockDepotChain,
6545               offsetOfBlockInDepot,
6546               sizeof(DWORD),
6547               &buffer,
6548               &bytesRead);
6549
6550   if (SUCCEEDED(res) && bytesRead != sizeof(DWORD))
6551     res = STG_E_READFAULT;
6552
6553   if (SUCCEEDED(res))
6554   {
6555     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
6556     return S_OK;
6557   }
6558
6559   return res;
6560 }
6561
6562 /******************************************************************************
6563  *       SmallBlockChainStream_SetNextBlockInChain
6564  *
6565  * Writes the index of the next block of the specified block in the small
6566  * block depot.
6567  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
6568  * To flag a block as free use BLOCK_UNUSED as nextBlock.
6569  */
6570 static void SmallBlockChainStream_SetNextBlockInChain(
6571   SmallBlockChainStream* This,
6572   ULONG                  blockIndex,
6573   ULONG                  nextBlock)
6574 {
6575   ULARGE_INTEGER offsetOfBlockInDepot;
6576   DWORD  buffer;
6577   ULONG  bytesWritten;
6578
6579   offsetOfBlockInDepot.u.HighPart = 0;
6580   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
6581
6582   StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
6583
6584   /*
6585    * Read those bytes in the buffer from the small block file.
6586    */
6587   BlockChainStream_WriteAt(
6588     This->parentStorage->smallBlockDepotChain,
6589     offsetOfBlockInDepot,
6590     sizeof(DWORD),
6591     &buffer,
6592     &bytesWritten);
6593 }
6594
6595 /******************************************************************************
6596  *      SmallBlockChainStream_FreeBlock
6597  *
6598  * Flag small block 'blockIndex' as free in the small block depot.
6599  */
6600 static void SmallBlockChainStream_FreeBlock(
6601   SmallBlockChainStream* This,
6602   ULONG                  blockIndex)
6603 {
6604   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
6605 }
6606
6607 /******************************************************************************
6608  *      SmallBlockChainStream_GetNextFreeBlock
6609  *
6610  * Returns the index of a free small block. The small block depot will be
6611  * enlarged if necessary. The small block chain will also be enlarged if
6612  * necessary.
6613  */
6614 static ULONG SmallBlockChainStream_GetNextFreeBlock(
6615   SmallBlockChainStream* This)
6616 {
6617   ULARGE_INTEGER offsetOfBlockInDepot;
6618   DWORD buffer;
6619   ULONG bytesRead;
6620   ULONG blockIndex = This->parentStorage->firstFreeSmallBlock;
6621   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
6622   HRESULT res = S_OK;
6623   ULONG smallBlocksPerBigBlock;
6624   DirEntry rootEntry;
6625   ULONG blocksRequired;
6626   ULARGE_INTEGER old_size, size_required;
6627
6628   offsetOfBlockInDepot.u.HighPart = 0;
6629
6630   /*
6631    * Scan the small block depot for a free block
6632    */
6633   while (nextBlockIndex != BLOCK_UNUSED)
6634   {
6635     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
6636
6637     res = BlockChainStream_ReadAt(
6638                 This->parentStorage->smallBlockDepotChain,
6639                 offsetOfBlockInDepot,
6640                 sizeof(DWORD),
6641                 &buffer,
6642                 &bytesRead);
6643
6644     /*
6645      * If we run out of space for the small block depot, enlarge it
6646      */
6647     if (SUCCEEDED(res) && bytesRead == sizeof(DWORD))
6648     {
6649       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
6650
6651       if (nextBlockIndex != BLOCK_UNUSED)
6652         blockIndex++;
6653     }
6654     else
6655     {
6656       ULONG count =
6657         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
6658
6659       BYTE smallBlockDepot[MAX_BIG_BLOCK_SIZE];
6660       ULARGE_INTEGER newSize, offset;
6661       ULONG bytesWritten;
6662
6663       newSize.QuadPart = (count + 1) * This->parentStorage->bigBlockSize;
6664       BlockChainStream_Enlarge(This->parentStorage->smallBlockDepotChain, newSize);
6665
6666       /*
6667        * Initialize all the small blocks to free
6668        */
6669       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
6670       offset.QuadPart = count * This->parentStorage->bigBlockSize;
6671       BlockChainStream_WriteAt(This->parentStorage->smallBlockDepotChain,
6672         offset, This->parentStorage->bigBlockSize, smallBlockDepot, &bytesWritten);
6673
6674       StorageImpl_SaveFileHeader(This->parentStorage);
6675     }
6676   }
6677
6678   This->parentStorage->firstFreeSmallBlock = blockIndex+1;
6679
6680   smallBlocksPerBigBlock =
6681     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
6682
6683   /*
6684    * Verify if we have to allocate big blocks to contain small blocks
6685    */
6686   blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
6687
6688   size_required.QuadPart = blocksRequired * This->parentStorage->bigBlockSize;
6689
6690   old_size = BlockChainStream_GetSize(This->parentStorage->smallBlockRootChain);
6691
6692   if (size_required.QuadPart > old_size.QuadPart)
6693   {
6694     BlockChainStream_SetSize(
6695       This->parentStorage->smallBlockRootChain,
6696       size_required);
6697
6698     StorageImpl_ReadDirEntry(
6699       This->parentStorage,
6700       This->parentStorage->base.storageDirEntry,
6701       &rootEntry);
6702
6703     rootEntry.size = size_required;
6704
6705     StorageImpl_WriteDirEntry(
6706       This->parentStorage,
6707       This->parentStorage->base.storageDirEntry,
6708       &rootEntry);
6709   }
6710
6711   return blockIndex;
6712 }
6713
6714 /******************************************************************************
6715  *      SmallBlockChainStream_ReadAt
6716  *
6717  * Reads a specified number of bytes from this chain at the specified offset.
6718  * bytesRead may be NULL.
6719  * Failure will be returned if the specified number of bytes has not been read.
6720  */
6721 HRESULT SmallBlockChainStream_ReadAt(
6722   SmallBlockChainStream* This,
6723   ULARGE_INTEGER         offset,
6724   ULONG                  size,
6725   void*                  buffer,
6726   ULONG*                 bytesRead)
6727 {
6728   HRESULT rc = S_OK;
6729   ULARGE_INTEGER offsetInBigBlockFile;
6730   ULONG blockNoInSequence =
6731     offset.u.LowPart / This->parentStorage->smallBlockSize;
6732
6733   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
6734   ULONG bytesToReadInBuffer;
6735   ULONG blockIndex;
6736   ULONG bytesReadFromBigBlockFile;
6737   BYTE* bufferWalker;
6738   ULARGE_INTEGER stream_size;
6739
6740   /*
6741    * This should never happen on a small block file.
6742    */
6743   assert(offset.u.HighPart==0);
6744
6745   *bytesRead   = 0;
6746
6747   stream_size = SmallBlockChainStream_GetSize(This);
6748   if (stream_size.QuadPart > offset.QuadPart)
6749     size = min(stream_size.QuadPart - offset.QuadPart, size);
6750   else
6751     return S_OK;
6752
6753   /*
6754    * Find the first block in the stream that contains part of the buffer.
6755    */
6756   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
6757
6758   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
6759   {
6760     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
6761     if(FAILED(rc))
6762       return rc;
6763     blockNoInSequence--;
6764   }
6765
6766   /*
6767    * Start reading the buffer.
6768    */
6769   bufferWalker = buffer;
6770
6771   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
6772   {
6773     /*
6774      * Calculate how many bytes we can copy from this small block.
6775      */
6776     bytesToReadInBuffer =
6777       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
6778
6779     /*
6780      * Calculate the offset of the small block in the small block file.
6781      */
6782     offsetInBigBlockFile.u.HighPart  = 0;
6783     offsetInBigBlockFile.u.LowPart   =
6784       blockIndex * This->parentStorage->smallBlockSize;
6785
6786     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
6787
6788     /*
6789      * Read those bytes in the buffer from the small block file.
6790      * The small block has already been identified so it shouldn't fail
6791      * unless the file is corrupt.
6792      */
6793     rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
6794       offsetInBigBlockFile,
6795       bytesToReadInBuffer,
6796       bufferWalker,
6797       &bytesReadFromBigBlockFile);
6798
6799     if (FAILED(rc))
6800       return rc;
6801
6802     if (!bytesReadFromBigBlockFile)
6803       return STG_E_DOCFILECORRUPT;
6804
6805     /*
6806      * Step to the next big block.
6807      */
6808     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
6809     if(FAILED(rc))
6810       return STG_E_DOCFILECORRUPT;
6811
6812     bufferWalker += bytesReadFromBigBlockFile;
6813     size         -= bytesReadFromBigBlockFile;
6814     *bytesRead   += bytesReadFromBigBlockFile;
6815     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
6816   }
6817
6818   return S_OK;
6819 }
6820
6821 /******************************************************************************
6822  *       SmallBlockChainStream_WriteAt
6823  *
6824  * Writes the specified number of bytes to this chain at the specified offset.
6825  * Will fail if not all specified number of bytes have been written.
6826  */
6827 HRESULT SmallBlockChainStream_WriteAt(
6828   SmallBlockChainStream* This,
6829   ULARGE_INTEGER offset,
6830   ULONG          size,
6831   const void*    buffer,
6832   ULONG*         bytesWritten)
6833 {
6834   ULARGE_INTEGER offsetInBigBlockFile;
6835   ULONG blockNoInSequence =
6836     offset.u.LowPart / This->parentStorage->smallBlockSize;
6837
6838   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
6839   ULONG bytesToWriteInBuffer;
6840   ULONG blockIndex;
6841   ULONG bytesWrittenToBigBlockFile;
6842   const BYTE* bufferWalker;
6843   HRESULT res;
6844
6845   /*
6846    * This should never happen on a small block file.
6847    */
6848   assert(offset.u.HighPart==0);
6849
6850   /*
6851    * Find the first block in the stream that contains part of the buffer.
6852    */
6853   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
6854
6855   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
6856   {
6857     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
6858       return STG_E_DOCFILECORRUPT;
6859     blockNoInSequence--;
6860   }
6861
6862   /*
6863    * Start writing the buffer.
6864    */
6865   *bytesWritten   = 0;
6866   bufferWalker = buffer;
6867   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
6868   {
6869     /*
6870      * Calculate how many bytes we can copy to this small block.
6871      */
6872     bytesToWriteInBuffer =
6873       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
6874
6875     /*
6876      * Calculate the offset of the small block in the small block file.
6877      */
6878     offsetInBigBlockFile.u.HighPart  = 0;
6879     offsetInBigBlockFile.u.LowPart   =
6880       blockIndex * This->parentStorage->smallBlockSize;
6881
6882     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
6883
6884     /*
6885      * Write those bytes in the buffer to the small block file.
6886      */
6887     res = BlockChainStream_WriteAt(
6888       This->parentStorage->smallBlockRootChain,
6889       offsetInBigBlockFile,
6890       bytesToWriteInBuffer,
6891       bufferWalker,
6892       &bytesWrittenToBigBlockFile);
6893     if (FAILED(res))
6894       return res;
6895
6896     /*
6897      * Step to the next big block.
6898      */
6899     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
6900                                                         &blockIndex)))
6901       return FALSE;
6902     bufferWalker  += bytesWrittenToBigBlockFile;
6903     size          -= bytesWrittenToBigBlockFile;
6904     *bytesWritten += bytesWrittenToBigBlockFile;
6905     offsetInBlock  = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
6906   }
6907
6908   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
6909 }
6910
6911 /******************************************************************************
6912  *       SmallBlockChainStream_Shrink
6913  *
6914  * Shrinks this chain in the small block depot.
6915  */
6916 static BOOL SmallBlockChainStream_Shrink(
6917   SmallBlockChainStream* This,
6918   ULARGE_INTEGER newSize)
6919 {
6920   ULONG blockIndex, extraBlock;
6921   ULONG numBlocks;
6922   ULONG count = 0;
6923
6924   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
6925
6926   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
6927     numBlocks++;
6928
6929   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
6930
6931   /*
6932    * Go to the new end of chain
6933    */
6934   while (count < numBlocks)
6935   {
6936     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
6937                                                         &blockIndex)))
6938       return FALSE;
6939     count++;
6940   }
6941
6942   /*
6943    * If the count is 0, we have a special case, the head of the chain was
6944    * just freed.
6945    */
6946   if (count == 0)
6947   {
6948     DirEntry chainEntry;
6949
6950     StorageImpl_ReadDirEntry(This->parentStorage,
6951                              This->ownerDirEntry,
6952                              &chainEntry);
6953
6954     chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
6955
6956     StorageImpl_WriteDirEntry(This->parentStorage,
6957                               This->ownerDirEntry,
6958                               &chainEntry);
6959
6960     /*
6961      * We start freeing the chain at the head block.
6962      */
6963     extraBlock = blockIndex;
6964   }
6965   else
6966   {
6967     /* Get the next block before marking the new end */
6968     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
6969                                                         &extraBlock)))
6970       return FALSE;
6971
6972     /* Mark the new end of chain */
6973     SmallBlockChainStream_SetNextBlockInChain(
6974       This,
6975       blockIndex,
6976       BLOCK_END_OF_CHAIN);
6977   }
6978
6979   /*
6980    * Mark the extra blocks as free
6981    */
6982   while (extraBlock != BLOCK_END_OF_CHAIN)
6983   {
6984     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
6985                                                         &blockIndex)))
6986       return FALSE;
6987     SmallBlockChainStream_FreeBlock(This, extraBlock);
6988     This->parentStorage->firstFreeSmallBlock = min(This->parentStorage->firstFreeSmallBlock, extraBlock);
6989     extraBlock = blockIndex;
6990   }
6991
6992   return TRUE;
6993 }
6994
6995 /******************************************************************************
6996  *      SmallBlockChainStream_Enlarge
6997  *
6998  * Grows this chain in the small block depot.
6999  */
7000 static BOOL SmallBlockChainStream_Enlarge(
7001   SmallBlockChainStream* This,
7002   ULARGE_INTEGER newSize)
7003 {
7004   ULONG blockIndex, currentBlock;
7005   ULONG newNumBlocks;
7006   ULONG oldNumBlocks = 0;
7007
7008   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
7009
7010   /*
7011    * Empty chain. Create the head.
7012    */
7013   if (blockIndex == BLOCK_END_OF_CHAIN)
7014   {
7015     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
7016     SmallBlockChainStream_SetNextBlockInChain(
7017         This,
7018         blockIndex,
7019         BLOCK_END_OF_CHAIN);
7020
7021     if (This->headOfStreamPlaceHolder != NULL)
7022     {
7023       *(This->headOfStreamPlaceHolder) = blockIndex;
7024     }
7025     else
7026     {
7027       DirEntry chainEntry;
7028
7029       StorageImpl_ReadDirEntry(This->parentStorage, This->ownerDirEntry,
7030                                    &chainEntry);
7031
7032       chainEntry.startingBlock = blockIndex;
7033
7034       StorageImpl_WriteDirEntry(This->parentStorage, This->ownerDirEntry,
7035                                   &chainEntry);
7036     }
7037   }
7038
7039   currentBlock = blockIndex;
7040
7041   /*
7042    * Figure out how many blocks are needed to contain this stream
7043    */
7044   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
7045
7046   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
7047     newNumBlocks++;
7048
7049   /*
7050    * Go to the current end of chain
7051    */
7052   while (blockIndex != BLOCK_END_OF_CHAIN)
7053   {
7054     oldNumBlocks++;
7055     currentBlock = blockIndex;
7056     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
7057       return FALSE;
7058   }
7059
7060   /*
7061    * Add new blocks to the chain
7062    */
7063   while (oldNumBlocks < newNumBlocks)
7064   {
7065     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
7066     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
7067
7068     SmallBlockChainStream_SetNextBlockInChain(
7069       This,
7070       blockIndex,
7071       BLOCK_END_OF_CHAIN);
7072
7073     currentBlock = blockIndex;
7074     oldNumBlocks++;
7075   }
7076
7077   return TRUE;
7078 }
7079
7080 /******************************************************************************
7081  *      SmallBlockChainStream_SetSize
7082  *
7083  * Sets the size of this stream.
7084  * The file will grow if we grow the chain.
7085  *
7086  * TODO: Free the actual blocks in the file when we shrink the chain.
7087  *       Currently, the blocks are still in the file. So the file size
7088  *       doesn't shrink even if we shrink streams.
7089  */
7090 BOOL SmallBlockChainStream_SetSize(
7091                 SmallBlockChainStream* This,
7092                 ULARGE_INTEGER    newSize)
7093 {
7094   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
7095
7096   if (newSize.u.LowPart == size.u.LowPart)
7097     return TRUE;
7098
7099   if (newSize.u.LowPart < size.u.LowPart)
7100   {
7101     SmallBlockChainStream_Shrink(This, newSize);
7102   }
7103   else
7104   {
7105     SmallBlockChainStream_Enlarge(This, newSize);
7106   }
7107
7108   return TRUE;
7109 }
7110
7111 /******************************************************************************
7112  *       SmallBlockChainStream_GetCount
7113  *
7114  * Returns the number of small blocks that comprises this chain.
7115  * This is not the size of the stream as the last block may not be full!
7116  *
7117  */
7118 static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
7119 {
7120     ULONG blockIndex;
7121     ULONG count = 0;
7122
7123     blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
7124
7125     while(blockIndex != BLOCK_END_OF_CHAIN)
7126     {
7127         count++;
7128
7129         if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This,
7130                         blockIndex, &blockIndex)))
7131             return 0;
7132     }
7133
7134     return count;
7135 }
7136
7137 /******************************************************************************
7138  *      SmallBlockChainStream_GetSize
7139  *
7140  * Returns the size of this chain.
7141  */
7142 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
7143 {
7144   DirEntry chainEntry;
7145
7146   if(This->headOfStreamPlaceHolder != NULL)
7147   {
7148     ULARGE_INTEGER result;
7149     result.u.HighPart = 0;
7150
7151     result.u.LowPart = SmallBlockChainStream_GetCount(This) *
7152         This->parentStorage->smallBlockSize;
7153
7154     return result;
7155   }
7156
7157   StorageImpl_ReadDirEntry(
7158     This->parentStorage,
7159     This->ownerDirEntry,
7160     &chainEntry);
7161
7162   return chainEntry.size;
7163 }
7164
7165 static HRESULT create_storagefile(
7166   LPCOLESTR pwcsName,
7167   DWORD       grfMode,
7168   DWORD       grfAttrs,
7169   STGOPTIONS* pStgOptions,
7170   REFIID      riid,
7171   void**      ppstgOpen)
7172 {
7173   StorageBaseImpl* newStorage = 0;
7174   HANDLE       hFile      = INVALID_HANDLE_VALUE;
7175   HRESULT        hr         = STG_E_INVALIDFLAG;
7176   DWORD          shareMode;
7177   DWORD          accessMode;
7178   DWORD          creationMode;
7179   DWORD          fileAttributes;
7180   WCHAR          tempFileName[MAX_PATH];
7181
7182   if (ppstgOpen == 0)
7183     return STG_E_INVALIDPOINTER;
7184
7185   if (pStgOptions->ulSectorSize != MIN_BIG_BLOCK_SIZE && pStgOptions->ulSectorSize != MAX_BIG_BLOCK_SIZE)
7186     return STG_E_INVALIDPARAMETER;
7187
7188   /* if no share mode given then DENY_NONE is the default */
7189   if (STGM_SHARE_MODE(grfMode) == 0)
7190       grfMode |= STGM_SHARE_DENY_NONE;
7191
7192   if ( FAILED( validateSTGM(grfMode) ))
7193     goto end;
7194
7195   /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
7196   switch(STGM_ACCESS_MODE(grfMode))
7197   {
7198   case STGM_WRITE:
7199   case STGM_READWRITE:
7200     break;
7201   default:
7202     goto end;
7203   }
7204
7205   /* in direct mode, can only use SHARE_EXCLUSIVE */
7206   if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
7207     goto end;
7208
7209   /* but in transacted mode, any share mode is valid */
7210
7211   /*
7212    * Generate a unique name.
7213    */
7214   if (pwcsName == 0)
7215   {
7216     WCHAR tempPath[MAX_PATH];
7217     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
7218
7219     memset(tempPath, 0, sizeof(tempPath));
7220     memset(tempFileName, 0, sizeof(tempFileName));
7221
7222     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
7223       tempPath[0] = '.';
7224
7225     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
7226       pwcsName = tempFileName;
7227     else
7228     {
7229       hr = STG_E_INSUFFICIENTMEMORY;
7230       goto end;
7231     }
7232
7233     creationMode = TRUNCATE_EXISTING;
7234   }
7235   else
7236   {
7237     creationMode = GetCreationModeFromSTGM(grfMode);
7238   }
7239
7240   /*
7241    * Interpret the STGM value grfMode
7242    */
7243   shareMode    = FILE_SHARE_READ | FILE_SHARE_WRITE;
7244   accessMode   = GetAccessModeFromSTGM(grfMode);
7245
7246   if (grfMode & STGM_DELETEONRELEASE)
7247     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
7248   else
7249     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
7250
7251   if (STGM_SHARE_MODE(grfMode) && !(grfMode & STGM_SHARE_DENY_NONE))
7252   {
7253     static int fixme;
7254     if (!fixme++)
7255       FIXME("Storage share mode not implemented.\n");
7256   }
7257
7258   *ppstgOpen = 0;
7259
7260   hFile = CreateFileW(pwcsName,
7261                         accessMode,
7262                         shareMode,
7263                         NULL,
7264                         creationMode,
7265                         fileAttributes,
7266                         0);
7267
7268   if (hFile == INVALID_HANDLE_VALUE)
7269   {
7270     if(GetLastError() == ERROR_FILE_EXISTS)
7271       hr = STG_E_FILEALREADYEXISTS;
7272     else
7273       hr = E_FAIL;
7274     goto end;
7275   }
7276
7277   /*
7278    * Allocate and initialize the new IStorage32object.
7279    */
7280   hr = Storage_Construct(
7281          hFile,
7282         pwcsName,
7283          NULL,
7284          grfMode,
7285          TRUE,
7286          TRUE,
7287          pStgOptions->ulSectorSize,
7288          &newStorage);
7289
7290   if (FAILED(hr))
7291   {
7292     goto end;
7293   }
7294
7295   hr = IStorage_QueryInterface((IStorage*)newStorage, riid, ppstgOpen);
7296
7297   IStorage_Release((IStorage*)newStorage);
7298
7299 end:
7300   TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
7301
7302   return hr;
7303 }
7304
7305 /******************************************************************************
7306  *    StgCreateDocfile  [OLE32.@]
7307  * Creates a new compound file storage object
7308  *
7309  * PARAMS
7310  *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
7311  *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
7312  *  reserved  [ ?] unused?, usually 0
7313  *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
7314  *
7315  * RETURNS
7316  *  S_OK if the file was successfully created
7317  *  some STG_E_ value if error
7318  * NOTES
7319  *  if pwcsName is NULL, create file with new unique name
7320  *  the function can returns
7321  *  STG_S_CONVERTED if the specified file was successfully converted to storage format
7322  *  (unrealized now)
7323  */
7324 HRESULT WINAPI StgCreateDocfile(
7325   LPCOLESTR pwcsName,
7326   DWORD       grfMode,
7327   DWORD       reserved,
7328   IStorage  **ppstgOpen)
7329 {
7330   STGOPTIONS stgoptions = {1, 0, 512};
7331
7332   TRACE("(%s, %x, %d, %p)\n",
7333         debugstr_w(pwcsName), grfMode,
7334         reserved, ppstgOpen);
7335
7336   if (ppstgOpen == 0)
7337     return STG_E_INVALIDPOINTER;
7338   if (reserved != 0)
7339     return STG_E_INVALIDPARAMETER;
7340
7341   return create_storagefile(pwcsName, grfMode, 0, &stgoptions, &IID_IStorage, (void**)ppstgOpen);
7342 }
7343
7344 /******************************************************************************
7345  *              StgCreateStorageEx        [OLE32.@]
7346  */
7347 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
7348 {
7349     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
7350           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
7351
7352     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
7353     {
7354         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
7355         return STG_E_INVALIDPARAMETER;  
7356     }
7357
7358     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
7359     {
7360         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
7361         return STG_E_INVALIDPARAMETER;  
7362     }
7363
7364     if (stgfmt == STGFMT_FILE)
7365     {
7366         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
7367         return STG_E_INVALIDPARAMETER;
7368     }
7369
7370     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
7371     {
7372         return create_storagefile(pwcsName, grfMode, grfAttrs, pStgOptions, riid, ppObjectOpen);
7373     }
7374
7375
7376     ERR("Invalid stgfmt argument\n");
7377     return STG_E_INVALIDPARAMETER;
7378 }
7379
7380 /******************************************************************************
7381  *              StgCreatePropSetStg       [OLE32.@]
7382  */
7383 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
7384  IPropertySetStorage **ppPropSetStg)
7385 {
7386     HRESULT hr;
7387
7388     TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
7389     if (reserved)
7390         hr = STG_E_INVALIDPARAMETER;
7391     else
7392         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
7393          (void**)ppPropSetStg);
7394     return hr;
7395 }
7396
7397 /******************************************************************************
7398  *              StgOpenStorageEx      [OLE32.@]
7399  */
7400 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
7401 {
7402     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
7403           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
7404
7405     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
7406     {
7407         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
7408         return STG_E_INVALIDPARAMETER;  
7409     }
7410
7411     switch (stgfmt)
7412     {
7413     case STGFMT_FILE:
7414         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
7415         return STG_E_INVALIDPARAMETER;
7416         
7417     case STGFMT_STORAGE:
7418         break;
7419
7420     case STGFMT_DOCFILE:
7421         if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
7422         {
7423             ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
7424             return STG_E_INVALIDPARAMETER;  
7425         }
7426         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
7427         break;
7428
7429     case STGFMT_ANY:
7430         WARN("STGFMT_ANY assuming storage\n");
7431         break;
7432
7433     default:
7434         return STG_E_INVALIDPARAMETER;
7435     }
7436
7437     return StgOpenStorage(pwcsName, NULL, grfMode, NULL, 0, (IStorage **)ppObjectOpen);
7438 }
7439
7440
7441 /******************************************************************************
7442  *              StgOpenStorage        [OLE32.@]
7443  */
7444 HRESULT WINAPI StgOpenStorage(
7445   const OLECHAR *pwcsName,
7446   IStorage      *pstgPriority,
7447   DWORD          grfMode,
7448   SNB            snbExclude,
7449   DWORD          reserved,
7450   IStorage     **ppstgOpen)
7451 {
7452   StorageBaseImpl* newStorage = 0;
7453   HRESULT        hr = S_OK;
7454   HANDLE         hFile = 0;
7455   DWORD          shareMode;
7456   DWORD          accessMode;
7457
7458   TRACE("(%s, %p, %x, %p, %d, %p)\n",
7459         debugstr_w(pwcsName), pstgPriority, grfMode,
7460         snbExclude, reserved, ppstgOpen);
7461
7462   if (pwcsName == 0)
7463   {
7464     hr = STG_E_INVALIDNAME;
7465     goto end;
7466   }
7467
7468   if (ppstgOpen == 0)
7469   {
7470     hr = STG_E_INVALIDPOINTER;
7471     goto end;
7472   }
7473
7474   if (reserved)
7475   {
7476     hr = STG_E_INVALIDPARAMETER;
7477     goto end;
7478   }
7479
7480   if (grfMode & STGM_PRIORITY)
7481   {
7482     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
7483       return STG_E_INVALIDFLAG;
7484     if (grfMode & STGM_DELETEONRELEASE)
7485       return STG_E_INVALIDFUNCTION;
7486     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
7487       return STG_E_INVALIDFLAG;
7488     grfMode &= ~0xf0; /* remove the existing sharing mode */
7489     grfMode |= STGM_SHARE_DENY_NONE;
7490
7491     /* STGM_PRIORITY stops other IStorage objects on the same file from
7492      * committing until the STGM_PRIORITY IStorage is closed. it also
7493      * stops non-transacted mode StgOpenStorage calls with write access from
7494      * succeeding. obviously, both of these cannot be achieved through just
7495      * file share flags */
7496     FIXME("STGM_PRIORITY mode not implemented correctly\n");
7497   }
7498
7499   /*
7500    * Validate the sharing mode
7501    */
7502   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
7503     switch(STGM_SHARE_MODE(grfMode))
7504     {
7505       case STGM_SHARE_EXCLUSIVE:
7506       case STGM_SHARE_DENY_WRITE:
7507         break;
7508       default:
7509         hr = STG_E_INVALIDFLAG;
7510         goto end;
7511     }
7512
7513   if ( FAILED( validateSTGM(grfMode) ) ||
7514        (grfMode&STGM_CREATE))
7515   {
7516     hr = STG_E_INVALIDFLAG;
7517     goto end;
7518   }
7519
7520   /* shared reading requires transacted mode */
7521   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
7522       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
7523      !(grfMode&STGM_TRANSACTED) )
7524   {
7525     hr = STG_E_INVALIDFLAG;
7526     goto end;
7527   }
7528
7529   /*
7530    * Interpret the STGM value grfMode
7531    */
7532   shareMode    = GetShareModeFromSTGM(grfMode);
7533   accessMode   = GetAccessModeFromSTGM(grfMode);
7534
7535   *ppstgOpen = 0;
7536
7537   hFile = CreateFileW( pwcsName,
7538                        accessMode,
7539                        shareMode,
7540                        NULL,
7541                        OPEN_EXISTING,
7542                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
7543                        0);
7544
7545   if (hFile==INVALID_HANDLE_VALUE)
7546   {
7547     DWORD last_error = GetLastError();
7548
7549     hr = E_FAIL;
7550
7551     switch (last_error)
7552     {
7553       case ERROR_FILE_NOT_FOUND:
7554         hr = STG_E_FILENOTFOUND;
7555         break;
7556
7557       case ERROR_PATH_NOT_FOUND:
7558         hr = STG_E_PATHNOTFOUND;
7559         break;
7560
7561       case ERROR_ACCESS_DENIED:
7562       case ERROR_WRITE_PROTECT:
7563         hr = STG_E_ACCESSDENIED;
7564         break;
7565
7566       case ERROR_SHARING_VIOLATION:
7567         hr = STG_E_SHAREVIOLATION;
7568         break;
7569
7570       default:
7571         hr = E_FAIL;
7572     }
7573
7574     goto end;
7575   }
7576
7577   /*
7578    * Refuse to open the file if it's too small to be a structured storage file
7579    * FIXME: verify the file when reading instead of here
7580    */
7581   if (GetFileSize(hFile, NULL) < 0x100)
7582   {
7583     CloseHandle(hFile);
7584     hr = STG_E_FILEALREADYEXISTS;
7585     goto end;
7586   }
7587
7588   /*
7589    * Allocate and initialize the new IStorage32object.
7590    */
7591   hr = Storage_Construct(
7592          hFile,
7593          pwcsName,
7594          NULL,
7595          grfMode,
7596          TRUE,
7597          FALSE,
7598          512,
7599          &newStorage);
7600
7601   if (FAILED(hr))
7602   {
7603     /*
7604      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
7605      */
7606     if(hr == STG_E_INVALIDHEADER)
7607         hr = STG_E_FILEALREADYEXISTS;
7608     goto end;
7609   }
7610
7611   /*
7612    * Get an "out" pointer for the caller.
7613    */
7614   *ppstgOpen = (IStorage*)newStorage;
7615
7616 end:
7617   TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
7618   return hr;
7619 }
7620
7621 /******************************************************************************
7622  *    StgCreateDocfileOnILockBytes    [OLE32.@]
7623  */
7624 HRESULT WINAPI StgCreateDocfileOnILockBytes(
7625       ILockBytes *plkbyt,
7626       DWORD grfMode,
7627       DWORD reserved,
7628       IStorage** ppstgOpen)
7629 {
7630   StorageBaseImpl* newStorage = 0;
7631   HRESULT        hr         = S_OK;
7632
7633   if ((ppstgOpen == 0) || (plkbyt == 0))
7634     return STG_E_INVALIDPOINTER;
7635
7636   /*
7637    * Allocate and initialize the new IStorage object.
7638    */
7639   hr = Storage_Construct(
7640          0,
7641         0,
7642          plkbyt,
7643          grfMode,
7644          FALSE,
7645          TRUE,
7646          512,
7647          &newStorage);
7648
7649   if (FAILED(hr))
7650   {
7651     return hr;
7652   }
7653
7654   /*
7655    * Get an "out" pointer for the caller.
7656    */
7657   *ppstgOpen = (IStorage*)newStorage;
7658
7659   return hr;
7660 }
7661
7662 /******************************************************************************
7663  *    StgOpenStorageOnILockBytes    [OLE32.@]
7664  */
7665 HRESULT WINAPI StgOpenStorageOnILockBytes(
7666       ILockBytes *plkbyt,
7667       IStorage *pstgPriority,
7668       DWORD grfMode,
7669       SNB snbExclude,
7670       DWORD reserved,
7671       IStorage **ppstgOpen)
7672 {
7673   StorageBaseImpl* newStorage = 0;
7674   HRESULT        hr = S_OK;
7675
7676   if ((plkbyt == 0) || (ppstgOpen == 0))
7677     return STG_E_INVALIDPOINTER;
7678
7679   if ( FAILED( validateSTGM(grfMode) ))
7680     return STG_E_INVALIDFLAG;
7681
7682   *ppstgOpen = 0;
7683
7684   /*
7685    * Allocate and initialize the new IStorage object.
7686    */
7687   hr = Storage_Construct(
7688          0,
7689          0,
7690          plkbyt,
7691          grfMode,
7692          FALSE,
7693          FALSE,
7694          512,
7695          &newStorage);
7696
7697   if (FAILED(hr))
7698   {
7699     return hr;
7700   }
7701
7702   /*
7703    * Get an "out" pointer for the caller.
7704    */
7705   *ppstgOpen = (IStorage*)newStorage;
7706
7707   return hr;
7708 }
7709
7710 /******************************************************************************
7711  *              StgSetTimes [ole32.@]
7712  *              StgSetTimes [OLE32.@]
7713  *
7714  *
7715  */
7716 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
7717                            FILETIME const *patime, FILETIME const *pmtime)
7718 {
7719   IStorage *stg = NULL;
7720   HRESULT r;
7721  
7722   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
7723
7724   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
7725                      0, 0, &stg);
7726   if( SUCCEEDED(r) )
7727   {
7728     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
7729     IStorage_Release(stg);
7730   }
7731
7732   return r;
7733 }
7734
7735 /******************************************************************************
7736  *              StgIsStorageILockBytes        [OLE32.@]
7737  *
7738  * Determines if the ILockBytes contains a storage object.
7739  */
7740 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
7741 {
7742   BYTE sig[8];
7743   ULARGE_INTEGER offset;
7744
7745   offset.u.HighPart = 0;
7746   offset.u.LowPart  = 0;
7747
7748   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
7749
7750   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
7751     return S_OK;
7752
7753   return S_FALSE;
7754 }
7755
7756 /******************************************************************************
7757  *              WriteClassStg        [OLE32.@]
7758  *
7759  * This method will store the specified CLSID in the specified storage object
7760  */
7761 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
7762 {
7763   HRESULT hRes;
7764
7765   if(!pStg)
7766     return E_INVALIDARG;
7767
7768   if(!rclsid)
7769     return STG_E_INVALIDPOINTER;
7770
7771   hRes = IStorage_SetClass(pStg, rclsid);
7772
7773   return hRes;
7774 }
7775
7776 /***********************************************************************
7777  *    ReadClassStg (OLE32.@)
7778  *
7779  * This method reads the CLSID previously written to a storage object with
7780  * the WriteClassStg.
7781  *
7782  * PARAMS
7783  *  pstg    [I] IStorage pointer
7784  *  pclsid  [O] Pointer to where the CLSID is written
7785  *
7786  * RETURNS
7787  *  Success: S_OK.
7788  *  Failure: HRESULT code.
7789  */
7790 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
7791
7792     STATSTG pstatstg;
7793     HRESULT hRes;
7794
7795     TRACE("(%p, %p)\n", pstg, pclsid);
7796
7797     if(!pstg || !pclsid)
7798         return E_INVALIDARG;
7799
7800    /*
7801     * read a STATSTG structure (contains the clsid) from the storage
7802     */
7803     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_NONAME);
7804
7805     if(SUCCEEDED(hRes))
7806         *pclsid=pstatstg.clsid;
7807
7808     return hRes;
7809 }
7810
7811 /***********************************************************************
7812  *    OleLoadFromStream (OLE32.@)
7813  *
7814  * This function loads an object from stream
7815  */
7816 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
7817 {
7818     CLSID       clsid;
7819     HRESULT     res;
7820     LPPERSISTSTREAM     xstm;
7821
7822     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
7823
7824     res=ReadClassStm(pStm,&clsid);
7825     if (FAILED(res))
7826         return res;
7827     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
7828     if (FAILED(res))
7829         return res;
7830     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
7831     if (FAILED(res)) {
7832         IUnknown_Release((IUnknown*)*ppvObj);
7833         return res;
7834     }
7835     res=IPersistStream_Load(xstm,pStm);
7836     IPersistStream_Release(xstm);
7837     /* FIXME: all refcounts ok at this point? I think they should be:
7838      *          pStm    : unchanged
7839      *          ppvObj  : 1
7840      *          xstm    : 0 (released)
7841      */
7842     return res;
7843 }
7844
7845 /***********************************************************************
7846  *    OleSaveToStream (OLE32.@)
7847  *
7848  * This function saves an object with the IPersistStream interface on it
7849  * to the specified stream.
7850  */
7851 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
7852 {
7853
7854     CLSID clsid;
7855     HRESULT res;
7856
7857     TRACE("(%p,%p)\n",pPStm,pStm);
7858
7859     res=IPersistStream_GetClassID(pPStm,&clsid);
7860
7861     if (SUCCEEDED(res)){
7862
7863         res=WriteClassStm(pStm,&clsid);
7864
7865         if (SUCCEEDED(res))
7866
7867             res=IPersistStream_Save(pPStm,pStm,TRUE);
7868     }
7869
7870     TRACE("Finished Save\n");
7871     return res;
7872 }
7873
7874 /****************************************************************************
7875  * This method validate a STGM parameter that can contain the values below
7876  *
7877  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
7878  * The stgm values contained in 0xffff0000 are bitmasks.
7879  *
7880  * STGM_DIRECT               0x00000000
7881  * STGM_TRANSACTED           0x00010000
7882  * STGM_SIMPLE               0x08000000
7883  *
7884  * STGM_READ                 0x00000000
7885  * STGM_WRITE                0x00000001
7886  * STGM_READWRITE            0x00000002
7887  *
7888  * STGM_SHARE_DENY_NONE      0x00000040
7889  * STGM_SHARE_DENY_READ      0x00000030
7890  * STGM_SHARE_DENY_WRITE     0x00000020
7891  * STGM_SHARE_EXCLUSIVE      0x00000010
7892  *
7893  * STGM_PRIORITY             0x00040000
7894  * STGM_DELETEONRELEASE      0x04000000
7895  *
7896  * STGM_CREATE               0x00001000
7897  * STGM_CONVERT              0x00020000
7898  * STGM_FAILIFTHERE          0x00000000
7899  *
7900  * STGM_NOSCRATCH            0x00100000
7901  * STGM_NOSNAPSHOT           0x00200000
7902  */
7903 static HRESULT validateSTGM(DWORD stgm)
7904 {
7905   DWORD access = STGM_ACCESS_MODE(stgm);
7906   DWORD share  = STGM_SHARE_MODE(stgm);
7907   DWORD create = STGM_CREATE_MODE(stgm);
7908
7909   if (stgm&~STGM_KNOWN_FLAGS)
7910   {
7911     ERR("unknown flags %08x\n", stgm);
7912     return E_FAIL;
7913   }
7914
7915   switch (access)
7916   {
7917   case STGM_READ:
7918   case STGM_WRITE:
7919   case STGM_READWRITE:
7920     break;
7921   default:
7922     return E_FAIL;
7923   }
7924
7925   switch (share)
7926   {
7927   case STGM_SHARE_DENY_NONE:
7928   case STGM_SHARE_DENY_READ:
7929   case STGM_SHARE_DENY_WRITE:
7930   case STGM_SHARE_EXCLUSIVE:
7931     break;
7932   default:
7933     return E_FAIL;
7934   }
7935
7936   switch (create)
7937   {
7938   case STGM_CREATE:
7939   case STGM_FAILIFTHERE:
7940     break;
7941   default:
7942     return E_FAIL;
7943   }
7944
7945   /*
7946    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
7947    */
7948   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
7949       return E_FAIL;
7950
7951   /*
7952    * STGM_CREATE | STGM_CONVERT
7953    * if both are false, STGM_FAILIFTHERE is set to TRUE
7954    */
7955   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
7956     return E_FAIL;
7957
7958   /*
7959    * STGM_NOSCRATCH requires STGM_TRANSACTED
7960    */
7961   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
7962     return E_FAIL;
7963
7964   /*
7965    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
7966    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
7967    */
7968   if ( (stgm & STGM_NOSNAPSHOT) &&
7969         (!(stgm & STGM_TRANSACTED) ||
7970          share == STGM_SHARE_EXCLUSIVE ||
7971          share == STGM_SHARE_DENY_WRITE) )
7972     return E_FAIL;
7973
7974   return S_OK;
7975 }
7976
7977 /****************************************************************************
7978  *      GetShareModeFromSTGM
7979  *
7980  * This method will return a share mode flag from a STGM value.
7981  * The STGM value is assumed valid.
7982  */
7983 static DWORD GetShareModeFromSTGM(DWORD stgm)
7984 {
7985   switch (STGM_SHARE_MODE(stgm))
7986   {
7987   case STGM_SHARE_DENY_NONE:
7988     return FILE_SHARE_READ | FILE_SHARE_WRITE;
7989   case STGM_SHARE_DENY_READ:
7990     return FILE_SHARE_WRITE;
7991   case STGM_SHARE_DENY_WRITE:
7992     return FILE_SHARE_READ;
7993   case STGM_SHARE_EXCLUSIVE:
7994     return 0;
7995   }
7996   ERR("Invalid share mode!\n");
7997   assert(0);
7998   return 0;
7999 }
8000
8001 /****************************************************************************
8002  *      GetAccessModeFromSTGM
8003  *
8004  * This method will return an access mode flag from a STGM value.
8005  * The STGM value is assumed valid.
8006  */
8007 static DWORD GetAccessModeFromSTGM(DWORD stgm)
8008 {
8009   switch (STGM_ACCESS_MODE(stgm))
8010   {
8011   case STGM_READ:
8012     return GENERIC_READ;
8013   case STGM_WRITE:
8014   case STGM_READWRITE:
8015     return GENERIC_READ | GENERIC_WRITE;
8016   }
8017   ERR("Invalid access mode!\n");
8018   assert(0);
8019   return 0;
8020 }
8021
8022 /****************************************************************************
8023  *      GetCreationModeFromSTGM
8024  *
8025  * This method will return a creation mode flag from a STGM value.
8026  * The STGM value is assumed valid.
8027  */
8028 static DWORD GetCreationModeFromSTGM(DWORD stgm)
8029 {
8030   switch(STGM_CREATE_MODE(stgm))
8031   {
8032   case STGM_CREATE:
8033     return CREATE_ALWAYS;
8034   case STGM_CONVERT:
8035     FIXME("STGM_CONVERT not implemented!\n");
8036     return CREATE_NEW;
8037   case STGM_FAILIFTHERE:
8038     return CREATE_NEW;
8039   }
8040   ERR("Invalid create mode!\n");
8041   assert(0);
8042   return 0;
8043 }
8044
8045
8046 /*************************************************************************
8047  * OLECONVERT_LoadOLE10 [Internal]
8048  *
8049  * Loads the OLE10 STREAM to memory
8050  *
8051  * PARAMS
8052  *     pOleStream   [I] The OLESTREAM
8053  *     pData        [I] Data Structure for the OLESTREAM Data
8054  *
8055  * RETURNS
8056  *     Success:  S_OK
8057  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
8058  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalid
8059  *
8060  * NOTES
8061  *     This function is used by OleConvertOLESTREAMToIStorage only.
8062  *
8063  *     Memory allocated for pData must be freed by the caller
8064  */
8065 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
8066 {
8067         DWORD dwSize;
8068         HRESULT hRes = S_OK;
8069         int nTryCnt=0;
8070         int max_try = 6;
8071
8072         pData->pData = NULL;
8073         pData->pstrOleObjFileName = NULL;
8074
8075         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
8076         {
8077         /* Get the OleID */
8078         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
8079         if(dwSize != sizeof(pData->dwOleID))
8080         {
8081                 hRes = CONVERT10_E_OLESTREAM_GET;
8082         }
8083         else if(pData->dwOleID != OLESTREAM_ID)
8084         {
8085                 hRes = CONVERT10_E_OLESTREAM_FMT;
8086         }
8087                 else
8088                 {
8089                         hRes = S_OK;
8090                         break;
8091                 }
8092         }
8093
8094         if(hRes == S_OK)
8095         {
8096                 /* Get the TypeID... more info needed for this field */
8097                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
8098                 if(dwSize != sizeof(pData->dwTypeID))
8099                 {
8100                         hRes = CONVERT10_E_OLESTREAM_GET;
8101                 }
8102         }
8103         if(hRes == S_OK)
8104         {
8105                 if(pData->dwTypeID != 0)
8106                 {
8107                         /* Get the length of the OleTypeName */
8108                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
8109                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
8110                         {
8111                                 hRes = CONVERT10_E_OLESTREAM_GET;
8112                         }
8113
8114                         if(hRes == S_OK)
8115                         {
8116                                 if(pData->dwOleTypeNameLength > 0)
8117                                 {
8118                                         /* Get the OleTypeName */
8119                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
8120                                         if(dwSize != pData->dwOleTypeNameLength)
8121                                         {
8122                                                 hRes = CONVERT10_E_OLESTREAM_GET;
8123                                         }
8124                                 }
8125                         }
8126                         if(bStrem1)
8127                         {
8128                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
8129                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
8130                                 {
8131                                         hRes = CONVERT10_E_OLESTREAM_GET;
8132                                 }
8133                         if(hRes == S_OK)
8134                         {
8135                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
8136                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
8137                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
8138                                         if(pData->pstrOleObjFileName)
8139                                         {
8140                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, pData->pstrOleObjFileName, pData->dwOleObjFileNameLength);
8141                                                 if(dwSize != pData->dwOleObjFileNameLength)
8142                                                 {
8143                                                         hRes = CONVERT10_E_OLESTREAM_GET;
8144                                                 }
8145                                         }
8146                                         else
8147                                                 hRes = CONVERT10_E_OLESTREAM_GET;
8148                                 }
8149                         }
8150                         else
8151                         {
8152                                 /* Get the Width of the Metafile */
8153                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
8154                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
8155                                 {
8156                                         hRes = CONVERT10_E_OLESTREAM_GET;
8157                                 }
8158                         if(hRes == S_OK)
8159                         {
8160                                 /* Get the Height of the Metafile */
8161                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
8162                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
8163                                 {
8164                                         hRes = CONVERT10_E_OLESTREAM_GET;
8165                                 }
8166                         }
8167                         }
8168                         if(hRes == S_OK)
8169                         {
8170                                 /* Get the Length of the Data */
8171                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
8172                                 if(dwSize != sizeof(pData->dwDataLength))
8173                                 {
8174                                         hRes = CONVERT10_E_OLESTREAM_GET;
8175                                 }
8176                         }
8177
8178                         if(hRes == S_OK) /* I don't know what this 8 byte information is. We have to figure out */
8179                         {
8180                                 if(!bStrem1) /* if it is a second OLE stream data */
8181                                 {
8182                                         pData->dwDataLength -= 8;
8183                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strUnknown, sizeof(pData->strUnknown));
8184                                         if(dwSize != sizeof(pData->strUnknown))
8185                                         {
8186                                                 hRes = CONVERT10_E_OLESTREAM_GET;
8187                                         }
8188                                 }
8189                         }
8190                         if(hRes == S_OK)
8191                         {
8192                                 if(pData->dwDataLength > 0)
8193                                 {
8194                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
8195
8196                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
8197                                         if(pData->pData)
8198                                         {
8199                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
8200                                                 if(dwSize != pData->dwDataLength)
8201                                                 {
8202                                                         hRes = CONVERT10_E_OLESTREAM_GET;
8203                                                 }
8204                                         }
8205                                         else
8206                                         {
8207                                                 hRes = CONVERT10_E_OLESTREAM_GET;
8208                                         }
8209                                 }
8210                         }
8211                 }
8212         }
8213         return hRes;
8214 }
8215
8216 /*************************************************************************
8217  * OLECONVERT_SaveOLE10 [Internal]
8218  *
8219  * Saves the OLE10 STREAM From memory
8220  *
8221  * PARAMS
8222  *     pData        [I] Data Structure for the OLESTREAM Data
8223  *     pOleStream   [I] The OLESTREAM to save
8224  *
8225  * RETURNS
8226  *     Success:  S_OK
8227  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
8228  *
8229  * NOTES
8230  *     This function is used by OleConvertIStorageToOLESTREAM only.
8231  *
8232  */
8233 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
8234 {
8235     DWORD dwSize;
8236     HRESULT hRes = S_OK;
8237
8238
8239    /* Set the OleID */
8240     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
8241     if(dwSize != sizeof(pData->dwOleID))
8242     {
8243         hRes = CONVERT10_E_OLESTREAM_PUT;
8244     }
8245
8246     if(hRes == S_OK)
8247     {
8248         /* Set the TypeID */
8249         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
8250         if(dwSize != sizeof(pData->dwTypeID))
8251         {
8252             hRes = CONVERT10_E_OLESTREAM_PUT;
8253         }
8254     }
8255
8256     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
8257     {
8258         /* Set the Length of the OleTypeName */
8259         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
8260         if(dwSize != sizeof(pData->dwOleTypeNameLength))
8261         {
8262             hRes = CONVERT10_E_OLESTREAM_PUT;
8263         }
8264
8265         if(hRes == S_OK)
8266         {
8267             if(pData->dwOleTypeNameLength > 0)
8268             {
8269                 /* Set the OleTypeName */
8270                 dwSize = pOleStream->lpstbl->Put(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
8271                 if(dwSize != pData->dwOleTypeNameLength)
8272                 {
8273                     hRes = CONVERT10_E_OLESTREAM_PUT;
8274                 }
8275             }
8276         }
8277
8278         if(hRes == S_OK)
8279         {
8280             /* Set the width of the Metafile */
8281             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
8282             if(dwSize != sizeof(pData->dwMetaFileWidth))
8283             {
8284                 hRes = CONVERT10_E_OLESTREAM_PUT;
8285             }
8286         }
8287
8288         if(hRes == S_OK)
8289         {
8290             /* Set the height of the Metafile */
8291             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
8292             if(dwSize != sizeof(pData->dwMetaFileHeight))
8293             {
8294                 hRes = CONVERT10_E_OLESTREAM_PUT;
8295             }
8296         }
8297
8298         if(hRes == S_OK)
8299         {
8300             /* Set the length of the Data */
8301             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
8302             if(dwSize != sizeof(pData->dwDataLength))
8303             {
8304                 hRes = CONVERT10_E_OLESTREAM_PUT;
8305             }
8306         }
8307
8308         if(hRes == S_OK)
8309         {
8310             if(pData->dwDataLength > 0)
8311             {
8312                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
8313                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
8314                 if(dwSize != pData->dwDataLength)
8315                 {
8316                     hRes = CONVERT10_E_OLESTREAM_PUT;
8317                 }
8318             }
8319         }
8320     }
8321     return hRes;
8322 }
8323
8324 /*************************************************************************
8325  * OLECONVERT_GetOLE20FromOLE10[Internal]
8326  *
8327  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
8328  * opens it, and copies the content to the dest IStorage for
8329  * OleConvertOLESTREAMToIStorage
8330  *
8331  *
8332  * PARAMS
8333  *     pDestStorage  [I] The IStorage to copy the data to
8334  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
8335  *     nBufferLength [I] The size of the buffer
8336  *
8337  * RETURNS
8338  *     Nothing
8339  *
8340  * NOTES
8341  *
8342  *
8343  */
8344 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBuffer, DWORD nBufferLength)
8345 {
8346     HRESULT hRes;
8347     HANDLE hFile;
8348     IStorage *pTempStorage;
8349     DWORD dwNumOfBytesWritten;
8350     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
8351     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
8352
8353     /* Create a temp File */
8354     GetTempPathW(MAX_PATH, wstrTempDir);
8355     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
8356     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
8357
8358     if(hFile != INVALID_HANDLE_VALUE)
8359     {
8360         /* Write IStorage Data to File */
8361         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
8362         CloseHandle(hFile);
8363
8364         /* Open and copy temp storage to the Dest Storage */
8365         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
8366         if(hRes == S_OK)
8367         {
8368             hRes = IStorage_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
8369             IStorage_Release(pTempStorage);
8370         }
8371         DeleteFileW(wstrTempFile);
8372     }
8373 }
8374
8375
8376 /*************************************************************************
8377  * OLECONVERT_WriteOLE20ToBuffer [Internal]
8378  *
8379  * Saves the OLE10 STREAM From memory
8380  *
8381  * PARAMS
8382  *     pStorage  [I] The Src IStorage to copy
8383  *     pData     [I] The Dest Memory to write to.
8384  *
8385  * RETURNS
8386  *     The size in bytes allocated for pData
8387  *
8388  * NOTES
8389  *     Memory allocated for pData must be freed by the caller
8390  *
8391  *     Used by OleConvertIStorageToOLESTREAM only.
8392  *
8393  */
8394 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
8395 {
8396     HANDLE hFile;
8397     HRESULT hRes;
8398     DWORD nDataLength = 0;
8399     IStorage *pTempStorage;
8400     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
8401     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
8402
8403     *pData = NULL;
8404
8405     /* Create temp Storage */
8406     GetTempPathW(MAX_PATH, wstrTempDir);
8407     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
8408     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
8409
8410     if(hRes == S_OK)
8411     {
8412         /* Copy Src Storage to the Temp Storage */
8413         IStorage_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
8414         IStorage_Release(pTempStorage);
8415
8416         /* Open Temp Storage as a file and copy to memory */
8417         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
8418         if(hFile != INVALID_HANDLE_VALUE)
8419         {
8420             nDataLength = GetFileSize(hFile, NULL);
8421             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
8422             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
8423             CloseHandle(hFile);
8424         }
8425         DeleteFileW(wstrTempFile);
8426     }
8427     return nDataLength;
8428 }
8429
8430 /*************************************************************************
8431  * OLECONVERT_CreateOleStream [Internal]
8432  *
8433  * Creates the "\001OLE" stream in the IStorage if necessary.
8434  *
8435  * PARAMS
8436  *     pStorage     [I] Dest storage to create the stream in
8437  *
8438  * RETURNS
8439  *     Nothing
8440  *
8441  * NOTES
8442  *     This function is used by OleConvertOLESTREAMToIStorage only.
8443  *
8444  *     This stream is still unknown, MS Word seems to have extra data
8445  *     but since the data is stored in the OLESTREAM there should be
8446  *     no need to recreate the stream.  If the stream is manually
8447  *     deleted it will create it with this default data.
8448  *
8449  */
8450 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
8451 {
8452     HRESULT hRes;
8453     IStream *pStream;
8454     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
8455     BYTE pOleStreamHeader [] =
8456     {
8457         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
8458         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8459         0x00, 0x00, 0x00, 0x00
8460     };
8461
8462     /* Create stream if not present */
8463     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
8464         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
8465
8466     if(hRes == S_OK)
8467     {
8468         /* Write default Data */
8469         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
8470         IStream_Release(pStream);
8471     }
8472 }
8473
8474 /* write a string to a stream, preceded by its length */
8475 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
8476 {
8477     HRESULT r;
8478     LPSTR str;
8479     DWORD len = 0;
8480
8481     if( string )
8482         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
8483     r = IStream_Write( stm, &len, sizeof(len), NULL);
8484     if( FAILED( r ) )
8485         return r;
8486     if(len == 0)
8487         return r;
8488     str = CoTaskMemAlloc( len );
8489     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
8490     r = IStream_Write( stm, str, len, NULL);
8491     CoTaskMemFree( str );
8492     return r;
8493 }
8494
8495 /* read a string preceded by its length from a stream */
8496 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
8497 {
8498     HRESULT r;
8499     DWORD len, count = 0;
8500     LPSTR str;
8501     LPWSTR wstr;
8502
8503     r = IStream_Read( stm, &len, sizeof(len), &count );
8504     if( FAILED( r ) )
8505         return r;
8506     if( count != sizeof(len) )
8507         return E_OUTOFMEMORY;
8508
8509     TRACE("%d bytes\n",len);
8510     
8511     str = CoTaskMemAlloc( len );
8512     if( !str )
8513         return E_OUTOFMEMORY;
8514     count = 0;
8515     r = IStream_Read( stm, str, len, &count );
8516     if( FAILED( r ) )
8517         return r;
8518     if( count != len )
8519     {
8520         CoTaskMemFree( str );
8521         return E_OUTOFMEMORY;
8522     }
8523
8524     TRACE("Read string %s\n",debugstr_an(str,len));
8525
8526     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
8527     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
8528     if( wstr )
8529          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
8530     CoTaskMemFree( str );
8531
8532     *string = wstr;
8533
8534     return r;
8535 }
8536
8537
8538 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
8539     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
8540 {
8541     IStream *pstm;
8542     HRESULT r = S_OK;
8543     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
8544
8545     static const BYTE unknown1[12] =
8546        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
8547          0xFF, 0xFF, 0xFF, 0xFF};
8548     static const BYTE unknown2[16] =
8549        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
8550          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
8551
8552     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
8553            debugstr_w(lpszUserType), debugstr_w(szClipName),
8554            debugstr_w(szProgIDName));
8555
8556     /*  Create a CompObj stream */
8557     r = IStorage_CreateStream(pstg, szwStreamName,
8558         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
8559     if( FAILED (r) )
8560         return r;
8561
8562     /* Write CompObj Structure to stream */
8563     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
8564
8565     if( SUCCEEDED( r ) )
8566         r = WriteClassStm( pstm, clsid );
8567
8568     if( SUCCEEDED( r ) )
8569         r = STREAM_WriteString( pstm, lpszUserType );
8570     if( SUCCEEDED( r ) )
8571         r = STREAM_WriteString( pstm, szClipName );
8572     if( SUCCEEDED( r ) )
8573         r = STREAM_WriteString( pstm, szProgIDName );
8574     if( SUCCEEDED( r ) )
8575         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
8576
8577     IStream_Release( pstm );
8578
8579     return r;
8580 }
8581
8582 /***********************************************************************
8583  *               WriteFmtUserTypeStg (OLE32.@)
8584  */
8585 HRESULT WINAPI WriteFmtUserTypeStg(
8586           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
8587 {
8588     HRESULT r;
8589     WCHAR szwClipName[0x40];
8590     CLSID clsid = CLSID_NULL;
8591     LPWSTR wstrProgID = NULL;
8592     DWORD n;
8593
8594     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
8595
8596     /* get the clipboard format name */
8597     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName)/sizeof(szwClipName[0]) );
8598     szwClipName[n]=0;
8599
8600     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
8601
8602     /* FIXME: There's room to save a CLSID and its ProgID, but
8603        the CLSID is not looked up in the registry and in all the
8604        tests I wrote it was CLSID_NULL.  Where does it come from?
8605     */
8606
8607     /* get the real program ID.  This may fail, but that's fine */
8608     ProgIDFromCLSID(&clsid, &wstrProgID);
8609
8610     TRACE("progid is %s\n",debugstr_w(wstrProgID));
8611
8612     r = STORAGE_WriteCompObj( pstg, &clsid, 
8613                               lpszUserType, szwClipName, wstrProgID );
8614
8615     CoTaskMemFree(wstrProgID);
8616
8617     return r;
8618 }
8619
8620
8621 /******************************************************************************
8622  *              ReadFmtUserTypeStg        [OLE32.@]
8623  */
8624 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
8625 {
8626     HRESULT r;
8627     IStream *stm = 0;
8628     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
8629     unsigned char unknown1[12];
8630     unsigned char unknown2[16];
8631     DWORD count;
8632     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
8633     CLSID clsid;
8634
8635     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
8636
8637     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
8638                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
8639     if( FAILED ( r ) )
8640     {
8641         WARN("Failed to open stream r = %08x\n", r);
8642         return r;
8643     }
8644
8645     /* read the various parts of the structure */
8646     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
8647     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
8648         goto end;
8649     r = ReadClassStm( stm, &clsid );
8650     if( FAILED( r ) )
8651         goto end;
8652
8653     r = STREAM_ReadString( stm, &szCLSIDName );
8654     if( FAILED( r ) )
8655         goto end;
8656
8657     r = STREAM_ReadString( stm, &szOleTypeName );
8658     if( FAILED( r ) )
8659         goto end;
8660
8661     r = STREAM_ReadString( stm, &szProgIDName );
8662     if( FAILED( r ) )
8663         goto end;
8664
8665     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
8666     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
8667         goto end;
8668
8669     /* ok, success... now we just need to store what we found */
8670     if( pcf )
8671         *pcf = RegisterClipboardFormatW( szOleTypeName );
8672     CoTaskMemFree( szOleTypeName );
8673
8674     if( lplpszUserType )
8675         *lplpszUserType = szCLSIDName;
8676     CoTaskMemFree( szProgIDName );
8677
8678 end:
8679     IStream_Release( stm );
8680
8681     return r;
8682 }
8683
8684
8685 /*************************************************************************
8686  * OLECONVERT_CreateCompObjStream [Internal]
8687  *
8688  * Creates a "\001CompObj" is the destination IStorage if necessary.
8689  *
8690  * PARAMS
8691  *     pStorage       [I] The dest IStorage to create the CompObj Stream
8692  *                        if necessary.
8693  *     strOleTypeName [I] The ProgID
8694  *
8695  * RETURNS
8696  *     Success:  S_OK
8697  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
8698  *
8699  * NOTES
8700  *     This function is used by OleConvertOLESTREAMToIStorage only.
8701  *
8702  *     The stream data is stored in the OLESTREAM and there should be
8703  *     no need to recreate the stream.  If the stream is manually
8704  *     deleted it will attempt to create it by querying the registry.
8705  *
8706  *
8707  */
8708 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
8709 {
8710     IStream *pStream;
8711     HRESULT hStorageRes, hRes = S_OK;
8712     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
8713     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
8714     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
8715
8716     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
8717     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
8718
8719     /* Initialize the CompObj structure */
8720     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
8721     memcpy(IStorageCompObj.byUnknown1, pCompObjUnknown1, sizeof(pCompObjUnknown1));
8722     memcpy(IStorageCompObj.byUnknown2, pCompObjUnknown2, sizeof(pCompObjUnknown2));
8723
8724
8725     /*  Create a CompObj stream if it doesn't exist */
8726     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
8727         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
8728     if(hStorageRes == S_OK)
8729     {
8730         /* copy the OleTypeName to the compobj struct */
8731         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
8732         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
8733
8734         /* copy the OleTypeName to the compobj struct */
8735         /* Note: in the test made, these were Identical      */
8736         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
8737         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
8738
8739         /* Get the CLSID */
8740         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
8741                              bufferW, OLESTREAM_MAX_STR_LEN );
8742         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
8743
8744         if(hRes == S_OK)
8745         {
8746             HKEY hKey;
8747             LONG hErr;
8748             /* Get the CLSID Default Name from the Registry */
8749             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
8750             if(hErr == ERROR_SUCCESS)
8751             {
8752                 char strTemp[OLESTREAM_MAX_STR_LEN];
8753                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
8754                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
8755                 if(hErr == ERROR_SUCCESS)
8756                 {
8757                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
8758                 }
8759                 RegCloseKey(hKey);
8760             }
8761         }
8762
8763         /* Write CompObj Structure to stream */
8764         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
8765
8766         WriteClassStm(pStream,&(IStorageCompObj.clsid));
8767
8768         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
8769         if(IStorageCompObj.dwCLSIDNameLength > 0)
8770         {
8771             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
8772         }
8773         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
8774         if(IStorageCompObj.dwOleTypeNameLength > 0)
8775         {
8776             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
8777         }
8778         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
8779         if(IStorageCompObj.dwProgIDNameLength > 0)
8780         {
8781             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
8782         }
8783         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
8784         IStream_Release(pStream);
8785     }
8786     return hRes;
8787 }
8788
8789
8790 /*************************************************************************
8791  * OLECONVERT_CreateOlePresStream[Internal]
8792  *
8793  * Creates the "\002OlePres000" Stream with the Metafile data
8794  *
8795  * PARAMS
8796  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
8797  *     dwExtentX    [I] Width of the Metafile
8798  *     dwExtentY    [I] Height of the Metafile
8799  *     pData        [I] Metafile data
8800  *     dwDataLength [I] Size of the Metafile data
8801  *
8802  * RETURNS
8803  *     Success:  S_OK
8804  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
8805  *
8806  * NOTES
8807  *     This function is used by OleConvertOLESTREAMToIStorage only.
8808  *
8809  */
8810 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
8811 {
8812     HRESULT hRes;
8813     IStream *pStream;
8814     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
8815     BYTE pOlePresStreamHeader [] =
8816     {
8817         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
8818         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
8819         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
8820         0x00, 0x00, 0x00, 0x00
8821     };
8822
8823     BYTE pOlePresStreamHeaderEmpty [] =
8824     {
8825         0x00, 0x00, 0x00, 0x00,
8826         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
8827         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
8828         0x00, 0x00, 0x00, 0x00
8829     };
8830
8831     /* Create the OlePres000 Stream */
8832     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
8833         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
8834
8835     if(hRes == S_OK)
8836     {
8837         DWORD nHeaderSize;
8838         OLECONVERT_ISTORAGE_OLEPRES OlePres;
8839
8840         memset(&OlePres, 0, sizeof(OlePres));
8841         /* Do we have any metafile data to save */
8842         if(dwDataLength > 0)
8843         {
8844             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
8845             nHeaderSize = sizeof(pOlePresStreamHeader);
8846         }
8847         else
8848         {
8849             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
8850             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
8851         }
8852         /* Set width and height of the metafile */
8853         OlePres.dwExtentX = dwExtentX;
8854         OlePres.dwExtentY = -dwExtentY;
8855
8856         /* Set Data and Length */
8857         if(dwDataLength > sizeof(METAFILEPICT16))
8858         {
8859             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
8860             OlePres.pData = &(pData[8]);
8861         }
8862         /* Save OlePres000 Data to Stream */
8863         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
8864         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
8865         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
8866         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
8867         if(OlePres.dwSize > 0)
8868         {
8869             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
8870         }
8871         IStream_Release(pStream);
8872     }
8873 }
8874
8875 /*************************************************************************
8876  * OLECONVERT_CreateOle10NativeStream [Internal]
8877  *
8878  * Creates the "\001Ole10Native" Stream (should contain a BMP)
8879  *
8880  * PARAMS
8881  *     pStorage     [I] Dest storage to create the stream in
8882  *     pData        [I] Ole10 Native Data (ex. bmp)
8883  *     dwDataLength [I] Size of the Ole10 Native Data
8884  *
8885  * RETURNS
8886  *     Nothing
8887  *
8888  * NOTES
8889  *     This function is used by OleConvertOLESTREAMToIStorage only.
8890  *
8891  *     Might need to verify the data and return appropriate error message
8892  *
8893  */
8894 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
8895 {
8896     HRESULT hRes;
8897     IStream *pStream;
8898     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
8899
8900     /* Create the Ole10Native Stream */
8901     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
8902         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
8903
8904     if(hRes == S_OK)
8905     {
8906         /* Write info to stream */
8907         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
8908         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
8909         IStream_Release(pStream);
8910     }
8911
8912 }
8913
8914 /*************************************************************************
8915  * OLECONVERT_GetOLE10ProgID [Internal]
8916  *
8917  * Finds the ProgID (or OleTypeID) from the IStorage
8918  *
8919  * PARAMS
8920  *     pStorage        [I] The Src IStorage to get the ProgID
8921  *     strProgID       [I] the ProgID string to get
8922  *     dwSize          [I] the size of the string
8923  *
8924  * RETURNS
8925  *     Success:  S_OK
8926  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
8927  *
8928  * NOTES
8929  *     This function is used by OleConvertIStorageToOLESTREAM only.
8930  *
8931  *
8932  */
8933 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
8934 {
8935     HRESULT hRes;
8936     IStream *pStream;
8937     LARGE_INTEGER iSeekPos;
8938     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
8939     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
8940
8941     /* Open the CompObj Stream */
8942     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
8943         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
8944     if(hRes == S_OK)
8945     {
8946
8947         /*Get the OleType from the CompObj Stream */
8948         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
8949         iSeekPos.u.HighPart = 0;
8950
8951         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
8952         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
8953         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
8954         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
8955         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
8956         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
8957         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
8958
8959         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
8960         if(*dwSize > 0)
8961         {
8962             IStream_Read(pStream, strProgID, *dwSize, NULL);
8963         }
8964         IStream_Release(pStream);
8965     }
8966     else
8967     {
8968         STATSTG stat;
8969         LPOLESTR wstrProgID;
8970
8971         /* Get the OleType from the registry */
8972         REFCLSID clsid = &(stat.clsid);
8973         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
8974         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
8975         if(hRes == S_OK)
8976         {
8977             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
8978         }
8979
8980     }
8981     return hRes;
8982 }
8983
8984 /*************************************************************************
8985  * OLECONVERT_GetOle10PresData [Internal]
8986  *
8987  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
8988  *
8989  * PARAMS
8990  *     pStorage     [I] Src IStroage
8991  *     pOleStream   [I] Dest OleStream Mem Struct
8992  *
8993  * RETURNS
8994  *     Nothing
8995  *
8996  * NOTES
8997  *     This function is used by OleConvertIStorageToOLESTREAM only.
8998  *
8999  *     Memory allocated for pData must be freed by the caller
9000  *
9001  *
9002  */
9003 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
9004 {
9005
9006     HRESULT hRes;
9007     IStream *pStream;
9008     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
9009
9010     /* Initialize Default data for OLESTREAM */
9011     pOleStreamData[0].dwOleID = OLESTREAM_ID;
9012     pOleStreamData[0].dwTypeID = 2;
9013     pOleStreamData[1].dwOleID = OLESTREAM_ID;
9014     pOleStreamData[1].dwTypeID = 0;
9015     pOleStreamData[0].dwMetaFileWidth = 0;
9016     pOleStreamData[0].dwMetaFileHeight = 0;
9017     pOleStreamData[0].pData = NULL;
9018     pOleStreamData[1].pData = NULL;
9019
9020     /* Open Ole10Native Stream */
9021     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
9022         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
9023     if(hRes == S_OK)
9024     {
9025
9026         /* Read Size and Data */
9027         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
9028         if(pOleStreamData->dwDataLength > 0)
9029         {
9030             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
9031             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
9032         }
9033         IStream_Release(pStream);
9034     }
9035
9036 }
9037
9038
9039 /*************************************************************************
9040  * OLECONVERT_GetOle20PresData[Internal]
9041  *
9042  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
9043  *
9044  * PARAMS
9045  *     pStorage         [I] Src IStroage
9046  *     pOleStreamData   [I] Dest OleStream Mem Struct
9047  *
9048  * RETURNS
9049  *     Nothing
9050  *
9051  * NOTES
9052  *     This function is used by OleConvertIStorageToOLESTREAM only.
9053  *
9054  *     Memory allocated for pData must be freed by the caller
9055  */
9056 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
9057 {
9058     HRESULT hRes;
9059     IStream *pStream;
9060     OLECONVERT_ISTORAGE_OLEPRES olePress;
9061     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
9062
9063     /* Initialize Default data for OLESTREAM */
9064     pOleStreamData[0].dwOleID = OLESTREAM_ID;
9065     pOleStreamData[0].dwTypeID = 2;
9066     pOleStreamData[0].dwMetaFileWidth = 0;
9067     pOleStreamData[0].dwMetaFileHeight = 0;
9068     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
9069     pOleStreamData[1].dwOleID = OLESTREAM_ID;
9070     pOleStreamData[1].dwTypeID = 0;
9071     pOleStreamData[1].dwOleTypeNameLength = 0;
9072     pOleStreamData[1].strOleTypeName[0] = 0;
9073     pOleStreamData[1].dwMetaFileWidth = 0;
9074     pOleStreamData[1].dwMetaFileHeight = 0;
9075     pOleStreamData[1].pData = NULL;
9076     pOleStreamData[1].dwDataLength = 0;
9077
9078
9079     /* Open OlePress000 stream */
9080     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
9081         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
9082     if(hRes == S_OK)
9083     {
9084         LARGE_INTEGER iSeekPos;
9085         METAFILEPICT16 MetaFilePict;
9086         static const char strMetafilePictName[] = "METAFILEPICT";
9087
9088         /* Set the TypeID for a Metafile */
9089         pOleStreamData[1].dwTypeID = 5;
9090
9091         /* Set the OleTypeName to Metafile */
9092         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
9093         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
9094
9095         iSeekPos.u.HighPart = 0;
9096         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
9097
9098         /* Get Presentation Data */
9099         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
9100         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
9101         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
9102         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
9103
9104         /*Set width and Height */
9105         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
9106         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
9107         if(olePress.dwSize > 0)
9108         {
9109             /* Set Length */
9110             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
9111
9112             /* Set MetaFilePict struct */
9113             MetaFilePict.mm = 8;
9114             MetaFilePict.xExt = olePress.dwExtentX;
9115             MetaFilePict.yExt = olePress.dwExtentY;
9116             MetaFilePict.hMF = 0;
9117
9118             /* Get Metafile Data */
9119             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
9120             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
9121             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
9122         }
9123         IStream_Release(pStream);
9124     }
9125 }
9126
9127 /*************************************************************************
9128  * OleConvertOLESTREAMToIStorage [OLE32.@]
9129  *
9130  * Read info on MSDN
9131  *
9132  * TODO
9133  *      DVTARGETDEVICE parameter is not handled
9134  *      Still unsure of some mem fields for OLE 10 Stream
9135  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
9136  *      and "\001OLE" streams
9137  *
9138  */
9139 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
9140     LPOLESTREAM pOleStream,
9141     LPSTORAGE pstg,
9142     const DVTARGETDEVICE* ptd)
9143 {
9144     int i;
9145     HRESULT hRes=S_OK;
9146     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
9147
9148     TRACE("%p %p %p\n", pOleStream, pstg, ptd);
9149
9150     memset(pOleStreamData, 0, sizeof(pOleStreamData));
9151
9152     if(ptd != NULL)
9153     {
9154         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
9155     }
9156
9157     if(pstg == NULL || pOleStream == NULL)
9158     {
9159         hRes = E_INVALIDARG;
9160     }
9161
9162     if(hRes == S_OK)
9163     {
9164         /* Load the OLESTREAM to Memory */
9165         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
9166     }
9167
9168     if(hRes == S_OK)
9169     {
9170         /* Load the OLESTREAM to Memory (part 2)*/
9171         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
9172     }
9173
9174     if(hRes == S_OK)
9175     {
9176
9177         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
9178         {
9179             /* Do we have the IStorage Data in the OLESTREAM */
9180             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
9181             {
9182                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
9183                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
9184             }
9185             else
9186             {
9187                 /* It must be an original OLE 1.0 source */
9188                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
9189             }
9190         }
9191         else
9192         {
9193             /* It must be an original OLE 1.0 source */
9194             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
9195         }
9196
9197         /* Create CompObj Stream if necessary */
9198         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
9199         if(hRes == S_OK)
9200         {
9201             /*Create the Ole Stream if necessary */
9202             OLECONVERT_CreateOleStream(pstg);
9203         }
9204     }
9205
9206
9207     /* Free allocated memory */
9208     for(i=0; i < 2; i++)
9209     {
9210         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
9211         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
9212         pOleStreamData[i].pstrOleObjFileName = NULL;
9213     }
9214     return hRes;
9215 }
9216
9217 /*************************************************************************
9218  * OleConvertIStorageToOLESTREAM [OLE32.@]
9219  *
9220  * Read info on MSDN
9221  *
9222  * Read info on MSDN
9223  *
9224  * TODO
9225  *      Still unsure of some mem fields for OLE 10 Stream
9226  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
9227  *      and "\001OLE" streams.
9228  *
9229  */
9230 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
9231     LPSTORAGE pstg,
9232     LPOLESTREAM pOleStream)
9233 {
9234     int i;
9235     HRESULT hRes = S_OK;
9236     IStream *pStream;
9237     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
9238     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
9239
9240     TRACE("%p %p\n", pstg, pOleStream);
9241
9242     memset(pOleStreamData, 0, sizeof(pOleStreamData));
9243
9244     if(pstg == NULL || pOleStream == NULL)
9245     {
9246         hRes = E_INVALIDARG;
9247     }
9248     if(hRes == S_OK)
9249     {
9250         /* Get the ProgID */
9251         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
9252         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
9253     }
9254     if(hRes == S_OK)
9255     {
9256         /* Was it originally Ole10 */
9257         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
9258         if(hRes == S_OK)
9259         {
9260             IStream_Release(pStream);
9261             /* Get Presentation Data for Ole10Native */
9262             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
9263         }
9264         else
9265         {
9266             /* Get Presentation Data (OLE20) */
9267             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
9268         }
9269
9270         /* Save OLESTREAM */
9271         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
9272         if(hRes == S_OK)
9273         {
9274             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
9275         }
9276
9277     }
9278
9279     /* Free allocated memory */
9280     for(i=0; i < 2; i++)
9281     {
9282         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
9283     }
9284
9285     return hRes;
9286 }
9287
9288 /***********************************************************************
9289  *              GetConvertStg (OLE32.@)
9290  */
9291 HRESULT WINAPI GetConvertStg(IStorage *stg) {
9292     FIXME("unimplemented stub!\n");
9293     return E_FAIL;
9294 }
9295
9296 /******************************************************************************
9297  * StgIsStorageFile [OLE32.@]
9298  * Verify if the file contains a storage object
9299  *
9300  * PARAMS
9301  *  fn      [ I] Filename
9302  *
9303  * RETURNS
9304  *  S_OK    if file has magic bytes as a storage object
9305  *  S_FALSE if file is not storage
9306  */
9307 HRESULT WINAPI
9308 StgIsStorageFile(LPCOLESTR fn)
9309 {
9310         HANDLE          hf;
9311         BYTE            magic[8];
9312         DWORD           bytes_read;
9313
9314         TRACE("%s\n", debugstr_w(fn));
9315         hf = CreateFileW(fn, GENERIC_READ,
9316                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
9317                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
9318
9319         if (hf == INVALID_HANDLE_VALUE)
9320                 return STG_E_FILENOTFOUND;
9321
9322         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
9323         {
9324                 WARN(" unable to read file\n");
9325                 CloseHandle(hf);
9326                 return S_FALSE;
9327         }
9328
9329         CloseHandle(hf);
9330
9331         if (bytes_read != 8) {
9332                 TRACE(" too short\n");
9333                 return S_FALSE;
9334         }
9335
9336         if (!memcmp(magic,STORAGE_magic,8)) {
9337                 TRACE(" -> YES\n");
9338                 return S_OK;
9339         }
9340
9341         TRACE(" -> Invalid header.\n");
9342         return S_FALSE;
9343 }
9344
9345 /***********************************************************************
9346  *              WriteClassStm (OLE32.@)
9347  *
9348  * Writes a CLSID to a stream.
9349  *
9350  * PARAMS
9351  *  pStm   [I] Stream to write to.
9352  *  rclsid [I] CLSID to write.
9353  *
9354  * RETURNS
9355  *  Success: S_OK.
9356  *  Failure: HRESULT code.
9357  */
9358 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
9359 {
9360     TRACE("(%p,%p)\n",pStm,rclsid);
9361
9362     if (!pStm || !rclsid)
9363         return E_INVALIDARG;
9364
9365     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
9366 }
9367
9368 /***********************************************************************
9369  *              ReadClassStm (OLE32.@)
9370  *
9371  * Reads a CLSID from a stream.
9372  *
9373  * PARAMS
9374  *  pStm   [I] Stream to read from.
9375  *  rclsid [O] CLSID to read.
9376  *
9377  * RETURNS
9378  *  Success: S_OK.
9379  *  Failure: HRESULT code.
9380  */
9381 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
9382 {
9383     ULONG nbByte;
9384     HRESULT res;
9385
9386     TRACE("(%p,%p)\n",pStm,pclsid);
9387
9388     if (!pStm || !pclsid)
9389         return E_INVALIDARG;
9390
9391     /* clear the output args */
9392     *pclsid = CLSID_NULL;
9393
9394     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
9395
9396     if (FAILED(res))
9397         return res;
9398
9399     if (nbByte != sizeof(CLSID))
9400         return STG_E_READFAULT;
9401     else
9402         return S_OK;
9403 }