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