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