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