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