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