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