user32: Reimplement 16-bit clipboard functions on top of the 32-bit ones.
[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_ACCESSDENIED;
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   /* Can't create a stream on read-only storage */
868   if ( STGM_ACCESS_MODE( This->openFlags ) == STGM_READ )
869     return STG_E_ACCESSDENIED;
870
871   /*
872    * Check that we're compatible with the parent's storage mode
873    * if not in transacted mode
874    */
875   if(!(This->openFlags & STGM_TRANSACTED)) {
876     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
877       return STG_E_ACCESSDENIED;
878   }
879
880   if(This->openFlags & STGM_SIMPLE)
881     if(grfMode & STGM_CREATE) return STG_E_INVALIDFLAG;
882
883   *ppstm = 0;
884
885   currentEntryRef = findElement(This,
886                                    This->storageDirEntry,
887                                    pwcsName,
888                                    &currentEntry);
889
890   if (currentEntryRef != DIRENTRY_NULL)
891   {
892     /*
893      * An element with this name already exists
894      */
895     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
896     {
897       IStorage_DestroyElement(iface, pwcsName);
898     }
899     else
900       return STG_E_FILEALREADYEXISTS;
901   }
902   else if (STGM_ACCESS_MODE(This->openFlags) == STGM_READ)
903   {
904     WARN("read-only storage\n");
905     return STG_E_ACCESSDENIED;
906   }
907
908   /*
909    * memset the empty entry
910    */
911   memset(&newStreamEntry, 0, sizeof(DirEntry));
912
913   newStreamEntry.sizeOfNameString =
914       ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
915
916   if (newStreamEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN)
917     return STG_E_INVALIDNAME;
918
919   strcpyW(newStreamEntry.name, pwcsName);
920
921   newStreamEntry.stgType       = STGTY_STREAM;
922   newStreamEntry.startingBlock = BLOCK_END_OF_CHAIN;
923   newStreamEntry.size.u.LowPart  = 0;
924   newStreamEntry.size.u.HighPart = 0;
925
926   newStreamEntry.leftChild        = DIRENTRY_NULL;
927   newStreamEntry.rightChild       = DIRENTRY_NULL;
928   newStreamEntry.dirRootEntry     = DIRENTRY_NULL;
929
930   /* call CoFileTime to get the current time
931   newStreamEntry.ctime
932   newStreamEntry.mtime
933   */
934
935   /*  newStreamEntry.clsid */
936
937   /*
938    * Create an entry with the new data
939    */
940   StorageBaseImpl_CreateDirEntry(This, &newStreamEntry, &newStreamEntryRef);
941   /*
942    * Insert the new entry in the parent storage's tree.
943    */
944   insertIntoTree(
945     This,
946     This->storageDirEntry,
947     newStreamEntryRef);
948
949   /*
950    * Open the stream to return it.
951    */
952   newStream = StgStreamImpl_Construct(This, grfMode, newStreamEntryRef);
953
954   if (newStream != 0)
955   {
956     *ppstm = (IStream*)newStream;
957
958     IStream_AddRef(*ppstm);
959   }
960   else
961   {
962     return STG_E_INSUFFICIENTMEMORY;
963   }
964
965   return S_OK;
966 }
967
968 /************************************************************************
969  * Storage32BaseImpl_SetClass (IStorage)
970  *
971  * This method will write the specified CLSID in the directory entry of this
972  * storage.
973  *
974  * See Windows documentation for more details on IStorage methods.
975  */
976 static HRESULT WINAPI StorageBaseImpl_SetClass(
977   IStorage*        iface,
978   REFCLSID         clsid) /* [in] */
979 {
980   StorageBaseImpl *This = (StorageBaseImpl *)iface;
981   HRESULT hRes;
982   DirEntry currentEntry;
983
984   TRACE("(%p, %p)\n", iface, clsid);
985
986   if (This->reverted)
987     return STG_E_REVERTED;
988
989   hRes = StorageBaseImpl_ReadDirEntry(This,
990                                       This->storageDirEntry,
991                                       &currentEntry);
992   if (SUCCEEDED(hRes))
993   {
994     currentEntry.clsid = *clsid;
995
996     hRes = StorageBaseImpl_WriteDirEntry(This,
997                                          This->storageDirEntry,
998                                          &currentEntry);
999   }
1000
1001   return hRes;
1002 }
1003
1004 /************************************************************************
1005 ** Storage32Impl implementation
1006 */
1007
1008 /************************************************************************
1009  * Storage32BaseImpl_CreateStorage (IStorage)
1010  *
1011  * This method will create the storage object within the provided storage.
1012  *
1013  * See Windows documentation for more details on IStorage methods.
1014  */
1015 static HRESULT WINAPI StorageBaseImpl_CreateStorage(
1016   IStorage*      iface,
1017   const OLECHAR  *pwcsName, /* [string][in] */
1018   DWORD            grfMode,   /* [in] */
1019   DWORD            reserved1, /* [in] */
1020   DWORD            reserved2, /* [in] */
1021   IStorage       **ppstg)   /* [out] */
1022 {
1023   StorageBaseImpl* const This=(StorageBaseImpl*)iface;
1024
1025   DirEntry         currentEntry;
1026   DirEntry         newEntry;
1027   DirRef           currentEntryRef;
1028   DirRef           newEntryRef;
1029   HRESULT          hr;
1030
1031   TRACE("(%p, %s, %x, %d, %d, %p)\n",
1032         iface, debugstr_w(pwcsName), grfMode,
1033         reserved1, reserved2, ppstg);
1034
1035   if (ppstg == 0)
1036     return STG_E_INVALIDPOINTER;
1037
1038   if (This->openFlags & STGM_SIMPLE)
1039   {
1040     return STG_E_INVALIDFUNCTION;
1041   }
1042
1043   if (pwcsName == 0)
1044     return STG_E_INVALIDNAME;
1045
1046   *ppstg = NULL;
1047
1048   if ( FAILED( validateSTGM(grfMode) ) ||
1049        (grfMode & STGM_DELETEONRELEASE) )
1050   {
1051     WARN("bad grfMode: 0x%x\n", grfMode);
1052     return STG_E_INVALIDFLAG;
1053   }
1054
1055   if (This->reverted)
1056     return STG_E_REVERTED;
1057
1058   /*
1059    * Check that we're compatible with the parent's storage mode
1060    */
1061   if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
1062   {
1063     WARN("access denied\n");
1064     return STG_E_ACCESSDENIED;
1065   }
1066
1067   currentEntryRef = findElement(This,
1068                                    This->storageDirEntry,
1069                                    pwcsName,
1070                                    &currentEntry);
1071
1072   if (currentEntryRef != DIRENTRY_NULL)
1073   {
1074     /*
1075      * An element with this name already exists
1076      */
1077     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE &&
1078         STGM_ACCESS_MODE(This->openFlags) != STGM_READ)
1079     {
1080       hr = IStorage_DestroyElement(iface, pwcsName);
1081       if (FAILED(hr))
1082         return hr;
1083     }
1084     else
1085     {
1086       WARN("file already exists\n");
1087       return STG_E_FILEALREADYEXISTS;
1088     }
1089   }
1090   else if (STGM_ACCESS_MODE(This->openFlags) == STGM_READ)
1091   {
1092     WARN("read-only storage\n");
1093     return STG_E_ACCESSDENIED;
1094   }
1095
1096   memset(&newEntry, 0, sizeof(DirEntry));
1097
1098   newEntry.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
1099
1100   if (newEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN)
1101   {
1102     FIXME("name too long\n");
1103     return STG_E_INVALIDNAME;
1104   }
1105
1106   strcpyW(newEntry.name, pwcsName);
1107
1108   newEntry.stgType       = STGTY_STORAGE;
1109   newEntry.startingBlock = BLOCK_END_OF_CHAIN;
1110   newEntry.size.u.LowPart  = 0;
1111   newEntry.size.u.HighPart = 0;
1112
1113   newEntry.leftChild        = DIRENTRY_NULL;
1114   newEntry.rightChild       = DIRENTRY_NULL;
1115   newEntry.dirRootEntry     = DIRENTRY_NULL;
1116
1117   /* call CoFileTime to get the current time
1118   newEntry.ctime
1119   newEntry.mtime
1120   */
1121
1122   /*  newEntry.clsid */
1123
1124   /*
1125    * Create a new directory entry for the storage
1126    */
1127   StorageBaseImpl_CreateDirEntry(This, &newEntry, &newEntryRef);
1128
1129   /*
1130    * Insert the new directory entry into the parent storage's tree
1131    */
1132   insertIntoTree(
1133     This,
1134     This->storageDirEntry,
1135     newEntryRef);
1136
1137   /*
1138    * Open it to get a pointer to return.
1139    */
1140   hr = IStorage_OpenStorage(iface, pwcsName, 0, grfMode, 0, 0, ppstg);
1141
1142   if( (hr != S_OK) || (*ppstg == NULL))
1143   {
1144     return hr;
1145   }
1146
1147
1148   return S_OK;
1149 }
1150
1151
1152 /***************************************************************************
1153  *
1154  * Internal Method
1155  *
1156  * Reserve a directory entry in the file and initialize it.
1157  */
1158 static HRESULT StorageImpl_CreateDirEntry(
1159   StorageBaseImpl *base,
1160   const DirEntry *newData,
1161   DirRef *index)
1162 {
1163   StorageImpl *storage = (StorageImpl*)base;
1164   ULONG       currentEntryIndex    = 0;
1165   ULONG       newEntryIndex        = DIRENTRY_NULL;
1166   HRESULT hr = S_OK;
1167   BYTE currentData[RAW_DIRENTRY_SIZE];
1168   WORD sizeOfNameString;
1169
1170   do
1171   {
1172     hr = StorageImpl_ReadRawDirEntry(storage,
1173                                      currentEntryIndex,
1174                                      currentData);
1175
1176     if (SUCCEEDED(hr))
1177     {
1178       StorageUtl_ReadWord(
1179         currentData,
1180         OFFSET_PS_NAMELENGTH,
1181         &sizeOfNameString);
1182
1183       if (sizeOfNameString == 0)
1184       {
1185         /*
1186          * The entry exists and is available, we found it.
1187          */
1188         newEntryIndex = currentEntryIndex;
1189       }
1190     }
1191     else
1192     {
1193       /*
1194        * We exhausted the directory entries, we will create more space below
1195        */
1196       newEntryIndex = currentEntryIndex;
1197     }
1198     currentEntryIndex++;
1199
1200   } while (newEntryIndex == DIRENTRY_NULL);
1201
1202   /*
1203    * grow the directory stream
1204    */
1205   if (FAILED(hr))
1206   {
1207     BYTE           emptyData[RAW_DIRENTRY_SIZE];
1208     ULARGE_INTEGER newSize;
1209     ULONG          entryIndex;
1210     ULONG          lastEntry     = 0;
1211     ULONG          blockCount    = 0;
1212
1213     /*
1214      * obtain the new count of blocks in the directory stream
1215      */
1216     blockCount = BlockChainStream_GetCount(
1217                    storage->rootBlockChain)+1;
1218
1219     /*
1220      * initialize the size used by the directory stream
1221      */
1222     newSize.u.HighPart = 0;
1223     newSize.u.LowPart  = storage->bigBlockSize * blockCount;
1224
1225     /*
1226      * add a block to the directory stream
1227      */
1228     BlockChainStream_SetSize(storage->rootBlockChain, newSize);
1229
1230     /*
1231      * memset the empty entry in order to initialize the unused newly
1232      * created entries
1233      */
1234     memset(&emptyData, 0, RAW_DIRENTRY_SIZE);
1235
1236     /*
1237      * initialize them
1238      */
1239     lastEntry = storage->bigBlockSize / RAW_DIRENTRY_SIZE * blockCount;
1240
1241     for(
1242       entryIndex = newEntryIndex + 1;
1243       entryIndex < lastEntry;
1244       entryIndex++)
1245     {
1246       StorageImpl_WriteRawDirEntry(
1247         storage,
1248         entryIndex,
1249         emptyData);
1250     }
1251   }
1252
1253   UpdateRawDirEntry(currentData, newData);
1254
1255   hr = StorageImpl_WriteRawDirEntry(storage, newEntryIndex, currentData);
1256
1257   if (SUCCEEDED(hr))
1258     *index = newEntryIndex;
1259
1260   return hr;
1261 }
1262
1263 /***************************************************************************
1264  *
1265  * Internal Method
1266  *
1267  * Mark a directory entry in the file as free.
1268  */
1269 static HRESULT StorageImpl_DestroyDirEntry(
1270   StorageBaseImpl *base,
1271   DirRef index)
1272 {
1273   HRESULT hr;
1274   BYTE emptyData[RAW_DIRENTRY_SIZE];
1275   StorageImpl *storage = (StorageImpl*)base;
1276
1277   memset(&emptyData, 0, RAW_DIRENTRY_SIZE);
1278
1279   hr = StorageImpl_WriteRawDirEntry(storage, index, emptyData);
1280
1281   return hr;
1282 }
1283
1284
1285 /***************************************************************************
1286  *
1287  * Internal Method
1288  *
1289  * Destroy an entry, its attached data, and all entries reachable from it.
1290  */
1291 static HRESULT DestroyReachableEntries(
1292   StorageBaseImpl *base,
1293   DirRef index)
1294 {
1295   HRESULT hr = S_OK;
1296   DirEntry data;
1297   ULARGE_INTEGER zero;
1298
1299   zero.QuadPart = 0;
1300
1301   if (index != DIRENTRY_NULL)
1302   {
1303     hr = StorageBaseImpl_ReadDirEntry(base, index, &data);
1304
1305     if (SUCCEEDED(hr))
1306       hr = DestroyReachableEntries(base, data.dirRootEntry);
1307
1308     if (SUCCEEDED(hr))
1309       hr = DestroyReachableEntries(base, data.leftChild);
1310
1311     if (SUCCEEDED(hr))
1312       hr = DestroyReachableEntries(base, data.rightChild);
1313
1314     if (SUCCEEDED(hr))
1315       hr = StorageBaseImpl_StreamSetSize(base, index, zero);
1316
1317     if (SUCCEEDED(hr))
1318       hr = StorageBaseImpl_DestroyDirEntry(base, index);
1319   }
1320
1321   return hr;
1322 }
1323
1324
1325 /****************************************************************************
1326  *
1327  * Internal Method
1328  *
1329  * Case insensitive comparison of DirEntry.name by first considering
1330  * their size.
1331  *
1332  * Returns <0 when name1 < name2
1333  *         >0 when name1 > name2
1334  *          0 when name1 == name2
1335  */
1336 static LONG entryNameCmp(
1337     const OLECHAR *name1,
1338     const OLECHAR *name2)
1339 {
1340   LONG diff      = lstrlenW(name1) - lstrlenW(name2);
1341
1342   while (diff == 0 && *name1 != 0)
1343   {
1344     /*
1345      * We compare the string themselves only when they are of the same length
1346      */
1347     diff = toupperW(*name1++) - toupperW(*name2++);
1348   }
1349
1350   return diff;
1351 }
1352
1353 /****************************************************************************
1354  *
1355  * Internal Method
1356  *
1357  * Add a directory entry to a storage
1358  */
1359 static HRESULT insertIntoTree(
1360   StorageBaseImpl *This,
1361   DirRef        parentStorageIndex,
1362   DirRef        newEntryIndex)
1363 {
1364   DirEntry currentEntry;
1365   DirEntry newEntry;
1366
1367   /*
1368    * Read the inserted entry
1369    */
1370   StorageBaseImpl_ReadDirEntry(This,
1371                                newEntryIndex,
1372                                &newEntry);
1373
1374   /*
1375    * Read the storage entry
1376    */
1377   StorageBaseImpl_ReadDirEntry(This,
1378                                parentStorageIndex,
1379                                &currentEntry);
1380
1381   if (currentEntry.dirRootEntry != DIRENTRY_NULL)
1382   {
1383     /*
1384      * The root storage contains some element, therefore, start the research
1385      * for the appropriate location.
1386      */
1387     BOOL found = 0;
1388     DirRef current, next, previous, currentEntryId;
1389
1390     /*
1391      * Keep a reference to the root of the storage's element tree
1392      */
1393     currentEntryId = currentEntry.dirRootEntry;
1394
1395     /*
1396      * Read
1397      */
1398     StorageBaseImpl_ReadDirEntry(This,
1399                                  currentEntry.dirRootEntry,
1400                                  &currentEntry);
1401
1402     previous = currentEntry.leftChild;
1403     next     = currentEntry.rightChild;
1404     current  = currentEntryId;
1405
1406     while (found == 0)
1407     {
1408       LONG diff = entryNameCmp( newEntry.name, currentEntry.name);
1409
1410       if (diff < 0)
1411       {
1412         if (previous != DIRENTRY_NULL)
1413         {
1414           StorageBaseImpl_ReadDirEntry(This,
1415                                        previous,
1416                                        &currentEntry);
1417           current = previous;
1418         }
1419         else
1420         {
1421           currentEntry.leftChild = newEntryIndex;
1422           StorageBaseImpl_WriteDirEntry(This,
1423                                         current,
1424                                         &currentEntry);
1425           found = 1;
1426         }
1427       }
1428       else if (diff > 0)
1429       {
1430         if (next != DIRENTRY_NULL)
1431         {
1432           StorageBaseImpl_ReadDirEntry(This,
1433                                        next,
1434                                        &currentEntry);
1435           current = next;
1436         }
1437         else
1438         {
1439           currentEntry.rightChild = newEntryIndex;
1440           StorageBaseImpl_WriteDirEntry(This,
1441                                         current,
1442                                         &currentEntry);
1443           found = 1;
1444         }
1445       }
1446       else
1447       {
1448         /*
1449          * Trying to insert an item with the same name in the
1450          * subtree structure.
1451          */
1452         return STG_E_FILEALREADYEXISTS;
1453       }
1454
1455       previous = currentEntry.leftChild;
1456       next     = currentEntry.rightChild;
1457     }
1458   }
1459   else
1460   {
1461     /*
1462      * The storage is empty, make the new entry the root of its element tree
1463      */
1464     currentEntry.dirRootEntry = newEntryIndex;
1465     StorageBaseImpl_WriteDirEntry(This,
1466                                   parentStorageIndex,
1467                                   &currentEntry);
1468   }
1469
1470   return S_OK;
1471 }
1472
1473 /****************************************************************************
1474  *
1475  * Internal Method
1476  *
1477  * Find and read the element of a storage with the given name.
1478  */
1479 static DirRef findElement(StorageBaseImpl *storage, DirRef storageEntry,
1480     const OLECHAR *name, DirEntry *data)
1481 {
1482   DirRef currentEntry;
1483
1484   /* Read the storage entry to find the root of the tree. */
1485   StorageBaseImpl_ReadDirEntry(storage, storageEntry, data);
1486
1487   currentEntry = data->dirRootEntry;
1488
1489   while (currentEntry != DIRENTRY_NULL)
1490   {
1491     LONG cmp;
1492
1493     StorageBaseImpl_ReadDirEntry(storage, currentEntry, data);
1494
1495     cmp = entryNameCmp(name, data->name);
1496
1497     if (cmp == 0)
1498       /* found it */
1499       break;
1500
1501     else if (cmp < 0)
1502       currentEntry = data->leftChild;
1503
1504     else if (cmp > 0)
1505       currentEntry = data->rightChild;
1506   }
1507
1508   return currentEntry;
1509 }
1510
1511 /****************************************************************************
1512  *
1513  * Internal Method
1514  *
1515  * Find and read the binary tree parent of the element with the given name.
1516  *
1517  * If there is no such element, find a place where it could be inserted and
1518  * return STG_E_FILENOTFOUND.
1519  */
1520 static HRESULT findTreeParent(StorageBaseImpl *storage, DirRef storageEntry,
1521     const OLECHAR *childName, DirEntry *parentData, DirRef *parentEntry,
1522     ULONG *relation)
1523 {
1524   DirRef childEntry;
1525   DirEntry childData;
1526
1527   /* Read the storage entry to find the root of the tree. */
1528   StorageBaseImpl_ReadDirEntry(storage, storageEntry, parentData);
1529
1530   *parentEntry = storageEntry;
1531   *relation = DIRENTRY_RELATION_DIR;
1532
1533   childEntry = parentData->dirRootEntry;
1534
1535   while (childEntry != DIRENTRY_NULL)
1536   {
1537     LONG cmp;
1538
1539     StorageBaseImpl_ReadDirEntry(storage, childEntry, &childData);
1540
1541     cmp = entryNameCmp(childName, childData.name);
1542
1543     if (cmp == 0)
1544       /* found it */
1545       break;
1546
1547     else if (cmp < 0)
1548     {
1549       *parentData = childData;
1550       *parentEntry = childEntry;
1551       *relation = DIRENTRY_RELATION_PREVIOUS;
1552
1553       childEntry = parentData->leftChild;
1554     }
1555
1556     else if (cmp > 0)
1557     {
1558       *parentData = childData;
1559       *parentEntry = childEntry;
1560       *relation = DIRENTRY_RELATION_NEXT;
1561
1562       childEntry = parentData->rightChild;
1563     }
1564   }
1565
1566   if (childEntry == DIRENTRY_NULL)
1567     return STG_E_FILENOTFOUND;
1568   else
1569     return S_OK;
1570 }
1571
1572
1573 /*************************************************************************
1574  * CopyTo (IStorage)
1575  */
1576 static HRESULT WINAPI StorageBaseImpl_CopyTo(
1577   IStorage*   iface,
1578   DWORD       ciidExclude,  /* [in] */
1579   const IID*  rgiidExclude, /* [size_is][unique][in] */
1580   SNB         snbExclude,   /* [unique][in] */
1581   IStorage*   pstgDest)     /* [unique][in] */
1582 {
1583   IEnumSTATSTG *elements     = 0;
1584   STATSTG      curElement, strStat;
1585   HRESULT      hr;
1586   IStorage     *pstgTmp, *pstgChild;
1587   IStream      *pstrTmp, *pstrChild;
1588   BOOL         skip = FALSE, skip_storage = FALSE, skip_stream = FALSE;
1589   int          i;
1590
1591   TRACE("(%p, %d, %p, %p, %p)\n",
1592         iface, ciidExclude, rgiidExclude,
1593         snbExclude, pstgDest);
1594
1595   if ( pstgDest == 0 )
1596     return STG_E_INVALIDPOINTER;
1597
1598   /*
1599    * Enumerate the elements
1600    */
1601   hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
1602
1603   if ( hr != S_OK )
1604     return hr;
1605
1606   /*
1607    * set the class ID
1608    */
1609   IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
1610   IStorage_SetClass( pstgDest, &curElement.clsid );
1611
1612   for(i = 0; i < ciidExclude; ++i)
1613   {
1614     if(IsEqualGUID(&IID_IStorage, &rgiidExclude[i]))
1615         skip_storage = TRUE;
1616     else if(IsEqualGUID(&IID_IStream, &rgiidExclude[i]))
1617         skip_stream = TRUE;
1618     else
1619         WARN("Unknown excluded GUID: %s\n", debugstr_guid(&rgiidExclude[i]));
1620   }
1621
1622   do
1623   {
1624     /*
1625      * Obtain the next element
1626      */
1627     hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
1628
1629     if ( hr == S_FALSE )
1630     {
1631       hr = S_OK;   /* done, every element has been copied */
1632       break;
1633     }
1634
1635     if ( snbExclude )
1636     {
1637       WCHAR **snb = snbExclude;
1638       skip = FALSE;
1639       while ( *snb != NULL && !skip )
1640       {
1641         if ( lstrcmpW(curElement.pwcsName, *snb) == 0 )
1642           skip = TRUE;
1643         ++snb;
1644       }
1645     }
1646
1647     if ( skip )
1648       goto cleanup;
1649
1650     if (curElement.type == STGTY_STORAGE)
1651     {
1652       if(skip_storage)
1653         goto cleanup;
1654
1655       /*
1656        * open child source storage
1657        */
1658       hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
1659                                  STGM_READ|STGM_SHARE_EXCLUSIVE,
1660                                  NULL, 0, &pstgChild );
1661
1662       if (hr != S_OK)
1663         goto cleanup;
1664
1665       /*
1666        * create a new storage in destination storage
1667        */
1668       hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
1669                                    STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1670                                    0, 0,
1671                                    &pstgTmp );
1672       /*
1673        * if it already exist, don't create a new one use this one
1674        */
1675       if (hr == STG_E_FILEALREADYEXISTS)
1676       {
1677         hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
1678                                    STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1679                                    NULL, 0, &pstgTmp );
1680       }
1681
1682       if (hr == S_OK)
1683       {
1684         /*
1685          * do the copy recursively
1686          */
1687         hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
1688                                  NULL, pstgTmp );
1689
1690         IStorage_Release( pstgTmp );
1691       }
1692
1693       IStorage_Release( pstgChild );
1694     }
1695     else if (curElement.type == STGTY_STREAM)
1696     {
1697       if(skip_stream)
1698         goto cleanup;
1699
1700       /*
1701        * create a new stream in destination storage. If the stream already
1702        * exist, it will be deleted and a new one will be created.
1703        */
1704       hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
1705                                   STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1706                                   0, 0, &pstrTmp );
1707
1708       if (hr != S_OK)
1709         goto cleanup;
1710
1711       /*
1712        * open child stream storage
1713        */
1714       hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
1715                                 STGM_READ|STGM_SHARE_EXCLUSIVE,
1716                                 0, &pstrChild );
1717
1718       if (hr == S_OK)
1719       {
1720         /*
1721          * Get the size of the source stream
1722          */
1723         IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1724
1725         /*
1726          * Set the size of the destination stream.
1727          */
1728         IStream_SetSize(pstrTmp, strStat.cbSize);
1729
1730         /*
1731          * do the copy
1732          */
1733         hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1734                              NULL, NULL );
1735
1736         IStream_Release( pstrChild );
1737       }
1738
1739       IStream_Release( pstrTmp );
1740     }
1741     else
1742     {
1743       WARN("unknown element type: %d\n", curElement.type);
1744     }
1745
1746 cleanup:
1747     CoTaskMemFree(curElement.pwcsName);
1748   } while (hr == S_OK);
1749
1750   /*
1751    * Clean-up
1752    */
1753   IEnumSTATSTG_Release(elements);
1754
1755   return hr;
1756 }
1757
1758 /*************************************************************************
1759  * MoveElementTo (IStorage)
1760  */
1761 static HRESULT WINAPI StorageBaseImpl_MoveElementTo(
1762   IStorage*     iface,
1763   const OLECHAR *pwcsName,   /* [string][in] */
1764   IStorage      *pstgDest,   /* [unique][in] */
1765   const OLECHAR *pwcsNewName,/* [string][in] */
1766   DWORD           grfFlags)    /* [in] */
1767 {
1768   FIXME("(%p %s %p %s %u): stub\n", iface,
1769          debugstr_w(pwcsName), pstgDest,
1770          debugstr_w(pwcsNewName), grfFlags);
1771   return E_NOTIMPL;
1772 }
1773
1774 /*************************************************************************
1775  * Commit (IStorage)
1776  *
1777  * Ensures that any changes made to a storage object open in transacted mode
1778  * are reflected in the parent storage
1779  *
1780  * NOTES
1781  *  Wine doesn't implement transacted mode, which seems to be a basic
1782  *  optimization, so we can ignore this stub for now.
1783  */
1784 static HRESULT WINAPI StorageImpl_Commit(
1785   IStorage*   iface,
1786   DWORD         grfCommitFlags)/* [in] */
1787 {
1788   FIXME("(%p %d): stub\n", iface, grfCommitFlags);
1789   return S_OK;
1790 }
1791
1792 /*************************************************************************
1793  * Revert (IStorage)
1794  *
1795  * Discard all changes that have been made since the last commit operation
1796  */
1797 static HRESULT WINAPI StorageImpl_Revert(
1798   IStorage* iface)
1799 {
1800   FIXME("(%p): stub\n", iface);
1801   return E_NOTIMPL;
1802 }
1803
1804 /*************************************************************************
1805  * DestroyElement (IStorage)
1806  *
1807  * Strategy: This implementation is built this way for simplicity not for speed.
1808  *          I always delete the topmost element of the enumeration and adjust
1809  *          the deleted element pointer all the time.  This takes longer to
1810  *          do but allow to reinvoke DestroyElement whenever we encounter a
1811  *          storage object.  The optimisation resides in the usage of another
1812  *          enumeration strategy that would give all the leaves of a storage
1813  *          first. (postfix order)
1814  */
1815 static HRESULT WINAPI StorageBaseImpl_DestroyElement(
1816   IStorage*     iface,
1817   const OLECHAR *pwcsName)/* [string][in] */
1818 {
1819   StorageBaseImpl* const This=(StorageBaseImpl*)iface;
1820
1821   HRESULT           hr = S_OK;
1822   DirEntry          entryToDelete;
1823   DirRef            entryToDeleteRef;
1824
1825   TRACE("(%p, %s)\n",
1826         iface, debugstr_w(pwcsName));
1827
1828   if (pwcsName==NULL)
1829     return STG_E_INVALIDPOINTER;
1830
1831   if (This->reverted)
1832     return STG_E_REVERTED;
1833
1834   if ( 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   if (grfMode & STGM_TRANSACTED)
6359     FIXME("Transacted mode not implemented.\n");
6360
6361   *ppstgOpen = 0;
6362
6363   hFile = CreateFileW(pwcsName,
6364                         accessMode,
6365                         shareMode,
6366                         NULL,
6367                         creationMode,
6368                         fileAttributes,
6369                         0);
6370
6371   if (hFile == INVALID_HANDLE_VALUE)
6372   {
6373     if(GetLastError() == ERROR_FILE_EXISTS)
6374       hr = STG_E_FILEALREADYEXISTS;
6375     else
6376       hr = E_FAIL;
6377     goto end;
6378   }
6379
6380   /*
6381    * Allocate and initialize the new IStorage32object.
6382    */
6383   hr = Storage_Construct(
6384          hFile,
6385         pwcsName,
6386          NULL,
6387          grfMode,
6388          TRUE,
6389          TRUE,
6390          &newStorage);
6391
6392   if (FAILED(hr))
6393   {
6394     goto end;
6395   }
6396
6397   /*
6398    * Get an "out" pointer for the caller.
6399    */
6400   *ppstgOpen = (IStorage*)newStorage;
6401
6402 end:
6403   TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
6404
6405   return hr;
6406 }
6407
6408 /******************************************************************************
6409  *              StgCreateStorageEx        [OLE32.@]
6410  */
6411 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
6412 {
6413     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
6414           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
6415
6416     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
6417     {
6418         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
6419         return STG_E_INVALIDPARAMETER;  
6420     }
6421
6422     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
6423     {
6424         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
6425         return STG_E_INVALIDPARAMETER;  
6426     }
6427
6428     if (stgfmt == STGFMT_FILE)
6429     {
6430         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
6431         return STG_E_INVALIDPARAMETER;
6432     }
6433
6434     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
6435     {
6436         FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
6437         return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); 
6438     }
6439
6440     ERR("Invalid stgfmt argument\n");
6441     return STG_E_INVALIDPARAMETER;
6442 }
6443
6444 /******************************************************************************
6445  *              StgCreatePropSetStg       [OLE32.@]
6446  */
6447 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
6448  IPropertySetStorage **ppPropSetStg)
6449 {
6450     HRESULT hr;
6451
6452     TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
6453     if (reserved)
6454         hr = STG_E_INVALIDPARAMETER;
6455     else
6456         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
6457          (void**)ppPropSetStg);
6458     return hr;
6459 }
6460
6461 /******************************************************************************
6462  *              StgOpenStorageEx      [OLE32.@]
6463  */
6464 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
6465 {
6466     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
6467           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
6468
6469     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
6470     {
6471         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
6472         return STG_E_INVALIDPARAMETER;  
6473     }
6474
6475     switch (stgfmt)
6476     {
6477     case STGFMT_FILE:
6478         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
6479         return STG_E_INVALIDPARAMETER;
6480         
6481     case STGFMT_STORAGE:
6482         break;
6483
6484     case STGFMT_DOCFILE:
6485         if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
6486         {
6487             ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
6488             return STG_E_INVALIDPARAMETER;  
6489         }
6490         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
6491         break;
6492
6493     case STGFMT_ANY:
6494         WARN("STGFMT_ANY assuming storage\n");
6495         break;
6496
6497     default:
6498         return STG_E_INVALIDPARAMETER;
6499     }
6500
6501     return StgOpenStorage(pwcsName, NULL, grfMode, NULL, 0, (IStorage **)ppObjectOpen);
6502 }
6503
6504
6505 /******************************************************************************
6506  *              StgOpenStorage        [OLE32.@]
6507  */
6508 HRESULT WINAPI StgOpenStorage(
6509   const OLECHAR *pwcsName,
6510   IStorage      *pstgPriority,
6511   DWORD          grfMode,
6512   SNB            snbExclude,
6513   DWORD          reserved,
6514   IStorage     **ppstgOpen)
6515 {
6516   StorageBaseImpl* newStorage = 0;
6517   HRESULT        hr = S_OK;
6518   HANDLE         hFile = 0;
6519   DWORD          shareMode;
6520   DWORD          accessMode;
6521
6522   TRACE("(%s, %p, %x, %p, %d, %p)\n",
6523         debugstr_w(pwcsName), pstgPriority, grfMode,
6524         snbExclude, reserved, ppstgOpen);
6525
6526   if (pwcsName == 0)
6527   {
6528     hr = STG_E_INVALIDNAME;
6529     goto end;
6530   }
6531
6532   if (ppstgOpen == 0)
6533   {
6534     hr = STG_E_INVALIDPOINTER;
6535     goto end;
6536   }
6537
6538   if (reserved)
6539   {
6540     hr = STG_E_INVALIDPARAMETER;
6541     goto end;
6542   }
6543
6544   if (grfMode & STGM_PRIORITY)
6545   {
6546     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
6547       return STG_E_INVALIDFLAG;
6548     if (grfMode & STGM_DELETEONRELEASE)
6549       return STG_E_INVALIDFUNCTION;
6550     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
6551       return STG_E_INVALIDFLAG;
6552     grfMode &= ~0xf0; /* remove the existing sharing mode */
6553     grfMode |= STGM_SHARE_DENY_NONE;
6554
6555     /* STGM_PRIORITY stops other IStorage objects on the same file from
6556      * committing until the STGM_PRIORITY IStorage is closed. it also
6557      * stops non-transacted mode StgOpenStorage calls with write access from
6558      * succeeding. obviously, both of these cannot be achieved through just
6559      * file share flags */
6560     FIXME("STGM_PRIORITY mode not implemented correctly\n");
6561   }
6562
6563   /*
6564    * Validate the sharing mode
6565    */
6566   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
6567     switch(STGM_SHARE_MODE(grfMode))
6568     {
6569       case STGM_SHARE_EXCLUSIVE:
6570       case STGM_SHARE_DENY_WRITE:
6571         break;
6572       default:
6573         hr = STG_E_INVALIDFLAG;
6574         goto end;
6575     }
6576
6577   if ( FAILED( validateSTGM(grfMode) ) ||
6578        (grfMode&STGM_CREATE))
6579   {
6580     hr = STG_E_INVALIDFLAG;
6581     goto end;
6582   }
6583
6584   /* shared reading requires transacted mode */
6585   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
6586       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
6587      !(grfMode&STGM_TRANSACTED) )
6588   {
6589     hr = STG_E_INVALIDFLAG;
6590     goto end;
6591   }
6592
6593   /*
6594    * Interpret the STGM value grfMode
6595    */
6596   shareMode    = GetShareModeFromSTGM(grfMode);
6597   accessMode   = GetAccessModeFromSTGM(grfMode);
6598
6599   *ppstgOpen = 0;
6600
6601   hFile = CreateFileW( pwcsName,
6602                        accessMode,
6603                        shareMode,
6604                        NULL,
6605                        OPEN_EXISTING,
6606                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
6607                        0);
6608
6609   if (hFile==INVALID_HANDLE_VALUE)
6610   {
6611     DWORD last_error = GetLastError();
6612
6613     hr = E_FAIL;
6614
6615     switch (last_error)
6616     {
6617       case ERROR_FILE_NOT_FOUND:
6618         hr = STG_E_FILENOTFOUND;
6619         break;
6620
6621       case ERROR_PATH_NOT_FOUND:
6622         hr = STG_E_PATHNOTFOUND;
6623         break;
6624
6625       case ERROR_ACCESS_DENIED:
6626       case ERROR_WRITE_PROTECT:
6627         hr = STG_E_ACCESSDENIED;
6628         break;
6629
6630       case ERROR_SHARING_VIOLATION:
6631         hr = STG_E_SHAREVIOLATION;
6632         break;
6633
6634       default:
6635         hr = E_FAIL;
6636     }
6637
6638     goto end;
6639   }
6640
6641   /*
6642    * Refuse to open the file if it's too small to be a structured storage file
6643    * FIXME: verify the file when reading instead of here
6644    */
6645   if (GetFileSize(hFile, NULL) < 0x100)
6646   {
6647     CloseHandle(hFile);
6648     hr = STG_E_FILEALREADYEXISTS;
6649     goto end;
6650   }
6651
6652   /*
6653    * Allocate and initialize the new IStorage32object.
6654    */
6655   hr = Storage_Construct(
6656          hFile,
6657          pwcsName,
6658          NULL,
6659          grfMode,
6660          TRUE,
6661          FALSE,
6662          &newStorage);
6663
6664   if (FAILED(hr))
6665   {
6666     /*
6667      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
6668      */
6669     if(hr == STG_E_INVALIDHEADER)
6670         hr = STG_E_FILEALREADYEXISTS;
6671     goto end;
6672   }
6673
6674   /*
6675    * Get an "out" pointer for the caller.
6676    */
6677   *ppstgOpen = (IStorage*)newStorage;
6678
6679 end:
6680   TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
6681   return hr;
6682 }
6683
6684 /******************************************************************************
6685  *    StgCreateDocfileOnILockBytes    [OLE32.@]
6686  */
6687 HRESULT WINAPI StgCreateDocfileOnILockBytes(
6688       ILockBytes *plkbyt,
6689       DWORD grfMode,
6690       DWORD reserved,
6691       IStorage** ppstgOpen)
6692 {
6693   StorageBaseImpl* newStorage = 0;
6694   HRESULT        hr         = S_OK;
6695
6696   if ((ppstgOpen == 0) || (plkbyt == 0))
6697     return STG_E_INVALIDPOINTER;
6698
6699   /*
6700    * Allocate and initialize the new IStorage object.
6701    */
6702   hr = Storage_Construct(
6703          0,
6704         0,
6705          plkbyt,
6706          grfMode,
6707          FALSE,
6708          TRUE,
6709          &newStorage);
6710
6711   if (FAILED(hr))
6712   {
6713     return hr;
6714   }
6715
6716   /*
6717    * Get an "out" pointer for the caller.
6718    */
6719   *ppstgOpen = (IStorage*)newStorage;
6720
6721   return hr;
6722 }
6723
6724 /******************************************************************************
6725  *    StgOpenStorageOnILockBytes    [OLE32.@]
6726  */
6727 HRESULT WINAPI StgOpenStorageOnILockBytes(
6728       ILockBytes *plkbyt,
6729       IStorage *pstgPriority,
6730       DWORD grfMode,
6731       SNB snbExclude,
6732       DWORD reserved,
6733       IStorage **ppstgOpen)
6734 {
6735   StorageBaseImpl* newStorage = 0;
6736   HRESULT        hr = S_OK;
6737
6738   if ((plkbyt == 0) || (ppstgOpen == 0))
6739     return STG_E_INVALIDPOINTER;
6740
6741   if ( FAILED( validateSTGM(grfMode) ))
6742     return STG_E_INVALIDFLAG;
6743
6744   *ppstgOpen = 0;
6745
6746   /*
6747    * Allocate and initialize the new IStorage object.
6748    */
6749   hr = Storage_Construct(
6750          0,
6751          0,
6752          plkbyt,
6753          grfMode,
6754          FALSE,
6755          FALSE,
6756          &newStorage);
6757
6758   if (FAILED(hr))
6759   {
6760     return hr;
6761   }
6762
6763   /*
6764    * Get an "out" pointer for the caller.
6765    */
6766   *ppstgOpen = (IStorage*)newStorage;
6767
6768   return hr;
6769 }
6770
6771 /******************************************************************************
6772  *              StgSetTimes [ole32.@]
6773  *              StgSetTimes [OLE32.@]
6774  *
6775  *
6776  */
6777 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6778                            FILETIME const *patime, FILETIME const *pmtime)
6779 {
6780   IStorage *stg = NULL;
6781   HRESULT r;
6782  
6783   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6784
6785   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6786                      0, 0, &stg);
6787   if( SUCCEEDED(r) )
6788   {
6789     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6790     IStorage_Release(stg);
6791   }
6792
6793   return r;
6794 }
6795
6796 /******************************************************************************
6797  *              StgIsStorageILockBytes        [OLE32.@]
6798  *
6799  * Determines if the ILockBytes contains a storage object.
6800  */
6801 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6802 {
6803   BYTE sig[8];
6804   ULARGE_INTEGER offset;
6805
6806   offset.u.HighPart = 0;
6807   offset.u.LowPart  = 0;
6808
6809   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6810
6811   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6812     return S_OK;
6813
6814   return S_FALSE;
6815 }
6816
6817 /******************************************************************************
6818  *              WriteClassStg        [OLE32.@]
6819  *
6820  * This method will store the specified CLSID in the specified storage object
6821  */
6822 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6823 {
6824   HRESULT hRes;
6825
6826   if(!pStg)
6827     return E_INVALIDARG;
6828
6829   if(!rclsid)
6830     return STG_E_INVALIDPOINTER;
6831
6832   hRes = IStorage_SetClass(pStg, rclsid);
6833
6834   return hRes;
6835 }
6836
6837 /***********************************************************************
6838  *    ReadClassStg (OLE32.@)
6839  *
6840  * This method reads the CLSID previously written to a storage object with
6841  * the WriteClassStg.
6842  *
6843  * PARAMS
6844  *  pstg    [I] IStorage pointer
6845  *  pclsid  [O] Pointer to where the CLSID is written
6846  *
6847  * RETURNS
6848  *  Success: S_OK.
6849  *  Failure: HRESULT code.
6850  */
6851 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6852
6853     STATSTG pstatstg;
6854     HRESULT hRes;
6855
6856     TRACE("(%p, %p)\n", pstg, pclsid);
6857
6858     if(!pstg || !pclsid)
6859         return E_INVALIDARG;
6860
6861    /*
6862     * read a STATSTG structure (contains the clsid) from the storage
6863     */
6864     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_NONAME);
6865
6866     if(SUCCEEDED(hRes))
6867         *pclsid=pstatstg.clsid;
6868
6869     return hRes;
6870 }
6871
6872 /***********************************************************************
6873  *    OleLoadFromStream (OLE32.@)
6874  *
6875  * This function loads an object from stream
6876  */
6877 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6878 {
6879     CLSID       clsid;
6880     HRESULT     res;
6881     LPPERSISTSTREAM     xstm;
6882
6883     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6884
6885     res=ReadClassStm(pStm,&clsid);
6886     if (FAILED(res))
6887         return res;
6888     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6889     if (FAILED(res))
6890         return res;
6891     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6892     if (FAILED(res)) {
6893         IUnknown_Release((IUnknown*)*ppvObj);
6894         return res;
6895     }
6896     res=IPersistStream_Load(xstm,pStm);
6897     IPersistStream_Release(xstm);
6898     /* FIXME: all refcounts ok at this point? I think they should be:
6899      *          pStm    : unchanged
6900      *          ppvObj  : 1
6901      *          xstm    : 0 (released)
6902      */
6903     return res;
6904 }
6905
6906 /***********************************************************************
6907  *    OleSaveToStream (OLE32.@)
6908  *
6909  * This function saves an object with the IPersistStream interface on it
6910  * to the specified stream.
6911  */
6912 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6913 {
6914
6915     CLSID clsid;
6916     HRESULT res;
6917
6918     TRACE("(%p,%p)\n",pPStm,pStm);
6919
6920     res=IPersistStream_GetClassID(pPStm,&clsid);
6921
6922     if (SUCCEEDED(res)){
6923
6924         res=WriteClassStm(pStm,&clsid);
6925
6926         if (SUCCEEDED(res))
6927
6928             res=IPersistStream_Save(pPStm,pStm,TRUE);
6929     }
6930
6931     TRACE("Finished Save\n");
6932     return res;
6933 }
6934
6935 /****************************************************************************
6936  * This method validate a STGM parameter that can contain the values below
6937  *
6938  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6939  * The stgm values contained in 0xffff0000 are bitmasks.
6940  *
6941  * STGM_DIRECT               0x00000000
6942  * STGM_TRANSACTED           0x00010000
6943  * STGM_SIMPLE               0x08000000
6944  *
6945  * STGM_READ                 0x00000000
6946  * STGM_WRITE                0x00000001
6947  * STGM_READWRITE            0x00000002
6948  *
6949  * STGM_SHARE_DENY_NONE      0x00000040
6950  * STGM_SHARE_DENY_READ      0x00000030
6951  * STGM_SHARE_DENY_WRITE     0x00000020
6952  * STGM_SHARE_EXCLUSIVE      0x00000010
6953  *
6954  * STGM_PRIORITY             0x00040000
6955  * STGM_DELETEONRELEASE      0x04000000
6956  *
6957  * STGM_CREATE               0x00001000
6958  * STGM_CONVERT              0x00020000
6959  * STGM_FAILIFTHERE          0x00000000
6960  *
6961  * STGM_NOSCRATCH            0x00100000
6962  * STGM_NOSNAPSHOT           0x00200000
6963  */
6964 static HRESULT validateSTGM(DWORD stgm)
6965 {
6966   DWORD access = STGM_ACCESS_MODE(stgm);
6967   DWORD share  = STGM_SHARE_MODE(stgm);
6968   DWORD create = STGM_CREATE_MODE(stgm);
6969
6970   if (stgm&~STGM_KNOWN_FLAGS)
6971   {
6972     ERR("unknown flags %08x\n", stgm);
6973     return E_FAIL;
6974   }
6975
6976   switch (access)
6977   {
6978   case STGM_READ:
6979   case STGM_WRITE:
6980   case STGM_READWRITE:
6981     break;
6982   default:
6983     return E_FAIL;
6984   }
6985
6986   switch (share)
6987   {
6988   case STGM_SHARE_DENY_NONE:
6989   case STGM_SHARE_DENY_READ:
6990   case STGM_SHARE_DENY_WRITE:
6991   case STGM_SHARE_EXCLUSIVE:
6992     break;
6993   default:
6994     return E_FAIL;
6995   }
6996
6997   switch (create)
6998   {
6999   case STGM_CREATE:
7000   case STGM_FAILIFTHERE:
7001     break;
7002   default:
7003     return E_FAIL;
7004   }
7005
7006   /*
7007    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
7008    */
7009   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
7010       return E_FAIL;
7011
7012   /*
7013    * STGM_CREATE | STGM_CONVERT
7014    * if both are false, STGM_FAILIFTHERE is set to TRUE
7015    */
7016   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
7017     return E_FAIL;
7018
7019   /*
7020    * STGM_NOSCRATCH requires STGM_TRANSACTED
7021    */
7022   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
7023     return E_FAIL;
7024
7025   /*
7026    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
7027    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
7028    */
7029   if ( (stgm & STGM_NOSNAPSHOT) &&
7030         (!(stgm & STGM_TRANSACTED) ||
7031          share == STGM_SHARE_EXCLUSIVE ||
7032          share == STGM_SHARE_DENY_WRITE) )
7033     return E_FAIL;
7034
7035   return S_OK;
7036 }
7037
7038 /****************************************************************************
7039  *      GetShareModeFromSTGM
7040  *
7041  * This method will return a share mode flag from a STGM value.
7042  * The STGM value is assumed valid.
7043  */
7044 static DWORD GetShareModeFromSTGM(DWORD stgm)
7045 {
7046   switch (STGM_SHARE_MODE(stgm))
7047   {
7048   case STGM_SHARE_DENY_NONE:
7049     return FILE_SHARE_READ | FILE_SHARE_WRITE;
7050   case STGM_SHARE_DENY_READ:
7051     return FILE_SHARE_WRITE;
7052   case STGM_SHARE_DENY_WRITE:
7053     return FILE_SHARE_READ;
7054   case STGM_SHARE_EXCLUSIVE:
7055     return 0;
7056   }
7057   ERR("Invalid share mode!\n");
7058   assert(0);
7059   return 0;
7060 }
7061
7062 /****************************************************************************
7063  *      GetAccessModeFromSTGM
7064  *
7065  * This method will return an access mode flag from a STGM value.
7066  * The STGM value is assumed valid.
7067  */
7068 static DWORD GetAccessModeFromSTGM(DWORD stgm)
7069 {
7070   switch (STGM_ACCESS_MODE(stgm))
7071   {
7072   case STGM_READ:
7073     return GENERIC_READ;
7074   case STGM_WRITE:
7075   case STGM_READWRITE:
7076     return GENERIC_READ | GENERIC_WRITE;
7077   }
7078   ERR("Invalid access mode!\n");
7079   assert(0);
7080   return 0;
7081 }
7082
7083 /****************************************************************************
7084  *      GetCreationModeFromSTGM
7085  *
7086  * This method will return a creation mode flag from a STGM value.
7087  * The STGM value is assumed valid.
7088  */
7089 static DWORD GetCreationModeFromSTGM(DWORD stgm)
7090 {
7091   switch(STGM_CREATE_MODE(stgm))
7092   {
7093   case STGM_CREATE:
7094     return CREATE_ALWAYS;
7095   case STGM_CONVERT:
7096     FIXME("STGM_CONVERT not implemented!\n");
7097     return CREATE_NEW;
7098   case STGM_FAILIFTHERE:
7099     return CREATE_NEW;
7100   }
7101   ERR("Invalid create mode!\n");
7102   assert(0);
7103   return 0;
7104 }
7105
7106
7107 /*************************************************************************
7108  * OLECONVERT_LoadOLE10 [Internal]
7109  *
7110  * Loads the OLE10 STREAM to memory
7111  *
7112  * PARAMS
7113  *     pOleStream   [I] The OLESTREAM
7114  *     pData        [I] Data Structure for the OLESTREAM Data
7115  *
7116  * RETURNS
7117  *     Success:  S_OK
7118  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
7119  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalid
7120  *
7121  * NOTES
7122  *     This function is used by OleConvertOLESTREAMToIStorage only.
7123  *
7124  *     Memory allocated for pData must be freed by the caller
7125  */
7126 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
7127 {
7128         DWORD dwSize;
7129         HRESULT hRes = S_OK;
7130         int nTryCnt=0;
7131         int max_try = 6;
7132
7133         pData->pData = NULL;
7134         pData->pstrOleObjFileName = NULL;
7135
7136         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
7137         {
7138         /* Get the OleID */
7139         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
7140         if(dwSize != sizeof(pData->dwOleID))
7141         {
7142                 hRes = CONVERT10_E_OLESTREAM_GET;
7143         }
7144         else if(pData->dwOleID != OLESTREAM_ID)
7145         {
7146                 hRes = CONVERT10_E_OLESTREAM_FMT;
7147         }
7148                 else
7149                 {
7150                         hRes = S_OK;
7151                         break;
7152                 }
7153         }
7154
7155         if(hRes == S_OK)
7156         {
7157                 /* Get the TypeID... more info needed for this field */
7158                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
7159                 if(dwSize != sizeof(pData->dwTypeID))
7160                 {
7161                         hRes = CONVERT10_E_OLESTREAM_GET;
7162                 }
7163         }
7164         if(hRes == S_OK)
7165         {
7166                 if(pData->dwTypeID != 0)
7167                 {
7168                         /* Get the length of the OleTypeName */
7169                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
7170                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
7171                         {
7172                                 hRes = CONVERT10_E_OLESTREAM_GET;
7173                         }
7174
7175                         if(hRes == S_OK)
7176                         {
7177                                 if(pData->dwOleTypeNameLength > 0)
7178                                 {
7179                                         /* Get the OleTypeName */
7180                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
7181                                         if(dwSize != pData->dwOleTypeNameLength)
7182                                         {
7183                                                 hRes = CONVERT10_E_OLESTREAM_GET;
7184                                         }
7185                                 }
7186                         }
7187                         if(bStrem1)
7188                         {
7189                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
7190                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
7191                                 {
7192                                         hRes = CONVERT10_E_OLESTREAM_GET;
7193                                 }
7194                         if(hRes == S_OK)
7195                         {
7196                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
7197                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
7198                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
7199                                         if(pData->pstrOleObjFileName)
7200                                         {
7201                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, pData->pstrOleObjFileName, pData->dwOleObjFileNameLength);
7202                                                 if(dwSize != pData->dwOleObjFileNameLength)
7203                                                 {
7204                                                         hRes = CONVERT10_E_OLESTREAM_GET;
7205                                                 }
7206                                         }
7207                                         else
7208                                                 hRes = CONVERT10_E_OLESTREAM_GET;
7209                                 }
7210                         }
7211                         else
7212                         {
7213                                 /* Get the Width of the Metafile */
7214                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
7215                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
7216                                 {
7217                                         hRes = CONVERT10_E_OLESTREAM_GET;
7218                                 }
7219                         if(hRes == S_OK)
7220                         {
7221                                 /* Get the Height of the Metafile */
7222                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
7223                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
7224                                 {
7225                                         hRes = CONVERT10_E_OLESTREAM_GET;
7226                                 }
7227                         }
7228                         }
7229                         if(hRes == S_OK)
7230                         {
7231                                 /* Get the Length of the Data */
7232                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
7233                                 if(dwSize != sizeof(pData->dwDataLength))
7234                                 {
7235                                         hRes = CONVERT10_E_OLESTREAM_GET;
7236                                 }
7237                         }
7238
7239                         if(hRes == S_OK) /* I don't know what this 8 byte information is. We have to figure out */
7240                         {
7241                                 if(!bStrem1) /* if it is a second OLE stream data */
7242                                 {
7243                                         pData->dwDataLength -= 8;
7244                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strUnknown, sizeof(pData->strUnknown));
7245                                         if(dwSize != sizeof(pData->strUnknown))
7246                                         {
7247                                                 hRes = CONVERT10_E_OLESTREAM_GET;
7248                                         }
7249                                 }
7250                         }
7251                         if(hRes == S_OK)
7252                         {
7253                                 if(pData->dwDataLength > 0)
7254                                 {
7255                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
7256
7257                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
7258                                         if(pData->pData)
7259                                         {
7260                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
7261                                                 if(dwSize != pData->dwDataLength)
7262                                                 {
7263                                                         hRes = CONVERT10_E_OLESTREAM_GET;
7264                                                 }
7265                                         }
7266                                         else
7267                                         {
7268                                                 hRes = CONVERT10_E_OLESTREAM_GET;
7269                                         }
7270                                 }
7271                         }
7272                 }
7273         }
7274         return hRes;
7275 }
7276
7277 /*************************************************************************
7278  * OLECONVERT_SaveOLE10 [Internal]
7279  *
7280  * Saves the OLE10 STREAM From memory
7281  *
7282  * PARAMS
7283  *     pData        [I] Data Structure for the OLESTREAM Data
7284  *     pOleStream   [I] The OLESTREAM to save
7285  *
7286  * RETURNS
7287  *     Success:  S_OK
7288  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7289  *
7290  * NOTES
7291  *     This function is used by OleConvertIStorageToOLESTREAM only.
7292  *
7293  */
7294 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
7295 {
7296     DWORD dwSize;
7297     HRESULT hRes = S_OK;
7298
7299
7300    /* Set the OleID */
7301     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
7302     if(dwSize != sizeof(pData->dwOleID))
7303     {
7304         hRes = CONVERT10_E_OLESTREAM_PUT;
7305     }
7306
7307     if(hRes == S_OK)
7308     {
7309         /* Set the TypeID */
7310         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
7311         if(dwSize != sizeof(pData->dwTypeID))
7312         {
7313             hRes = CONVERT10_E_OLESTREAM_PUT;
7314         }
7315     }
7316
7317     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
7318     {
7319         /* Set the Length of the OleTypeName */
7320         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
7321         if(dwSize != sizeof(pData->dwOleTypeNameLength))
7322         {
7323             hRes = CONVERT10_E_OLESTREAM_PUT;
7324         }
7325
7326         if(hRes == S_OK)
7327         {
7328             if(pData->dwOleTypeNameLength > 0)
7329             {
7330                 /* Set the OleTypeName */
7331                 dwSize = pOleStream->lpstbl->Put(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
7332                 if(dwSize != pData->dwOleTypeNameLength)
7333                 {
7334                     hRes = CONVERT10_E_OLESTREAM_PUT;
7335                 }
7336             }
7337         }
7338
7339         if(hRes == S_OK)
7340         {
7341             /* Set the width of the Metafile */
7342             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
7343             if(dwSize != sizeof(pData->dwMetaFileWidth))
7344             {
7345                 hRes = CONVERT10_E_OLESTREAM_PUT;
7346             }
7347         }
7348
7349         if(hRes == S_OK)
7350         {
7351             /* Set the height of the Metafile */
7352             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
7353             if(dwSize != sizeof(pData->dwMetaFileHeight))
7354             {
7355                 hRes = CONVERT10_E_OLESTREAM_PUT;
7356             }
7357         }
7358
7359         if(hRes == S_OK)
7360         {
7361             /* Set the length of the Data */
7362             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
7363             if(dwSize != sizeof(pData->dwDataLength))
7364             {
7365                 hRes = CONVERT10_E_OLESTREAM_PUT;
7366             }
7367         }
7368
7369         if(hRes == S_OK)
7370         {
7371             if(pData->dwDataLength > 0)
7372             {
7373                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
7374                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
7375                 if(dwSize != pData->dwDataLength)
7376                 {
7377                     hRes = CONVERT10_E_OLESTREAM_PUT;
7378                 }
7379             }
7380         }
7381     }
7382     return hRes;
7383 }
7384
7385 /*************************************************************************
7386  * OLECONVERT_GetOLE20FromOLE10[Internal]
7387  *
7388  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
7389  * opens it, and copies the content to the dest IStorage for
7390  * OleConvertOLESTREAMToIStorage
7391  *
7392  *
7393  * PARAMS
7394  *     pDestStorage  [I] The IStorage to copy the data to
7395  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
7396  *     nBufferLength [I] The size of the buffer
7397  *
7398  * RETURNS
7399  *     Nothing
7400  *
7401  * NOTES
7402  *
7403  *
7404  */
7405 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBuffer, DWORD nBufferLength)
7406 {
7407     HRESULT hRes;
7408     HANDLE hFile;
7409     IStorage *pTempStorage;
7410     DWORD dwNumOfBytesWritten;
7411     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
7412     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
7413
7414     /* Create a temp File */
7415     GetTempPathW(MAX_PATH, wstrTempDir);
7416     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
7417     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
7418
7419     if(hFile != INVALID_HANDLE_VALUE)
7420     {
7421         /* Write IStorage Data to File */
7422         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
7423         CloseHandle(hFile);
7424
7425         /* Open and copy temp storage to the Dest Storage */
7426         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
7427         if(hRes == S_OK)
7428         {
7429             hRes = IStorage_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
7430             IStorage_Release(pTempStorage);
7431         }
7432         DeleteFileW(wstrTempFile);
7433     }
7434 }
7435
7436
7437 /*************************************************************************
7438  * OLECONVERT_WriteOLE20ToBuffer [Internal]
7439  *
7440  * Saves the OLE10 STREAM From memory
7441  *
7442  * PARAMS
7443  *     pStorage  [I] The Src IStorage to copy
7444  *     pData     [I] The Dest Memory to write to.
7445  *
7446  * RETURNS
7447  *     The size in bytes allocated for pData
7448  *
7449  * NOTES
7450  *     Memory allocated for pData must be freed by the caller
7451  *
7452  *     Used by OleConvertIStorageToOLESTREAM only.
7453  *
7454  */
7455 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
7456 {
7457     HANDLE hFile;
7458     HRESULT hRes;
7459     DWORD nDataLength = 0;
7460     IStorage *pTempStorage;
7461     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
7462     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
7463
7464     *pData = NULL;
7465
7466     /* Create temp Storage */
7467     GetTempPathW(MAX_PATH, wstrTempDir);
7468     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
7469     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
7470
7471     if(hRes == S_OK)
7472     {
7473         /* Copy Src Storage to the Temp Storage */
7474         IStorage_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
7475         IStorage_Release(pTempStorage);
7476
7477         /* Open Temp Storage as a file and copy to memory */
7478         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7479         if(hFile != INVALID_HANDLE_VALUE)
7480         {
7481             nDataLength = GetFileSize(hFile, NULL);
7482             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
7483             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
7484             CloseHandle(hFile);
7485         }
7486         DeleteFileW(wstrTempFile);
7487     }
7488     return nDataLength;
7489 }
7490
7491 /*************************************************************************
7492  * OLECONVERT_CreateOleStream [Internal]
7493  *
7494  * Creates the "\001OLE" stream in the IStorage if necessary.
7495  *
7496  * PARAMS
7497  *     pStorage     [I] Dest storage to create the stream in
7498  *
7499  * RETURNS
7500  *     Nothing
7501  *
7502  * NOTES
7503  *     This function is used by OleConvertOLESTREAMToIStorage only.
7504  *
7505  *     This stream is still unknown, MS Word seems to have extra data
7506  *     but since the data is stored in the OLESTREAM there should be
7507  *     no need to recreate the stream.  If the stream is manually
7508  *     deleted it will create it with this default data.
7509  *
7510  */
7511 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
7512 {
7513     HRESULT hRes;
7514     IStream *pStream;
7515     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
7516     BYTE pOleStreamHeader [] =
7517     {
7518         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
7519         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7520         0x00, 0x00, 0x00, 0x00
7521     };
7522
7523     /* Create stream if not present */
7524     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7525         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7526
7527     if(hRes == S_OK)
7528     {
7529         /* Write default Data */
7530         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
7531         IStream_Release(pStream);
7532     }
7533 }
7534
7535 /* write a string to a stream, preceded by its length */
7536 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
7537 {
7538     HRESULT r;
7539     LPSTR str;
7540     DWORD len = 0;
7541
7542     if( string )
7543         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
7544     r = IStream_Write( stm, &len, sizeof(len), NULL);
7545     if( FAILED( r ) )
7546         return r;
7547     if(len == 0)
7548         return r;
7549     str = CoTaskMemAlloc( len );
7550     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
7551     r = IStream_Write( stm, str, len, NULL);
7552     CoTaskMemFree( str );
7553     return r;
7554 }
7555
7556 /* read a string preceded by its length from a stream */
7557 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
7558 {
7559     HRESULT r;
7560     DWORD len, count = 0;
7561     LPSTR str;
7562     LPWSTR wstr;
7563
7564     r = IStream_Read( stm, &len, sizeof(len), &count );
7565     if( FAILED( r ) )
7566         return r;
7567     if( count != sizeof(len) )
7568         return E_OUTOFMEMORY;
7569
7570     TRACE("%d bytes\n",len);
7571     
7572     str = CoTaskMemAlloc( len );
7573     if( !str )
7574         return E_OUTOFMEMORY;
7575     count = 0;
7576     r = IStream_Read( stm, str, len, &count );
7577     if( FAILED( r ) )
7578         return r;
7579     if( count != len )
7580     {
7581         CoTaskMemFree( str );
7582         return E_OUTOFMEMORY;
7583     }
7584
7585     TRACE("Read string %s\n",debugstr_an(str,len));
7586
7587     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
7588     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
7589     if( wstr )
7590          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
7591     CoTaskMemFree( str );
7592
7593     *string = wstr;
7594
7595     return r;
7596 }
7597
7598
7599 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
7600     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
7601 {
7602     IStream *pstm;
7603     HRESULT r = S_OK;
7604     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7605
7606     static const BYTE unknown1[12] =
7607        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
7608          0xFF, 0xFF, 0xFF, 0xFF};
7609     static const BYTE unknown2[16] =
7610        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
7611          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
7612
7613     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
7614            debugstr_w(lpszUserType), debugstr_w(szClipName),
7615            debugstr_w(szProgIDName));
7616
7617     /*  Create a CompObj stream */
7618     r = IStorage_CreateStream(pstg, szwStreamName,
7619         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
7620     if( FAILED (r) )
7621         return r;
7622
7623     /* Write CompObj Structure to stream */
7624     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
7625
7626     if( SUCCEEDED( r ) )
7627         r = WriteClassStm( pstm, clsid );
7628
7629     if( SUCCEEDED( r ) )
7630         r = STREAM_WriteString( pstm, lpszUserType );
7631     if( SUCCEEDED( r ) )
7632         r = STREAM_WriteString( pstm, szClipName );
7633     if( SUCCEEDED( r ) )
7634         r = STREAM_WriteString( pstm, szProgIDName );
7635     if( SUCCEEDED( r ) )
7636         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
7637
7638     IStream_Release( pstm );
7639
7640     return r;
7641 }
7642
7643 /***********************************************************************
7644  *               WriteFmtUserTypeStg (OLE32.@)
7645  */
7646 HRESULT WINAPI WriteFmtUserTypeStg(
7647           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
7648 {
7649     HRESULT r;
7650     WCHAR szwClipName[0x40];
7651     CLSID clsid = CLSID_NULL;
7652     LPWSTR wstrProgID = NULL;
7653     DWORD n;
7654
7655     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
7656
7657     /* get the clipboard format name */
7658     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName)/sizeof(szwClipName[0]) );
7659     szwClipName[n]=0;
7660
7661     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
7662
7663     /* FIXME: There's room to save a CLSID and its ProgID, but
7664        the CLSID is not looked up in the registry and in all the
7665        tests I wrote it was CLSID_NULL.  Where does it come from?
7666     */
7667
7668     /* get the real program ID.  This may fail, but that's fine */
7669     ProgIDFromCLSID(&clsid, &wstrProgID);
7670
7671     TRACE("progid is %s\n",debugstr_w(wstrProgID));
7672
7673     r = STORAGE_WriteCompObj( pstg, &clsid, 
7674                               lpszUserType, szwClipName, wstrProgID );
7675
7676     CoTaskMemFree(wstrProgID);
7677
7678     return r;
7679 }
7680
7681
7682 /******************************************************************************
7683  *              ReadFmtUserTypeStg        [OLE32.@]
7684  */
7685 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
7686 {
7687     HRESULT r;
7688     IStream *stm = 0;
7689     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
7690     unsigned char unknown1[12];
7691     unsigned char unknown2[16];
7692     DWORD count;
7693     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
7694     CLSID clsid;
7695
7696     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
7697
7698     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
7699                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
7700     if( FAILED ( r ) )
7701     {
7702         WARN("Failed to open stream r = %08x\n", r);
7703         return r;
7704     }
7705
7706     /* read the various parts of the structure */
7707     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
7708     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
7709         goto end;
7710     r = ReadClassStm( stm, &clsid );
7711     if( FAILED( r ) )
7712         goto end;
7713
7714     r = STREAM_ReadString( stm, &szCLSIDName );
7715     if( FAILED( r ) )
7716         goto end;
7717
7718     r = STREAM_ReadString( stm, &szOleTypeName );
7719     if( FAILED( r ) )
7720         goto end;
7721
7722     r = STREAM_ReadString( stm, &szProgIDName );
7723     if( FAILED( r ) )
7724         goto end;
7725
7726     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7727     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7728         goto end;
7729
7730     /* ok, success... now we just need to store what we found */
7731     if( pcf )
7732         *pcf = RegisterClipboardFormatW( szOleTypeName );
7733     CoTaskMemFree( szOleTypeName );
7734
7735     if( lplpszUserType )
7736         *lplpszUserType = szCLSIDName;
7737     CoTaskMemFree( szProgIDName );
7738
7739 end:
7740     IStream_Release( stm );
7741
7742     return r;
7743 }
7744
7745
7746 /*************************************************************************
7747  * OLECONVERT_CreateCompObjStream [Internal]
7748  *
7749  * Creates a "\001CompObj" is the destination IStorage if necessary.
7750  *
7751  * PARAMS
7752  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7753  *                        if necessary.
7754  *     strOleTypeName [I] The ProgID
7755  *
7756  * RETURNS
7757  *     Success:  S_OK
7758  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7759  *
7760  * NOTES
7761  *     This function is used by OleConvertOLESTREAMToIStorage only.
7762  *
7763  *     The stream data is stored in the OLESTREAM and there should be
7764  *     no need to recreate the stream.  If the stream is manually
7765  *     deleted it will attempt to create it by querying the registry.
7766  *
7767  *
7768  */
7769 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7770 {
7771     IStream *pStream;
7772     HRESULT hStorageRes, hRes = S_OK;
7773     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7774     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7775     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7776
7777     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7778     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7779
7780     /* Initialize the CompObj structure */
7781     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7782     memcpy(IStorageCompObj.byUnknown1, pCompObjUnknown1, sizeof(pCompObjUnknown1));
7783     memcpy(IStorageCompObj.byUnknown2, pCompObjUnknown2, sizeof(pCompObjUnknown2));
7784
7785
7786     /*  Create a CompObj stream if it doesn't exist */
7787     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7788         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7789     if(hStorageRes == S_OK)
7790     {
7791         /* copy the OleTypeName to the compobj struct */
7792         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7793         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7794
7795         /* copy the OleTypeName to the compobj struct */
7796         /* Note: in the test made, these were Identical      */
7797         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7798         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7799
7800         /* Get the CLSID */
7801         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7802                              bufferW, OLESTREAM_MAX_STR_LEN );
7803         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7804
7805         if(hRes == S_OK)
7806         {
7807             HKEY hKey;
7808             LONG hErr;
7809             /* Get the CLSID Default Name from the Registry */
7810             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7811             if(hErr == ERROR_SUCCESS)
7812             {
7813                 char strTemp[OLESTREAM_MAX_STR_LEN];
7814                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7815                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7816                 if(hErr == ERROR_SUCCESS)
7817                 {
7818                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7819                 }
7820                 RegCloseKey(hKey);
7821             }
7822         }
7823
7824         /* Write CompObj Structure to stream */
7825         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7826
7827         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7828
7829         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7830         if(IStorageCompObj.dwCLSIDNameLength > 0)
7831         {
7832             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7833         }
7834         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7835         if(IStorageCompObj.dwOleTypeNameLength > 0)
7836         {
7837             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7838         }
7839         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7840         if(IStorageCompObj.dwProgIDNameLength > 0)
7841         {
7842             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7843         }
7844         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7845         IStream_Release(pStream);
7846     }
7847     return hRes;
7848 }
7849
7850
7851 /*************************************************************************
7852  * OLECONVERT_CreateOlePresStream[Internal]
7853  *
7854  * Creates the "\002OlePres000" Stream with the Metafile data
7855  *
7856  * PARAMS
7857  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7858  *     dwExtentX    [I] Width of the Metafile
7859  *     dwExtentY    [I] Height of the Metafile
7860  *     pData        [I] Metafile data
7861  *     dwDataLength [I] Size of the Metafile data
7862  *
7863  * RETURNS
7864  *     Success:  S_OK
7865  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7866  *
7867  * NOTES
7868  *     This function is used by OleConvertOLESTREAMToIStorage only.
7869  *
7870  */
7871 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7872 {
7873     HRESULT hRes;
7874     IStream *pStream;
7875     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7876     BYTE pOlePresStreamHeader [] =
7877     {
7878         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7879         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7880         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7881         0x00, 0x00, 0x00, 0x00
7882     };
7883
7884     BYTE pOlePresStreamHeaderEmpty [] =
7885     {
7886         0x00, 0x00, 0x00, 0x00,
7887         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7888         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7889         0x00, 0x00, 0x00, 0x00
7890     };
7891
7892     /* Create the OlePres000 Stream */
7893     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7894         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7895
7896     if(hRes == S_OK)
7897     {
7898         DWORD nHeaderSize;
7899         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7900
7901         memset(&OlePres, 0, sizeof(OlePres));
7902         /* Do we have any metafile data to save */
7903         if(dwDataLength > 0)
7904         {
7905             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7906             nHeaderSize = sizeof(pOlePresStreamHeader);
7907         }
7908         else
7909         {
7910             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7911             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7912         }
7913         /* Set width and height of the metafile */
7914         OlePres.dwExtentX = dwExtentX;
7915         OlePres.dwExtentY = -dwExtentY;
7916
7917         /* Set Data and Length */
7918         if(dwDataLength > sizeof(METAFILEPICT16))
7919         {
7920             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7921             OlePres.pData = &(pData[8]);
7922         }
7923         /* Save OlePres000 Data to Stream */
7924         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7925         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7926         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7927         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7928         if(OlePres.dwSize > 0)
7929         {
7930             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7931         }
7932         IStream_Release(pStream);
7933     }
7934 }
7935
7936 /*************************************************************************
7937  * OLECONVERT_CreateOle10NativeStream [Internal]
7938  *
7939  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7940  *
7941  * PARAMS
7942  *     pStorage     [I] Dest storage to create the stream in
7943  *     pData        [I] Ole10 Native Data (ex. bmp)
7944  *     dwDataLength [I] Size of the Ole10 Native Data
7945  *
7946  * RETURNS
7947  *     Nothing
7948  *
7949  * NOTES
7950  *     This function is used by OleConvertOLESTREAMToIStorage only.
7951  *
7952  *     Might need to verify the data and return appropriate error message
7953  *
7954  */
7955 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
7956 {
7957     HRESULT hRes;
7958     IStream *pStream;
7959     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7960
7961     /* Create the Ole10Native Stream */
7962     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7963         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7964
7965     if(hRes == S_OK)
7966     {
7967         /* Write info to stream */
7968         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7969         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7970         IStream_Release(pStream);
7971     }
7972
7973 }
7974
7975 /*************************************************************************
7976  * OLECONVERT_GetOLE10ProgID [Internal]
7977  *
7978  * Finds the ProgID (or OleTypeID) from the IStorage
7979  *
7980  * PARAMS
7981  *     pStorage        [I] The Src IStorage to get the ProgID
7982  *     strProgID       [I] the ProgID string to get
7983  *     dwSize          [I] the size of the string
7984  *
7985  * RETURNS
7986  *     Success:  S_OK
7987  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7988  *
7989  * NOTES
7990  *     This function is used by OleConvertIStorageToOLESTREAM only.
7991  *
7992  *
7993  */
7994 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7995 {
7996     HRESULT hRes;
7997     IStream *pStream;
7998     LARGE_INTEGER iSeekPos;
7999     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
8000     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
8001
8002     /* Open the CompObj Stream */
8003     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
8004         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
8005     if(hRes == S_OK)
8006     {
8007
8008         /*Get the OleType from the CompObj Stream */
8009         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
8010         iSeekPos.u.HighPart = 0;
8011
8012         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
8013         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
8014         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
8015         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
8016         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
8017         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
8018         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
8019
8020         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
8021         if(*dwSize > 0)
8022         {
8023             IStream_Read(pStream, strProgID, *dwSize, NULL);
8024         }
8025         IStream_Release(pStream);
8026     }
8027     else
8028     {
8029         STATSTG stat;
8030         LPOLESTR wstrProgID;
8031
8032         /* Get the OleType from the registry */
8033         REFCLSID clsid = &(stat.clsid);
8034         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
8035         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
8036         if(hRes == S_OK)
8037         {
8038             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
8039         }
8040
8041     }
8042     return hRes;
8043 }
8044
8045 /*************************************************************************
8046  * OLECONVERT_GetOle10PresData [Internal]
8047  *
8048  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
8049  *
8050  * PARAMS
8051  *     pStorage     [I] Src IStroage
8052  *     pOleStream   [I] Dest OleStream Mem Struct
8053  *
8054  * RETURNS
8055  *     Nothing
8056  *
8057  * NOTES
8058  *     This function is used by OleConvertIStorageToOLESTREAM only.
8059  *
8060  *     Memory allocated for pData must be freed by the caller
8061  *
8062  *
8063  */
8064 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
8065 {
8066
8067     HRESULT hRes;
8068     IStream *pStream;
8069     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
8070
8071     /* Initialize Default data for OLESTREAM */
8072     pOleStreamData[0].dwOleID = OLESTREAM_ID;
8073     pOleStreamData[0].dwTypeID = 2;
8074     pOleStreamData[1].dwOleID = OLESTREAM_ID;
8075     pOleStreamData[1].dwTypeID = 0;
8076     pOleStreamData[0].dwMetaFileWidth = 0;
8077     pOleStreamData[0].dwMetaFileHeight = 0;
8078     pOleStreamData[0].pData = NULL;
8079     pOleStreamData[1].pData = NULL;
8080
8081     /* Open Ole10Native Stream */
8082     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
8083         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
8084     if(hRes == S_OK)
8085     {
8086
8087         /* Read Size and Data */
8088         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
8089         if(pOleStreamData->dwDataLength > 0)
8090         {
8091             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
8092             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
8093         }
8094         IStream_Release(pStream);
8095     }
8096
8097 }
8098
8099
8100 /*************************************************************************
8101  * OLECONVERT_GetOle20PresData[Internal]
8102  *
8103  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
8104  *
8105  * PARAMS
8106  *     pStorage         [I] Src IStroage
8107  *     pOleStreamData   [I] Dest OleStream Mem Struct
8108  *
8109  * RETURNS
8110  *     Nothing
8111  *
8112  * NOTES
8113  *     This function is used by OleConvertIStorageToOLESTREAM only.
8114  *
8115  *     Memory allocated for pData must be freed by the caller
8116  */
8117 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
8118 {
8119     HRESULT hRes;
8120     IStream *pStream;
8121     OLECONVERT_ISTORAGE_OLEPRES olePress;
8122     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
8123
8124     /* Initialize Default data for OLESTREAM */
8125     pOleStreamData[0].dwOleID = OLESTREAM_ID;
8126     pOleStreamData[0].dwTypeID = 2;
8127     pOleStreamData[0].dwMetaFileWidth = 0;
8128     pOleStreamData[0].dwMetaFileHeight = 0;
8129     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
8130     pOleStreamData[1].dwOleID = OLESTREAM_ID;
8131     pOleStreamData[1].dwTypeID = 0;
8132     pOleStreamData[1].dwOleTypeNameLength = 0;
8133     pOleStreamData[1].strOleTypeName[0] = 0;
8134     pOleStreamData[1].dwMetaFileWidth = 0;
8135     pOleStreamData[1].dwMetaFileHeight = 0;
8136     pOleStreamData[1].pData = NULL;
8137     pOleStreamData[1].dwDataLength = 0;
8138
8139
8140     /* Open OlePress000 stream */
8141     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
8142         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
8143     if(hRes == S_OK)
8144     {
8145         LARGE_INTEGER iSeekPos;
8146         METAFILEPICT16 MetaFilePict;
8147         static const char strMetafilePictName[] = "METAFILEPICT";
8148
8149         /* Set the TypeID for a Metafile */
8150         pOleStreamData[1].dwTypeID = 5;
8151
8152         /* Set the OleTypeName to Metafile */
8153         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
8154         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
8155
8156         iSeekPos.u.HighPart = 0;
8157         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
8158
8159         /* Get Presentation Data */
8160         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
8161         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
8162         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
8163         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
8164
8165         /*Set width and Height */
8166         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
8167         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
8168         if(olePress.dwSize > 0)
8169         {
8170             /* Set Length */
8171             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
8172
8173             /* Set MetaFilePict struct */
8174             MetaFilePict.mm = 8;
8175             MetaFilePict.xExt = olePress.dwExtentX;
8176             MetaFilePict.yExt = olePress.dwExtentY;
8177             MetaFilePict.hMF = 0;
8178
8179             /* Get Metafile Data */
8180             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
8181             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
8182             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
8183         }
8184         IStream_Release(pStream);
8185     }
8186 }
8187
8188 /*************************************************************************
8189  * OleConvertOLESTREAMToIStorage [OLE32.@]
8190  *
8191  * Read info on MSDN
8192  *
8193  * TODO
8194  *      DVTARGETDEVICE parameter is not handled
8195  *      Still unsure of some mem fields for OLE 10 Stream
8196  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
8197  *      and "\001OLE" streams
8198  *
8199  */
8200 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
8201     LPOLESTREAM pOleStream,
8202     LPSTORAGE pstg,
8203     const DVTARGETDEVICE* ptd)
8204 {
8205     int i;
8206     HRESULT hRes=S_OK;
8207     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
8208
8209     TRACE("%p %p %p\n", pOleStream, pstg, ptd);
8210
8211     memset(pOleStreamData, 0, sizeof(pOleStreamData));
8212
8213     if(ptd != NULL)
8214     {
8215         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
8216     }
8217
8218     if(pstg == NULL || pOleStream == NULL)
8219     {
8220         hRes = E_INVALIDARG;
8221     }
8222
8223     if(hRes == S_OK)
8224     {
8225         /* Load the OLESTREAM to Memory */
8226         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
8227     }
8228
8229     if(hRes == S_OK)
8230     {
8231         /* Load the OLESTREAM to Memory (part 2)*/
8232         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
8233     }
8234
8235     if(hRes == S_OK)
8236     {
8237
8238         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
8239         {
8240             /* Do we have the IStorage Data in the OLESTREAM */
8241             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
8242             {
8243                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
8244                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
8245             }
8246             else
8247             {
8248                 /* It must be an original OLE 1.0 source */
8249                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
8250             }
8251         }
8252         else
8253         {
8254             /* It must be an original OLE 1.0 source */
8255             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
8256         }
8257
8258         /* Create CompObj Stream if necessary */
8259         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
8260         if(hRes == S_OK)
8261         {
8262             /*Create the Ole Stream if necessary */
8263             OLECONVERT_CreateOleStream(pstg);
8264         }
8265     }
8266
8267
8268     /* Free allocated memory */
8269     for(i=0; i < 2; i++)
8270     {
8271         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
8272         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
8273         pOleStreamData[i].pstrOleObjFileName = NULL;
8274     }
8275     return hRes;
8276 }
8277
8278 /*************************************************************************
8279  * OleConvertIStorageToOLESTREAM [OLE32.@]
8280  *
8281  * Read info on MSDN
8282  *
8283  * Read info on MSDN
8284  *
8285  * TODO
8286  *      Still unsure of some mem fields for OLE 10 Stream
8287  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
8288  *      and "\001OLE" streams.
8289  *
8290  */
8291 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
8292     LPSTORAGE pstg,
8293     LPOLESTREAM pOleStream)
8294 {
8295     int i;
8296     HRESULT hRes = S_OK;
8297     IStream *pStream;
8298     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
8299     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
8300
8301     TRACE("%p %p\n", pstg, pOleStream);
8302
8303     memset(pOleStreamData, 0, sizeof(pOleStreamData));
8304
8305     if(pstg == NULL || pOleStream == NULL)
8306     {
8307         hRes = E_INVALIDARG;
8308     }
8309     if(hRes == S_OK)
8310     {
8311         /* Get the ProgID */
8312         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
8313         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
8314     }
8315     if(hRes == S_OK)
8316     {
8317         /* Was it originally Ole10 */
8318         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
8319         if(hRes == S_OK)
8320         {
8321             IStream_Release(pStream);
8322             /* Get Presentation Data for Ole10Native */
8323             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
8324         }
8325         else
8326         {
8327             /* Get Presentation Data (OLE20) */
8328             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
8329         }
8330
8331         /* Save OLESTREAM */
8332         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
8333         if(hRes == S_OK)
8334         {
8335             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
8336         }
8337
8338     }
8339
8340     /* Free allocated memory */
8341     for(i=0; i < 2; i++)
8342     {
8343         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
8344     }
8345
8346     return hRes;
8347 }
8348
8349 /***********************************************************************
8350  *              GetConvertStg (OLE32.@)
8351  */
8352 HRESULT WINAPI GetConvertStg(IStorage *stg) {
8353     FIXME("unimplemented stub!\n");
8354     return E_FAIL;
8355 }
8356
8357 /******************************************************************************
8358  * StgIsStorageFile [OLE32.@]
8359  * Verify if the file contains a storage object
8360  *
8361  * PARAMS
8362  *  fn      [ I] Filename
8363  *
8364  * RETURNS
8365  *  S_OK    if file has magic bytes as a storage object
8366  *  S_FALSE if file is not storage
8367  */
8368 HRESULT WINAPI
8369 StgIsStorageFile(LPCOLESTR fn)
8370 {
8371         HANDLE          hf;
8372         BYTE            magic[8];
8373         DWORD           bytes_read;
8374
8375         TRACE("%s\n", debugstr_w(fn));
8376         hf = CreateFileW(fn, GENERIC_READ,
8377                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
8378                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
8379
8380         if (hf == INVALID_HANDLE_VALUE)
8381                 return STG_E_FILENOTFOUND;
8382
8383         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
8384         {
8385                 WARN(" unable to read file\n");
8386                 CloseHandle(hf);
8387                 return S_FALSE;
8388         }
8389
8390         CloseHandle(hf);
8391
8392         if (bytes_read != 8) {
8393                 WARN(" too short\n");
8394                 return S_FALSE;
8395         }
8396
8397         if (!memcmp(magic,STORAGE_magic,8)) {
8398                 WARN(" -> YES\n");
8399                 return S_OK;
8400         }
8401
8402         WARN(" -> Invalid header.\n");
8403         return S_FALSE;
8404 }
8405
8406 /***********************************************************************
8407  *              WriteClassStm (OLE32.@)
8408  *
8409  * Writes a CLSID to a stream.
8410  *
8411  * PARAMS
8412  *  pStm   [I] Stream to write to.
8413  *  rclsid [I] CLSID to write.
8414  *
8415  * RETURNS
8416  *  Success: S_OK.
8417  *  Failure: HRESULT code.
8418  */
8419 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
8420 {
8421     TRACE("(%p,%p)\n",pStm,rclsid);
8422
8423     if (!pStm || !rclsid)
8424         return E_INVALIDARG;
8425
8426     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
8427 }
8428
8429 /***********************************************************************
8430  *              ReadClassStm (OLE32.@)
8431  *
8432  * Reads a CLSID from a stream.
8433  *
8434  * PARAMS
8435  *  pStm   [I] Stream to read from.
8436  *  rclsid [O] CLSID to read.
8437  *
8438  * RETURNS
8439  *  Success: S_OK.
8440  *  Failure: HRESULT code.
8441  */
8442 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
8443 {
8444     ULONG nbByte;
8445     HRESULT res;
8446
8447     TRACE("(%p,%p)\n",pStm,pclsid);
8448
8449     if (!pStm || !pclsid)
8450         return E_INVALIDARG;
8451
8452     /* clear the output args */
8453     *pclsid = CLSID_NULL;
8454
8455     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
8456
8457     if (FAILED(res))
8458         return res;
8459
8460     if (nbByte != sizeof(CLSID))
8461         return STG_E_READFAULT;
8462     else
8463         return S_OK;
8464 }