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