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