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