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