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