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