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