kernel32: Properly handle bare console on input.
[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);
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
2764   /*
2765    * Start searching for free blocks with block 0.
2766    */
2767   This->prevFreeBlock = 0;
2768
2769   This->firstFreeSmallBlock = 0;
2770
2771   /*
2772    * Create the block chain abstractions.
2773    */
2774   if(!(This->rootBlockChain =
2775        BlockChainStream_Construct(This, &This->rootStartBlock, DIRENTRY_NULL)))
2776   {
2777     hr = STG_E_READFAULT;
2778     goto end;
2779   }
2780
2781   if(!(This->smallBlockDepotChain =
2782        BlockChainStream_Construct(This, &This->smallBlockDepotStart,
2783                                   DIRENTRY_NULL)))
2784   {
2785     hr = STG_E_READFAULT;
2786     goto end;
2787   }
2788
2789   /*
2790    * Write the root storage entry (memory only)
2791    */
2792   if (create)
2793   {
2794     DirEntry rootEntry;
2795     /*
2796      * Initialize the directory table
2797      */
2798     memset(&rootEntry, 0, sizeof(rootEntry));
2799     MultiByteToWideChar( CP_ACP, 0, rootEntryName, -1, rootEntry.name,
2800                          sizeof(rootEntry.name)/sizeof(WCHAR) );
2801     rootEntry.sizeOfNameString = (strlenW(rootEntry.name)+1) * sizeof(WCHAR);
2802     rootEntry.stgType          = STGTY_ROOT;
2803     rootEntry.leftChild = DIRENTRY_NULL;
2804     rootEntry.rightChild     = DIRENTRY_NULL;
2805     rootEntry.dirRootEntry     = DIRENTRY_NULL;
2806     rootEntry.startingBlock    = BLOCK_END_OF_CHAIN;
2807     rootEntry.size.u.HighPart    = 0;
2808     rootEntry.size.u.LowPart     = 0;
2809
2810     StorageImpl_WriteDirEntry(This, 0, &rootEntry);
2811   }
2812
2813   /*
2814    * Find the ID of the root storage.
2815    */
2816   currentEntryRef = 0;
2817
2818   do
2819   {
2820     hr = StorageImpl_ReadDirEntry(
2821                       This,
2822                       currentEntryRef,
2823                       &currentEntry);
2824
2825     if (SUCCEEDED(hr))
2826     {
2827       if ( (currentEntry.sizeOfNameString != 0 ) &&
2828            (currentEntry.stgType          == STGTY_ROOT) )
2829       {
2830         This->base.storageDirEntry = currentEntryRef;
2831       }
2832     }
2833
2834     currentEntryRef++;
2835
2836   } while (SUCCEEDED(hr) && (This->base.storageDirEntry == DIRENTRY_NULL) );
2837
2838   if (FAILED(hr))
2839   {
2840     hr = STG_E_READFAULT;
2841     goto end;
2842   }
2843
2844   /*
2845    * Create the block chain abstraction for the small block root chain.
2846    */
2847   if(!(This->smallBlockRootChain =
2848        BlockChainStream_Construct(This, NULL, This->base.storageDirEntry)))
2849   {
2850     hr = STG_E_READFAULT;
2851   }
2852
2853 end:
2854   if (FAILED(hr))
2855   {
2856     IStorage_Release((IStorage*)This);
2857     *result = NULL;
2858   }
2859   else
2860   {
2861     StorageImpl_Flush((StorageBaseImpl*)This);
2862     *result = This;
2863   }
2864
2865   return hr;
2866 }
2867
2868 static void StorageImpl_Invalidate(StorageBaseImpl* iface)
2869 {
2870   StorageImpl *This = (StorageImpl*) iface;
2871
2872   StorageBaseImpl_DeleteAll(&This->base);
2873
2874   This->base.reverted = 1;
2875 }
2876
2877 static void StorageImpl_Destroy(StorageBaseImpl* iface)
2878 {
2879   StorageImpl *This = (StorageImpl*) iface;
2880   int i;
2881   TRACE("(%p)\n", This);
2882
2883   StorageImpl_Flush(iface);
2884
2885   StorageImpl_Invalidate(iface);
2886
2887   BlockChainStream_Destroy(This->smallBlockRootChain);
2888   BlockChainStream_Destroy(This->rootBlockChain);
2889   BlockChainStream_Destroy(This->smallBlockDepotChain);
2890
2891   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
2892     BlockChainStream_Destroy(This->blockChainCache[i]);
2893
2894   if (This->lockBytes)
2895     ILockBytes_Release(This->lockBytes);
2896   HeapFree(GetProcessHeap(), 0, This);
2897 }
2898
2899 static HRESULT StorageImpl_Flush(StorageBaseImpl* iface)
2900 {
2901   StorageImpl *This = (StorageImpl*) iface;
2902   int i;
2903   HRESULT hr;
2904   TRACE("(%p)\n", This);
2905
2906   hr = BlockChainStream_Flush(This->smallBlockRootChain);
2907
2908   if (SUCCEEDED(hr))
2909     hr = BlockChainStream_Flush(This->rootBlockChain);
2910
2911   if (SUCCEEDED(hr))
2912     hr = BlockChainStream_Flush(This->smallBlockDepotChain);
2913
2914   for (i=0; SUCCEEDED(hr) && i<BLOCKCHAIN_CACHE_SIZE; i++)
2915     if (This->blockChainCache[i])
2916       hr = BlockChainStream_Flush(This->blockChainCache[i]);
2917
2918   if (SUCCEEDED(hr))
2919     hr = ILockBytes_Flush(This->lockBytes);
2920
2921   return hr;
2922 }
2923
2924 /******************************************************************************
2925  *      Storage32Impl_GetNextFreeBigBlock
2926  *
2927  * Returns the index of the next free big block.
2928  * If the big block depot is filled, this method will enlarge it.
2929  *
2930  */
2931 static ULONG StorageImpl_GetNextFreeBigBlock(
2932   StorageImpl* This)
2933 {
2934   ULONG depotBlockIndexPos;
2935   BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
2936   BOOL success;
2937   ULONG depotBlockOffset;
2938   ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
2939   ULONG nextBlockIndex    = BLOCK_SPECIAL;
2940   int   depotIndex        = 0;
2941   ULONG freeBlock         = BLOCK_UNUSED;
2942   ULARGE_INTEGER neededSize;
2943   STATSTG statstg;
2944
2945   depotIndex = This->prevFreeBlock / blocksPerDepot;
2946   depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2947
2948   /*
2949    * Scan the entire big block depot until we find a block marked free
2950    */
2951   while (nextBlockIndex != BLOCK_UNUSED)
2952   {
2953     if (depotIndex < COUNT_BBDEPOTINHEADER)
2954     {
2955       depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2956
2957       /*
2958        * Grow the primary depot.
2959        */
2960       if (depotBlockIndexPos == BLOCK_UNUSED)
2961       {
2962         depotBlockIndexPos = depotIndex*blocksPerDepot;
2963
2964         /*
2965          * Add a block depot.
2966          */
2967         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2968         This->bigBlockDepotCount++;
2969         This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2970
2971         /*
2972          * Flag it as a block depot.
2973          */
2974         StorageImpl_SetNextBlockInChain(This,
2975                                           depotBlockIndexPos,
2976                                           BLOCK_SPECIAL);
2977
2978         /* Save new header information.
2979          */
2980         StorageImpl_SaveFileHeader(This);
2981       }
2982     }
2983     else
2984     {
2985       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2986
2987       if (depotBlockIndexPos == BLOCK_UNUSED)
2988       {
2989         /*
2990          * Grow the extended depot.
2991          */
2992         ULONG extIndex       = BLOCK_UNUSED;
2993         ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
2994         ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2995
2996         if (extBlockOffset == 0)
2997         {
2998           /* We need an extended block.
2999            */
3000           extIndex = Storage32Impl_AddExtBlockDepot(This);
3001           This->extBigBlockDepotCount++;
3002           depotBlockIndexPos = extIndex + 1;
3003         }
3004         else
3005           depotBlockIndexPos = depotIndex * blocksPerDepot;
3006
3007         /*
3008          * Add a block depot and mark it in the extended block.
3009          */
3010         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
3011         This->bigBlockDepotCount++;
3012         Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
3013
3014         /* Flag the block depot.
3015          */
3016         StorageImpl_SetNextBlockInChain(This,
3017                                           depotBlockIndexPos,
3018                                           BLOCK_SPECIAL);
3019
3020         /* If necessary, flag the extended depot block.
3021          */
3022         if (extIndex != BLOCK_UNUSED)
3023           StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
3024
3025         /* Save header information.
3026          */
3027         StorageImpl_SaveFileHeader(This);
3028       }
3029     }
3030
3031     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
3032
3033     if (success)
3034     {
3035       while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
3036               ( nextBlockIndex != BLOCK_UNUSED))
3037       {
3038         StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
3039
3040         if (nextBlockIndex == BLOCK_UNUSED)
3041         {
3042           freeBlock = (depotIndex * blocksPerDepot) +
3043                       (depotBlockOffset/sizeof(ULONG));
3044         }
3045
3046         depotBlockOffset += sizeof(ULONG);
3047       }
3048     }
3049
3050     depotIndex++;
3051     depotBlockOffset = 0;
3052   }
3053
3054   /*
3055    * make sure that the block physically exists before using it
3056    */
3057   neededSize.QuadPart = StorageImpl_GetBigBlockOffset(This, freeBlock)+This->bigBlockSize;
3058
3059   ILockBytes_Stat(This->lockBytes, &statstg, STATFLAG_NONAME);
3060
3061   if (neededSize.QuadPart > statstg.cbSize.QuadPart)
3062     ILockBytes_SetSize(This->lockBytes, neededSize);
3063
3064   This->prevFreeBlock = freeBlock;
3065
3066   return freeBlock;
3067 }
3068
3069 /******************************************************************************
3070  *      Storage32Impl_AddBlockDepot
3071  *
3072  * This will create a depot block, essentially it is a block initialized
3073  * to BLOCK_UNUSEDs.
3074  */
3075 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
3076 {
3077   BYTE blockBuffer[MAX_BIG_BLOCK_SIZE];
3078
3079   /*
3080    * Initialize blocks as free
3081    */
3082   memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
3083   StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
3084 }
3085
3086 /******************************************************************************
3087  *      Storage32Impl_GetExtDepotBlock
3088  *
3089  * Returns the index of the block that corresponds to the specified depot
3090  * index. This method is only for depot indexes equal or greater than
3091  * COUNT_BBDEPOTINHEADER.
3092  */
3093 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
3094 {
3095   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
3096   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
3097   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
3098   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
3099   ULONG blockIndex             = BLOCK_UNUSED;
3100   ULONG extBlockIndex          = This->extBigBlockDepotStart;
3101
3102   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
3103
3104   if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
3105     return BLOCK_UNUSED;
3106
3107   while (extBlockCount > 0)
3108   {
3109     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
3110     extBlockCount--;
3111   }
3112
3113   if (extBlockIndex != BLOCK_UNUSED)
3114     StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex,
3115                         extBlockOffset * sizeof(ULONG), &blockIndex);
3116
3117   return blockIndex;
3118 }
3119
3120 /******************************************************************************
3121  *      Storage32Impl_SetExtDepotBlock
3122  *
3123  * Associates the specified block index to the specified depot index.
3124  * This method is only for depot indexes equal or greater than
3125  * COUNT_BBDEPOTINHEADER.
3126  */
3127 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
3128 {
3129   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
3130   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
3131   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
3132   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
3133   ULONG extBlockIndex          = This->extBigBlockDepotStart;
3134
3135   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
3136
3137   while (extBlockCount > 0)
3138   {
3139     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
3140     extBlockCount--;
3141   }
3142
3143   if (extBlockIndex != BLOCK_UNUSED)
3144   {
3145     StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
3146                         extBlockOffset * sizeof(ULONG),
3147                         blockIndex);
3148   }
3149 }
3150
3151 /******************************************************************************
3152  *      Storage32Impl_AddExtBlockDepot
3153  *
3154  * Creates an extended depot block.
3155  */
3156 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
3157 {
3158   ULONG numExtBlocks           = This->extBigBlockDepotCount;
3159   ULONG nextExtBlock           = This->extBigBlockDepotStart;
3160   BYTE  depotBuffer[MAX_BIG_BLOCK_SIZE];
3161   ULONG index                  = BLOCK_UNUSED;
3162   ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
3163   ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
3164   ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
3165
3166   index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
3167           blocksPerDepotBlock;
3168
3169   if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
3170   {
3171     /*
3172      * The first extended block.
3173      */
3174     This->extBigBlockDepotStart = index;
3175   }
3176   else
3177   {
3178     unsigned int i;
3179     /*
3180      * Follow the chain to the last one.
3181      */
3182     for (i = 0; i < (numExtBlocks - 1); i++)
3183     {
3184       nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
3185     }
3186
3187     /*
3188      * Add the new extended block to the chain.
3189      */
3190     StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
3191                                      index);
3192   }
3193
3194   /*
3195    * Initialize this block.
3196    */
3197   memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
3198   StorageImpl_WriteBigBlock(This, index, depotBuffer);
3199
3200   return index;
3201 }
3202
3203 /******************************************************************************
3204  *      Storage32Impl_FreeBigBlock
3205  *
3206  * This method will flag the specified block as free in the big block depot.
3207  */
3208 static void StorageImpl_FreeBigBlock(
3209   StorageImpl* This,
3210   ULONG          blockIndex)
3211 {
3212   StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
3213
3214   if (blockIndex < This->prevFreeBlock)
3215     This->prevFreeBlock = blockIndex;
3216 }
3217
3218 /************************************************************************
3219  * Storage32Impl_GetNextBlockInChain
3220  *
3221  * This method will retrieve the block index of the next big block in
3222  * in the chain.
3223  *
3224  * Params:  This       - Pointer to the Storage object.
3225  *          blockIndex - Index of the block to retrieve the chain
3226  *                       for.
3227  *          nextBlockIndex - receives the return value.
3228  *
3229  * Returns: This method returns the index of the next block in the chain.
3230  *          It will return the constants:
3231  *              BLOCK_SPECIAL - If the block given was not part of a
3232  *                              chain.
3233  *              BLOCK_END_OF_CHAIN - If the block given was the last in
3234  *                                   a chain.
3235  *              BLOCK_UNUSED - If the block given was not past of a chain
3236  *                             and is available.
3237  *              BLOCK_EXTBBDEPOT - This block is part of the extended
3238  *                                 big block depot.
3239  *
3240  * See Windows documentation for more details on IStorage methods.
3241  */
3242 static HRESULT StorageImpl_GetNextBlockInChain(
3243   StorageImpl* This,
3244   ULONG        blockIndex,
3245   ULONG*       nextBlockIndex)
3246 {
3247   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
3248   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
3249   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
3250   BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
3251   BOOL success;
3252   ULONG depotBlockIndexPos;
3253   int index, num_blocks;
3254
3255   *nextBlockIndex   = BLOCK_SPECIAL;
3256
3257   if(depotBlockCount >= This->bigBlockDepotCount)
3258   {
3259     WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount,
3260          This->bigBlockDepotCount);
3261     return STG_E_READFAULT;
3262   }
3263
3264   /*
3265    * Cache the currently accessed depot block.
3266    */
3267   if (depotBlockCount != This->indexBlockDepotCached)
3268   {
3269     This->indexBlockDepotCached = depotBlockCount;
3270
3271     if (depotBlockCount < COUNT_BBDEPOTINHEADER)
3272     {
3273       depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
3274     }
3275     else
3276     {
3277       /*
3278        * We have to look in the extended depot.
3279        */
3280       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
3281     }
3282
3283     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
3284
3285     if (!success)
3286       return STG_E_READFAULT;
3287
3288     num_blocks = This->bigBlockSize / 4;
3289
3290     for (index = 0; index < num_blocks; index++)
3291     {
3292       StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
3293       This->blockDepotCached[index] = *nextBlockIndex;
3294     }
3295   }
3296
3297   *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
3298
3299   return S_OK;
3300 }
3301
3302 /******************************************************************************
3303  *      Storage32Impl_GetNextExtendedBlock
3304  *
3305  * Given an extended block this method will return the next extended block.
3306  *
3307  * NOTES:
3308  * The last ULONG of an extended block is the block index of the next
3309  * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
3310  * depot.
3311  *
3312  * Return values:
3313  *    - The index of the next extended block
3314  *    - BLOCK_UNUSED: there is no next extended block.
3315  *    - Any other return values denotes failure.
3316  */
3317 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
3318 {
3319   ULONG nextBlockIndex   = BLOCK_SPECIAL;
3320   ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
3321
3322   StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
3323                         &nextBlockIndex);
3324
3325   return nextBlockIndex;
3326 }
3327
3328 /******************************************************************************
3329  *      Storage32Impl_SetNextBlockInChain
3330  *
3331  * This method will write the index of the specified block's next block
3332  * in the big block depot.
3333  *
3334  * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
3335  *              do the following
3336  *
3337  * Storage32Impl_SetNextBlockInChain(This, 3, 1);
3338  * Storage32Impl_SetNextBlockInChain(This, 1, 7);
3339  * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
3340  *
3341  */
3342 static void StorageImpl_SetNextBlockInChain(
3343           StorageImpl* This,
3344           ULONG          blockIndex,
3345           ULONG          nextBlock)
3346 {
3347   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
3348   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
3349   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
3350   ULONG depotBlockIndexPos;
3351
3352   assert(depotBlockCount < This->bigBlockDepotCount);
3353   assert(blockIndex != nextBlock);
3354
3355   if (depotBlockCount < COUNT_BBDEPOTINHEADER)
3356   {
3357     depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
3358   }
3359   else
3360   {
3361     /*
3362      * We have to look in the extended depot.
3363      */
3364     depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
3365   }
3366
3367   StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
3368                         nextBlock);
3369   /*
3370    * Update the cached block depot, if necessary.
3371    */
3372   if (depotBlockCount == This->indexBlockDepotCached)
3373   {
3374     This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
3375   }
3376 }
3377
3378 /******************************************************************************
3379  *      Storage32Impl_LoadFileHeader
3380  *
3381  * This method will read in the file header
3382  */
3383 static HRESULT StorageImpl_LoadFileHeader(
3384           StorageImpl* This)
3385 {
3386   HRESULT hr;
3387   BYTE    headerBigBlock[HEADER_SIZE];
3388   int     index;
3389   ULARGE_INTEGER offset;
3390   DWORD bytes_read;
3391
3392   TRACE("\n");
3393   /*
3394    * Get a pointer to the big block of data containing the header.
3395    */
3396   offset.u.HighPart = 0;
3397   offset.u.LowPart = 0;
3398   hr = StorageImpl_ReadAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_read);
3399   if (SUCCEEDED(hr) && bytes_read != HEADER_SIZE)
3400     hr = STG_E_FILENOTFOUND;
3401
3402   /*
3403    * Extract the information from the header.
3404    */
3405   if (SUCCEEDED(hr))
3406   {
3407     /*
3408      * Check for the "magic number" signature and return an error if it is not
3409      * found.
3410      */
3411     if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
3412     {
3413       return STG_E_OLDFORMAT;
3414     }
3415
3416     if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
3417     {
3418       return STG_E_INVALIDHEADER;
3419     }
3420
3421     StorageUtl_ReadWord(
3422       headerBigBlock,
3423       OFFSET_BIGBLOCKSIZEBITS,
3424       &This->bigBlockSizeBits);
3425
3426     StorageUtl_ReadWord(
3427       headerBigBlock,
3428       OFFSET_SMALLBLOCKSIZEBITS,
3429       &This->smallBlockSizeBits);
3430
3431     StorageUtl_ReadDWord(
3432       headerBigBlock,
3433       OFFSET_BBDEPOTCOUNT,
3434       &This->bigBlockDepotCount);
3435
3436     StorageUtl_ReadDWord(
3437       headerBigBlock,
3438       OFFSET_ROOTSTARTBLOCK,
3439       &This->rootStartBlock);
3440
3441     StorageUtl_ReadDWord(
3442       headerBigBlock,
3443       OFFSET_SMALLBLOCKLIMIT,
3444       &This->smallBlockLimit);
3445
3446     StorageUtl_ReadDWord(
3447       headerBigBlock,
3448       OFFSET_SBDEPOTSTART,
3449       &This->smallBlockDepotStart);
3450
3451     StorageUtl_ReadDWord(
3452       headerBigBlock,
3453       OFFSET_EXTBBDEPOTSTART,
3454       &This->extBigBlockDepotStart);
3455
3456     StorageUtl_ReadDWord(
3457       headerBigBlock,
3458       OFFSET_EXTBBDEPOTCOUNT,
3459       &This->extBigBlockDepotCount);
3460
3461     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3462     {
3463       StorageUtl_ReadDWord(
3464         headerBigBlock,
3465         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3466         &(This->bigBlockDepotStart[index]));
3467     }
3468
3469     /*
3470      * Make the bitwise arithmetic to get the size of the blocks in bytes.
3471      */
3472     This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
3473     This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
3474
3475     /*
3476      * Right now, the code is making some assumptions about the size of the
3477      * blocks, just make sure they are what we're expecting.
3478      */
3479     if ((This->bigBlockSize != MIN_BIG_BLOCK_SIZE && This->bigBlockSize != MAX_BIG_BLOCK_SIZE) ||
3480         This->smallBlockSize != DEF_SMALL_BLOCK_SIZE ||
3481         This->smallBlockLimit != LIMIT_TO_USE_SMALL_BLOCK)
3482     {
3483         FIXME("Broken OLE storage file? bigblock=0x%x, smallblock=0x%x, sblimit=0x%x\n",
3484             This->bigBlockSize, This->smallBlockSize, This->smallBlockLimit);
3485         hr = STG_E_INVALIDHEADER;
3486     }
3487     else
3488         hr = S_OK;
3489   }
3490
3491   return hr;
3492 }
3493
3494 /******************************************************************************
3495  *      Storage32Impl_SaveFileHeader
3496  *
3497  * This method will save to the file the header
3498  */
3499 static void StorageImpl_SaveFileHeader(
3500           StorageImpl* This)
3501 {
3502   BYTE   headerBigBlock[HEADER_SIZE];
3503   int    index;
3504   HRESULT hr;
3505   ULARGE_INTEGER offset;
3506   DWORD bytes_read, bytes_written;
3507   DWORD major_version, dirsectorcount;
3508
3509   /*
3510    * Get a pointer to the big block of data containing the header.
3511    */
3512   offset.u.HighPart = 0;
3513   offset.u.LowPart = 0;
3514   hr = StorageImpl_ReadAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_read);
3515   if (SUCCEEDED(hr) && bytes_read != HEADER_SIZE)
3516     hr = STG_E_FILENOTFOUND;
3517
3518   if (This->bigBlockSizeBits == 0x9)
3519     major_version = 3;
3520   else if (This->bigBlockSizeBits == 0xc)
3521     major_version = 4;
3522   else
3523   {
3524     ERR("invalid big block shift 0x%x\n", This->bigBlockSizeBits);
3525     major_version = 4;
3526   }
3527
3528   /*
3529    * If the block read failed, the file is probably new.
3530    */
3531   if (FAILED(hr))
3532   {
3533     /*
3534      * Initialize for all unknown fields.
3535      */
3536     memset(headerBigBlock, 0, HEADER_SIZE);
3537
3538     /*
3539      * Initialize the magic number.
3540      */
3541     memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
3542   }
3543
3544   /*
3545    * Write the information to the header.
3546    */
3547   StorageUtl_WriteWord(
3548     headerBigBlock,
3549     OFFSET_MINORVERSION,
3550     0x3e);
3551
3552   StorageUtl_WriteWord(
3553     headerBigBlock,
3554     OFFSET_MAJORVERSION,
3555     major_version);
3556
3557   StorageUtl_WriteWord(
3558     headerBigBlock,
3559     OFFSET_BYTEORDERMARKER,
3560     (WORD)-2);
3561
3562   StorageUtl_WriteWord(
3563     headerBigBlock,
3564     OFFSET_BIGBLOCKSIZEBITS,
3565     This->bigBlockSizeBits);
3566
3567   StorageUtl_WriteWord(
3568     headerBigBlock,
3569     OFFSET_SMALLBLOCKSIZEBITS,
3570     This->smallBlockSizeBits);
3571
3572   if (major_version >= 4)
3573   {
3574     if (This->rootBlockChain)
3575       dirsectorcount = BlockChainStream_GetCount(This->rootBlockChain);
3576     else
3577       /* This file is being created, and it will start out with one block. */
3578       dirsectorcount = 1;
3579   }
3580   else
3581     /* This field must be 0 in versions older than 4 */
3582     dirsectorcount = 0;
3583
3584   StorageUtl_WriteDWord(
3585     headerBigBlock,
3586     OFFSET_DIRSECTORCOUNT,
3587     dirsectorcount);
3588
3589   StorageUtl_WriteDWord(
3590     headerBigBlock,
3591     OFFSET_BBDEPOTCOUNT,
3592     This->bigBlockDepotCount);
3593
3594   StorageUtl_WriteDWord(
3595     headerBigBlock,
3596     OFFSET_ROOTSTARTBLOCK,
3597     This->rootStartBlock);
3598
3599   StorageUtl_WriteDWord(
3600     headerBigBlock,
3601     OFFSET_SMALLBLOCKLIMIT,
3602     This->smallBlockLimit);
3603
3604   StorageUtl_WriteDWord(
3605     headerBigBlock,
3606     OFFSET_SBDEPOTSTART,
3607     This->smallBlockDepotStart);
3608
3609   StorageUtl_WriteDWord(
3610     headerBigBlock,
3611     OFFSET_SBDEPOTCOUNT,
3612     This->smallBlockDepotChain ?
3613      BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
3614
3615   StorageUtl_WriteDWord(
3616     headerBigBlock,
3617     OFFSET_EXTBBDEPOTSTART,
3618     This->extBigBlockDepotStart);
3619
3620   StorageUtl_WriteDWord(
3621     headerBigBlock,
3622     OFFSET_EXTBBDEPOTCOUNT,
3623     This->extBigBlockDepotCount);
3624
3625   for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3626   {
3627     StorageUtl_WriteDWord(
3628       headerBigBlock,
3629       OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3630       (This->bigBlockDepotStart[index]));
3631   }
3632
3633   /*
3634    * Write the big block back to the file.
3635    */
3636   StorageImpl_WriteAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_written);
3637 }
3638
3639 /******************************************************************************
3640  *      StorageImpl_ReadRawDirEntry
3641  *
3642  * This method will read the raw data from a directory entry in the file.
3643  *
3644  * buffer must be RAW_DIRENTRY_SIZE bytes long.
3645  */
3646 HRESULT StorageImpl_ReadRawDirEntry(StorageImpl *This, ULONG index, BYTE *buffer)
3647 {
3648   ULARGE_INTEGER offset;
3649   HRESULT hr;
3650   ULONG bytesRead;
3651
3652   offset.u.HighPart = 0;
3653   offset.u.LowPart  = index * RAW_DIRENTRY_SIZE;
3654
3655   hr = BlockChainStream_ReadAt(
3656                     This->rootBlockChain,
3657                     offset,
3658                     RAW_DIRENTRY_SIZE,
3659                     buffer,
3660                     &bytesRead);
3661
3662   if (bytesRead != RAW_DIRENTRY_SIZE)
3663     return STG_E_READFAULT;
3664
3665   return hr;
3666 }
3667
3668 /******************************************************************************
3669  *      StorageImpl_WriteRawDirEntry
3670  *
3671  * This method will write the raw data from a directory entry in the file.
3672  *
3673  * buffer must be RAW_DIRENTRY_SIZE bytes long.
3674  */
3675 HRESULT StorageImpl_WriteRawDirEntry(StorageImpl *This, ULONG index, const BYTE *buffer)
3676 {
3677   ULARGE_INTEGER offset;
3678   HRESULT hr;
3679   ULONG bytesRead;
3680
3681   offset.u.HighPart = 0;
3682   offset.u.LowPart  = index * RAW_DIRENTRY_SIZE;
3683
3684   hr = BlockChainStream_WriteAt(
3685                     This->rootBlockChain,
3686                     offset,
3687                     RAW_DIRENTRY_SIZE,
3688                     buffer,
3689                     &bytesRead);
3690
3691   return hr;
3692 }
3693
3694 /******************************************************************************
3695  *      UpdateRawDirEntry
3696  *
3697  * Update raw directory entry data from the fields in newData.
3698  *
3699  * buffer must be RAW_DIRENTRY_SIZE bytes long.
3700  */
3701 void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData)
3702 {
3703   memset(buffer, 0, RAW_DIRENTRY_SIZE);
3704
3705   memcpy(
3706     buffer + OFFSET_PS_NAME,
3707     newData->name,
3708     DIRENTRY_NAME_BUFFER_LEN );
3709
3710   memcpy(buffer + OFFSET_PS_STGTYPE, &newData->stgType, 1);
3711
3712   StorageUtl_WriteWord(
3713     buffer,
3714       OFFSET_PS_NAMELENGTH,
3715       newData->sizeOfNameString);
3716
3717   StorageUtl_WriteDWord(
3718     buffer,
3719       OFFSET_PS_LEFTCHILD,
3720       newData->leftChild);
3721
3722   StorageUtl_WriteDWord(
3723     buffer,
3724       OFFSET_PS_RIGHTCHILD,
3725       newData->rightChild);
3726
3727   StorageUtl_WriteDWord(
3728     buffer,
3729       OFFSET_PS_DIRROOT,
3730       newData->dirRootEntry);
3731
3732   StorageUtl_WriteGUID(
3733     buffer,
3734       OFFSET_PS_GUID,
3735       &newData->clsid);
3736
3737   StorageUtl_WriteDWord(
3738     buffer,
3739       OFFSET_PS_CTIMELOW,
3740       newData->ctime.dwLowDateTime);
3741
3742   StorageUtl_WriteDWord(
3743     buffer,
3744       OFFSET_PS_CTIMEHIGH,
3745       newData->ctime.dwHighDateTime);
3746
3747   StorageUtl_WriteDWord(
3748     buffer,
3749       OFFSET_PS_MTIMELOW,
3750       newData->mtime.dwLowDateTime);
3751
3752   StorageUtl_WriteDWord(
3753     buffer,
3754       OFFSET_PS_MTIMEHIGH,
3755       newData->ctime.dwHighDateTime);
3756
3757   StorageUtl_WriteDWord(
3758     buffer,
3759       OFFSET_PS_STARTBLOCK,
3760       newData->startingBlock);
3761
3762   StorageUtl_WriteDWord(
3763     buffer,
3764       OFFSET_PS_SIZE,
3765       newData->size.u.LowPart);
3766 }
3767
3768 /******************************************************************************
3769  *      Storage32Impl_ReadDirEntry
3770  *
3771  * This method will read the specified directory entry.
3772  */
3773 HRESULT StorageImpl_ReadDirEntry(
3774   StorageImpl* This,
3775   DirRef         index,
3776   DirEntry*      buffer)
3777 {
3778   BYTE           currentEntry[RAW_DIRENTRY_SIZE];
3779   HRESULT        readRes;
3780
3781   readRes = StorageImpl_ReadRawDirEntry(This, index, currentEntry);
3782
3783   if (SUCCEEDED(readRes))
3784   {
3785     memset(buffer->name, 0, sizeof(buffer->name));
3786     memcpy(
3787       buffer->name,
3788       (WCHAR *)currentEntry+OFFSET_PS_NAME,
3789       DIRENTRY_NAME_BUFFER_LEN );
3790     TRACE("storage name: %s\n", debugstr_w(buffer->name));
3791
3792     memcpy(&buffer->stgType, currentEntry + OFFSET_PS_STGTYPE, 1);
3793
3794     StorageUtl_ReadWord(
3795       currentEntry,
3796       OFFSET_PS_NAMELENGTH,
3797       &buffer->sizeOfNameString);
3798
3799     StorageUtl_ReadDWord(
3800       currentEntry,
3801       OFFSET_PS_LEFTCHILD,
3802       &buffer->leftChild);
3803
3804     StorageUtl_ReadDWord(
3805       currentEntry,
3806       OFFSET_PS_RIGHTCHILD,
3807       &buffer->rightChild);
3808
3809     StorageUtl_ReadDWord(
3810       currentEntry,
3811       OFFSET_PS_DIRROOT,
3812       &buffer->dirRootEntry);
3813
3814     StorageUtl_ReadGUID(
3815       currentEntry,
3816       OFFSET_PS_GUID,
3817       &buffer->clsid);
3818
3819     StorageUtl_ReadDWord(
3820       currentEntry,
3821       OFFSET_PS_CTIMELOW,
3822       &buffer->ctime.dwLowDateTime);
3823
3824     StorageUtl_ReadDWord(
3825       currentEntry,
3826       OFFSET_PS_CTIMEHIGH,
3827       &buffer->ctime.dwHighDateTime);
3828
3829     StorageUtl_ReadDWord(
3830       currentEntry,
3831       OFFSET_PS_MTIMELOW,
3832       &buffer->mtime.dwLowDateTime);
3833
3834     StorageUtl_ReadDWord(
3835       currentEntry,
3836       OFFSET_PS_MTIMEHIGH,
3837       &buffer->mtime.dwHighDateTime);
3838
3839     StorageUtl_ReadDWord(
3840       currentEntry,
3841       OFFSET_PS_STARTBLOCK,
3842       &buffer->startingBlock);
3843
3844     StorageUtl_ReadDWord(
3845       currentEntry,
3846       OFFSET_PS_SIZE,
3847       &buffer->size.u.LowPart);
3848
3849     buffer->size.u.HighPart = 0;
3850   }
3851
3852   return readRes;
3853 }
3854
3855 /*********************************************************************
3856  * Write the specified directory entry to the file
3857  */
3858 HRESULT StorageImpl_WriteDirEntry(
3859   StorageImpl*          This,
3860   DirRef                index,
3861   const DirEntry*       buffer)
3862 {
3863   BYTE           currentEntry[RAW_DIRENTRY_SIZE];
3864   HRESULT        writeRes;
3865
3866   UpdateRawDirEntry(currentEntry, buffer);
3867
3868   writeRes = StorageImpl_WriteRawDirEntry(This, index, currentEntry);
3869   return writeRes;
3870 }
3871
3872 static BOOL StorageImpl_ReadBigBlock(
3873   StorageImpl* This,
3874   ULONG          blockIndex,
3875   void*          buffer)
3876 {
3877   ULARGE_INTEGER ulOffset;
3878   DWORD  read;
3879
3880   ulOffset.u.HighPart = 0;
3881   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3882
3883   StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
3884   return (read == This->bigBlockSize);
3885 }
3886
3887 static BOOL StorageImpl_ReadDWordFromBigBlock(
3888   StorageImpl*  This,
3889   ULONG         blockIndex,
3890   ULONG         offset,
3891   DWORD*        value)
3892 {
3893   ULARGE_INTEGER ulOffset;
3894   DWORD  read;
3895   DWORD  tmp;
3896
3897   ulOffset.u.HighPart = 0;
3898   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3899   ulOffset.u.LowPart += offset;
3900
3901   StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
3902   *value = lendian32toh(tmp);
3903   return (read == sizeof(DWORD));
3904 }
3905
3906 static BOOL StorageImpl_WriteBigBlock(
3907   StorageImpl*  This,
3908   ULONG         blockIndex,
3909   const void*   buffer)
3910 {
3911   ULARGE_INTEGER ulOffset;
3912   DWORD  wrote;
3913
3914   ulOffset.u.HighPart = 0;
3915   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3916
3917   StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
3918   return (wrote == This->bigBlockSize);
3919 }
3920
3921 static BOOL StorageImpl_WriteDWordToBigBlock(
3922   StorageImpl* This,
3923   ULONG         blockIndex,
3924   ULONG         offset,
3925   DWORD         value)
3926 {
3927   ULARGE_INTEGER ulOffset;
3928   DWORD  wrote;
3929
3930   ulOffset.u.HighPart = 0;
3931   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3932   ulOffset.u.LowPart += offset;
3933
3934   value = htole32(value);
3935   StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
3936   return (wrote == sizeof(DWORD));
3937 }
3938
3939 /******************************************************************************
3940  *              Storage32Impl_SmallBlocksToBigBlocks
3941  *
3942  * This method will convert a small block chain to a big block chain.
3943  * The small block chain will be destroyed.
3944  */
3945 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3946                       StorageImpl* This,
3947                       SmallBlockChainStream** ppsbChain)
3948 {
3949   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3950   ULARGE_INTEGER size, offset;
3951   ULONG cbRead, cbWritten;
3952   ULARGE_INTEGER cbTotalRead;
3953   DirRef streamEntryRef;
3954   HRESULT resWrite = S_OK;
3955   HRESULT resRead;
3956   DirEntry streamEntry;
3957   BYTE *buffer;
3958   BlockChainStream *bbTempChain = NULL;
3959   BlockChainStream *bigBlockChain = NULL;
3960
3961   /*
3962    * Create a temporary big block chain that doesn't have
3963    * an associated directory entry. This temporary chain will be
3964    * used to copy data from small blocks to big blocks.
3965    */
3966   bbTempChain = BlockChainStream_Construct(This,
3967                                            &bbHeadOfChain,
3968                                            DIRENTRY_NULL);
3969   if(!bbTempChain) return NULL;
3970   /*
3971    * Grow the big block chain.
3972    */
3973   size = SmallBlockChainStream_GetSize(*ppsbChain);
3974   BlockChainStream_SetSize(bbTempChain, size);
3975
3976   /*
3977    * Copy the contents of the small block chain to the big block chain
3978    * by small block size increments.
3979    */
3980   offset.u.LowPart = 0;
3981   offset.u.HighPart = 0;
3982   cbTotalRead.QuadPart = 0;
3983
3984   buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3985   do
3986   {
3987     resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3988                                            offset,
3989                                            min(This->smallBlockSize, size.u.LowPart - offset.u.LowPart),
3990                                            buffer,
3991                                            &cbRead);
3992     if (FAILED(resRead))
3993         break;
3994
3995     if (cbRead > 0)
3996     {
3997         cbTotalRead.QuadPart += cbRead;
3998
3999         resWrite = BlockChainStream_WriteAt(bbTempChain,
4000                                             offset,
4001                                             cbRead,
4002                                             buffer,
4003                                             &cbWritten);
4004
4005         if (FAILED(resWrite))
4006             break;
4007
4008         offset.u.LowPart += cbRead;
4009     }
4010     else
4011     {
4012         resRead = STG_E_READFAULT;
4013         break;
4014     }
4015   } while (cbTotalRead.QuadPart < size.QuadPart);
4016   HeapFree(GetProcessHeap(),0,buffer);
4017
4018   size.u.HighPart = 0;
4019   size.u.LowPart  = 0;
4020
4021   if (FAILED(resRead) || FAILED(resWrite))
4022   {
4023     ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
4024     BlockChainStream_SetSize(bbTempChain, size);
4025     BlockChainStream_Destroy(bbTempChain);
4026     return NULL;
4027   }
4028
4029   /*
4030    * Destroy the small block chain.
4031    */
4032   streamEntryRef = (*ppsbChain)->ownerDirEntry;
4033   SmallBlockChainStream_SetSize(*ppsbChain, size);
4034   SmallBlockChainStream_Destroy(*ppsbChain);
4035   *ppsbChain = 0;
4036
4037   /*
4038    * Change the directory entry. This chain is now a big block chain
4039    * and it doesn't reside in the small blocks chain anymore.
4040    */
4041   StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry);
4042
4043   streamEntry.startingBlock = bbHeadOfChain;
4044
4045   StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry);
4046
4047   /*
4048    * Destroy the temporary entryless big block chain.
4049    * Create a new big block chain associated with this entry.
4050    */
4051   BlockChainStream_Destroy(bbTempChain);
4052   bigBlockChain = BlockChainStream_Construct(This,
4053                                              NULL,
4054                                              streamEntryRef);
4055
4056   return bigBlockChain;
4057 }
4058
4059 /******************************************************************************
4060  *              Storage32Impl_BigBlocksToSmallBlocks
4061  *
4062  * This method will convert a big block chain to a small block chain.
4063  * The big block chain will be destroyed on success.
4064  */
4065 SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks(
4066                            StorageImpl* This,
4067                            BlockChainStream** ppbbChain)
4068 {
4069     ULARGE_INTEGER size, offset, cbTotalRead;
4070     ULONG cbRead, cbWritten, sbHeadOfChain = BLOCK_END_OF_CHAIN;
4071     DirRef streamEntryRef;
4072     HRESULT resWrite = S_OK, resRead;
4073     DirEntry streamEntry;
4074     BYTE* buffer;
4075     SmallBlockChainStream* sbTempChain;
4076
4077     TRACE("%p %p\n", This, ppbbChain);
4078
4079     sbTempChain = SmallBlockChainStream_Construct(This, &sbHeadOfChain,
4080             DIRENTRY_NULL);
4081
4082     if(!sbTempChain)
4083         return NULL;
4084
4085     size = BlockChainStream_GetSize(*ppbbChain);
4086     SmallBlockChainStream_SetSize(sbTempChain, size);
4087
4088     offset.u.HighPart = 0;
4089     offset.u.LowPart = 0;
4090     cbTotalRead.QuadPart = 0;
4091     buffer = HeapAlloc(GetProcessHeap(), 0, This->bigBlockSize);
4092     do
4093     {
4094         resRead = BlockChainStream_ReadAt(*ppbbChain, offset,
4095                 min(This->bigBlockSize, size.u.LowPart - offset.u.LowPart),
4096                 buffer, &cbRead);
4097
4098         if(FAILED(resRead))
4099             break;
4100
4101         if(cbRead > 0)
4102         {
4103             cbTotalRead.QuadPart += cbRead;
4104
4105             resWrite = SmallBlockChainStream_WriteAt(sbTempChain, offset,
4106                     cbRead, buffer, &cbWritten);
4107
4108             if(FAILED(resWrite))
4109                 break;
4110
4111             offset.u.LowPart += cbRead;
4112         }
4113         else
4114         {
4115             resRead = STG_E_READFAULT;
4116             break;
4117         }
4118     }while(cbTotalRead.QuadPart < size.QuadPart);
4119     HeapFree(GetProcessHeap(), 0, buffer);
4120
4121     size.u.HighPart = 0;
4122     size.u.LowPart = 0;
4123
4124     if(FAILED(resRead) || FAILED(resWrite))
4125     {
4126         ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
4127         SmallBlockChainStream_SetSize(sbTempChain, size);
4128         SmallBlockChainStream_Destroy(sbTempChain);
4129         return NULL;
4130     }
4131
4132     /* destroy the original big block chain */
4133     streamEntryRef = (*ppbbChain)->ownerDirEntry;
4134     BlockChainStream_SetSize(*ppbbChain, size);
4135     BlockChainStream_Destroy(*ppbbChain);
4136     *ppbbChain = NULL;
4137
4138     StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry);
4139     streamEntry.startingBlock = sbHeadOfChain;
4140     StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry);
4141
4142     SmallBlockChainStream_Destroy(sbTempChain);
4143     return SmallBlockChainStream_Construct(This, NULL, streamEntryRef);
4144 }
4145
4146 static HRESULT StorageBaseImpl_CopyStream(
4147   StorageBaseImpl *dst, DirRef dst_entry,
4148   StorageBaseImpl *src, DirRef src_entry)
4149 {
4150   HRESULT hr;
4151   BYTE data[4096];
4152   DirEntry srcdata;
4153   ULARGE_INTEGER bytes_copied;
4154   ULONG bytestocopy, bytesread, byteswritten;
4155
4156   hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &srcdata);
4157
4158   if (SUCCEEDED(hr))
4159   {
4160     hr = StorageBaseImpl_StreamSetSize(dst, dst_entry, srcdata.size);
4161
4162     bytes_copied.QuadPart = 0;
4163     while (bytes_copied.QuadPart < srcdata.size.QuadPart && SUCCEEDED(hr))
4164     {
4165       bytestocopy = min(4096, srcdata.size.QuadPart - bytes_copied.QuadPart);
4166
4167       hr = StorageBaseImpl_StreamReadAt(src, src_entry, bytes_copied, bytestocopy,
4168         data, &bytesread);
4169       if (SUCCEEDED(hr) && bytesread != bytestocopy) hr = STG_E_READFAULT;
4170
4171       if (SUCCEEDED(hr))
4172         hr = StorageBaseImpl_StreamWriteAt(dst, dst_entry, bytes_copied, bytestocopy,
4173           data, &byteswritten);
4174       if (SUCCEEDED(hr))
4175       {
4176         if (byteswritten != bytestocopy) hr = STG_E_WRITEFAULT;
4177         bytes_copied.QuadPart += byteswritten;
4178       }
4179     }
4180   }
4181
4182   return hr;
4183 }
4184
4185 static DirRef TransactedSnapshotImpl_FindFreeEntry(TransactedSnapshotImpl *This)
4186 {
4187   DirRef result=This->firstFreeEntry;
4188
4189   while (result < This->entries_size && This->entries[result].inuse)
4190     result++;
4191
4192   if (result == This->entries_size)
4193   {
4194     ULONG new_size = This->entries_size * 2;
4195     TransactedDirEntry *new_entries;
4196
4197     new_entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * new_size);
4198     if (!new_entries) return DIRENTRY_NULL;
4199
4200     memcpy(new_entries, This->entries, sizeof(TransactedDirEntry) * This->entries_size);
4201     HeapFree(GetProcessHeap(), 0, This->entries);
4202
4203     This->entries = new_entries;
4204     This->entries_size = new_size;
4205   }
4206
4207   This->entries[result].inuse = 1;
4208
4209   This->firstFreeEntry = result+1;
4210
4211   return result;
4212 }
4213
4214 static DirRef TransactedSnapshotImpl_CreateStubEntry(
4215   TransactedSnapshotImpl *This, DirRef parentEntryRef)
4216 {
4217   DirRef stubEntryRef;
4218   TransactedDirEntry *entry;
4219
4220   stubEntryRef = TransactedSnapshotImpl_FindFreeEntry(This);
4221
4222   if (stubEntryRef != DIRENTRY_NULL)
4223   {
4224     entry = &This->entries[stubEntryRef];
4225
4226     entry->newTransactedParentEntry = entry->transactedParentEntry = parentEntryRef;
4227
4228     entry->read = 0;
4229   }
4230
4231   return stubEntryRef;
4232 }
4233
4234 static HRESULT TransactedSnapshotImpl_EnsureReadEntry(
4235   TransactedSnapshotImpl *This, DirRef entry)
4236 {
4237   HRESULT hr=S_OK;
4238   DirEntry data;
4239
4240   if (!This->entries[entry].read)
4241   {
4242     hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
4243         This->entries[entry].transactedParentEntry,
4244         &data);
4245
4246     if (SUCCEEDED(hr) && data.leftChild != DIRENTRY_NULL)
4247     {
4248       data.leftChild = TransactedSnapshotImpl_CreateStubEntry(This, data.leftChild);
4249
4250       if (data.leftChild == DIRENTRY_NULL)
4251         hr = E_OUTOFMEMORY;
4252     }
4253
4254     if (SUCCEEDED(hr) && data.rightChild != DIRENTRY_NULL)
4255     {
4256       data.rightChild = TransactedSnapshotImpl_CreateStubEntry(This, data.rightChild);
4257
4258       if (data.rightChild == DIRENTRY_NULL)
4259         hr = E_OUTOFMEMORY;
4260     }
4261
4262     if (SUCCEEDED(hr) && data.dirRootEntry != DIRENTRY_NULL)
4263     {
4264       data.dirRootEntry = TransactedSnapshotImpl_CreateStubEntry(This, data.dirRootEntry);
4265
4266       if (data.dirRootEntry == DIRENTRY_NULL)
4267         hr = E_OUTOFMEMORY;
4268     }
4269
4270     if (SUCCEEDED(hr))
4271     {
4272       memcpy(&This->entries[entry].data, &data, sizeof(DirEntry));
4273       This->entries[entry].read = 1;
4274     }
4275   }
4276
4277   return hr;
4278 }
4279
4280 static HRESULT TransactedSnapshotImpl_MakeStreamDirty(
4281   TransactedSnapshotImpl *This, DirRef entry)
4282 {
4283   HRESULT hr = S_OK;
4284
4285   if (!This->entries[entry].stream_dirty)
4286   {
4287     DirEntry new_entrydata;
4288
4289     memset(&new_entrydata, 0, sizeof(DirEntry));
4290     new_entrydata.name[0] = 'S';
4291     new_entrydata.sizeOfNameString = 1;
4292     new_entrydata.stgType = STGTY_STREAM;
4293     new_entrydata.startingBlock = BLOCK_END_OF_CHAIN;
4294     new_entrydata.leftChild = DIRENTRY_NULL;
4295     new_entrydata.rightChild = DIRENTRY_NULL;
4296     new_entrydata.dirRootEntry = DIRENTRY_NULL;
4297
4298     hr = StorageBaseImpl_CreateDirEntry(This->scratch, &new_entrydata,
4299       &This->entries[entry].stream_entry);
4300
4301     if (SUCCEEDED(hr) && This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
4302     {
4303       hr = StorageBaseImpl_CopyStream(
4304         This->scratch, This->entries[entry].stream_entry,
4305         This->transactedParent, This->entries[entry].transactedParentEntry);
4306
4307       if (FAILED(hr))
4308         StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[entry].stream_entry);
4309     }
4310
4311     if (SUCCEEDED(hr))
4312       This->entries[entry].stream_dirty = 1;
4313
4314     if (This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
4315     {
4316       /* Since this entry is modified, and we aren't using its stream data, we
4317        * no longer care about the original entry. */
4318       DirRef delete_ref;
4319       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[entry].transactedParentEntry);
4320
4321       if (delete_ref != DIRENTRY_NULL)
4322         This->entries[delete_ref].deleted = 1;
4323
4324       This->entries[entry].transactedParentEntry = This->entries[entry].newTransactedParentEntry = DIRENTRY_NULL;
4325     }
4326   }
4327
4328   return hr;
4329 }
4330
4331 /* Find the first entry in a depth-first traversal. */
4332 static DirRef TransactedSnapshotImpl_FindFirstChild(
4333   TransactedSnapshotImpl* This, DirRef parent)
4334 {
4335   DirRef cursor, prev;
4336   TransactedDirEntry *entry;
4337
4338   cursor = parent;
4339   entry = &This->entries[cursor];
4340   while (entry->read)
4341   {
4342     if (entry->data.leftChild != DIRENTRY_NULL)
4343     {
4344       prev = cursor;
4345       cursor = entry->data.leftChild;
4346       entry = &This->entries[cursor];
4347       entry->parent = prev;
4348     }
4349     else if (entry->data.rightChild != DIRENTRY_NULL)
4350     {
4351       prev = cursor;
4352       cursor = entry->data.rightChild;
4353       entry = &This->entries[cursor];
4354       entry->parent = prev;
4355     }
4356     else if (entry->data.dirRootEntry != DIRENTRY_NULL)
4357     {
4358       prev = cursor;
4359       cursor = entry->data.dirRootEntry;
4360       entry = &This->entries[cursor];
4361       entry->parent = prev;
4362     }
4363     else
4364       break;
4365   }
4366
4367   return cursor;
4368 }
4369
4370 /* Find the next entry in a depth-first traversal. */
4371 static DirRef TransactedSnapshotImpl_FindNextChild(
4372   TransactedSnapshotImpl* This, DirRef current)
4373 {
4374   DirRef parent;
4375   TransactedDirEntry *parent_entry;
4376
4377   parent = This->entries[current].parent;
4378   parent_entry = &This->entries[parent];
4379
4380   if (parent != DIRENTRY_NULL && parent_entry->data.dirRootEntry != current)
4381   {
4382     if (parent_entry->data.rightChild != current && parent_entry->data.rightChild != DIRENTRY_NULL)
4383     {
4384       This->entries[parent_entry->data.rightChild].parent = parent;
4385       return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.rightChild);
4386     }
4387
4388     if (parent_entry->data.dirRootEntry != DIRENTRY_NULL)
4389     {
4390       This->entries[parent_entry->data.dirRootEntry].parent = parent;
4391       return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.dirRootEntry);
4392     }
4393   }
4394
4395   return parent;
4396 }
4397
4398 /* Return TRUE if we've made a copy of this entry for committing to the parent. */
4399 static inline BOOL TransactedSnapshotImpl_MadeCopy(
4400   TransactedSnapshotImpl* This, DirRef entry)
4401 {
4402   return entry != DIRENTRY_NULL &&
4403     This->entries[entry].newTransactedParentEntry != This->entries[entry].transactedParentEntry;
4404 }
4405
4406 /* Destroy the entries created by CopyTree. */
4407 static void TransactedSnapshotImpl_DestroyTemporaryCopy(
4408   TransactedSnapshotImpl* This, DirRef stop)
4409 {
4410   DirRef cursor;
4411   TransactedDirEntry *entry;
4412   ULARGE_INTEGER zero;
4413
4414   zero.QuadPart = 0;
4415
4416   if (!This->entries[This->base.storageDirEntry].read)
4417     return;
4418
4419   cursor = This->entries[This->base.storageDirEntry].data.dirRootEntry;
4420
4421   if (cursor == DIRENTRY_NULL)
4422     return;
4423
4424   cursor = TransactedSnapshotImpl_FindFirstChild(This, cursor);
4425
4426   while (cursor != DIRENTRY_NULL && cursor != stop)
4427   {
4428     if (TransactedSnapshotImpl_MadeCopy(This, cursor))
4429     {
4430       entry = &This->entries[cursor];
4431
4432       if (entry->stream_dirty)
4433         StorageBaseImpl_StreamSetSize(This->transactedParent,
4434           entry->newTransactedParentEntry, zero);
4435
4436       StorageBaseImpl_DestroyDirEntry(This->transactedParent,
4437         entry->newTransactedParentEntry);
4438
4439       entry->newTransactedParentEntry = entry->transactedParentEntry;
4440     }
4441
4442     cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
4443   }
4444 }
4445
4446 /* Make a copy of our edited tree that we can use in the parent. */
4447 static HRESULT TransactedSnapshotImpl_CopyTree(TransactedSnapshotImpl* This)
4448 {
4449   DirRef cursor;
4450   TransactedDirEntry *entry;
4451   HRESULT hr = S_OK;
4452
4453   cursor = This->base.storageDirEntry;
4454   entry = &This->entries[cursor];
4455   entry->parent = DIRENTRY_NULL;
4456   entry->newTransactedParentEntry = entry->transactedParentEntry;
4457
4458   if (entry->data.dirRootEntry == DIRENTRY_NULL)
4459     return S_OK;
4460
4461   This->entries[entry->data.dirRootEntry].parent = DIRENTRY_NULL;
4462
4463   cursor = TransactedSnapshotImpl_FindFirstChild(This, entry->data.dirRootEntry);
4464   entry = &This->entries[cursor];
4465
4466   while (cursor != DIRENTRY_NULL)
4467   {
4468     /* Make a copy of this entry in the transacted parent. */
4469     if (!entry->read ||
4470         (!entry->dirty && !entry->stream_dirty &&
4471          !TransactedSnapshotImpl_MadeCopy(This, entry->data.leftChild) &&
4472          !TransactedSnapshotImpl_MadeCopy(This, entry->data.rightChild) &&
4473          !TransactedSnapshotImpl_MadeCopy(This, entry->data.dirRootEntry)))
4474       entry->newTransactedParentEntry = entry->transactedParentEntry;
4475     else
4476     {
4477       DirEntry newData;
4478
4479       memcpy(&newData, &entry->data, sizeof(DirEntry));
4480
4481       newData.size.QuadPart = 0;
4482       newData.startingBlock = BLOCK_END_OF_CHAIN;
4483
4484       if (newData.leftChild != DIRENTRY_NULL)
4485         newData.leftChild = This->entries[newData.leftChild].newTransactedParentEntry;
4486
4487       if (newData.rightChild != DIRENTRY_NULL)
4488         newData.rightChild = This->entries[newData.rightChild].newTransactedParentEntry;
4489
4490       if (newData.dirRootEntry != DIRENTRY_NULL)
4491         newData.dirRootEntry = This->entries[newData.dirRootEntry].newTransactedParentEntry;
4492
4493       hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &newData,
4494         &entry->newTransactedParentEntry);
4495       if (FAILED(hr))
4496       {
4497         TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor);
4498         return hr;
4499       }
4500
4501       if (entry->stream_dirty)
4502       {
4503         hr = StorageBaseImpl_CopyStream(
4504           This->transactedParent, entry->newTransactedParentEntry,
4505           This->scratch, entry->stream_entry);
4506       }
4507       else if (entry->data.size.QuadPart)
4508       {
4509         hr = StorageBaseImpl_StreamLink(
4510           This->transactedParent, entry->newTransactedParentEntry,
4511           entry->transactedParentEntry);
4512       }
4513
4514       if (FAILED(hr))
4515       {
4516         cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
4517         TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor);
4518         return hr;
4519       }
4520     }
4521
4522     cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
4523     entry = &This->entries[cursor];
4524   }
4525
4526   return hr;
4527 }
4528
4529 static HRESULT WINAPI TransactedSnapshotImpl_Commit(
4530   IStorage*            iface,
4531   DWORD                  grfCommitFlags)  /* [in] */
4532 {
4533   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
4534   TransactedDirEntry *root_entry;
4535   DirRef i, dir_root_ref;
4536   DirEntry data;
4537   ULARGE_INTEGER zero;
4538   HRESULT hr;
4539
4540   zero.QuadPart = 0;
4541
4542   TRACE("(%p,%x)\n", iface, grfCommitFlags);
4543
4544   /* Cannot commit a read-only transacted storage */
4545   if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
4546     return STG_E_ACCESSDENIED;
4547
4548   /* To prevent data loss, we create the new structure in the file before we
4549    * delete the old one, so that in case of errors the old data is intact. We
4550    * shouldn't do this if STGC_OVERWRITE is set, but that flag should only be
4551    * needed in the rare situation where we have just enough free disk space to
4552    * overwrite the existing data. */
4553
4554   root_entry = &This->entries[This->base.storageDirEntry];
4555
4556   if (!root_entry->read)
4557     return S_OK;
4558
4559   hr = TransactedSnapshotImpl_CopyTree(This);
4560   if (FAILED(hr)) return hr;
4561
4562   if (root_entry->data.dirRootEntry == DIRENTRY_NULL)
4563     dir_root_ref = DIRENTRY_NULL;
4564   else
4565     dir_root_ref = This->entries[root_entry->data.dirRootEntry].newTransactedParentEntry;
4566
4567   hr = StorageBaseImpl_Flush(This->transactedParent);
4568
4569   /* Update the storage to use the new data in one step. */
4570   if (SUCCEEDED(hr))
4571     hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
4572       root_entry->transactedParentEntry, &data);
4573
4574   if (SUCCEEDED(hr))
4575   {
4576     data.dirRootEntry = dir_root_ref;
4577     data.clsid = root_entry->data.clsid;
4578     data.ctime = root_entry->data.ctime;
4579     data.mtime = root_entry->data.mtime;
4580
4581     hr = StorageBaseImpl_WriteDirEntry(This->transactedParent,
4582       root_entry->transactedParentEntry, &data);
4583   }
4584
4585   /* Try to flush after updating the root storage, but if the flush fails, keep
4586    * going, on the theory that it'll either succeed later or the subsequent
4587    * writes will fail. */
4588   StorageBaseImpl_Flush(This->transactedParent);
4589
4590   if (SUCCEEDED(hr))
4591   {
4592     /* Destroy the old now-orphaned data. */
4593     for (i=0; i<This->entries_size; i++)
4594     {
4595       TransactedDirEntry *entry = &This->entries[i];
4596       if (entry->inuse)
4597       {
4598         if (entry->deleted)
4599         {
4600           StorageBaseImpl_StreamSetSize(This->transactedParent,
4601             entry->transactedParentEntry, zero);
4602           StorageBaseImpl_DestroyDirEntry(This->transactedParent,
4603             entry->transactedParentEntry);
4604           memset(entry, 0, sizeof(TransactedDirEntry));
4605           This->firstFreeEntry = min(i, This->firstFreeEntry);
4606         }
4607         else if (entry->read && entry->transactedParentEntry != entry->newTransactedParentEntry)
4608         {
4609           if (entry->transactedParentEntry != DIRENTRY_NULL)
4610             StorageBaseImpl_DestroyDirEntry(This->transactedParent,
4611               entry->transactedParentEntry);
4612           if (entry->stream_dirty)
4613           {
4614             StorageBaseImpl_StreamSetSize(This->scratch, entry->stream_entry, zero);
4615             StorageBaseImpl_DestroyDirEntry(This->scratch, entry->stream_entry);
4616             entry->stream_dirty = 0;
4617           }
4618           entry->dirty = 0;
4619           entry->transactedParentEntry = entry->newTransactedParentEntry;
4620         }
4621       }
4622     }
4623   }
4624   else
4625   {
4626     TransactedSnapshotImpl_DestroyTemporaryCopy(This, DIRENTRY_NULL);
4627   }
4628
4629   if (SUCCEEDED(hr))
4630     hr = StorageBaseImpl_Flush(This->transactedParent);
4631
4632   return hr;
4633 }
4634
4635 static HRESULT WINAPI TransactedSnapshotImpl_Revert(
4636   IStorage*            iface)
4637 {
4638   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
4639   ULARGE_INTEGER zero;
4640   ULONG i;
4641
4642   TRACE("(%p)\n", iface);
4643
4644   /* Destroy the open objects. */
4645   StorageBaseImpl_DeleteAll(&This->base);
4646
4647   /* Clear out the scratch file. */
4648   zero.QuadPart = 0;
4649   for (i=0; i<This->entries_size; i++)
4650   {
4651     if (This->entries[i].stream_dirty)
4652     {
4653       StorageBaseImpl_StreamSetSize(This->scratch, This->entries[i].stream_entry,
4654         zero);
4655
4656       StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[i].stream_entry);
4657     }
4658   }
4659
4660   memset(This->entries, 0, sizeof(TransactedDirEntry) * This->entries_size);
4661
4662   This->firstFreeEntry = 0;
4663   This->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(This, This->transactedParent->storageDirEntry);
4664
4665   return S_OK;
4666 }
4667
4668 static void TransactedSnapshotImpl_Invalidate(StorageBaseImpl* This)
4669 {
4670   if (!This->reverted)
4671   {
4672     TRACE("Storage invalidated (stg=%p)\n", This);
4673
4674     This->reverted = 1;
4675
4676     StorageBaseImpl_DeleteAll(This);
4677   }
4678 }
4679
4680 static void TransactedSnapshotImpl_Destroy( StorageBaseImpl *iface)
4681 {
4682   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
4683
4684   TransactedSnapshotImpl_Revert((IStorage*)iface);
4685
4686   IStorage_Release((IStorage*)This->transactedParent);
4687
4688   IStorage_Release((IStorage*)This->scratch);
4689
4690   HeapFree(GetProcessHeap(), 0, This->entries);
4691
4692   HeapFree(GetProcessHeap(), 0, This);
4693 }
4694
4695 static HRESULT TransactedSnapshotImpl_Flush(StorageBaseImpl* iface)
4696 {
4697   /* We only need to flush when committing. */
4698   return S_OK;
4699 }
4700
4701 static HRESULT TransactedSnapshotImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
4702 {
4703   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
4704
4705   return StorageBaseImpl_GetFilename(This->transactedParent, result);
4706 }
4707
4708 static HRESULT TransactedSnapshotImpl_CreateDirEntry(StorageBaseImpl *base,
4709   const DirEntry *newData, DirRef *index)
4710 {
4711   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4712   DirRef new_ref;
4713   TransactedDirEntry *new_entry;
4714
4715   new_ref = TransactedSnapshotImpl_FindFreeEntry(This);
4716   if (new_ref == DIRENTRY_NULL)
4717     return E_OUTOFMEMORY;
4718
4719   new_entry = &This->entries[new_ref];
4720
4721   new_entry->newTransactedParentEntry = new_entry->transactedParentEntry = DIRENTRY_NULL;
4722   new_entry->read = 1;
4723   new_entry->dirty = 1;
4724   memcpy(&new_entry->data, newData, sizeof(DirEntry));
4725
4726   *index = new_ref;
4727
4728   TRACE("%s l=%x r=%x d=%x <-- %x\n", debugstr_w(newData->name), newData->leftChild, newData->rightChild, newData->dirRootEntry, *index);
4729
4730   return S_OK;
4731 }
4732
4733 static HRESULT TransactedSnapshotImpl_WriteDirEntry(StorageBaseImpl *base,
4734   DirRef index, const DirEntry *data)
4735 {
4736   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4737   HRESULT hr;
4738
4739   TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
4740
4741   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
4742   if (FAILED(hr)) return hr;
4743
4744   memcpy(&This->entries[index].data, data, sizeof(DirEntry));
4745
4746   if (index != This->base.storageDirEntry)
4747   {
4748     This->entries[index].dirty = 1;
4749
4750     if (data->size.QuadPart == 0 &&
4751         This->entries[index].transactedParentEntry != DIRENTRY_NULL)
4752     {
4753       /* Since this entry is modified, and we aren't using its stream data, we
4754        * no longer care about the original entry. */
4755       DirRef delete_ref;
4756       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
4757
4758       if (delete_ref != DIRENTRY_NULL)
4759         This->entries[delete_ref].deleted = 1;
4760
4761       This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
4762     }
4763   }
4764
4765   return S_OK;
4766 }
4767
4768 static HRESULT TransactedSnapshotImpl_ReadDirEntry(StorageBaseImpl *base,
4769   DirRef index, DirEntry *data)
4770 {
4771   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4772   HRESULT hr;
4773
4774   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
4775   if (FAILED(hr)) return hr;
4776
4777   memcpy(data, &This->entries[index].data, sizeof(DirEntry));
4778
4779   TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
4780
4781   return S_OK;
4782 }
4783
4784 static HRESULT TransactedSnapshotImpl_DestroyDirEntry(StorageBaseImpl *base,
4785   DirRef index)
4786 {
4787   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4788
4789   if (This->entries[index].transactedParentEntry == DIRENTRY_NULL ||
4790       This->entries[index].data.size.QuadPart != 0)
4791   {
4792     /* If we deleted this entry while it has stream data. We must have left the
4793      * data because some other entry is using it, and we need to leave the
4794      * original entry alone. */
4795     memset(&This->entries[index], 0, sizeof(TransactedDirEntry));
4796     This->firstFreeEntry = min(index, This->firstFreeEntry);
4797   }
4798   else
4799   {
4800     This->entries[index].deleted = 1;
4801   }
4802
4803   return S_OK;
4804 }
4805
4806 static HRESULT TransactedSnapshotImpl_StreamReadAt(StorageBaseImpl *base,
4807   DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
4808 {
4809   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4810
4811   if (This->entries[index].stream_dirty)
4812   {
4813     return StorageBaseImpl_StreamReadAt(This->scratch,
4814         This->entries[index].stream_entry, offset, size, buffer, bytesRead);
4815   }
4816   else if (This->entries[index].transactedParentEntry == DIRENTRY_NULL)
4817   {
4818     /* This stream doesn't live in the parent, and we haven't allocated storage
4819      * for it yet */
4820     *bytesRead = 0;
4821     return S_OK;
4822   }
4823   else
4824   {
4825     return StorageBaseImpl_StreamReadAt(This->transactedParent,
4826         This->entries[index].transactedParentEntry, offset, size, buffer, bytesRead);
4827   }
4828 }
4829
4830 static HRESULT TransactedSnapshotImpl_StreamWriteAt(StorageBaseImpl *base,
4831   DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
4832 {
4833   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4834   HRESULT hr;
4835
4836   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
4837   if (FAILED(hr)) return hr;
4838
4839   hr = TransactedSnapshotImpl_MakeStreamDirty(This, index);
4840   if (FAILED(hr)) return hr;
4841
4842   hr = StorageBaseImpl_StreamWriteAt(This->scratch,
4843     This->entries[index].stream_entry, offset, size, buffer, bytesWritten);
4844
4845   if (SUCCEEDED(hr) && size != 0)
4846     This->entries[index].data.size.QuadPart = max(
4847         This->entries[index].data.size.QuadPart,
4848         offset.QuadPart + size);
4849
4850   return hr;
4851 }
4852
4853 static HRESULT TransactedSnapshotImpl_StreamSetSize(StorageBaseImpl *base,
4854   DirRef index, ULARGE_INTEGER newsize)
4855 {
4856   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4857   HRESULT hr;
4858
4859   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
4860   if (FAILED(hr)) return hr;
4861
4862   if (This->entries[index].data.size.QuadPart == newsize.QuadPart)
4863     return S_OK;
4864
4865   if (newsize.QuadPart == 0)
4866   {
4867     /* Destroy any parent references or entries in the scratch file. */
4868     if (This->entries[index].stream_dirty)
4869     {
4870       ULARGE_INTEGER zero;
4871       zero.QuadPart = 0;
4872       StorageBaseImpl_StreamSetSize(This->scratch,
4873         This->entries[index].stream_entry, zero);
4874       StorageBaseImpl_DestroyDirEntry(This->scratch,
4875         This->entries[index].stream_entry);
4876       This->entries[index].stream_dirty = 0;
4877     }
4878     else if (This->entries[index].transactedParentEntry != DIRENTRY_NULL)
4879     {
4880       DirRef delete_ref;
4881       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
4882
4883       if (delete_ref != DIRENTRY_NULL)
4884         This->entries[delete_ref].deleted = 1;
4885
4886       This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
4887     }
4888   }
4889   else
4890   {
4891     hr = TransactedSnapshotImpl_MakeStreamDirty(This, index);
4892     if (FAILED(hr)) return hr;
4893
4894     hr = StorageBaseImpl_StreamSetSize(This->scratch,
4895       This->entries[index].stream_entry, newsize);
4896   }
4897
4898   if (SUCCEEDED(hr))
4899     This->entries[index].data.size = newsize;
4900
4901   return hr;
4902 }
4903
4904 static HRESULT TransactedSnapshotImpl_StreamLink(StorageBaseImpl *base,
4905   DirRef dst, DirRef src)
4906 {
4907   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
4908   HRESULT hr;
4909   TransactedDirEntry *dst_entry, *src_entry;
4910
4911   hr = TransactedSnapshotImpl_EnsureReadEntry(This, src);
4912   if (FAILED(hr)) return hr;
4913
4914   hr = TransactedSnapshotImpl_EnsureReadEntry(This, dst);
4915   if (FAILED(hr)) return hr;
4916
4917   dst_entry = &This->entries[dst];
4918   src_entry = &This->entries[src];
4919
4920   dst_entry->stream_dirty = src_entry->stream_dirty;
4921   dst_entry->stream_entry = src_entry->stream_entry;
4922   dst_entry->transactedParentEntry = src_entry->transactedParentEntry;
4923   dst_entry->newTransactedParentEntry = src_entry->newTransactedParentEntry;
4924   dst_entry->data.size = src_entry->data.size;
4925
4926   return S_OK;
4927 }
4928
4929 static const IStorageVtbl TransactedSnapshotImpl_Vtbl =
4930 {
4931     StorageBaseImpl_QueryInterface,
4932     StorageBaseImpl_AddRef,
4933     StorageBaseImpl_Release,
4934     StorageBaseImpl_CreateStream,
4935     StorageBaseImpl_OpenStream,
4936     StorageBaseImpl_CreateStorage,
4937     StorageBaseImpl_OpenStorage,
4938     StorageBaseImpl_CopyTo,
4939     StorageBaseImpl_MoveElementTo,
4940     TransactedSnapshotImpl_Commit,
4941     TransactedSnapshotImpl_Revert,
4942     StorageBaseImpl_EnumElements,
4943     StorageBaseImpl_DestroyElement,
4944     StorageBaseImpl_RenameElement,
4945     StorageBaseImpl_SetElementTimes,
4946     StorageBaseImpl_SetClass,
4947     StorageBaseImpl_SetStateBits,
4948     StorageBaseImpl_Stat
4949 };
4950
4951 static const StorageBaseImplVtbl TransactedSnapshotImpl_BaseVtbl =
4952 {
4953   TransactedSnapshotImpl_Destroy,
4954   TransactedSnapshotImpl_Invalidate,
4955   TransactedSnapshotImpl_Flush,
4956   TransactedSnapshotImpl_GetFilename,
4957   TransactedSnapshotImpl_CreateDirEntry,
4958   TransactedSnapshotImpl_WriteDirEntry,
4959   TransactedSnapshotImpl_ReadDirEntry,
4960   TransactedSnapshotImpl_DestroyDirEntry,
4961   TransactedSnapshotImpl_StreamReadAt,
4962   TransactedSnapshotImpl_StreamWriteAt,
4963   TransactedSnapshotImpl_StreamSetSize,
4964   TransactedSnapshotImpl_StreamLink
4965 };
4966
4967 static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage,
4968   TransactedSnapshotImpl** result)
4969 {
4970   HRESULT hr;
4971
4972   *result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedSnapshotImpl));
4973   if (*result)
4974   {
4975     (*result)->base.lpVtbl = &TransactedSnapshotImpl_Vtbl;
4976
4977     /* This is OK because the property set storage functions use the IStorage functions. */
4978     (*result)->base.pssVtbl = parentStorage->pssVtbl;
4979
4980     (*result)->base.baseVtbl = &TransactedSnapshotImpl_BaseVtbl;
4981
4982     list_init(&(*result)->base.strmHead);
4983
4984     list_init(&(*result)->base.storageHead);
4985
4986     (*result)->base.ref = 1;
4987
4988     (*result)->base.openFlags = parentStorage->openFlags;
4989
4990     /* Create a new temporary storage to act as the scratch file. */
4991     hr = StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
4992         0, (IStorage**)&(*result)->scratch);
4993
4994     if (SUCCEEDED(hr))
4995     {
4996         ULONG num_entries = 20;
4997
4998         (*result)->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * num_entries);
4999
5000         (*result)->entries_size = num_entries;
5001
5002         (*result)->firstFreeEntry = 0;
5003
5004         if ((*result)->entries)
5005         {
5006             /* parentStorage already has 1 reference, which we take over here. */
5007             (*result)->transactedParent = parentStorage;
5008
5009             parentStorage->transactedChild = (StorageBaseImpl*)*result;
5010
5011             (*result)->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(*result, parentStorage->storageDirEntry);
5012         }
5013         else
5014         {
5015             IStorage_Release((IStorage*)(*result)->scratch);
5016
5017             hr = E_OUTOFMEMORY;
5018         }
5019     }
5020
5021     if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, (*result));
5022
5023     return hr;
5024   }
5025   else
5026     return E_OUTOFMEMORY;
5027 }
5028
5029 static HRESULT Storage_ConstructTransacted(StorageBaseImpl *parentStorage,
5030   StorageBaseImpl** result)
5031 {
5032   static int fixme=0;
5033
5034   if (parentStorage->openFlags & (STGM_NOSCRATCH|STGM_NOSNAPSHOT) && !fixme++)
5035   {
5036     FIXME("Unimplemented flags %x\n", parentStorage->openFlags);
5037   }
5038
5039   return TransactedSnapshotImpl_Construct(parentStorage,
5040     (TransactedSnapshotImpl**)result);
5041 }
5042
5043 static HRESULT Storage_Construct(
5044   HANDLE       hFile,
5045   LPCOLESTR    pwcsName,
5046   ILockBytes*  pLkbyt,
5047   DWORD        openFlags,
5048   BOOL         fileBased,
5049   BOOL         create,
5050   ULONG        sector_size,
5051   StorageBaseImpl** result)
5052 {
5053   StorageImpl *newStorage;
5054   StorageBaseImpl *newTransactedStorage;
5055   HRESULT hr;
5056
5057   hr = StorageImpl_Construct(hFile, pwcsName, pLkbyt, openFlags, fileBased, create, sector_size, &newStorage);
5058   if (FAILED(hr)) goto end;
5059
5060   if (openFlags & STGM_TRANSACTED)
5061   {
5062     hr = Storage_ConstructTransacted(&newStorage->base, &newTransactedStorage);
5063     if (FAILED(hr))
5064       IStorage_Release((IStorage*)newStorage);
5065     else
5066       *result = newTransactedStorage;
5067   }
5068   else
5069     *result = &newStorage->base;
5070
5071 end:
5072   return hr;
5073 }
5074
5075 static void StorageInternalImpl_Invalidate( StorageBaseImpl *base )
5076 {
5077   StorageInternalImpl* This = (StorageInternalImpl*) base;
5078
5079   if (!This->base.reverted)
5080   {
5081     TRACE("Storage invalidated (stg=%p)\n", This);
5082
5083     This->base.reverted = 1;
5084
5085     This->parentStorage = NULL;
5086
5087     StorageBaseImpl_DeleteAll(&This->base);
5088
5089     list_remove(&This->ParentListEntry);
5090   }
5091 }
5092
5093 static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
5094 {
5095   StorageInternalImpl* This = (StorageInternalImpl*) iface;
5096
5097   StorageInternalImpl_Invalidate(&This->base);
5098
5099   HeapFree(GetProcessHeap(), 0, This);
5100 }
5101
5102 static HRESULT StorageInternalImpl_Flush(StorageBaseImpl* iface)
5103 {
5104   StorageInternalImpl* This = (StorageInternalImpl*) iface;
5105
5106   return StorageBaseImpl_Flush(This->parentStorage);
5107 }
5108
5109 static HRESULT StorageInternalImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
5110 {
5111   StorageInternalImpl* This = (StorageInternalImpl*) iface;
5112
5113   return StorageBaseImpl_GetFilename(This->parentStorage, result);
5114 }
5115
5116 static HRESULT StorageInternalImpl_CreateDirEntry(StorageBaseImpl *base,
5117   const DirEntry *newData, DirRef *index)
5118 {
5119   StorageInternalImpl* This = (StorageInternalImpl*) base;
5120
5121   return StorageBaseImpl_CreateDirEntry(This->parentStorage,
5122     newData, index);
5123 }
5124
5125 static HRESULT StorageInternalImpl_WriteDirEntry(StorageBaseImpl *base,
5126   DirRef index, const DirEntry *data)
5127 {
5128   StorageInternalImpl* This = (StorageInternalImpl*) base;
5129
5130   return StorageBaseImpl_WriteDirEntry(This->parentStorage,
5131     index, data);
5132 }
5133
5134 static HRESULT StorageInternalImpl_ReadDirEntry(StorageBaseImpl *base,
5135   DirRef index, DirEntry *data)
5136 {
5137   StorageInternalImpl* This = (StorageInternalImpl*) base;
5138
5139   return StorageBaseImpl_ReadDirEntry(This->parentStorage,
5140     index, data);
5141 }
5142
5143 static HRESULT StorageInternalImpl_DestroyDirEntry(StorageBaseImpl *base,
5144   DirRef index)
5145 {
5146   StorageInternalImpl* This = (StorageInternalImpl*) base;
5147
5148   return StorageBaseImpl_DestroyDirEntry(This->parentStorage,
5149     index);
5150 }
5151
5152 static HRESULT StorageInternalImpl_StreamReadAt(StorageBaseImpl *base,
5153   DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
5154 {
5155   StorageInternalImpl* This = (StorageInternalImpl*) base;
5156
5157   return StorageBaseImpl_StreamReadAt(This->parentStorage,
5158     index, offset, size, buffer, bytesRead);
5159 }
5160
5161 static HRESULT StorageInternalImpl_StreamWriteAt(StorageBaseImpl *base,
5162   DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
5163 {
5164   StorageInternalImpl* This = (StorageInternalImpl*) base;
5165
5166   return StorageBaseImpl_StreamWriteAt(This->parentStorage,
5167     index, offset, size, buffer, bytesWritten);
5168 }
5169
5170 static HRESULT StorageInternalImpl_StreamSetSize(StorageBaseImpl *base,
5171   DirRef index, ULARGE_INTEGER newsize)
5172 {
5173   StorageInternalImpl* This = (StorageInternalImpl*) base;
5174
5175   return StorageBaseImpl_StreamSetSize(This->parentStorage,
5176     index, newsize);
5177 }
5178
5179 static HRESULT StorageInternalImpl_StreamLink(StorageBaseImpl *base,
5180   DirRef dst, DirRef src)
5181 {
5182   StorageInternalImpl* This = (StorageInternalImpl*) base;
5183
5184   return StorageBaseImpl_StreamLink(This->parentStorage,
5185     dst, src);
5186 }
5187
5188 /******************************************************************************
5189 **
5190 ** Storage32InternalImpl_Commit
5191 **
5192 */
5193 static HRESULT WINAPI StorageInternalImpl_Commit(
5194   IStorage*            iface,
5195   DWORD                  grfCommitFlags)  /* [in] */
5196 {
5197   StorageBaseImpl* base = (StorageBaseImpl*) iface;
5198   TRACE("(%p,%x)\n", iface, grfCommitFlags);
5199   return StorageBaseImpl_Flush(base);
5200 }
5201
5202 /******************************************************************************
5203 **
5204 ** Storage32InternalImpl_Revert
5205 **
5206 */
5207 static HRESULT WINAPI StorageInternalImpl_Revert(
5208   IStorage*            iface)
5209 {
5210   FIXME("(%p): stub\n", iface);
5211   return S_OK;
5212 }
5213
5214 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
5215 {
5216   IStorage_Release((IStorage*)This->parentStorage);
5217   HeapFree(GetProcessHeap(), 0, This);
5218 }
5219
5220 static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
5221   IEnumSTATSTG*     iface,
5222   REFIID            riid,
5223   void**            ppvObject)
5224 {
5225   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5226
5227   if (ppvObject==0)
5228     return E_INVALIDARG;
5229
5230   *ppvObject = 0;
5231
5232   if (IsEqualGUID(&IID_IUnknown, riid) ||
5233       IsEqualGUID(&IID_IEnumSTATSTG, riid))
5234   {
5235     *ppvObject = This;
5236     IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
5237     return S_OK;
5238   }
5239
5240   return E_NOINTERFACE;
5241 }
5242
5243 static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
5244   IEnumSTATSTG* iface)
5245 {
5246   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5247   return InterlockedIncrement(&This->ref);
5248 }
5249
5250 static ULONG   WINAPI IEnumSTATSTGImpl_Release(
5251   IEnumSTATSTG* iface)
5252 {
5253   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5254
5255   ULONG newRef;
5256
5257   newRef = InterlockedDecrement(&This->ref);
5258
5259   if (newRef==0)
5260   {
5261     IEnumSTATSTGImpl_Destroy(This);
5262   }
5263
5264   return newRef;
5265 }
5266
5267 static HRESULT IEnumSTATSTGImpl_GetNextRef(
5268   IEnumSTATSTGImpl* This,
5269   DirRef *ref)
5270 {
5271   DirRef result = DIRENTRY_NULL;
5272   DirRef searchNode;
5273   DirEntry entry;
5274   HRESULT hr;
5275   WCHAR result_name[DIRENTRY_NAME_MAX_LEN];
5276
5277   hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
5278     This->parentStorage->storageDirEntry, &entry);
5279   searchNode = entry.dirRootEntry;
5280
5281   while (SUCCEEDED(hr) && searchNode != DIRENTRY_NULL)
5282   {
5283     hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, searchNode, &entry);
5284
5285     if (SUCCEEDED(hr))
5286     {
5287       LONG diff = entryNameCmp( entry.name, This->name);
5288
5289       if (diff <= 0)
5290       {
5291         searchNode = entry.rightChild;
5292       }
5293       else
5294       {
5295         result = searchNode;
5296         memcpy(result_name, entry.name, sizeof(result_name));
5297         searchNode = entry.leftChild;
5298       }
5299     }
5300   }
5301
5302   if (SUCCEEDED(hr))
5303   {
5304     *ref = result;
5305     if (result != DIRENTRY_NULL)
5306       memcpy(This->name, result_name, sizeof(result_name));
5307   }
5308
5309   return hr;
5310 }
5311
5312 static HRESULT WINAPI IEnumSTATSTGImpl_Next(
5313   IEnumSTATSTG* iface,
5314   ULONG             celt,
5315   STATSTG*          rgelt,
5316   ULONG*            pceltFetched)
5317 {
5318   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5319
5320   DirEntry    currentEntry;
5321   STATSTG*    currentReturnStruct = rgelt;
5322   ULONG       objectFetched       = 0;
5323   DirRef      currentSearchNode;
5324   HRESULT     hr=S_OK;
5325
5326   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
5327     return E_INVALIDARG;
5328
5329   if (This->parentStorage->reverted)
5330     return STG_E_REVERTED;
5331
5332   /*
5333    * To avoid the special case, get another pointer to a ULONG value if
5334    * the caller didn't supply one.
5335    */
5336   if (pceltFetched==0)
5337     pceltFetched = &objectFetched;
5338
5339   /*
5340    * Start the iteration, we will iterate until we hit the end of the
5341    * linked list or until we hit the number of items to iterate through
5342    */
5343   *pceltFetched = 0;
5344
5345   while ( *pceltFetched < celt )
5346   {
5347     hr = IEnumSTATSTGImpl_GetNextRef(This, &currentSearchNode);
5348
5349     if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL)
5350       break;
5351
5352     /*
5353      * Read the entry from the storage.
5354      */
5355     StorageBaseImpl_ReadDirEntry(This->parentStorage,
5356       currentSearchNode,
5357       &currentEntry);
5358
5359     /*
5360      * Copy the information to the return buffer.
5361      */
5362     StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage,
5363       currentReturnStruct,
5364       &currentEntry,
5365       STATFLAG_DEFAULT);
5366
5367     /*
5368      * Step to the next item in the iteration
5369      */
5370     (*pceltFetched)++;
5371     currentReturnStruct++;
5372   }
5373
5374   if (SUCCEEDED(hr) && *pceltFetched != celt)
5375     hr = S_FALSE;
5376
5377   return hr;
5378 }
5379
5380
5381 static HRESULT WINAPI IEnumSTATSTGImpl_Skip(
5382   IEnumSTATSTG* iface,
5383   ULONG             celt)
5384 {
5385   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5386
5387   ULONG       objectFetched       = 0;
5388   DirRef      currentSearchNode;
5389   HRESULT     hr=S_OK;
5390
5391   if (This->parentStorage->reverted)
5392     return STG_E_REVERTED;
5393
5394   while ( (objectFetched < celt) )
5395   {
5396     hr = IEnumSTATSTGImpl_GetNextRef(This, &currentSearchNode);
5397
5398     if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL)
5399       break;
5400
5401     objectFetched++;
5402   }
5403
5404   if (SUCCEEDED(hr) && objectFetched != celt)
5405     return S_FALSE;
5406
5407   return hr;
5408 }
5409
5410 static HRESULT WINAPI IEnumSTATSTGImpl_Reset(
5411   IEnumSTATSTG* iface)
5412 {
5413   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5414
5415   if (This->parentStorage->reverted)
5416     return STG_E_REVERTED;
5417
5418   This->name[0] = 0;
5419
5420   return S_OK;
5421 }
5422
5423 static HRESULT WINAPI IEnumSTATSTGImpl_Clone(
5424   IEnumSTATSTG* iface,
5425   IEnumSTATSTG**    ppenum)
5426 {
5427   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
5428
5429   IEnumSTATSTGImpl* newClone;
5430
5431   if (This->parentStorage->reverted)
5432     return STG_E_REVERTED;
5433
5434   /*
5435    * Perform a sanity check on the parameters.
5436    */
5437   if (ppenum==0)
5438     return E_INVALIDARG;
5439
5440   newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
5441                This->storageDirEntry);
5442
5443
5444   /*
5445    * The new clone enumeration must point to the same current node as
5446    * the ole one.
5447    */
5448   memcpy(newClone->name, This->name, sizeof(newClone->name));
5449
5450   *ppenum = (IEnumSTATSTG*)newClone;
5451
5452   /*
5453    * Don't forget to nail down a reference to the clone before
5454    * returning it.
5455    */
5456   IEnumSTATSTGImpl_AddRef(*ppenum);
5457
5458   return S_OK;
5459 }
5460
5461 /*
5462  * Virtual function table for the IEnumSTATSTGImpl class.
5463  */
5464 static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
5465 {
5466     IEnumSTATSTGImpl_QueryInterface,
5467     IEnumSTATSTGImpl_AddRef,
5468     IEnumSTATSTGImpl_Release,
5469     IEnumSTATSTGImpl_Next,
5470     IEnumSTATSTGImpl_Skip,
5471     IEnumSTATSTGImpl_Reset,
5472     IEnumSTATSTGImpl_Clone
5473 };
5474
5475 /******************************************************************************
5476 ** IEnumSTATSTGImpl implementation
5477 */
5478
5479 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
5480   StorageBaseImpl* parentStorage,
5481   DirRef         storageDirEntry)
5482 {
5483   IEnumSTATSTGImpl* newEnumeration;
5484
5485   newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
5486
5487   if (newEnumeration!=0)
5488   {
5489     /*
5490      * Set-up the virtual function table and reference count.
5491      */
5492     newEnumeration->lpVtbl    = &IEnumSTATSTGImpl_Vtbl;
5493     newEnumeration->ref       = 0;
5494
5495     /*
5496      * We want to nail-down the reference to the storage in case the
5497      * enumeration out-lives the storage in the client application.
5498      */
5499     newEnumeration->parentStorage = parentStorage;
5500     IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
5501
5502     newEnumeration->storageDirEntry   = storageDirEntry;
5503
5504     /*
5505      * Make sure the current node of the iterator is the first one.
5506      */
5507     IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
5508   }
5509
5510   return newEnumeration;
5511 }
5512
5513 /*
5514  * Virtual function table for the Storage32InternalImpl class.
5515  */
5516 static const IStorageVtbl Storage32InternalImpl_Vtbl =
5517 {
5518     StorageBaseImpl_QueryInterface,
5519     StorageBaseImpl_AddRef,
5520     StorageBaseImpl_Release,
5521     StorageBaseImpl_CreateStream,
5522     StorageBaseImpl_OpenStream,
5523     StorageBaseImpl_CreateStorage,
5524     StorageBaseImpl_OpenStorage,
5525     StorageBaseImpl_CopyTo,
5526     StorageBaseImpl_MoveElementTo,
5527     StorageInternalImpl_Commit,
5528     StorageInternalImpl_Revert,
5529     StorageBaseImpl_EnumElements,
5530     StorageBaseImpl_DestroyElement,
5531     StorageBaseImpl_RenameElement,
5532     StorageBaseImpl_SetElementTimes,
5533     StorageBaseImpl_SetClass,
5534     StorageBaseImpl_SetStateBits,
5535     StorageBaseImpl_Stat
5536 };
5537
5538 static const StorageBaseImplVtbl StorageInternalImpl_BaseVtbl =
5539 {
5540   StorageInternalImpl_Destroy,
5541   StorageInternalImpl_Invalidate,
5542   StorageInternalImpl_Flush,
5543   StorageInternalImpl_GetFilename,
5544   StorageInternalImpl_CreateDirEntry,
5545   StorageInternalImpl_WriteDirEntry,
5546   StorageInternalImpl_ReadDirEntry,
5547   StorageInternalImpl_DestroyDirEntry,
5548   StorageInternalImpl_StreamReadAt,
5549   StorageInternalImpl_StreamWriteAt,
5550   StorageInternalImpl_StreamSetSize,
5551   StorageInternalImpl_StreamLink
5552 };
5553
5554 /******************************************************************************
5555 ** Storage32InternalImpl implementation
5556 */
5557
5558 static StorageInternalImpl* StorageInternalImpl_Construct(
5559   StorageBaseImpl* parentStorage,
5560   DWORD        openFlags,
5561   DirRef       storageDirEntry)
5562 {
5563   StorageInternalImpl* newStorage;
5564
5565   newStorage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StorageInternalImpl));
5566
5567   if (newStorage!=0)
5568   {
5569     list_init(&newStorage->base.strmHead);
5570
5571     list_init(&newStorage->base.storageHead);
5572
5573     /*
5574      * Initialize the virtual function table.
5575      */
5576     newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
5577     newStorage->base.pssVtbl = &IPropertySetStorage_Vtbl;
5578     newStorage->base.baseVtbl = &StorageInternalImpl_BaseVtbl;
5579     newStorage->base.openFlags = (openFlags & ~STGM_CREATE);
5580
5581     newStorage->base.reverted = 0;
5582
5583     newStorage->base.ref = 1;
5584
5585     newStorage->parentStorage = parentStorage;
5586
5587     /*
5588      * Keep a reference to the directory entry of this storage
5589      */
5590     newStorage->base.storageDirEntry = storageDirEntry;
5591
5592     newStorage->base.create = 0;
5593
5594     return newStorage;
5595   }
5596
5597   return 0;
5598 }
5599
5600 /******************************************************************************
5601 ** StorageUtl implementation
5602 */
5603
5604 void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
5605 {
5606   WORD tmp;
5607
5608   memcpy(&tmp, buffer+offset, sizeof(WORD));
5609   *value = lendian16toh(tmp);
5610 }
5611
5612 void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
5613 {
5614   value = htole16(value);
5615   memcpy(buffer+offset, &value, sizeof(WORD));
5616 }
5617
5618 void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
5619 {
5620   DWORD tmp;
5621
5622   memcpy(&tmp, buffer+offset, sizeof(DWORD));
5623   *value = lendian32toh(tmp);
5624 }
5625
5626 void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
5627 {
5628   value = htole32(value);
5629   memcpy(buffer+offset, &value, sizeof(DWORD));
5630 }
5631
5632 void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
5633  ULARGE_INTEGER* value)
5634 {
5635 #ifdef WORDS_BIGENDIAN
5636     ULARGE_INTEGER tmp;
5637
5638     memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
5639     value->u.LowPart = htole32(tmp.u.HighPart);
5640     value->u.HighPart = htole32(tmp.u.LowPart);
5641 #else
5642     memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
5643 #endif
5644 }
5645
5646 void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
5647  const ULARGE_INTEGER *value)
5648 {
5649 #ifdef WORDS_BIGENDIAN
5650     ULARGE_INTEGER tmp;
5651
5652     tmp.u.LowPart = htole32(value->u.HighPart);
5653     tmp.u.HighPart = htole32(value->u.LowPart);
5654     memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
5655 #else
5656     memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
5657 #endif
5658 }
5659
5660 void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
5661 {
5662   StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
5663   StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
5664   StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
5665
5666   memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
5667 }
5668
5669 void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
5670 {
5671   StorageUtl_WriteDWord(buffer, offset,   value->Data1);
5672   StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
5673   StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
5674
5675   memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
5676 }
5677
5678 void StorageUtl_CopyDirEntryToSTATSTG(
5679   StorageBaseImpl*      storage,
5680   STATSTG*              destination,
5681   const DirEntry*       source,
5682   int                   statFlags)
5683 {
5684   /*
5685    * The copy of the string occurs only when the flag is not set
5686    */
5687   if (!(statFlags & STATFLAG_NONAME) && source->stgType == STGTY_ROOT)
5688   {
5689     /* Use the filename for the root storage. */
5690     destination->pwcsName = 0;
5691     StorageBaseImpl_GetFilename(storage, &destination->pwcsName);
5692   }
5693   else if( ((statFlags & STATFLAG_NONAME) != 0) ||
5694        (source->name[0] == 0) )
5695   {
5696     destination->pwcsName = 0;
5697   }
5698   else
5699   {
5700     destination->pwcsName =
5701       CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
5702
5703     strcpyW(destination->pwcsName, source->name);
5704   }
5705
5706   switch (source->stgType)
5707   {
5708     case STGTY_STORAGE:
5709     case STGTY_ROOT:
5710       destination->type = STGTY_STORAGE;
5711       break;
5712     case STGTY_STREAM:
5713       destination->type = STGTY_STREAM;
5714       break;
5715     default:
5716       destination->type = STGTY_STREAM;
5717       break;
5718   }
5719
5720   destination->cbSize            = source->size;
5721 /*
5722   currentReturnStruct->mtime     = {0}; TODO
5723   currentReturnStruct->ctime     = {0};
5724   currentReturnStruct->atime     = {0};
5725 */
5726   destination->grfMode           = 0;
5727   destination->grfLocksSupported = 0;
5728   destination->clsid             = source->clsid;
5729   destination->grfStateBits      = 0;
5730   destination->reserved          = 0;
5731 }
5732
5733 /******************************************************************************
5734 ** BlockChainStream implementation
5735 */
5736
5737 /* Read and save the index of all blocks in this stream. */
5738 HRESULT BlockChainStream_UpdateIndexCache(BlockChainStream* This)
5739 {
5740   ULONG  next_sector, next_offset;
5741   HRESULT hr;
5742   struct BlockChainRun *last_run;
5743
5744   if (This->indexCacheLen == 0)
5745   {
5746     last_run = NULL;
5747     next_offset = 0;
5748     next_sector = BlockChainStream_GetHeadOfChain(This);
5749   }
5750   else
5751   {
5752     last_run = &This->indexCache[This->indexCacheLen-1];
5753     next_offset = last_run->lastOffset+1;
5754     hr = StorageImpl_GetNextBlockInChain(This->parentStorage,
5755         last_run->firstSector + last_run->lastOffset - last_run->firstOffset,
5756         &next_sector);
5757     if (FAILED(hr)) return hr;
5758   }
5759
5760   while (next_sector != BLOCK_END_OF_CHAIN)
5761   {
5762     if (!last_run || next_sector != last_run->firstSector + next_offset - last_run->firstOffset)
5763     {
5764       /* Add the current block to the cache. */
5765       if (This->indexCacheSize == 0)
5766       {
5767         This->indexCache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*16);
5768         if (!This->indexCache) return E_OUTOFMEMORY;
5769         This->indexCacheSize = 16;
5770       }
5771       else if (This->indexCacheSize == This->indexCacheLen)
5772       {
5773         struct BlockChainRun *new_cache;
5774         ULONG new_size;
5775
5776         new_size = This->indexCacheSize * 2;
5777         new_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*new_size);
5778         if (!new_cache) return E_OUTOFMEMORY;
5779         memcpy(new_cache, This->indexCache, sizeof(struct BlockChainRun)*This->indexCacheLen);
5780
5781         HeapFree(GetProcessHeap(), 0, This->indexCache);
5782         This->indexCache = new_cache;
5783         This->indexCacheSize = new_size;
5784       }
5785
5786       This->indexCacheLen++;
5787       last_run = &This->indexCache[This->indexCacheLen-1];
5788       last_run->firstSector = next_sector;
5789       last_run->firstOffset = next_offset;
5790     }
5791
5792     last_run->lastOffset = next_offset;
5793
5794     /* Find the next block. */
5795     next_offset++;
5796     hr = StorageImpl_GetNextBlockInChain(This->parentStorage, next_sector, &next_sector);
5797     if (FAILED(hr)) return hr;
5798   }
5799
5800   if (This->indexCacheLen)
5801   {
5802     This->tailIndex = last_run->firstSector + last_run->lastOffset - last_run->firstOffset;
5803     This->numBlocks = last_run->lastOffset+1;
5804   }
5805   else
5806   {
5807     This->tailIndex = BLOCK_END_OF_CHAIN;
5808     This->numBlocks = 0;
5809   }
5810
5811   return S_OK;
5812 }
5813
5814 /* Locate the nth block in this stream. */
5815 ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset)
5816 {
5817   ULONG min_offset = 0, max_offset = This->numBlocks-1;
5818   ULONG min_run = 0, max_run = This->indexCacheLen-1;
5819
5820   if (offset >= This->numBlocks)
5821     return BLOCK_END_OF_CHAIN;
5822
5823   while (min_run < max_run)
5824   {
5825     ULONG run_to_check = min_run + (offset - min_offset) * (max_run - min_run) / (max_offset - min_offset);
5826     if (offset < This->indexCache[run_to_check].firstOffset)
5827     {
5828       max_offset = This->indexCache[run_to_check].firstOffset-1;
5829       max_run = run_to_check-1;
5830     }
5831     else if (offset > This->indexCache[run_to_check].lastOffset)
5832     {
5833       min_offset = This->indexCache[run_to_check].lastOffset+1;
5834       min_run = run_to_check+1;
5835     }
5836     else
5837       /* Block is in this run. */
5838       min_run = max_run = run_to_check;
5839   }
5840
5841   return This->indexCache[min_run].firstSector + offset - This->indexCache[min_run].firstOffset;
5842 }
5843
5844 HRESULT BlockChainStream_GetBlockAtOffset(BlockChainStream *This,
5845     ULONG index, BlockChainBlock **block, ULONG *sector, BOOL create)
5846 {
5847   BlockChainBlock *result=NULL;
5848   int i;
5849
5850   for (i=0; i<2; i++)
5851     if (This->cachedBlocks[i].index == index)
5852     {
5853       *sector = This->cachedBlocks[i].sector;
5854       *block = &This->cachedBlocks[i];
5855       return S_OK;
5856     }
5857
5858   *sector = BlockChainStream_GetSectorOfOffset(This, index);
5859   if (*sector == BLOCK_END_OF_CHAIN)
5860     return STG_E_DOCFILECORRUPT;
5861
5862   if (create)
5863   {
5864     if (This->cachedBlocks[0].index == 0xffffffff)
5865       result = &This->cachedBlocks[0];
5866     else if (This->cachedBlocks[1].index == 0xffffffff)
5867       result = &This->cachedBlocks[1];
5868     else
5869     {
5870       result = &This->cachedBlocks[This->blockToEvict++];
5871       if (This->blockToEvict == 2)
5872         This->blockToEvict = 0;
5873     }
5874
5875     if (result->dirty)
5876     {
5877       if (!StorageImpl_WriteBigBlock(This->parentStorage, result->sector, result->data))
5878         return STG_E_WRITEFAULT;
5879       result->dirty = 0;
5880     }
5881
5882     result->read = 0;
5883     result->index = index;
5884     result->sector = *sector;
5885   }
5886
5887   *block = result;
5888   return S_OK;
5889 }
5890
5891 BlockChainStream* BlockChainStream_Construct(
5892   StorageImpl* parentStorage,
5893   ULONG*         headOfStreamPlaceHolder,
5894   DirRef         dirEntry)
5895 {
5896   BlockChainStream* newStream;
5897
5898   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
5899
5900   newStream->parentStorage           = parentStorage;
5901   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
5902   newStream->ownerDirEntry           = dirEntry;
5903   newStream->indexCache              = NULL;
5904   newStream->indexCacheLen           = 0;
5905   newStream->indexCacheSize          = 0;
5906   newStream->cachedBlocks[0].index = 0xffffffff;
5907   newStream->cachedBlocks[0].dirty = 0;
5908   newStream->cachedBlocks[1].index = 0xffffffff;
5909   newStream->cachedBlocks[1].dirty = 0;
5910   newStream->blockToEvict          = 0;
5911
5912   if (FAILED(BlockChainStream_UpdateIndexCache(newStream)))
5913   {
5914     HeapFree(GetProcessHeap(), 0, newStream->indexCache);
5915     HeapFree(GetProcessHeap(), 0, newStream);
5916     return NULL;
5917   }
5918
5919   return newStream;
5920 }
5921
5922 HRESULT BlockChainStream_Flush(BlockChainStream* This)
5923 {
5924   int i;
5925   if (!This) return S_OK;
5926   for (i=0; i<2; i++)
5927   {
5928     if (This->cachedBlocks[i].dirty)
5929     {
5930       if (StorageImpl_WriteBigBlock(This->parentStorage, This->cachedBlocks[i].sector, This->cachedBlocks[i].data))
5931         This->cachedBlocks[i].dirty = 0;
5932       else
5933         return STG_E_WRITEFAULT;
5934     }
5935   }
5936   return S_OK;
5937 }
5938
5939 void BlockChainStream_Destroy(BlockChainStream* This)
5940 {
5941   if (This)
5942   {
5943     BlockChainStream_Flush(This);
5944     HeapFree(GetProcessHeap(), 0, This->indexCache);
5945   }
5946   HeapFree(GetProcessHeap(), 0, This);
5947 }
5948
5949 /******************************************************************************
5950  *      BlockChainStream_GetHeadOfChain
5951  *
5952  * Returns the head of this stream chain.
5953  * Some special chains don't have directory entries, their heads are kept in
5954  * This->headOfStreamPlaceHolder.
5955  *
5956  */
5957 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
5958 {
5959   DirEntry  chainEntry;
5960   HRESULT   hr;
5961
5962   if (This->headOfStreamPlaceHolder != 0)
5963     return *(This->headOfStreamPlaceHolder);
5964
5965   if (This->ownerDirEntry != DIRENTRY_NULL)
5966   {
5967     hr = StorageImpl_ReadDirEntry(
5968                       This->parentStorage,
5969                       This->ownerDirEntry,
5970                       &chainEntry);
5971
5972     if (SUCCEEDED(hr))
5973     {
5974       return chainEntry.startingBlock;
5975     }
5976   }
5977
5978   return BLOCK_END_OF_CHAIN;
5979 }
5980
5981 /******************************************************************************
5982  *       BlockChainStream_GetCount
5983  *
5984  * Returns the number of blocks that comprises this chain.
5985  * This is not the size of the stream as the last block may not be full!
5986  */
5987 static ULONG BlockChainStream_GetCount(BlockChainStream* This)
5988 {
5989   return This->numBlocks;
5990 }
5991
5992 /******************************************************************************
5993  *      BlockChainStream_ReadAt
5994  *
5995  * Reads a specified number of bytes from this chain at the specified offset.
5996  * bytesRead may be NULL.
5997  * Failure will be returned if the specified number of bytes has not been read.
5998  */
5999 HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
6000   ULARGE_INTEGER offset,
6001   ULONG          size,
6002   void*          buffer,
6003   ULONG*         bytesRead)
6004 {
6005   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
6006   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
6007   ULONG bytesToReadInBuffer;
6008   ULONG blockIndex;
6009   BYTE* bufferWalker;
6010   ULARGE_INTEGER stream_size;
6011   HRESULT hr;
6012   BlockChainBlock *cachedBlock;
6013
6014   TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
6015
6016   /*
6017    * Find the first block in the stream that contains part of the buffer.
6018    */
6019   blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
6020
6021   *bytesRead   = 0;
6022
6023   stream_size = BlockChainStream_GetSize(This);
6024   if (stream_size.QuadPart > offset.QuadPart)
6025     size = min(stream_size.QuadPart - offset.QuadPart, size);
6026   else
6027     return S_OK;
6028
6029   /*
6030    * Start reading the buffer.
6031    */
6032   bufferWalker = buffer;
6033
6034   while (size > 0)
6035   {
6036     ULARGE_INTEGER ulOffset;
6037     DWORD bytesReadAt;
6038
6039     /*
6040      * Calculate how many bytes we can copy from this big block.
6041      */
6042     bytesToReadInBuffer =
6043       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
6044
6045     hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToReadInBuffer);
6046
6047     if (FAILED(hr))
6048       return hr;
6049
6050     if (!cachedBlock)
6051     {
6052       /* Not in cache, and we're going to read past the end of the block. */
6053       ulOffset.u.HighPart = 0;
6054       ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
6055                                offsetInBlock;
6056
6057       StorageImpl_ReadAt(This->parentStorage,
6058            ulOffset,
6059            bufferWalker,
6060            bytesToReadInBuffer,
6061            &bytesReadAt);
6062     }
6063     else
6064     {
6065       if (!cachedBlock->read)
6066       {
6067         if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
6068           return STG_E_READFAULT;
6069
6070         cachedBlock->read = 1;
6071       }
6072
6073       memcpy(bufferWalker, cachedBlock->data+offsetInBlock, bytesToReadInBuffer);
6074       bytesReadAt = bytesToReadInBuffer;
6075     }
6076
6077     blockNoInSequence++;
6078     bufferWalker += bytesReadAt;
6079     size         -= bytesReadAt;
6080     *bytesRead   += bytesReadAt;
6081     offsetInBlock = 0;  /* There is no offset on the next block */
6082
6083     if (bytesToReadInBuffer != bytesReadAt)
6084         break;
6085   }
6086
6087   return S_OK;
6088 }
6089
6090 /******************************************************************************
6091  *      BlockChainStream_WriteAt
6092  *
6093  * Writes the specified number of bytes to this chain at the specified offset.
6094  * Will fail if not all specified number of bytes have been written.
6095  */
6096 HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
6097   ULARGE_INTEGER    offset,
6098   ULONG             size,
6099   const void*       buffer,
6100   ULONG*            bytesWritten)
6101 {
6102   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
6103   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
6104   ULONG bytesToWrite;
6105   ULONG blockIndex;
6106   const BYTE* bufferWalker;
6107   HRESULT hr;
6108   BlockChainBlock *cachedBlock;
6109
6110   *bytesWritten   = 0;
6111   bufferWalker = buffer;
6112
6113   while (size > 0)
6114   {
6115     ULARGE_INTEGER ulOffset;
6116     DWORD bytesWrittenAt;
6117
6118     /*
6119      * Calculate how many bytes we can copy to this big block.
6120      */
6121     bytesToWrite =
6122       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
6123
6124     hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToWrite);
6125
6126     /* BlockChainStream_SetSize should have already been called to ensure we have
6127      * enough blocks in the chain to write into */
6128     if (FAILED(hr))
6129     {
6130       ERR("not enough blocks in chain to write data\n");
6131       return hr;
6132     }
6133
6134     if (!cachedBlock)
6135     {
6136       /* Not in cache, and we're going to write past the end of the block. */
6137       ulOffset.u.HighPart = 0;
6138       ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
6139                                offsetInBlock;
6140
6141       StorageImpl_WriteAt(This->parentStorage,
6142            ulOffset,
6143            bufferWalker,
6144            bytesToWrite,
6145            &bytesWrittenAt);
6146     }
6147     else
6148     {
6149       if (!cachedBlock->read && bytesToWrite != This->parentStorage->bigBlockSize)
6150       {
6151         if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
6152           return STG_E_READFAULT;
6153       }
6154
6155       memcpy(cachedBlock->data+offsetInBlock, bufferWalker, bytesToWrite);
6156       bytesWrittenAt = bytesToWrite;
6157       cachedBlock->read = 1;
6158       cachedBlock->dirty = 1;
6159     }
6160
6161     blockNoInSequence++;
6162     bufferWalker  += bytesWrittenAt;
6163     size          -= bytesWrittenAt;
6164     *bytesWritten += bytesWrittenAt;
6165     offsetInBlock  = 0;      /* There is no offset on the next block */
6166
6167     if (bytesWrittenAt != bytesToWrite)
6168       break;
6169   }
6170
6171   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
6172 }
6173
6174 /******************************************************************************
6175  *      BlockChainStream_Shrink
6176  *
6177  * Shrinks this chain in the big block depot.
6178  */
6179 static BOOL BlockChainStream_Shrink(BlockChainStream* This,
6180                                     ULARGE_INTEGER    newSize)
6181 {
6182   ULONG blockIndex;
6183   ULONG numBlocks;
6184   int i;
6185
6186   /*
6187    * Figure out how many blocks are needed to contain the new size
6188    */
6189   numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
6190
6191   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
6192     numBlocks++;
6193
6194   if (numBlocks)
6195   {
6196     /*
6197      * Go to the new end of chain
6198      */
6199     blockIndex = BlockChainStream_GetSectorOfOffset(This, numBlocks-1);
6200
6201     /* Mark the new end of chain */
6202     StorageImpl_SetNextBlockInChain(
6203       This->parentStorage,
6204       blockIndex,
6205       BLOCK_END_OF_CHAIN);
6206
6207     This->tailIndex = blockIndex;
6208   }
6209   else
6210   {
6211     if (This->headOfStreamPlaceHolder != 0)
6212     {
6213       *This->headOfStreamPlaceHolder = BLOCK_END_OF_CHAIN;
6214     }
6215     else
6216     {
6217       DirEntry chainEntry;
6218       assert(This->ownerDirEntry != DIRENTRY_NULL);
6219
6220       StorageImpl_ReadDirEntry(
6221         This->parentStorage,
6222         This->ownerDirEntry,
6223         &chainEntry);
6224
6225       chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
6226
6227       StorageImpl_WriteDirEntry(
6228         This->parentStorage,
6229         This->ownerDirEntry,
6230         &chainEntry);
6231     }
6232
6233     This->tailIndex = BLOCK_END_OF_CHAIN;
6234   }
6235
6236   This->numBlocks = numBlocks;
6237
6238   /*
6239    * Mark the extra blocks as free
6240    */
6241   while (This->indexCacheLen && This->indexCache[This->indexCacheLen-1].lastOffset >= numBlocks)
6242   {
6243     struct BlockChainRun *last_run = &This->indexCache[This->indexCacheLen-1];
6244     StorageImpl_FreeBigBlock(This->parentStorage,
6245       last_run->firstSector + last_run->lastOffset - last_run->firstOffset);
6246     if (last_run->lastOffset == last_run->firstOffset)
6247       This->indexCacheLen--;
6248     else
6249       last_run->lastOffset--;
6250   }
6251
6252   /*
6253    * Reset the last accessed block cache.
6254    */
6255   for (i=0; i<2; i++)
6256   {
6257     if (This->cachedBlocks[i].index >= numBlocks)
6258     {
6259       This->cachedBlocks[i].index = 0xffffffff;
6260       This->cachedBlocks[i].dirty = 0;
6261     }
6262   }
6263
6264   return TRUE;
6265 }
6266
6267 /******************************************************************************
6268  *      BlockChainStream_Enlarge
6269  *
6270  * Grows this chain in the big block depot.
6271  */
6272 static BOOL BlockChainStream_Enlarge(BlockChainStream* This,
6273                                      ULARGE_INTEGER    newSize)
6274 {
6275   ULONG blockIndex, currentBlock;
6276   ULONG newNumBlocks;
6277   ULONG oldNumBlocks = 0;
6278
6279   blockIndex = BlockChainStream_GetHeadOfChain(This);
6280
6281   /*
6282    * Empty chain. Create the head.
6283    */
6284   if (blockIndex == BLOCK_END_OF_CHAIN)
6285   {
6286     blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
6287     StorageImpl_SetNextBlockInChain(This->parentStorage,
6288                                       blockIndex,
6289                                       BLOCK_END_OF_CHAIN);
6290
6291     if (This->headOfStreamPlaceHolder != 0)
6292     {
6293       *(This->headOfStreamPlaceHolder) = blockIndex;
6294     }
6295     else
6296     {
6297       DirEntry chainEntry;
6298       assert(This->ownerDirEntry != DIRENTRY_NULL);
6299
6300       StorageImpl_ReadDirEntry(
6301         This->parentStorage,
6302         This->ownerDirEntry,
6303         &chainEntry);
6304
6305       chainEntry.startingBlock = blockIndex;
6306
6307       StorageImpl_WriteDirEntry(
6308         This->parentStorage,
6309         This->ownerDirEntry,
6310         &chainEntry);
6311     }
6312
6313     This->tailIndex = blockIndex;
6314     This->numBlocks = 1;
6315   }
6316
6317   /*
6318    * Figure out how many blocks are needed to contain this stream
6319    */
6320   newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
6321
6322   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
6323     newNumBlocks++;
6324
6325   /*
6326    * Go to the current end of chain
6327    */
6328   if (This->tailIndex == BLOCK_END_OF_CHAIN)
6329   {
6330     currentBlock = blockIndex;
6331
6332     while (blockIndex != BLOCK_END_OF_CHAIN)
6333     {
6334       This->numBlocks++;
6335       currentBlock = blockIndex;
6336
6337       if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
6338                                                 &blockIndex)))
6339         return FALSE;
6340     }
6341
6342     This->tailIndex = currentBlock;
6343   }
6344
6345   currentBlock = This->tailIndex;
6346   oldNumBlocks = This->numBlocks;
6347
6348   /*
6349    * Add new blocks to the chain
6350    */
6351   if (oldNumBlocks < newNumBlocks)
6352   {
6353     while (oldNumBlocks < newNumBlocks)
6354     {
6355       blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
6356
6357       StorageImpl_SetNextBlockInChain(
6358         This->parentStorage,
6359         currentBlock,
6360         blockIndex);
6361
6362       StorageImpl_SetNextBlockInChain(
6363         This->parentStorage,
6364         blockIndex,
6365         BLOCK_END_OF_CHAIN);
6366
6367       currentBlock = blockIndex;
6368       oldNumBlocks++;
6369     }
6370
6371     This->tailIndex = blockIndex;
6372     This->numBlocks = newNumBlocks;
6373   }
6374
6375   if (FAILED(BlockChainStream_UpdateIndexCache(This)))
6376     return FALSE;
6377
6378   return TRUE;
6379 }
6380
6381 /******************************************************************************
6382  *      BlockChainStream_SetSize
6383  *
6384  * Sets the size of this stream. The big block depot will be updated.
6385  * The file will grow if we grow the chain.
6386  *
6387  * TODO: Free the actual blocks in the file when we shrink the chain.
6388  *       Currently, the blocks are still in the file. So the file size
6389  *       doesn't shrink even if we shrink streams.
6390  */
6391 BOOL BlockChainStream_SetSize(
6392   BlockChainStream* This,
6393   ULARGE_INTEGER    newSize)
6394 {
6395   ULARGE_INTEGER size = BlockChainStream_GetSize(This);
6396
6397   if (newSize.u.LowPart == size.u.LowPart)
6398     return TRUE;
6399
6400   if (newSize.u.LowPart < size.u.LowPart)
6401   {
6402     BlockChainStream_Shrink(This, newSize);
6403   }
6404   else
6405   {
6406     BlockChainStream_Enlarge(This, newSize);
6407   }
6408
6409   return TRUE;
6410 }
6411
6412 /******************************************************************************
6413  *      BlockChainStream_GetSize
6414  *
6415  * Returns the size of this chain.
6416  * Will return the block count if this chain doesn't have a directory entry.
6417  */
6418 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
6419 {
6420   DirEntry chainEntry;
6421
6422   if(This->headOfStreamPlaceHolder == NULL)
6423   {
6424     /*
6425      * This chain has a directory entry so use the size value from there.
6426      */
6427     StorageImpl_ReadDirEntry(
6428       This->parentStorage,
6429       This->ownerDirEntry,
6430       &chainEntry);
6431
6432     return chainEntry.size;
6433   }
6434   else
6435   {
6436     /*
6437      * this chain is a chain that does not have a directory entry, figure out the
6438      * size by making the product number of used blocks times the
6439      * size of them
6440      */
6441     ULARGE_INTEGER result;
6442     result.u.HighPart = 0;
6443
6444     result.u.LowPart  =
6445       BlockChainStream_GetCount(This) *
6446       This->parentStorage->bigBlockSize;
6447
6448     return result;
6449   }
6450 }
6451
6452 /******************************************************************************
6453 ** SmallBlockChainStream implementation
6454 */
6455
6456 SmallBlockChainStream* SmallBlockChainStream_Construct(
6457   StorageImpl* parentStorage,
6458   ULONG*         headOfStreamPlaceHolder,
6459   DirRef         dirEntry)
6460 {
6461   SmallBlockChainStream* newStream;
6462
6463   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
6464
6465   newStream->parentStorage      = parentStorage;
6466   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
6467   newStream->ownerDirEntry      = dirEntry;
6468
6469   return newStream;
6470 }
6471
6472 void SmallBlockChainStream_Destroy(
6473   SmallBlockChainStream* This)
6474 {
6475   HeapFree(GetProcessHeap(), 0, This);
6476 }
6477
6478 /******************************************************************************
6479  *      SmallBlockChainStream_GetHeadOfChain
6480  *
6481  * Returns the head of this chain of small blocks.
6482  */
6483 static ULONG SmallBlockChainStream_GetHeadOfChain(
6484   SmallBlockChainStream* This)
6485 {
6486   DirEntry  chainEntry;
6487   HRESULT   hr;
6488
6489   if (This->headOfStreamPlaceHolder != NULL)
6490     return *(This->headOfStreamPlaceHolder);
6491
6492   if (This->ownerDirEntry)
6493   {
6494     hr = StorageImpl_ReadDirEntry(
6495                       This->parentStorage,
6496                       This->ownerDirEntry,
6497                       &chainEntry);
6498
6499     if (SUCCEEDED(hr))
6500     {
6501       return chainEntry.startingBlock;
6502     }
6503
6504   }
6505
6506   return BLOCK_END_OF_CHAIN;
6507 }
6508
6509 /******************************************************************************
6510  *      SmallBlockChainStream_GetNextBlockInChain
6511  *
6512  * Returns the index of the next small block in this chain.
6513  *
6514  * Return Values:
6515  *    - BLOCK_END_OF_CHAIN: end of this chain
6516  *    - BLOCK_UNUSED: small block 'blockIndex' is free
6517  */
6518 static HRESULT SmallBlockChainStream_GetNextBlockInChain(
6519   SmallBlockChainStream* This,
6520   ULONG                  blockIndex,
6521   ULONG*                 nextBlockInChain)
6522 {
6523   ULARGE_INTEGER offsetOfBlockInDepot;
6524   DWORD  buffer;
6525   ULONG  bytesRead;
6526   HRESULT res;
6527
6528   *nextBlockInChain = BLOCK_END_OF_CHAIN;
6529
6530   offsetOfBlockInDepot.u.HighPart = 0;
6531   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
6532
6533   /*
6534    * Read those bytes in the buffer from the small block file.
6535    */
6536   res = BlockChainStream_ReadAt(
6537               This->parentStorage->smallBlockDepotChain,
6538               offsetOfBlockInDepot,
6539               sizeof(DWORD),
6540               &buffer,
6541               &bytesRead);
6542
6543   if (SUCCEEDED(res) && bytesRead != sizeof(DWORD))
6544     res = STG_E_READFAULT;
6545
6546   if (SUCCEEDED(res))
6547   {
6548     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
6549     return S_OK;
6550   }
6551
6552   return res;
6553 }
6554
6555 /******************************************************************************
6556  *       SmallBlockChainStream_SetNextBlockInChain
6557  *
6558  * Writes the index of the next block of the specified block in the small
6559  * block depot.
6560  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
6561  * To flag a block as free use BLOCK_UNUSED as nextBlock.
6562  */
6563 static void SmallBlockChainStream_SetNextBlockInChain(
6564   SmallBlockChainStream* This,
6565   ULONG                  blockIndex,
6566   ULONG                  nextBlock)
6567 {
6568   ULARGE_INTEGER offsetOfBlockInDepot;
6569   DWORD  buffer;
6570   ULONG  bytesWritten;
6571
6572   offsetOfBlockInDepot.u.HighPart = 0;
6573   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
6574
6575   StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
6576
6577   /*
6578    * Read those bytes in the buffer from the small block file.
6579    */
6580   BlockChainStream_WriteAt(
6581     This->parentStorage->smallBlockDepotChain,
6582     offsetOfBlockInDepot,
6583     sizeof(DWORD),
6584     &buffer,
6585     &bytesWritten);
6586 }
6587
6588 /******************************************************************************
6589  *      SmallBlockChainStream_FreeBlock
6590  *
6591  * Flag small block 'blockIndex' as free in the small block depot.
6592  */
6593 static void SmallBlockChainStream_FreeBlock(
6594   SmallBlockChainStream* This,
6595   ULONG                  blockIndex)
6596 {
6597   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
6598 }
6599
6600 /******************************************************************************
6601  *      SmallBlockChainStream_GetNextFreeBlock
6602  *
6603  * Returns the index of a free small block. The small block depot will be
6604  * enlarged if necessary. The small block chain will also be enlarged if
6605  * necessary.
6606  */
6607 static ULONG SmallBlockChainStream_GetNextFreeBlock(
6608   SmallBlockChainStream* This)
6609 {
6610   ULARGE_INTEGER offsetOfBlockInDepot;
6611   DWORD buffer;
6612   ULONG bytesRead;
6613   ULONG blockIndex = This->parentStorage->firstFreeSmallBlock;
6614   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
6615   HRESULT res = S_OK;
6616   ULONG smallBlocksPerBigBlock;
6617   DirEntry rootEntry;
6618   ULONG blocksRequired;
6619   ULARGE_INTEGER old_size, size_required;
6620
6621   offsetOfBlockInDepot.u.HighPart = 0;
6622
6623   /*
6624    * Scan the small block depot for a free block
6625    */
6626   while (nextBlockIndex != BLOCK_UNUSED)
6627   {
6628     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
6629
6630     res = BlockChainStream_ReadAt(
6631                 This->parentStorage->smallBlockDepotChain,
6632                 offsetOfBlockInDepot,
6633                 sizeof(DWORD),
6634                 &buffer,
6635                 &bytesRead);
6636
6637     /*
6638      * If we run out of space for the small block depot, enlarge it
6639      */
6640     if (SUCCEEDED(res) && bytesRead == sizeof(DWORD))
6641     {
6642       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
6643
6644       if (nextBlockIndex != BLOCK_UNUSED)
6645         blockIndex++;
6646     }
6647     else
6648     {
6649       ULONG count =
6650         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
6651
6652       BYTE smallBlockDepot[MAX_BIG_BLOCK_SIZE];
6653       ULARGE_INTEGER newSize, offset;
6654       ULONG bytesWritten;
6655
6656       newSize.QuadPart = (count + 1) * This->parentStorage->bigBlockSize;
6657       BlockChainStream_Enlarge(This->parentStorage->smallBlockDepotChain, newSize);
6658
6659       /*
6660        * Initialize all the small blocks to free
6661        */
6662       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
6663       offset.QuadPart = count * This->parentStorage->bigBlockSize;
6664       BlockChainStream_WriteAt(This->parentStorage->smallBlockDepotChain,
6665         offset, This->parentStorage->bigBlockSize, smallBlockDepot, &bytesWritten);
6666
6667       StorageImpl_SaveFileHeader(This->parentStorage);
6668     }
6669   }
6670
6671   This->parentStorage->firstFreeSmallBlock = blockIndex+1;
6672
6673   smallBlocksPerBigBlock =
6674     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
6675
6676   /*
6677    * Verify if we have to allocate big blocks to contain small blocks
6678    */
6679   blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
6680
6681   size_required.QuadPart = blocksRequired * This->parentStorage->bigBlockSize;
6682
6683   old_size = BlockChainStream_GetSize(This->parentStorage->smallBlockRootChain);
6684
6685   if (size_required.QuadPart > old_size.QuadPart)
6686   {
6687     BlockChainStream_SetSize(
6688       This->parentStorage->smallBlockRootChain,
6689       size_required);
6690
6691     StorageImpl_ReadDirEntry(
6692       This->parentStorage,
6693       This->parentStorage->base.storageDirEntry,
6694       &rootEntry);
6695
6696     rootEntry.size = size_required;
6697
6698     StorageImpl_WriteDirEntry(
6699       This->parentStorage,
6700       This->parentStorage->base.storageDirEntry,
6701       &rootEntry);
6702   }
6703
6704   return blockIndex;
6705 }
6706
6707 /******************************************************************************
6708  *      SmallBlockChainStream_ReadAt
6709  *
6710  * Reads a specified number of bytes from this chain at the specified offset.
6711  * bytesRead may be NULL.
6712  * Failure will be returned if the specified number of bytes has not been read.
6713  */
6714 HRESULT SmallBlockChainStream_ReadAt(
6715   SmallBlockChainStream* This,
6716   ULARGE_INTEGER         offset,
6717   ULONG                  size,
6718   void*                  buffer,
6719   ULONG*                 bytesRead)
6720 {
6721   HRESULT rc = S_OK;
6722   ULARGE_INTEGER offsetInBigBlockFile;
6723   ULONG blockNoInSequence =
6724     offset.u.LowPart / This->parentStorage->smallBlockSize;
6725
6726   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
6727   ULONG bytesToReadInBuffer;
6728   ULONG blockIndex;
6729   ULONG bytesReadFromBigBlockFile;
6730   BYTE* bufferWalker;
6731   ULARGE_INTEGER stream_size;
6732
6733   /*
6734    * This should never happen on a small block file.
6735    */
6736   assert(offset.u.HighPart==0);
6737
6738   *bytesRead   = 0;
6739
6740   stream_size = SmallBlockChainStream_GetSize(This);
6741   if (stream_size.QuadPart > offset.QuadPart)
6742     size = min(stream_size.QuadPart - offset.QuadPart, size);
6743   else
6744     return S_OK;
6745
6746   /*
6747    * Find the first block in the stream that contains part of the buffer.
6748    */
6749   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
6750
6751   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
6752   {
6753     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
6754     if(FAILED(rc))
6755       return rc;
6756     blockNoInSequence--;
6757   }
6758
6759   /*
6760    * Start reading the buffer.
6761    */
6762   bufferWalker = buffer;
6763
6764   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
6765   {
6766     /*
6767      * Calculate how many bytes we can copy from this small block.
6768      */
6769     bytesToReadInBuffer =
6770       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
6771
6772     /*
6773      * Calculate the offset of the small block in the small block file.
6774      */
6775     offsetInBigBlockFile.u.HighPart  = 0;
6776     offsetInBigBlockFile.u.LowPart   =
6777       blockIndex * This->parentStorage->smallBlockSize;
6778
6779     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
6780
6781     /*
6782      * Read those bytes in the buffer from the small block file.
6783      * The small block has already been identified so it shouldn't fail
6784      * unless the file is corrupt.
6785      */
6786     rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
6787       offsetInBigBlockFile,
6788       bytesToReadInBuffer,
6789       bufferWalker,
6790       &bytesReadFromBigBlockFile);
6791
6792     if (FAILED(rc))
6793       return rc;
6794
6795     if (!bytesReadFromBigBlockFile)
6796       return STG_E_DOCFILECORRUPT;
6797
6798     /*
6799      * Step to the next big block.
6800      */
6801     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
6802     if(FAILED(rc))
6803       return STG_E_DOCFILECORRUPT;
6804
6805     bufferWalker += bytesReadFromBigBlockFile;
6806     size         -= bytesReadFromBigBlockFile;
6807     *bytesRead   += bytesReadFromBigBlockFile;
6808     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
6809   }
6810
6811   return S_OK;
6812 }
6813
6814 /******************************************************************************
6815  *       SmallBlockChainStream_WriteAt
6816  *
6817  * Writes the specified number of bytes to this chain at the specified offset.
6818  * Will fail if not all specified number of bytes have been written.
6819  */
6820 HRESULT SmallBlockChainStream_WriteAt(
6821   SmallBlockChainStream* This,
6822   ULARGE_INTEGER offset,
6823   ULONG          size,
6824   const void*    buffer,
6825   ULONG*         bytesWritten)
6826 {
6827   ULARGE_INTEGER offsetInBigBlockFile;
6828   ULONG blockNoInSequence =
6829     offset.u.LowPart / This->parentStorage->smallBlockSize;
6830
6831   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
6832   ULONG bytesToWriteInBuffer;
6833   ULONG blockIndex;
6834   ULONG bytesWrittenToBigBlockFile;
6835   const BYTE* bufferWalker;
6836   HRESULT res;
6837
6838   /*
6839    * This should never happen on a small block file.
6840    */
6841   assert(offset.u.HighPart==0);
6842
6843   /*
6844    * Find the first block in the stream that contains part of the buffer.
6845    */
6846   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
6847
6848   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
6849   {
6850     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
6851       return STG_E_DOCFILECORRUPT;
6852     blockNoInSequence--;
6853   }
6854
6855   /*
6856    * Start writing the buffer.
6857    */
6858   *bytesWritten   = 0;
6859   bufferWalker = buffer;
6860   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
6861   {
6862     /*
6863      * Calculate how many bytes we can copy to this small block.
6864      */
6865     bytesToWriteInBuffer =
6866       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
6867
6868     /*
6869      * Calculate the offset of the small block in the small block file.
6870      */
6871     offsetInBigBlockFile.u.HighPart  = 0;
6872     offsetInBigBlockFile.u.LowPart   =
6873       blockIndex * This->parentStorage->smallBlockSize;
6874
6875     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
6876
6877     /*
6878      * Write those bytes in the buffer to the small block file.
6879      */
6880     res = BlockChainStream_WriteAt(
6881       This->parentStorage->smallBlockRootChain,
6882       offsetInBigBlockFile,
6883       bytesToWriteInBuffer,
6884       bufferWalker,
6885       &bytesWrittenToBigBlockFile);
6886     if (FAILED(res))
6887       return res;
6888
6889     /*
6890      * Step to the next big block.
6891      */
6892     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
6893                                                         &blockIndex)))
6894       return FALSE;
6895     bufferWalker  += bytesWrittenToBigBlockFile;
6896     size          -= bytesWrittenToBigBlockFile;
6897     *bytesWritten += bytesWrittenToBigBlockFile;
6898     offsetInBlock  = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
6899   }
6900
6901   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
6902 }
6903
6904 /******************************************************************************
6905  *       SmallBlockChainStream_Shrink
6906  *
6907  * Shrinks this chain in the small block depot.
6908  */
6909 static BOOL SmallBlockChainStream_Shrink(
6910   SmallBlockChainStream* This,
6911   ULARGE_INTEGER newSize)
6912 {
6913   ULONG blockIndex, extraBlock;
6914   ULONG numBlocks;
6915   ULONG count = 0;
6916
6917   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
6918
6919   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
6920     numBlocks++;
6921
6922   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
6923
6924   /*
6925    * Go to the new end of chain
6926    */
6927   while (count < numBlocks)
6928   {
6929     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
6930                                                         &blockIndex)))
6931       return FALSE;
6932     count++;
6933   }
6934
6935   /*
6936    * If the count is 0, we have a special case, the head of the chain was
6937    * just freed.
6938    */
6939   if (count == 0)
6940   {
6941     DirEntry chainEntry;
6942
6943     StorageImpl_ReadDirEntry(This->parentStorage,
6944                              This->ownerDirEntry,
6945                              &chainEntry);
6946
6947     chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
6948
6949     StorageImpl_WriteDirEntry(This->parentStorage,
6950                               This->ownerDirEntry,
6951                               &chainEntry);
6952
6953     /*
6954      * We start freeing the chain at the head block.
6955      */
6956     extraBlock = blockIndex;
6957   }
6958   else
6959   {
6960     /* Get the next block before marking the new end */
6961     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
6962                                                         &extraBlock)))
6963       return FALSE;
6964
6965     /* Mark the new end of chain */
6966     SmallBlockChainStream_SetNextBlockInChain(
6967       This,
6968       blockIndex,
6969       BLOCK_END_OF_CHAIN);
6970   }
6971
6972   /*
6973    * Mark the extra blocks as free
6974    */
6975   while (extraBlock != BLOCK_END_OF_CHAIN)
6976   {
6977     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
6978                                                         &blockIndex)))
6979       return FALSE;
6980     SmallBlockChainStream_FreeBlock(This, extraBlock);
6981     This->parentStorage->firstFreeSmallBlock = min(This->parentStorage->firstFreeSmallBlock, extraBlock);
6982     extraBlock = blockIndex;
6983   }
6984
6985   return TRUE;
6986 }
6987
6988 /******************************************************************************
6989  *      SmallBlockChainStream_Enlarge
6990  *
6991  * Grows this chain in the small block depot.
6992  */
6993 static BOOL SmallBlockChainStream_Enlarge(
6994   SmallBlockChainStream* This,
6995   ULARGE_INTEGER newSize)
6996 {
6997   ULONG blockIndex, currentBlock;
6998   ULONG newNumBlocks;
6999   ULONG oldNumBlocks = 0;
7000
7001   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
7002
7003   /*
7004    * Empty chain. Create the head.
7005    */
7006   if (blockIndex == BLOCK_END_OF_CHAIN)
7007   {
7008     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
7009     SmallBlockChainStream_SetNextBlockInChain(
7010         This,
7011         blockIndex,
7012         BLOCK_END_OF_CHAIN);
7013
7014     if (This->headOfStreamPlaceHolder != NULL)
7015     {
7016       *(This->headOfStreamPlaceHolder) = blockIndex;
7017     }
7018     else
7019     {
7020       DirEntry chainEntry;
7021
7022       StorageImpl_ReadDirEntry(This->parentStorage, This->ownerDirEntry,
7023                                    &chainEntry);
7024
7025       chainEntry.startingBlock = blockIndex;
7026
7027       StorageImpl_WriteDirEntry(This->parentStorage, This->ownerDirEntry,
7028                                   &chainEntry);
7029     }
7030   }
7031
7032   currentBlock = blockIndex;
7033
7034   /*
7035    * Figure out how many blocks are needed to contain this stream
7036    */
7037   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
7038
7039   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
7040     newNumBlocks++;
7041
7042   /*
7043    * Go to the current end of chain
7044    */
7045   while (blockIndex != BLOCK_END_OF_CHAIN)
7046   {
7047     oldNumBlocks++;
7048     currentBlock = blockIndex;
7049     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
7050       return FALSE;
7051   }
7052
7053   /*
7054    * Add new blocks to the chain
7055    */
7056   while (oldNumBlocks < newNumBlocks)
7057   {
7058     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
7059     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
7060
7061     SmallBlockChainStream_SetNextBlockInChain(
7062       This,
7063       blockIndex,
7064       BLOCK_END_OF_CHAIN);
7065
7066     currentBlock = blockIndex;
7067     oldNumBlocks++;
7068   }
7069
7070   return TRUE;
7071 }
7072
7073 /******************************************************************************
7074  *      SmallBlockChainStream_SetSize
7075  *
7076  * Sets the size of this stream.
7077  * The file will grow if we grow the chain.
7078  *
7079  * TODO: Free the actual blocks in the file when we shrink the chain.
7080  *       Currently, the blocks are still in the file. So the file size
7081  *       doesn't shrink even if we shrink streams.
7082  */
7083 BOOL SmallBlockChainStream_SetSize(
7084                 SmallBlockChainStream* This,
7085                 ULARGE_INTEGER    newSize)
7086 {
7087   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
7088
7089   if (newSize.u.LowPart == size.u.LowPart)
7090     return TRUE;
7091
7092   if (newSize.u.LowPart < size.u.LowPart)
7093   {
7094     SmallBlockChainStream_Shrink(This, newSize);
7095   }
7096   else
7097   {
7098     SmallBlockChainStream_Enlarge(This, newSize);
7099   }
7100
7101   return TRUE;
7102 }
7103
7104 /******************************************************************************
7105  *       SmallBlockChainStream_GetCount
7106  *
7107  * Returns the number of small blocks that comprises this chain.
7108  * This is not the size of the stream as the last block may not be full!
7109  *
7110  */
7111 static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
7112 {
7113     ULONG blockIndex;
7114     ULONG count = 0;
7115
7116     blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
7117
7118     while(blockIndex != BLOCK_END_OF_CHAIN)
7119     {
7120         count++;
7121
7122         if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This,
7123                         blockIndex, &blockIndex)))
7124             return 0;
7125     }
7126
7127     return count;
7128 }
7129
7130 /******************************************************************************
7131  *      SmallBlockChainStream_GetSize
7132  *
7133  * Returns the size of this chain.
7134  */
7135 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
7136 {
7137   DirEntry chainEntry;
7138
7139   if(This->headOfStreamPlaceHolder != NULL)
7140   {
7141     ULARGE_INTEGER result;
7142     result.u.HighPart = 0;
7143
7144     result.u.LowPart = SmallBlockChainStream_GetCount(This) *
7145         This->parentStorage->smallBlockSize;
7146
7147     return result;
7148   }
7149
7150   StorageImpl_ReadDirEntry(
7151     This->parentStorage,
7152     This->ownerDirEntry,
7153     &chainEntry);
7154
7155   return chainEntry.size;
7156 }
7157
7158 static HRESULT create_storagefile(
7159   LPCOLESTR pwcsName,
7160   DWORD       grfMode,
7161   DWORD       grfAttrs,
7162   STGOPTIONS* pStgOptions,
7163   REFIID      riid,
7164   void**      ppstgOpen)
7165 {
7166   StorageBaseImpl* newStorage = 0;
7167   HANDLE       hFile      = INVALID_HANDLE_VALUE;
7168   HRESULT        hr         = STG_E_INVALIDFLAG;
7169   DWORD          shareMode;
7170   DWORD          accessMode;
7171   DWORD          creationMode;
7172   DWORD          fileAttributes;
7173   WCHAR          tempFileName[MAX_PATH];
7174
7175   if (ppstgOpen == 0)
7176     return STG_E_INVALIDPOINTER;
7177
7178   if (pStgOptions->ulSectorSize != MIN_BIG_BLOCK_SIZE && pStgOptions->ulSectorSize != MAX_BIG_BLOCK_SIZE)
7179     return STG_E_INVALIDPARAMETER;
7180
7181   /* if no share mode given then DENY_NONE is the default */
7182   if (STGM_SHARE_MODE(grfMode) == 0)
7183       grfMode |= STGM_SHARE_DENY_NONE;
7184
7185   if ( FAILED( validateSTGM(grfMode) ))
7186     goto end;
7187
7188   /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
7189   switch(STGM_ACCESS_MODE(grfMode))
7190   {
7191   case STGM_WRITE:
7192   case STGM_READWRITE:
7193     break;
7194   default:
7195     goto end;
7196   }
7197
7198   /* in direct mode, can only use SHARE_EXCLUSIVE */
7199   if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
7200     goto end;
7201
7202   /* but in transacted mode, any share mode is valid */
7203
7204   /*
7205    * Generate a unique name.
7206    */
7207   if (pwcsName == 0)
7208   {
7209     WCHAR tempPath[MAX_PATH];
7210     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
7211
7212     memset(tempPath, 0, sizeof(tempPath));
7213     memset(tempFileName, 0, sizeof(tempFileName));
7214
7215     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
7216       tempPath[0] = '.';
7217
7218     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
7219       pwcsName = tempFileName;
7220     else
7221     {
7222       hr = STG_E_INSUFFICIENTMEMORY;
7223       goto end;
7224     }
7225
7226     creationMode = TRUNCATE_EXISTING;
7227   }
7228   else
7229   {
7230     creationMode = GetCreationModeFromSTGM(grfMode);
7231   }
7232
7233   /*
7234    * Interpret the STGM value grfMode
7235    */
7236   shareMode    = FILE_SHARE_READ | FILE_SHARE_WRITE;
7237   accessMode   = GetAccessModeFromSTGM(grfMode);
7238
7239   if (grfMode & STGM_DELETEONRELEASE)
7240     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
7241   else
7242     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
7243
7244   if (STGM_SHARE_MODE(grfMode) && !(grfMode & STGM_SHARE_DENY_NONE))
7245   {
7246     static int fixme;
7247     if (!fixme++)
7248       FIXME("Storage share mode not implemented.\n");
7249   }
7250
7251   *ppstgOpen = 0;
7252
7253   hFile = CreateFileW(pwcsName,
7254                         accessMode,
7255                         shareMode,
7256                         NULL,
7257                         creationMode,
7258                         fileAttributes,
7259                         0);
7260
7261   if (hFile == INVALID_HANDLE_VALUE)
7262   {
7263     if(GetLastError() == ERROR_FILE_EXISTS)
7264       hr = STG_E_FILEALREADYEXISTS;
7265     else
7266       hr = E_FAIL;
7267     goto end;
7268   }
7269
7270   /*
7271    * Allocate and initialize the new IStorage32object.
7272    */
7273   hr = Storage_Construct(
7274          hFile,
7275         pwcsName,
7276          NULL,
7277          grfMode,
7278          TRUE,
7279          TRUE,
7280          pStgOptions->ulSectorSize,
7281          &newStorage);
7282
7283   if (FAILED(hr))
7284   {
7285     goto end;
7286   }
7287
7288   hr = IStorage_QueryInterface((IStorage*)newStorage, riid, ppstgOpen);
7289
7290   IStorage_Release((IStorage*)newStorage);
7291
7292 end:
7293   TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
7294
7295   return hr;
7296 }
7297
7298 /******************************************************************************
7299  *    StgCreateDocfile  [OLE32.@]
7300  * Creates a new compound file storage object
7301  *
7302  * PARAMS
7303  *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
7304  *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
7305  *  reserved  [ ?] unused?, usually 0
7306  *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
7307  *
7308  * RETURNS
7309  *  S_OK if the file was successfully created
7310  *  some STG_E_ value if error
7311  * NOTES
7312  *  if pwcsName is NULL, create file with new unique name
7313  *  the function can returns
7314  *  STG_S_CONVERTED if the specified file was successfully converted to storage format
7315  *  (unrealized now)
7316  */
7317 HRESULT WINAPI StgCreateDocfile(
7318   LPCOLESTR pwcsName,
7319   DWORD       grfMode,
7320   DWORD       reserved,
7321   IStorage  **ppstgOpen)
7322 {
7323   STGOPTIONS stgoptions = {1, 0, 512};
7324
7325   TRACE("(%s, %x, %d, %p)\n",
7326         debugstr_w(pwcsName), grfMode,
7327         reserved, ppstgOpen);
7328
7329   if (ppstgOpen == 0)
7330     return STG_E_INVALIDPOINTER;
7331   if (reserved != 0)
7332     return STG_E_INVALIDPARAMETER;
7333
7334   return create_storagefile(pwcsName, grfMode, 0, &stgoptions, &IID_IStorage, (void**)ppstgOpen);
7335 }
7336
7337 /******************************************************************************
7338  *              StgCreateStorageEx        [OLE32.@]
7339  */
7340 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
7341 {
7342     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
7343           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
7344
7345     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
7346     {
7347         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
7348         return STG_E_INVALIDPARAMETER;  
7349     }
7350
7351     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
7352     {
7353         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
7354         return STG_E_INVALIDPARAMETER;  
7355     }
7356
7357     if (stgfmt == STGFMT_FILE)
7358     {
7359         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
7360         return STG_E_INVALIDPARAMETER;
7361     }
7362
7363     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
7364     {
7365         return create_storagefile(pwcsName, grfMode, grfAttrs, pStgOptions, riid, ppObjectOpen);
7366     }
7367
7368
7369     ERR("Invalid stgfmt argument\n");
7370     return STG_E_INVALIDPARAMETER;
7371 }
7372
7373 /******************************************************************************
7374  *              StgCreatePropSetStg       [OLE32.@]
7375  */
7376 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
7377  IPropertySetStorage **ppPropSetStg)
7378 {
7379     HRESULT hr;
7380
7381     TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
7382     if (reserved)
7383         hr = STG_E_INVALIDPARAMETER;
7384     else
7385         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
7386          (void**)ppPropSetStg);
7387     return hr;
7388 }
7389
7390 /******************************************************************************
7391  *              StgOpenStorageEx      [OLE32.@]
7392  */
7393 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
7394 {
7395     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
7396           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
7397
7398     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
7399     {
7400         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
7401         return STG_E_INVALIDPARAMETER;  
7402     }
7403
7404     switch (stgfmt)
7405     {
7406     case STGFMT_FILE:
7407         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
7408         return STG_E_INVALIDPARAMETER;
7409         
7410     case STGFMT_STORAGE:
7411         break;
7412
7413     case STGFMT_DOCFILE:
7414         if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
7415         {
7416             ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
7417             return STG_E_INVALIDPARAMETER;  
7418         }
7419         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
7420         break;
7421
7422     case STGFMT_ANY:
7423         WARN("STGFMT_ANY assuming storage\n");
7424         break;
7425
7426     default:
7427         return STG_E_INVALIDPARAMETER;
7428     }
7429
7430     return StgOpenStorage(pwcsName, NULL, grfMode, NULL, 0, (IStorage **)ppObjectOpen);
7431 }
7432
7433
7434 /******************************************************************************
7435  *              StgOpenStorage        [OLE32.@]
7436  */
7437 HRESULT WINAPI StgOpenStorage(
7438   const OLECHAR *pwcsName,
7439   IStorage      *pstgPriority,
7440   DWORD          grfMode,
7441   SNB            snbExclude,
7442   DWORD          reserved,
7443   IStorage     **ppstgOpen)
7444 {
7445   StorageBaseImpl* newStorage = 0;
7446   HRESULT        hr = S_OK;
7447   HANDLE         hFile = 0;
7448   DWORD          shareMode;
7449   DWORD          accessMode;
7450
7451   TRACE("(%s, %p, %x, %p, %d, %p)\n",
7452         debugstr_w(pwcsName), pstgPriority, grfMode,
7453         snbExclude, reserved, ppstgOpen);
7454
7455   if (pwcsName == 0)
7456   {
7457     hr = STG_E_INVALIDNAME;
7458     goto end;
7459   }
7460
7461   if (ppstgOpen == 0)
7462   {
7463     hr = STG_E_INVALIDPOINTER;
7464     goto end;
7465   }
7466
7467   if (reserved)
7468   {
7469     hr = STG_E_INVALIDPARAMETER;
7470     goto end;
7471   }
7472
7473   if (grfMode & STGM_PRIORITY)
7474   {
7475     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
7476       return STG_E_INVALIDFLAG;
7477     if (grfMode & STGM_DELETEONRELEASE)
7478       return STG_E_INVALIDFUNCTION;
7479     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
7480       return STG_E_INVALIDFLAG;
7481     grfMode &= ~0xf0; /* remove the existing sharing mode */
7482     grfMode |= STGM_SHARE_DENY_NONE;
7483
7484     /* STGM_PRIORITY stops other IStorage objects on the same file from
7485      * committing until the STGM_PRIORITY IStorage is closed. it also
7486      * stops non-transacted mode StgOpenStorage calls with write access from
7487      * succeeding. obviously, both of these cannot be achieved through just
7488      * file share flags */
7489     FIXME("STGM_PRIORITY mode not implemented correctly\n");
7490   }
7491
7492   /*
7493    * Validate the sharing mode
7494    */
7495   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
7496     switch(STGM_SHARE_MODE(grfMode))
7497     {
7498       case STGM_SHARE_EXCLUSIVE:
7499       case STGM_SHARE_DENY_WRITE:
7500         break;
7501       default:
7502         hr = STG_E_INVALIDFLAG;
7503         goto end;
7504     }
7505
7506   if ( FAILED( validateSTGM(grfMode) ) ||
7507        (grfMode&STGM_CREATE))
7508   {
7509     hr = STG_E_INVALIDFLAG;
7510     goto end;
7511   }
7512
7513   /* shared reading requires transacted mode */
7514   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
7515       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
7516      !(grfMode&STGM_TRANSACTED) )
7517   {
7518     hr = STG_E_INVALIDFLAG;
7519     goto end;
7520   }
7521
7522   /*
7523    * Interpret the STGM value grfMode
7524    */
7525   shareMode    = GetShareModeFromSTGM(grfMode);
7526   accessMode   = GetAccessModeFromSTGM(grfMode);
7527
7528   *ppstgOpen = 0;
7529
7530   hFile = CreateFileW( pwcsName,
7531                        accessMode,
7532                        shareMode,
7533                        NULL,
7534                        OPEN_EXISTING,
7535                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
7536                        0);
7537
7538   if (hFile==INVALID_HANDLE_VALUE)
7539   {
7540     DWORD last_error = GetLastError();
7541
7542     hr = E_FAIL;
7543
7544     switch (last_error)
7545     {
7546       case ERROR_FILE_NOT_FOUND:
7547         hr = STG_E_FILENOTFOUND;
7548         break;
7549
7550       case ERROR_PATH_NOT_FOUND:
7551         hr = STG_E_PATHNOTFOUND;
7552         break;
7553
7554       case ERROR_ACCESS_DENIED:
7555       case ERROR_WRITE_PROTECT:
7556         hr = STG_E_ACCESSDENIED;
7557         break;
7558
7559       case ERROR_SHARING_VIOLATION:
7560         hr = STG_E_SHAREVIOLATION;
7561         break;
7562
7563       default:
7564         hr = E_FAIL;
7565     }
7566
7567     goto end;
7568   }
7569
7570   /*
7571    * Refuse to open the file if it's too small to be a structured storage file
7572    * FIXME: verify the file when reading instead of here
7573    */
7574   if (GetFileSize(hFile, NULL) < 0x100)
7575   {
7576     CloseHandle(hFile);
7577     hr = STG_E_FILEALREADYEXISTS;
7578     goto end;
7579   }
7580
7581   /*
7582    * Allocate and initialize the new IStorage32object.
7583    */
7584   hr = Storage_Construct(
7585          hFile,
7586          pwcsName,
7587          NULL,
7588          grfMode,
7589          TRUE,
7590          FALSE,
7591          512,
7592          &newStorage);
7593
7594   if (FAILED(hr))
7595   {
7596     /*
7597      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
7598      */
7599     if(hr == STG_E_INVALIDHEADER)
7600         hr = STG_E_FILEALREADYEXISTS;
7601     goto end;
7602   }
7603
7604   /*
7605    * Get an "out" pointer for the caller.
7606    */
7607   *ppstgOpen = (IStorage*)newStorage;
7608
7609 end:
7610   TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
7611   return hr;
7612 }
7613
7614 /******************************************************************************
7615  *    StgCreateDocfileOnILockBytes    [OLE32.@]
7616  */
7617 HRESULT WINAPI StgCreateDocfileOnILockBytes(
7618       ILockBytes *plkbyt,
7619       DWORD grfMode,
7620       DWORD reserved,
7621       IStorage** ppstgOpen)
7622 {
7623   StorageBaseImpl* newStorage = 0;
7624   HRESULT        hr         = S_OK;
7625
7626   if ((ppstgOpen == 0) || (plkbyt == 0))
7627     return STG_E_INVALIDPOINTER;
7628
7629   /*
7630    * Allocate and initialize the new IStorage object.
7631    */
7632   hr = Storage_Construct(
7633          0,
7634         0,
7635          plkbyt,
7636          grfMode,
7637          FALSE,
7638          TRUE,
7639          512,
7640          &newStorage);
7641
7642   if (FAILED(hr))
7643   {
7644     return hr;
7645   }
7646
7647   /*
7648    * Get an "out" pointer for the caller.
7649    */
7650   *ppstgOpen = (IStorage*)newStorage;
7651
7652   return hr;
7653 }
7654
7655 /******************************************************************************
7656  *    StgOpenStorageOnILockBytes    [OLE32.@]
7657  */
7658 HRESULT WINAPI StgOpenStorageOnILockBytes(
7659       ILockBytes *plkbyt,
7660       IStorage *pstgPriority,
7661       DWORD grfMode,
7662       SNB snbExclude,
7663       DWORD reserved,
7664       IStorage **ppstgOpen)
7665 {
7666   StorageBaseImpl* newStorage = 0;
7667   HRESULT        hr = S_OK;
7668
7669   if ((plkbyt == 0) || (ppstgOpen == 0))
7670     return STG_E_INVALIDPOINTER;
7671
7672   if ( FAILED( validateSTGM(grfMode) ))
7673     return STG_E_INVALIDFLAG;
7674
7675   *ppstgOpen = 0;
7676
7677   /*
7678    * Allocate and initialize the new IStorage object.
7679    */
7680   hr = Storage_Construct(
7681          0,
7682          0,
7683          plkbyt,
7684          grfMode,
7685          FALSE,
7686          FALSE,
7687          512,
7688          &newStorage);
7689
7690   if (FAILED(hr))
7691   {
7692     return hr;
7693   }
7694
7695   /*
7696    * Get an "out" pointer for the caller.
7697    */
7698   *ppstgOpen = (IStorage*)newStorage;
7699
7700   return hr;
7701 }
7702
7703 /******************************************************************************
7704  *              StgSetTimes [ole32.@]
7705  *              StgSetTimes [OLE32.@]
7706  *
7707  *
7708  */
7709 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
7710                            FILETIME const *patime, FILETIME const *pmtime)
7711 {
7712   IStorage *stg = NULL;
7713   HRESULT r;
7714  
7715   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
7716
7717   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
7718                      0, 0, &stg);
7719   if( SUCCEEDED(r) )
7720   {
7721     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
7722     IStorage_Release(stg);
7723   }
7724
7725   return r;
7726 }
7727
7728 /******************************************************************************
7729  *              StgIsStorageILockBytes        [OLE32.@]
7730  *
7731  * Determines if the ILockBytes contains a storage object.
7732  */
7733 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
7734 {
7735   BYTE sig[8];
7736   ULARGE_INTEGER offset;
7737
7738   offset.u.HighPart = 0;
7739   offset.u.LowPart  = 0;
7740
7741   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
7742
7743   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
7744     return S_OK;
7745
7746   return S_FALSE;
7747 }
7748
7749 /******************************************************************************
7750  *              WriteClassStg        [OLE32.@]
7751  *
7752  * This method will store the specified CLSID in the specified storage object
7753  */
7754 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
7755 {
7756   HRESULT hRes;
7757
7758   if(!pStg)
7759     return E_INVALIDARG;
7760
7761   if(!rclsid)
7762     return STG_E_INVALIDPOINTER;
7763
7764   hRes = IStorage_SetClass(pStg, rclsid);
7765
7766   return hRes;
7767 }
7768
7769 /***********************************************************************
7770  *    ReadClassStg (OLE32.@)
7771  *
7772  * This method reads the CLSID previously written to a storage object with
7773  * the WriteClassStg.
7774  *
7775  * PARAMS
7776  *  pstg    [I] IStorage pointer
7777  *  pclsid  [O] Pointer to where the CLSID is written
7778  *
7779  * RETURNS
7780  *  Success: S_OK.
7781  *  Failure: HRESULT code.
7782  */
7783 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
7784
7785     STATSTG pstatstg;
7786     HRESULT hRes;
7787
7788     TRACE("(%p, %p)\n", pstg, pclsid);
7789
7790     if(!pstg || !pclsid)
7791         return E_INVALIDARG;
7792
7793    /*
7794     * read a STATSTG structure (contains the clsid) from the storage
7795     */
7796     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_NONAME);
7797
7798     if(SUCCEEDED(hRes))
7799         *pclsid=pstatstg.clsid;
7800
7801     return hRes;
7802 }
7803
7804 /***********************************************************************
7805  *    OleLoadFromStream (OLE32.@)
7806  *
7807  * This function loads an object from stream
7808  */
7809 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
7810 {
7811     CLSID       clsid;
7812     HRESULT     res;
7813     LPPERSISTSTREAM     xstm;
7814
7815     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
7816
7817     res=ReadClassStm(pStm,&clsid);
7818     if (FAILED(res))
7819         return res;
7820     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
7821     if (FAILED(res))
7822         return res;
7823     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
7824     if (FAILED(res)) {
7825         IUnknown_Release((IUnknown*)*ppvObj);
7826         return res;
7827     }
7828     res=IPersistStream_Load(xstm,pStm);
7829     IPersistStream_Release(xstm);
7830     /* FIXME: all refcounts ok at this point? I think they should be:
7831      *          pStm    : unchanged
7832      *          ppvObj  : 1
7833      *          xstm    : 0 (released)
7834      */
7835     return res;
7836 }
7837
7838 /***********************************************************************
7839  *    OleSaveToStream (OLE32.@)
7840  *
7841  * This function saves an object with the IPersistStream interface on it
7842  * to the specified stream.
7843  */
7844 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
7845 {
7846
7847     CLSID clsid;
7848     HRESULT res;
7849
7850     TRACE("(%p,%p)\n",pPStm,pStm);
7851
7852     res=IPersistStream_GetClassID(pPStm,&clsid);
7853
7854     if (SUCCEEDED(res)){
7855
7856         res=WriteClassStm(pStm,&clsid);
7857
7858         if (SUCCEEDED(res))
7859
7860             res=IPersistStream_Save(pPStm,pStm,TRUE);
7861     }
7862
7863     TRACE("Finished Save\n");
7864     return res;
7865 }
7866
7867 /****************************************************************************
7868  * This method validate a STGM parameter that can contain the values below
7869  *
7870  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
7871  * The stgm values contained in 0xffff0000 are bitmasks.
7872  *
7873  * STGM_DIRECT               0x00000000
7874  * STGM_TRANSACTED           0x00010000
7875  * STGM_SIMPLE               0x08000000
7876  *
7877  * STGM_READ                 0x00000000
7878  * STGM_WRITE                0x00000001
7879  * STGM_READWRITE            0x00000002
7880  *
7881  * STGM_SHARE_DENY_NONE      0x00000040
7882  * STGM_SHARE_DENY_READ      0x00000030
7883  * STGM_SHARE_DENY_WRITE     0x00000020
7884  * STGM_SHARE_EXCLUSIVE      0x00000010
7885  *
7886  * STGM_PRIORITY             0x00040000
7887  * STGM_DELETEONRELEASE      0x04000000
7888  *
7889  * STGM_CREATE               0x00001000
7890  * STGM_CONVERT              0x00020000
7891  * STGM_FAILIFTHERE          0x00000000
7892  *
7893  * STGM_NOSCRATCH            0x00100000
7894  * STGM_NOSNAPSHOT           0x00200000
7895  */
7896 static HRESULT validateSTGM(DWORD stgm)
7897 {
7898   DWORD access = STGM_ACCESS_MODE(stgm);
7899   DWORD share  = STGM_SHARE_MODE(stgm);
7900   DWORD create = STGM_CREATE_MODE(stgm);
7901
7902   if (stgm&~STGM_KNOWN_FLAGS)
7903   {
7904     ERR("unknown flags %08x\n", stgm);
7905     return E_FAIL;
7906   }
7907
7908   switch (access)
7909   {
7910   case STGM_READ:
7911   case STGM_WRITE:
7912   case STGM_READWRITE:
7913     break;
7914   default:
7915     return E_FAIL;
7916   }
7917
7918   switch (share)
7919   {
7920   case STGM_SHARE_DENY_NONE:
7921   case STGM_SHARE_DENY_READ:
7922   case STGM_SHARE_DENY_WRITE:
7923   case STGM_SHARE_EXCLUSIVE:
7924     break;
7925   default:
7926     return E_FAIL;
7927   }
7928
7929   switch (create)
7930   {
7931   case STGM_CREATE:
7932   case STGM_FAILIFTHERE:
7933     break;
7934   default:
7935     return E_FAIL;
7936   }
7937
7938   /*
7939    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
7940    */
7941   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
7942       return E_FAIL;
7943
7944   /*
7945    * STGM_CREATE | STGM_CONVERT
7946    * if both are false, STGM_FAILIFTHERE is set to TRUE
7947    */
7948   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
7949     return E_FAIL;
7950
7951   /*
7952    * STGM_NOSCRATCH requires STGM_TRANSACTED
7953    */
7954   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
7955     return E_FAIL;
7956
7957   /*
7958    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
7959    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
7960    */
7961   if ( (stgm & STGM_NOSNAPSHOT) &&
7962         (!(stgm & STGM_TRANSACTED) ||
7963          share == STGM_SHARE_EXCLUSIVE ||
7964          share == STGM_SHARE_DENY_WRITE) )
7965     return E_FAIL;
7966
7967   return S_OK;
7968 }
7969
7970 /****************************************************************************
7971  *      GetShareModeFromSTGM
7972  *
7973  * This method will return a share mode flag from a STGM value.
7974  * The STGM value is assumed valid.
7975  */
7976 static DWORD GetShareModeFromSTGM(DWORD stgm)
7977 {
7978   switch (STGM_SHARE_MODE(stgm))
7979   {
7980   case STGM_SHARE_DENY_NONE:
7981     return FILE_SHARE_READ | FILE_SHARE_WRITE;
7982   case STGM_SHARE_DENY_READ:
7983     return FILE_SHARE_WRITE;
7984   case STGM_SHARE_DENY_WRITE:
7985     return FILE_SHARE_READ;
7986   case STGM_SHARE_EXCLUSIVE:
7987     return 0;
7988   }
7989   ERR("Invalid share mode!\n");
7990   assert(0);
7991   return 0;
7992 }
7993
7994 /****************************************************************************
7995  *      GetAccessModeFromSTGM
7996  *
7997  * This method will return an access mode flag from a STGM value.
7998  * The STGM value is assumed valid.
7999  */
8000 static DWORD GetAccessModeFromSTGM(DWORD stgm)
8001 {
8002   switch (STGM_ACCESS_MODE(stgm))
8003   {
8004   case STGM_READ:
8005     return GENERIC_READ;
8006   case STGM_WRITE:
8007   case STGM_READWRITE:
8008     return GENERIC_READ | GENERIC_WRITE;
8009   }
8010   ERR("Invalid access mode!\n");
8011   assert(0);
8012   return 0;
8013 }
8014
8015 /****************************************************************************
8016  *      GetCreationModeFromSTGM
8017  *
8018  * This method will return a creation mode flag from a STGM value.
8019  * The STGM value is assumed valid.
8020  */
8021 static DWORD GetCreationModeFromSTGM(DWORD stgm)
8022 {
8023   switch(STGM_CREATE_MODE(stgm))
8024   {
8025   case STGM_CREATE:
8026     return CREATE_ALWAYS;
8027   case STGM_CONVERT:
8028     FIXME("STGM_CONVERT not implemented!\n");
8029     return CREATE_NEW;
8030   case STGM_FAILIFTHERE:
8031     return CREATE_NEW;
8032   }
8033   ERR("Invalid create mode!\n");
8034   assert(0);
8035   return 0;
8036 }
8037
8038
8039 /*************************************************************************
8040  * OLECONVERT_LoadOLE10 [Internal]
8041  *
8042  * Loads the OLE10 STREAM to memory
8043  *
8044  * PARAMS
8045  *     pOleStream   [I] The OLESTREAM
8046  *     pData        [I] Data Structure for the OLESTREAM Data
8047  *
8048  * RETURNS
8049  *     Success:  S_OK
8050  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
8051  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalid
8052  *
8053  * NOTES
8054  *     This function is used by OleConvertOLESTREAMToIStorage only.
8055  *
8056  *     Memory allocated for pData must be freed by the caller
8057  */
8058 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
8059 {
8060         DWORD dwSize;
8061         HRESULT hRes = S_OK;
8062         int nTryCnt=0;
8063         int max_try = 6;
8064
8065         pData->pData = NULL;
8066         pData->pstrOleObjFileName = NULL;
8067
8068         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
8069         {
8070         /* Get the OleID */
8071         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
8072         if(dwSize != sizeof(pData->dwOleID))
8073         {
8074                 hRes = CONVERT10_E_OLESTREAM_GET;
8075         }
8076         else if(pData->dwOleID != OLESTREAM_ID)
8077         {
8078                 hRes = CONVERT10_E_OLESTREAM_FMT;
8079         }
8080                 else
8081                 {
8082                         hRes = S_OK;
8083                         break;
8084                 }
8085         }
8086
8087         if(hRes == S_OK)
8088         {
8089                 /* Get the TypeID... more info needed for this field */
8090                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
8091                 if(dwSize != sizeof(pData->dwTypeID))
8092                 {
8093                         hRes = CONVERT10_E_OLESTREAM_GET;
8094                 }
8095         }
8096         if(hRes == S_OK)
8097         {
8098                 if(pData->dwTypeID != 0)
8099                 {
8100                         /* Get the length of the OleTypeName */
8101                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
8102                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
8103                         {
8104                                 hRes = CONVERT10_E_OLESTREAM_GET;
8105                         }
8106
8107                         if(hRes == S_OK)
8108                         {
8109                                 if(pData->dwOleTypeNameLength > 0)
8110                                 {
8111                                         /* Get the OleTypeName */
8112                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
8113                                         if(dwSize != pData->dwOleTypeNameLength)
8114                                         {
8115                                                 hRes = CONVERT10_E_OLESTREAM_GET;
8116                                         }
8117                                 }
8118                         }
8119                         if(bStrem1)
8120                         {
8121                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
8122                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
8123                                 {
8124                                         hRes = CONVERT10_E_OLESTREAM_GET;
8125                                 }
8126                         if(hRes == S_OK)
8127                         {
8128                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
8129                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
8130                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
8131                                         if(pData->pstrOleObjFileName)
8132                                         {
8133                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, pData->pstrOleObjFileName, pData->dwOleObjFileNameLength);
8134                                                 if(dwSize != pData->dwOleObjFileNameLength)
8135                                                 {
8136                                                         hRes = CONVERT10_E_OLESTREAM_GET;
8137                                                 }
8138                                         }
8139                                         else
8140                                                 hRes = CONVERT10_E_OLESTREAM_GET;
8141                                 }
8142                         }
8143                         else
8144                         {
8145                                 /* Get the Width of the Metafile */
8146                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
8147                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
8148                                 {
8149                                         hRes = CONVERT10_E_OLESTREAM_GET;
8150                                 }
8151                         if(hRes == S_OK)
8152                         {
8153                                 /* Get the Height of the Metafile */
8154                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
8155                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
8156                                 {
8157                                         hRes = CONVERT10_E_OLESTREAM_GET;
8158                                 }
8159                         }
8160                         }
8161                         if(hRes == S_OK)
8162                         {
8163                                 /* Get the Length of the Data */
8164                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
8165                                 if(dwSize != sizeof(pData->dwDataLength))
8166                                 {
8167                                         hRes = CONVERT10_E_OLESTREAM_GET;
8168                                 }
8169                         }
8170
8171                         if(hRes == S_OK) /* I don't know what this 8 byte information is. We have to figure out */
8172                         {
8173                                 if(!bStrem1) /* if it is a second OLE stream data */
8174                                 {
8175                                         pData->dwDataLength -= 8;
8176                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strUnknown, sizeof(pData->strUnknown));
8177                                         if(dwSize != sizeof(pData->strUnknown))
8178                                         {
8179                                                 hRes = CONVERT10_E_OLESTREAM_GET;
8180                                         }
8181                                 }
8182                         }
8183                         if(hRes == S_OK)
8184                         {
8185                                 if(pData->dwDataLength > 0)
8186                                 {
8187                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
8188
8189                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
8190                                         if(pData->pData)
8191                                         {
8192                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
8193                                                 if(dwSize != pData->dwDataLength)
8194                                                 {
8195                                                         hRes = CONVERT10_E_OLESTREAM_GET;
8196                                                 }
8197                                         }
8198                                         else
8199                                         {
8200                                                 hRes = CONVERT10_E_OLESTREAM_GET;
8201                                         }
8202                                 }
8203                         }
8204                 }
8205         }
8206         return hRes;
8207 }
8208
8209 /*************************************************************************
8210  * OLECONVERT_SaveOLE10 [Internal]
8211  *
8212  * Saves the OLE10 STREAM From memory
8213  *
8214  * PARAMS
8215  *     pData        [I] Data Structure for the OLESTREAM Data
8216  *     pOleStream   [I] The OLESTREAM to save
8217  *
8218  * RETURNS
8219  *     Success:  S_OK
8220  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
8221  *
8222  * NOTES
8223  *     This function is used by OleConvertIStorageToOLESTREAM only.
8224  *
8225  */
8226 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
8227 {
8228     DWORD dwSize;
8229     HRESULT hRes = S_OK;
8230
8231
8232    /* Set the OleID */
8233     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
8234     if(dwSize != sizeof(pData->dwOleID))
8235     {
8236         hRes = CONVERT10_E_OLESTREAM_PUT;
8237     }
8238
8239     if(hRes == S_OK)
8240     {
8241         /* Set the TypeID */
8242         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
8243         if(dwSize != sizeof(pData->dwTypeID))
8244         {
8245             hRes = CONVERT10_E_OLESTREAM_PUT;
8246         }
8247     }
8248
8249     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
8250     {
8251         /* Set the Length of the OleTypeName */
8252         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
8253         if(dwSize != sizeof(pData->dwOleTypeNameLength))
8254         {
8255             hRes = CONVERT10_E_OLESTREAM_PUT;
8256         }
8257
8258         if(hRes == S_OK)
8259         {
8260             if(pData->dwOleTypeNameLength > 0)
8261             {
8262                 /* Set the OleTypeName */
8263                 dwSize = pOleStream->lpstbl->Put(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
8264                 if(dwSize != pData->dwOleTypeNameLength)
8265                 {
8266                     hRes = CONVERT10_E_OLESTREAM_PUT;
8267                 }
8268             }
8269         }
8270
8271         if(hRes == S_OK)
8272         {
8273             /* Set the width of the Metafile */
8274             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
8275             if(dwSize != sizeof(pData->dwMetaFileWidth))
8276             {
8277                 hRes = CONVERT10_E_OLESTREAM_PUT;
8278             }
8279         }
8280
8281         if(hRes == S_OK)
8282         {
8283             /* Set the height of the Metafile */
8284             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
8285             if(dwSize != sizeof(pData->dwMetaFileHeight))
8286             {
8287                 hRes = CONVERT10_E_OLESTREAM_PUT;
8288             }
8289         }
8290
8291         if(hRes == S_OK)
8292         {
8293             /* Set the length of the Data */
8294             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
8295             if(dwSize != sizeof(pData->dwDataLength))
8296             {
8297                 hRes = CONVERT10_E_OLESTREAM_PUT;
8298             }
8299         }
8300
8301         if(hRes == S_OK)
8302         {
8303             if(pData->dwDataLength > 0)
8304             {
8305                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
8306                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
8307                 if(dwSize != pData->dwDataLength)
8308                 {
8309                     hRes = CONVERT10_E_OLESTREAM_PUT;
8310                 }
8311             }
8312         }
8313     }
8314     return hRes;
8315 }
8316
8317 /*************************************************************************
8318  * OLECONVERT_GetOLE20FromOLE10[Internal]
8319  *
8320  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
8321  * opens it, and copies the content to the dest IStorage for
8322  * OleConvertOLESTREAMToIStorage
8323  *
8324  *
8325  * PARAMS
8326  *     pDestStorage  [I] The IStorage to copy the data to
8327  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
8328  *     nBufferLength [I] The size of the buffer
8329  *
8330  * RETURNS
8331  *     Nothing
8332  *
8333  * NOTES
8334  *
8335  *
8336  */
8337 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBuffer, DWORD nBufferLength)
8338 {
8339     HRESULT hRes;
8340     HANDLE hFile;
8341     IStorage *pTempStorage;
8342     DWORD dwNumOfBytesWritten;
8343     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
8344     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
8345
8346     /* Create a temp File */
8347     GetTempPathW(MAX_PATH, wstrTempDir);
8348     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
8349     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
8350
8351     if(hFile != INVALID_HANDLE_VALUE)
8352     {
8353         /* Write IStorage Data to File */
8354         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
8355         CloseHandle(hFile);
8356
8357         /* Open and copy temp storage to the Dest Storage */
8358         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
8359         if(hRes == S_OK)
8360         {
8361             hRes = IStorage_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
8362             IStorage_Release(pTempStorage);
8363         }
8364         DeleteFileW(wstrTempFile);
8365     }
8366 }
8367
8368
8369 /*************************************************************************
8370  * OLECONVERT_WriteOLE20ToBuffer [Internal]
8371  *
8372  * Saves the OLE10 STREAM From memory
8373  *
8374  * PARAMS
8375  *     pStorage  [I] The Src IStorage to copy
8376  *     pData     [I] The Dest Memory to write to.
8377  *
8378  * RETURNS
8379  *     The size in bytes allocated for pData
8380  *
8381  * NOTES
8382  *     Memory allocated for pData must be freed by the caller
8383  *
8384  *     Used by OleConvertIStorageToOLESTREAM only.
8385  *
8386  */
8387 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
8388 {
8389     HANDLE hFile;
8390     HRESULT hRes;
8391     DWORD nDataLength = 0;
8392     IStorage *pTempStorage;
8393     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
8394     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
8395
8396     *pData = NULL;
8397
8398     /* Create temp Storage */
8399     GetTempPathW(MAX_PATH, wstrTempDir);
8400     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
8401     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
8402
8403     if(hRes == S_OK)
8404     {
8405         /* Copy Src Storage to the Temp Storage */
8406         IStorage_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
8407         IStorage_Release(pTempStorage);
8408
8409         /* Open Temp Storage as a file and copy to memory */
8410         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
8411         if(hFile != INVALID_HANDLE_VALUE)
8412         {
8413             nDataLength = GetFileSize(hFile, NULL);
8414             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
8415             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
8416             CloseHandle(hFile);
8417         }
8418         DeleteFileW(wstrTempFile);
8419     }
8420     return nDataLength;
8421 }
8422
8423 /*************************************************************************
8424  * OLECONVERT_CreateOleStream [Internal]
8425  *
8426  * Creates the "\001OLE" stream in the IStorage if necessary.
8427  *
8428  * PARAMS
8429  *     pStorage     [I] Dest storage to create the stream in
8430  *
8431  * RETURNS
8432  *     Nothing
8433  *
8434  * NOTES
8435  *     This function is used by OleConvertOLESTREAMToIStorage only.
8436  *
8437  *     This stream is still unknown, MS Word seems to have extra data
8438  *     but since the data is stored in the OLESTREAM there should be
8439  *     no need to recreate the stream.  If the stream is manually
8440  *     deleted it will create it with this default data.
8441  *
8442  */
8443 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
8444 {
8445     HRESULT hRes;
8446     IStream *pStream;
8447     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
8448     BYTE pOleStreamHeader [] =
8449     {
8450         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
8451         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8452         0x00, 0x00, 0x00, 0x00
8453     };
8454
8455     /* Create stream if not present */
8456     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
8457         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
8458
8459     if(hRes == S_OK)
8460     {
8461         /* Write default Data */
8462         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
8463         IStream_Release(pStream);
8464     }
8465 }
8466
8467 /* write a string to a stream, preceded by its length */
8468 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
8469 {
8470     HRESULT r;
8471     LPSTR str;
8472     DWORD len = 0;
8473
8474     if( string )
8475         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
8476     r = IStream_Write( stm, &len, sizeof(len), NULL);
8477     if( FAILED( r ) )
8478         return r;
8479     if(len == 0)
8480         return r;
8481     str = CoTaskMemAlloc( len );
8482     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
8483     r = IStream_Write( stm, str, len, NULL);
8484     CoTaskMemFree( str );
8485     return r;
8486 }
8487
8488 /* read a string preceded by its length from a stream */
8489 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
8490 {
8491     HRESULT r;
8492     DWORD len, count = 0;
8493     LPSTR str;
8494     LPWSTR wstr;
8495
8496     r = IStream_Read( stm, &len, sizeof(len), &count );
8497     if( FAILED( r ) )
8498         return r;
8499     if( count != sizeof(len) )
8500         return E_OUTOFMEMORY;
8501
8502     TRACE("%d bytes\n",len);
8503     
8504     str = CoTaskMemAlloc( len );
8505     if( !str )
8506         return E_OUTOFMEMORY;
8507     count = 0;
8508     r = IStream_Read( stm, str, len, &count );
8509     if( FAILED( r ) )
8510         return r;
8511     if( count != len )
8512     {
8513         CoTaskMemFree( str );
8514         return E_OUTOFMEMORY;
8515     }
8516
8517     TRACE("Read string %s\n",debugstr_an(str,len));
8518
8519     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
8520     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
8521     if( wstr )
8522          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
8523     CoTaskMemFree( str );
8524
8525     *string = wstr;
8526
8527     return r;
8528 }
8529
8530
8531 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
8532     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
8533 {
8534     IStream *pstm;
8535     HRESULT r = S_OK;
8536     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
8537
8538     static const BYTE unknown1[12] =
8539        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
8540          0xFF, 0xFF, 0xFF, 0xFF};
8541     static const BYTE unknown2[16] =
8542        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
8543          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
8544
8545     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
8546            debugstr_w(lpszUserType), debugstr_w(szClipName),
8547            debugstr_w(szProgIDName));
8548
8549     /*  Create a CompObj stream */
8550     r = IStorage_CreateStream(pstg, szwStreamName,
8551         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
8552     if( FAILED (r) )
8553         return r;
8554
8555     /* Write CompObj Structure to stream */
8556     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
8557
8558     if( SUCCEEDED( r ) )
8559         r = WriteClassStm( pstm, clsid );
8560
8561     if( SUCCEEDED( r ) )
8562         r = STREAM_WriteString( pstm, lpszUserType );
8563     if( SUCCEEDED( r ) )
8564         r = STREAM_WriteString( pstm, szClipName );
8565     if( SUCCEEDED( r ) )
8566         r = STREAM_WriteString( pstm, szProgIDName );
8567     if( SUCCEEDED( r ) )
8568         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
8569
8570     IStream_Release( pstm );
8571
8572     return r;
8573 }
8574
8575 /***********************************************************************
8576  *               WriteFmtUserTypeStg (OLE32.@)
8577  */
8578 HRESULT WINAPI WriteFmtUserTypeStg(
8579           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
8580 {
8581     HRESULT r;
8582     WCHAR szwClipName[0x40];
8583     CLSID clsid = CLSID_NULL;
8584     LPWSTR wstrProgID = NULL;
8585     DWORD n;
8586
8587     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
8588
8589     /* get the clipboard format name */
8590     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName)/sizeof(szwClipName[0]) );
8591     szwClipName[n]=0;
8592
8593     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
8594
8595     /* FIXME: There's room to save a CLSID and its ProgID, but
8596        the CLSID is not looked up in the registry and in all the
8597        tests I wrote it was CLSID_NULL.  Where does it come from?
8598     */
8599
8600     /* get the real program ID.  This may fail, but that's fine */
8601     ProgIDFromCLSID(&clsid, &wstrProgID);
8602
8603     TRACE("progid is %s\n",debugstr_w(wstrProgID));
8604
8605     r = STORAGE_WriteCompObj( pstg, &clsid, 
8606                               lpszUserType, szwClipName, wstrProgID );
8607
8608     CoTaskMemFree(wstrProgID);
8609
8610     return r;
8611 }
8612
8613
8614 /******************************************************************************
8615  *              ReadFmtUserTypeStg        [OLE32.@]
8616  */
8617 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
8618 {
8619     HRESULT r;
8620     IStream *stm = 0;
8621     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
8622     unsigned char unknown1[12];
8623     unsigned char unknown2[16];
8624     DWORD count;
8625     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
8626     CLSID clsid;
8627
8628     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
8629
8630     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
8631                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
8632     if( FAILED ( r ) )
8633     {
8634         WARN("Failed to open stream r = %08x\n", r);
8635         return r;
8636     }
8637
8638     /* read the various parts of the structure */
8639     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
8640     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
8641         goto end;
8642     r = ReadClassStm( stm, &clsid );
8643     if( FAILED( r ) )
8644         goto end;
8645
8646     r = STREAM_ReadString( stm, &szCLSIDName );
8647     if( FAILED( r ) )
8648         goto end;
8649
8650     r = STREAM_ReadString( stm, &szOleTypeName );
8651     if( FAILED( r ) )
8652         goto end;
8653
8654     r = STREAM_ReadString( stm, &szProgIDName );
8655     if( FAILED( r ) )
8656         goto end;
8657
8658     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
8659     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
8660         goto end;
8661
8662     /* ok, success... now we just need to store what we found */
8663     if( pcf )
8664         *pcf = RegisterClipboardFormatW( szOleTypeName );
8665     CoTaskMemFree( szOleTypeName );
8666
8667     if( lplpszUserType )
8668         *lplpszUserType = szCLSIDName;
8669     CoTaskMemFree( szProgIDName );
8670
8671 end:
8672     IStream_Release( stm );
8673
8674     return r;
8675 }
8676
8677
8678 /*************************************************************************
8679  * OLECONVERT_CreateCompObjStream [Internal]
8680  *
8681  * Creates a "\001CompObj" is the destination IStorage if necessary.
8682  *
8683  * PARAMS
8684  *     pStorage       [I] The dest IStorage to create the CompObj Stream
8685  *                        if necessary.
8686  *     strOleTypeName [I] The ProgID
8687  *
8688  * RETURNS
8689  *     Success:  S_OK
8690  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
8691  *
8692  * NOTES
8693  *     This function is used by OleConvertOLESTREAMToIStorage only.
8694  *
8695  *     The stream data is stored in the OLESTREAM and there should be
8696  *     no need to recreate the stream.  If the stream is manually
8697  *     deleted it will attempt to create it by querying the registry.
8698  *
8699  *
8700  */
8701 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
8702 {
8703     IStream *pStream;
8704     HRESULT hStorageRes, hRes = S_OK;
8705     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
8706     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
8707     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
8708
8709     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
8710     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
8711
8712     /* Initialize the CompObj structure */
8713     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
8714     memcpy(IStorageCompObj.byUnknown1, pCompObjUnknown1, sizeof(pCompObjUnknown1));
8715     memcpy(IStorageCompObj.byUnknown2, pCompObjUnknown2, sizeof(pCompObjUnknown2));
8716
8717
8718     /*  Create a CompObj stream if it doesn't exist */
8719     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
8720         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
8721     if(hStorageRes == S_OK)
8722     {
8723         /* copy the OleTypeName to the compobj struct */
8724         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
8725         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
8726
8727         /* copy the OleTypeName to the compobj struct */
8728         /* Note: in the test made, these were Identical      */
8729         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
8730         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
8731
8732         /* Get the CLSID */
8733         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
8734                              bufferW, OLESTREAM_MAX_STR_LEN );
8735         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
8736
8737         if(hRes == S_OK)
8738         {
8739             HKEY hKey;
8740             LONG hErr;
8741             /* Get the CLSID Default Name from the Registry */
8742             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
8743             if(hErr == ERROR_SUCCESS)
8744             {
8745                 char strTemp[OLESTREAM_MAX_STR_LEN];
8746                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
8747                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
8748                 if(hErr == ERROR_SUCCESS)
8749                 {
8750                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
8751                 }
8752                 RegCloseKey(hKey);
8753             }
8754         }
8755
8756         /* Write CompObj Structure to stream */
8757         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
8758
8759         WriteClassStm(pStream,&(IStorageCompObj.clsid));
8760
8761         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
8762         if(IStorageCompObj.dwCLSIDNameLength > 0)
8763         {
8764             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
8765         }
8766         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
8767         if(IStorageCompObj.dwOleTypeNameLength > 0)
8768         {
8769             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
8770         }
8771         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
8772         if(IStorageCompObj.dwProgIDNameLength > 0)
8773         {
8774             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
8775         }
8776         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
8777         IStream_Release(pStream);
8778     }
8779     return hRes;
8780 }
8781
8782
8783 /*************************************************************************
8784  * OLECONVERT_CreateOlePresStream[Internal]
8785  *
8786  * Creates the "\002OlePres000" Stream with the Metafile data
8787  *
8788  * PARAMS
8789  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
8790  *     dwExtentX    [I] Width of the Metafile
8791  *     dwExtentY    [I] Height of the Metafile
8792  *     pData        [I] Metafile data
8793  *     dwDataLength [I] Size of the Metafile data
8794  *
8795  * RETURNS
8796  *     Success:  S_OK
8797  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
8798  *
8799  * NOTES
8800  *     This function is used by OleConvertOLESTREAMToIStorage only.
8801  *
8802  */
8803 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
8804 {
8805     HRESULT hRes;
8806     IStream *pStream;
8807     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
8808     BYTE pOlePresStreamHeader [] =
8809     {
8810         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
8811         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
8812         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
8813         0x00, 0x00, 0x00, 0x00
8814     };
8815
8816     BYTE pOlePresStreamHeaderEmpty [] =
8817     {
8818         0x00, 0x00, 0x00, 0x00,
8819         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
8820         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
8821         0x00, 0x00, 0x00, 0x00
8822     };
8823
8824     /* Create the OlePres000 Stream */
8825     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
8826         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
8827
8828     if(hRes == S_OK)
8829     {
8830         DWORD nHeaderSize;
8831         OLECONVERT_ISTORAGE_OLEPRES OlePres;
8832
8833         memset(&OlePres, 0, sizeof(OlePres));
8834         /* Do we have any metafile data to save */
8835         if(dwDataLength > 0)
8836         {
8837             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
8838             nHeaderSize = sizeof(pOlePresStreamHeader);
8839         }
8840         else
8841         {
8842             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
8843             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
8844         }
8845         /* Set width and height of the metafile */
8846         OlePres.dwExtentX = dwExtentX;
8847         OlePres.dwExtentY = -dwExtentY;
8848
8849         /* Set Data and Length */
8850         if(dwDataLength > sizeof(METAFILEPICT16))
8851         {
8852             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
8853             OlePres.pData = &(pData[8]);
8854         }
8855         /* Save OlePres000 Data to Stream */
8856         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
8857         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
8858         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
8859         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
8860         if(OlePres.dwSize > 0)
8861         {
8862             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
8863         }
8864         IStream_Release(pStream);
8865     }
8866 }
8867
8868 /*************************************************************************
8869  * OLECONVERT_CreateOle10NativeStream [Internal]
8870  *
8871  * Creates the "\001Ole10Native" Stream (should contain a BMP)
8872  *
8873  * PARAMS
8874  *     pStorage     [I] Dest storage to create the stream in
8875  *     pData        [I] Ole10 Native Data (ex. bmp)
8876  *     dwDataLength [I] Size of the Ole10 Native Data
8877  *
8878  * RETURNS
8879  *     Nothing
8880  *
8881  * NOTES
8882  *     This function is used by OleConvertOLESTREAMToIStorage only.
8883  *
8884  *     Might need to verify the data and return appropriate error message
8885  *
8886  */
8887 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
8888 {
8889     HRESULT hRes;
8890     IStream *pStream;
8891     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
8892
8893     /* Create the Ole10Native Stream */
8894     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
8895         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
8896
8897     if(hRes == S_OK)
8898     {
8899         /* Write info to stream */
8900         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
8901         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
8902         IStream_Release(pStream);
8903     }
8904
8905 }
8906
8907 /*************************************************************************
8908  * OLECONVERT_GetOLE10ProgID [Internal]
8909  *
8910  * Finds the ProgID (or OleTypeID) from the IStorage
8911  *
8912  * PARAMS
8913  *     pStorage        [I] The Src IStorage to get the ProgID
8914  *     strProgID       [I] the ProgID string to get
8915  *     dwSize          [I] the size of the string
8916  *
8917  * RETURNS
8918  *     Success:  S_OK
8919  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
8920  *
8921  * NOTES
8922  *     This function is used by OleConvertIStorageToOLESTREAM only.
8923  *
8924  *
8925  */
8926 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
8927 {
8928     HRESULT hRes;
8929     IStream *pStream;
8930     LARGE_INTEGER iSeekPos;
8931     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
8932     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
8933
8934     /* Open the CompObj Stream */
8935     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
8936         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
8937     if(hRes == S_OK)
8938     {
8939
8940         /*Get the OleType from the CompObj Stream */
8941         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
8942         iSeekPos.u.HighPart = 0;
8943
8944         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
8945         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
8946         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
8947         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
8948         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
8949         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
8950         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
8951
8952         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
8953         if(*dwSize > 0)
8954         {
8955             IStream_Read(pStream, strProgID, *dwSize, NULL);
8956         }
8957         IStream_Release(pStream);
8958     }
8959     else
8960     {
8961         STATSTG stat;
8962         LPOLESTR wstrProgID;
8963
8964         /* Get the OleType from the registry */
8965         REFCLSID clsid = &(stat.clsid);
8966         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
8967         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
8968         if(hRes == S_OK)
8969         {
8970             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
8971         }
8972
8973     }
8974     return hRes;
8975 }
8976
8977 /*************************************************************************
8978  * OLECONVERT_GetOle10PresData [Internal]
8979  *
8980  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
8981  *
8982  * PARAMS
8983  *     pStorage     [I] Src IStroage
8984  *     pOleStream   [I] Dest OleStream Mem Struct
8985  *
8986  * RETURNS
8987  *     Nothing
8988  *
8989  * NOTES
8990  *     This function is used by OleConvertIStorageToOLESTREAM only.
8991  *
8992  *     Memory allocated for pData must be freed by the caller
8993  *
8994  *
8995  */
8996 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
8997 {
8998
8999     HRESULT hRes;
9000     IStream *pStream;
9001     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
9002
9003     /* Initialize Default data for OLESTREAM */
9004     pOleStreamData[0].dwOleID = OLESTREAM_ID;
9005     pOleStreamData[0].dwTypeID = 2;
9006     pOleStreamData[1].dwOleID = OLESTREAM_ID;
9007     pOleStreamData[1].dwTypeID = 0;
9008     pOleStreamData[0].dwMetaFileWidth = 0;
9009     pOleStreamData[0].dwMetaFileHeight = 0;
9010     pOleStreamData[0].pData = NULL;
9011     pOleStreamData[1].pData = NULL;
9012
9013     /* Open Ole10Native Stream */
9014     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
9015         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
9016     if(hRes == S_OK)
9017     {
9018
9019         /* Read Size and Data */
9020         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
9021         if(pOleStreamData->dwDataLength > 0)
9022         {
9023             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
9024             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
9025         }
9026         IStream_Release(pStream);
9027     }
9028
9029 }
9030
9031
9032 /*************************************************************************
9033  * OLECONVERT_GetOle20PresData[Internal]
9034  *
9035  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
9036  *
9037  * PARAMS
9038  *     pStorage         [I] Src IStroage
9039  *     pOleStreamData   [I] Dest OleStream Mem Struct
9040  *
9041  * RETURNS
9042  *     Nothing
9043  *
9044  * NOTES
9045  *     This function is used by OleConvertIStorageToOLESTREAM only.
9046  *
9047  *     Memory allocated for pData must be freed by the caller
9048  */
9049 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
9050 {
9051     HRESULT hRes;
9052     IStream *pStream;
9053     OLECONVERT_ISTORAGE_OLEPRES olePress;
9054     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
9055
9056     /* Initialize Default data for OLESTREAM */
9057     pOleStreamData[0].dwOleID = OLESTREAM_ID;
9058     pOleStreamData[0].dwTypeID = 2;
9059     pOleStreamData[0].dwMetaFileWidth = 0;
9060     pOleStreamData[0].dwMetaFileHeight = 0;
9061     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
9062     pOleStreamData[1].dwOleID = OLESTREAM_ID;
9063     pOleStreamData[1].dwTypeID = 0;
9064     pOleStreamData[1].dwOleTypeNameLength = 0;
9065     pOleStreamData[1].strOleTypeName[0] = 0;
9066     pOleStreamData[1].dwMetaFileWidth = 0;
9067     pOleStreamData[1].dwMetaFileHeight = 0;
9068     pOleStreamData[1].pData = NULL;
9069     pOleStreamData[1].dwDataLength = 0;
9070
9071
9072     /* Open OlePress000 stream */
9073     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
9074         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
9075     if(hRes == S_OK)
9076     {
9077         LARGE_INTEGER iSeekPos;
9078         METAFILEPICT16 MetaFilePict;
9079         static const char strMetafilePictName[] = "METAFILEPICT";
9080
9081         /* Set the TypeID for a Metafile */
9082         pOleStreamData[1].dwTypeID = 5;
9083
9084         /* Set the OleTypeName to Metafile */
9085         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
9086         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
9087
9088         iSeekPos.u.HighPart = 0;
9089         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
9090
9091         /* Get Presentation Data */
9092         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
9093         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
9094         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
9095         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
9096
9097         /*Set width and Height */
9098         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
9099         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
9100         if(olePress.dwSize > 0)
9101         {
9102             /* Set Length */
9103             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
9104
9105             /* Set MetaFilePict struct */
9106             MetaFilePict.mm = 8;
9107             MetaFilePict.xExt = olePress.dwExtentX;
9108             MetaFilePict.yExt = olePress.dwExtentY;
9109             MetaFilePict.hMF = 0;
9110
9111             /* Get Metafile Data */
9112             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
9113             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
9114             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
9115         }
9116         IStream_Release(pStream);
9117     }
9118 }
9119
9120 /*************************************************************************
9121  * OleConvertOLESTREAMToIStorage [OLE32.@]
9122  *
9123  * Read info on MSDN
9124  *
9125  * TODO
9126  *      DVTARGETDEVICE parameter is not handled
9127  *      Still unsure of some mem fields for OLE 10 Stream
9128  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
9129  *      and "\001OLE" streams
9130  *
9131  */
9132 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
9133     LPOLESTREAM pOleStream,
9134     LPSTORAGE pstg,
9135     const DVTARGETDEVICE* ptd)
9136 {
9137     int i;
9138     HRESULT hRes=S_OK;
9139     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
9140
9141     TRACE("%p %p %p\n", pOleStream, pstg, ptd);
9142
9143     memset(pOleStreamData, 0, sizeof(pOleStreamData));
9144
9145     if(ptd != NULL)
9146     {
9147         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
9148     }
9149
9150     if(pstg == NULL || pOleStream == NULL)
9151     {
9152         hRes = E_INVALIDARG;
9153     }
9154
9155     if(hRes == S_OK)
9156     {
9157         /* Load the OLESTREAM to Memory */
9158         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
9159     }
9160
9161     if(hRes == S_OK)
9162     {
9163         /* Load the OLESTREAM to Memory (part 2)*/
9164         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
9165     }
9166
9167     if(hRes == S_OK)
9168     {
9169
9170         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
9171         {
9172             /* Do we have the IStorage Data in the OLESTREAM */
9173             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
9174             {
9175                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
9176                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
9177             }
9178             else
9179             {
9180                 /* It must be an original OLE 1.0 source */
9181                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
9182             }
9183         }
9184         else
9185         {
9186             /* It must be an original OLE 1.0 source */
9187             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
9188         }
9189
9190         /* Create CompObj Stream if necessary */
9191         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
9192         if(hRes == S_OK)
9193         {
9194             /*Create the Ole Stream if necessary */
9195             OLECONVERT_CreateOleStream(pstg);
9196         }
9197     }
9198
9199
9200     /* Free allocated memory */
9201     for(i=0; i < 2; i++)
9202     {
9203         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
9204         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
9205         pOleStreamData[i].pstrOleObjFileName = NULL;
9206     }
9207     return hRes;
9208 }
9209
9210 /*************************************************************************
9211  * OleConvertIStorageToOLESTREAM [OLE32.@]
9212  *
9213  * Read info on MSDN
9214  *
9215  * Read info on MSDN
9216  *
9217  * TODO
9218  *      Still unsure of some mem fields for OLE 10 Stream
9219  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
9220  *      and "\001OLE" streams.
9221  *
9222  */
9223 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
9224     LPSTORAGE pstg,
9225     LPOLESTREAM pOleStream)
9226 {
9227     int i;
9228     HRESULT hRes = S_OK;
9229     IStream *pStream;
9230     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
9231     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
9232
9233     TRACE("%p %p\n", pstg, pOleStream);
9234
9235     memset(pOleStreamData, 0, sizeof(pOleStreamData));
9236
9237     if(pstg == NULL || pOleStream == NULL)
9238     {
9239         hRes = E_INVALIDARG;
9240     }
9241     if(hRes == S_OK)
9242     {
9243         /* Get the ProgID */
9244         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
9245         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
9246     }
9247     if(hRes == S_OK)
9248     {
9249         /* Was it originally Ole10 */
9250         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
9251         if(hRes == S_OK)
9252         {
9253             IStream_Release(pStream);
9254             /* Get Presentation Data for Ole10Native */
9255             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
9256         }
9257         else
9258         {
9259             /* Get Presentation Data (OLE20) */
9260             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
9261         }
9262
9263         /* Save OLESTREAM */
9264         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
9265         if(hRes == S_OK)
9266         {
9267             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
9268         }
9269
9270     }
9271
9272     /* Free allocated memory */
9273     for(i=0; i < 2; i++)
9274     {
9275         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
9276     }
9277
9278     return hRes;
9279 }
9280
9281 /***********************************************************************
9282  *              GetConvertStg (OLE32.@)
9283  */
9284 HRESULT WINAPI GetConvertStg(IStorage *stg) {
9285     FIXME("unimplemented stub!\n");
9286     return E_FAIL;
9287 }
9288
9289 /******************************************************************************
9290  * StgIsStorageFile [OLE32.@]
9291  * Verify if the file contains a storage object
9292  *
9293  * PARAMS
9294  *  fn      [ I] Filename
9295  *
9296  * RETURNS
9297  *  S_OK    if file has magic bytes as a storage object
9298  *  S_FALSE if file is not storage
9299  */
9300 HRESULT WINAPI
9301 StgIsStorageFile(LPCOLESTR fn)
9302 {
9303         HANDLE          hf;
9304         BYTE            magic[8];
9305         DWORD           bytes_read;
9306
9307         TRACE("%s\n", debugstr_w(fn));
9308         hf = CreateFileW(fn, GENERIC_READ,
9309                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
9310                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
9311
9312         if (hf == INVALID_HANDLE_VALUE)
9313                 return STG_E_FILENOTFOUND;
9314
9315         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
9316         {
9317                 WARN(" unable to read file\n");
9318                 CloseHandle(hf);
9319                 return S_FALSE;
9320         }
9321
9322         CloseHandle(hf);
9323
9324         if (bytes_read != 8) {
9325                 TRACE(" too short\n");
9326                 return S_FALSE;
9327         }
9328
9329         if (!memcmp(magic,STORAGE_magic,8)) {
9330                 TRACE(" -> YES\n");
9331                 return S_OK;
9332         }
9333
9334         TRACE(" -> Invalid header.\n");
9335         return S_FALSE;
9336 }
9337
9338 /***********************************************************************
9339  *              WriteClassStm (OLE32.@)
9340  *
9341  * Writes a CLSID to a stream.
9342  *
9343  * PARAMS
9344  *  pStm   [I] Stream to write to.
9345  *  rclsid [I] CLSID to write.
9346  *
9347  * RETURNS
9348  *  Success: S_OK.
9349  *  Failure: HRESULT code.
9350  */
9351 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
9352 {
9353     TRACE("(%p,%p)\n",pStm,rclsid);
9354
9355     if (!pStm || !rclsid)
9356         return E_INVALIDARG;
9357
9358     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
9359 }
9360
9361 /***********************************************************************
9362  *              ReadClassStm (OLE32.@)
9363  *
9364  * Reads a CLSID from a stream.
9365  *
9366  * PARAMS
9367  *  pStm   [I] Stream to read from.
9368  *  rclsid [O] CLSID to read.
9369  *
9370  * RETURNS
9371  *  Success: S_OK.
9372  *  Failure: HRESULT code.
9373  */
9374 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
9375 {
9376     ULONG nbByte;
9377     HRESULT res;
9378
9379     TRACE("(%p,%p)\n",pStm,pclsid);
9380
9381     if (!pStm || !pclsid)
9382         return E_INVALIDARG;
9383
9384     /* clear the output args */
9385     *pclsid = CLSID_NULL;
9386
9387     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
9388
9389     if (FAILED(res))
9390         return res;
9391
9392     if (nbByte != sizeof(CLSID))
9393         return STG_E_READFAULT;
9394     else
9395         return S_OK;
9396 }