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