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