ole32: Move the Running Object Table test in marshal.c to moniker.c to put it with...
[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 %d\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 %d\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, %x, %d, %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("<-- %08x\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, %x, %p, %d, %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("<-- %08x\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, %d, %p, %d, %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, %x)\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: %d, cbSize.Low/High: %d/%d, grfMode: %08x, grfLocksSupported: %d, grfStateBits: %08x\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
739   }
740   TRACE("<-- %08x\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, %x, %d, %d, %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, %x, %d, %d, %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%x\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, %d, %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: %d\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 %u): 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 %d): 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 %d, bigBlockDepotCount %d\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   HRESULT        readRes;
3307   ULONG          bytesRead;
3308
3309   offsetInPropSet.u.HighPart = 0;
3310   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3311
3312   readRes = BlockChainStream_ReadAt(
3313                     This->rootBlockChain,
3314                     offsetInPropSet,
3315                     PROPSET_BLOCK_SIZE,
3316                     currentProperty,
3317                     &bytesRead);
3318
3319   if (SUCCEEDED(readRes))
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 SUCCEEDED(readRes) ? TRUE : FALSE;
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   HRESULT        writeRes;
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   writeRes = BlockChainStream_WriteAt(This->rootBlockChain,
3476                                       offsetInPropSet,
3477                                       PROPSET_BLOCK_SIZE,
3478                                       currentProperty,
3479                                       &bytesWritten);
3480   return SUCCEEDED(writeRes) ? TRUE : FALSE;
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;
3559   ULARGE_INTEGER cbTotalRead;
3560   ULONG propertyIndex;
3561   HRESULT resWrite = S_OK;
3562   HRESULT resRead;
3563   StgProperty chainProperty;
3564   BYTE *buffer;
3565   BlockChainStream *bbTempChain = NULL;
3566   BlockChainStream *bigBlockChain = NULL;
3567
3568   /*
3569    * Create a temporary big block chain that doesn't have
3570    * an associated property. This temporary chain will be
3571    * used to copy data from small blocks to big blocks.
3572    */
3573   bbTempChain = BlockChainStream_Construct(This,
3574                                            &bbHeadOfChain,
3575                                            PROPERTY_NULL);
3576   if(!bbTempChain) return NULL;
3577   /*
3578    * Grow the big block chain.
3579    */
3580   size = SmallBlockChainStream_GetSize(*ppsbChain);
3581   BlockChainStream_SetSize(bbTempChain, size);
3582
3583   /*
3584    * Copy the contents of the small block chain to the big block chain
3585    * by small block size increments.
3586    */
3587   offset.u.LowPart = 0;
3588   offset.u.HighPart = 0;
3589   cbTotalRead.QuadPart = 0;
3590
3591   buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3592   do
3593   {
3594     resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3595                                            offset,
3596                                            This->smallBlockSize,
3597                                            buffer,
3598                                            &cbRead);
3599     if (FAILED(resRead))
3600         break;
3601
3602     if (cbRead > 0)
3603     {
3604         cbTotalRead.QuadPart += cbRead;
3605
3606         resWrite = BlockChainStream_WriteAt(bbTempChain,
3607                                             offset,
3608                                             cbRead,
3609                                             buffer,
3610                                             &cbWritten);
3611
3612         if (FAILED(resWrite))
3613             break;
3614
3615         offset.u.LowPart += This->smallBlockSize;
3616     }
3617   } while (cbTotalRead.QuadPart < size.QuadPart);
3618   HeapFree(GetProcessHeap(),0,buffer);
3619
3620   if (FAILED(resRead) || FAILED(resWrite))
3621   {
3622     ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
3623     BlockChainStream_Destroy(bbTempChain);
3624     return NULL;
3625   }
3626
3627   /*
3628    * Destroy the small block chain.
3629    */
3630   propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3631   size.u.HighPart = 0;
3632   size.u.LowPart  = 0;
3633   SmallBlockChainStream_SetSize(*ppsbChain, size);
3634   SmallBlockChainStream_Destroy(*ppsbChain);
3635   *ppsbChain = 0;
3636
3637   /*
3638    * Change the property information. This chain is now a big block chain
3639    * and it doesn't reside in the small blocks chain anymore.
3640    */
3641   StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3642
3643   chainProperty.startingBlock = bbHeadOfChain;
3644
3645   StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3646
3647   /*
3648    * Destroy the temporary propertyless big block chain.
3649    * Create a new big block chain associated with this property.
3650    */
3651   BlockChainStream_Destroy(bbTempChain);
3652   bigBlockChain = BlockChainStream_Construct(This,
3653                                              NULL,
3654                                              propertyIndex);
3655
3656   return bigBlockChain;
3657 }
3658
3659 static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
3660 {
3661   StorageInternalImpl* This = (StorageInternalImpl*) iface;
3662
3663   StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);
3664   HeapFree(GetProcessHeap(), 0, This);
3665 }
3666
3667 /******************************************************************************
3668 **
3669 ** Storage32InternalImpl_Commit
3670 **
3671 ** The non-root storages cannot be opened in transacted mode thus this function
3672 ** does nothing.
3673 */
3674 static HRESULT WINAPI StorageInternalImpl_Commit(
3675   IStorage*            iface,
3676   DWORD                  grfCommitFlags)  /* [in] */
3677 {
3678   return S_OK;
3679 }
3680
3681 /******************************************************************************
3682 **
3683 ** Storage32InternalImpl_Revert
3684 **
3685 ** The non-root storages cannot be opened in transacted mode thus this function
3686 ** does nothing.
3687 */
3688 static HRESULT WINAPI StorageInternalImpl_Revert(
3689   IStorage*            iface)
3690 {
3691   return S_OK;
3692 }
3693
3694 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3695 {
3696   IStorage_Release((IStorage*)This->parentStorage);
3697   HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3698   HeapFree(GetProcessHeap(), 0, This);
3699 }
3700
3701 static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3702   IEnumSTATSTG*     iface,
3703   REFIID            riid,
3704   void**            ppvObject)
3705 {
3706   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3707
3708   /*
3709    * Perform a sanity check on the parameters.
3710    */
3711   if (ppvObject==0)
3712     return E_INVALIDARG;
3713
3714   /*
3715    * Initialize the return parameter.
3716    */
3717   *ppvObject = 0;
3718
3719   /*
3720    * Compare the riid with the interface IDs implemented by this object.
3721    */
3722   if (IsEqualGUID(&IID_IUnknown, riid) ||
3723       IsEqualGUID(&IID_IEnumSTATSTG, riid))
3724   {
3725     *ppvObject = (IEnumSTATSTG*)This;
3726     IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
3727     return S_OK;
3728   }
3729
3730   return E_NOINTERFACE;
3731 }
3732
3733 static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
3734   IEnumSTATSTG* iface)
3735 {
3736   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3737   return InterlockedIncrement(&This->ref);
3738 }
3739
3740 static ULONG   WINAPI IEnumSTATSTGImpl_Release(
3741   IEnumSTATSTG* iface)
3742 {
3743   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3744
3745   ULONG newRef;
3746
3747   newRef = InterlockedDecrement(&This->ref);
3748
3749   /*
3750    * If the reference count goes down to 0, perform suicide.
3751    */
3752   if (newRef==0)
3753   {
3754     IEnumSTATSTGImpl_Destroy(This);
3755   }
3756
3757   return newRef;
3758 }
3759
3760 static HRESULT WINAPI IEnumSTATSTGImpl_Next(
3761   IEnumSTATSTG* iface,
3762   ULONG             celt,
3763   STATSTG*          rgelt,
3764   ULONG*            pceltFetched)
3765 {
3766   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3767
3768   StgProperty currentProperty;
3769   STATSTG*    currentReturnStruct = rgelt;
3770   ULONG       objectFetched       = 0;
3771   ULONG      currentSearchNode;
3772
3773   /*
3774    * Perform a sanity check on the parameters.
3775    */
3776   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3777     return E_INVALIDARG;
3778
3779   /*
3780    * To avoid the special case, get another pointer to a ULONG value if
3781    * the caller didn't supply one.
3782    */
3783   if (pceltFetched==0)
3784     pceltFetched = &objectFetched;
3785
3786   /*
3787    * Start the iteration, we will iterate until we hit the end of the
3788    * linked list or until we hit the number of items to iterate through
3789    */
3790   *pceltFetched = 0;
3791
3792   /*
3793    * Start with the node at the top of the stack.
3794    */
3795   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3796
3797   while ( ( *pceltFetched < celt) &&
3798           ( currentSearchNode!=PROPERTY_NULL) )
3799   {
3800     /*
3801      * Remove the top node from the stack
3802      */
3803     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3804
3805     /*
3806      * Read the property from the storage.
3807      */
3808     StorageImpl_ReadProperty(This->parentStorage,
3809       currentSearchNode,
3810       &currentProperty);
3811
3812     /*
3813      * Copy the information to the return buffer.
3814      */
3815     StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3816       &currentProperty,
3817       STATFLAG_DEFAULT);
3818
3819     /*
3820      * Step to the next item in the iteration
3821      */
3822     (*pceltFetched)++;
3823     currentReturnStruct++;
3824
3825     /*
3826      * Push the next search node in the search stack.
3827      */
3828     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3829
3830     /*
3831      * continue the iteration.
3832      */
3833     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3834   }
3835
3836   if (*pceltFetched == celt)
3837     return S_OK;
3838
3839   return S_FALSE;
3840 }
3841
3842
3843 static HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3844   IEnumSTATSTG* iface,
3845   ULONG             celt)
3846 {
3847   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3848
3849   StgProperty currentProperty;
3850   ULONG       objectFetched       = 0;
3851   ULONG       currentSearchNode;
3852
3853   /*
3854    * Start with the node at the top of the stack.
3855    */
3856   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3857
3858   while ( (objectFetched < celt) &&
3859           (currentSearchNode!=PROPERTY_NULL) )
3860   {
3861     /*
3862      * Remove the top node from the stack
3863      */
3864     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3865
3866     /*
3867      * Read the property from the storage.
3868      */
3869     StorageImpl_ReadProperty(This->parentStorage,
3870       currentSearchNode,
3871       &currentProperty);
3872
3873     /*
3874      * Step to the next item in the iteration
3875      */
3876     objectFetched++;
3877
3878     /*
3879      * Push the next search node in the search stack.
3880      */
3881     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3882
3883     /*
3884      * continue the iteration.
3885      */
3886     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3887   }
3888
3889   if (objectFetched == celt)
3890     return S_OK;
3891
3892   return S_FALSE;
3893 }
3894
3895 static HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3896   IEnumSTATSTG* iface)
3897 {
3898   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3899
3900   StgProperty rootProperty;
3901   BOOL      readSuccessful;
3902
3903   /*
3904    * Re-initialize the search stack to an empty stack
3905    */
3906   This->stackSize = 0;
3907
3908   /*
3909    * Read the root property from the storage.
3910    */
3911   readSuccessful = StorageImpl_ReadProperty(
3912                     This->parentStorage,
3913                     This->firstPropertyNode,
3914                     &rootProperty);
3915
3916   if (readSuccessful)
3917   {
3918     assert(rootProperty.sizeOfNameString!=0);
3919
3920     /*
3921      * Push the search node in the search stack.
3922      */
3923     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3924   }
3925
3926   return S_OK;
3927 }
3928
3929 static HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3930   IEnumSTATSTG* iface,
3931   IEnumSTATSTG**    ppenum)
3932 {
3933   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3934
3935   IEnumSTATSTGImpl* newClone;
3936
3937   /*
3938    * Perform a sanity check on the parameters.
3939    */
3940   if (ppenum==0)
3941     return E_INVALIDARG;
3942
3943   newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3944                This->firstPropertyNode);
3945
3946
3947   /*
3948    * The new clone enumeration must point to the same current node as
3949    * the ole one.
3950    */
3951   newClone->stackSize    = This->stackSize    ;
3952   newClone->stackMaxSize = This->stackMaxSize ;
3953   newClone->stackToVisit =
3954     HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3955
3956   memcpy(
3957     newClone->stackToVisit,
3958     This->stackToVisit,
3959     sizeof(ULONG) * newClone->stackSize);
3960
3961   *ppenum = (IEnumSTATSTG*)newClone;
3962
3963   /*
3964    * Don't forget to nail down a reference to the clone before
3965    * returning it.
3966    */
3967   IEnumSTATSTGImpl_AddRef(*ppenum);
3968
3969   return S_OK;
3970 }
3971
3972 static INT IEnumSTATSTGImpl_FindParentProperty(
3973   IEnumSTATSTGImpl *This,
3974   ULONG             childProperty,
3975   StgProperty      *currentProperty,
3976   ULONG            *thisNodeId)
3977 {
3978   ULONG currentSearchNode;
3979   ULONG foundNode;
3980
3981   /*
3982    * To avoid the special case, get another pointer to a ULONG value if
3983    * the caller didn't supply one.
3984    */
3985   if (thisNodeId==0)
3986     thisNodeId = &foundNode;
3987
3988   /*
3989    * Start with the node at the top of the stack.
3990    */
3991   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3992
3993
3994   while (currentSearchNode!=PROPERTY_NULL)
3995   {
3996     /*
3997      * Store the current node in the returned parameters
3998      */
3999     *thisNodeId = currentSearchNode;
4000
4001     /*
4002      * Remove the top node from the stack
4003      */
4004     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
4005
4006     /*
4007      * Read the property from the storage.
4008      */
4009     StorageImpl_ReadProperty(
4010       This->parentStorage,
4011       currentSearchNode,
4012       currentProperty);
4013
4014     if (currentProperty->previousProperty == childProperty)
4015       return PROPERTY_RELATION_PREVIOUS;
4016
4017     else if (currentProperty->nextProperty == childProperty)
4018       return PROPERTY_RELATION_NEXT;
4019
4020     else if (currentProperty->dirProperty == childProperty)
4021       return PROPERTY_RELATION_DIR;
4022
4023     /*
4024      * Push the next search node in the search stack.
4025      */
4026     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
4027
4028     /*
4029      * continue the iteration.
4030      */
4031     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4032   }
4033
4034   return PROPERTY_NULL;
4035 }
4036
4037 static ULONG IEnumSTATSTGImpl_FindProperty(
4038   IEnumSTATSTGImpl* This,
4039   const OLECHAR*  lpszPropName,
4040   StgProperty*      currentProperty)
4041 {
4042   ULONG currentSearchNode;
4043
4044   /*
4045    * Start with the node at the top of the stack.
4046    */
4047   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4048
4049   while (currentSearchNode!=PROPERTY_NULL)
4050   {
4051     /*
4052      * Remove the top node from the stack
4053      */
4054     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
4055
4056     /*
4057      * Read the property from the storage.
4058      */
4059     StorageImpl_ReadProperty(This->parentStorage,
4060       currentSearchNode,
4061       currentProperty);
4062
4063     if ( propertyNameCmp(
4064           (const OLECHAR*)currentProperty->name,
4065           (const OLECHAR*)lpszPropName) == 0)
4066       return currentSearchNode;
4067
4068     /*
4069      * Push the next search node in the search stack.
4070      */
4071     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
4072
4073     /*
4074      * continue the iteration.
4075      */
4076     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4077   }
4078
4079   return PROPERTY_NULL;
4080 }
4081
4082 static void IEnumSTATSTGImpl_PushSearchNode(
4083   IEnumSTATSTGImpl* This,
4084   ULONG             nodeToPush)
4085 {
4086   StgProperty rootProperty;
4087   BOOL      readSuccessful;
4088
4089   /*
4090    * First, make sure we're not trying to push an unexisting node.
4091    */
4092   if (nodeToPush==PROPERTY_NULL)
4093     return;
4094
4095   /*
4096    * First push the node to the stack
4097    */
4098   if (This->stackSize == This->stackMaxSize)
4099   {
4100     This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
4101
4102     This->stackToVisit = HeapReAlloc(
4103                            GetProcessHeap(),
4104                            0,
4105                            This->stackToVisit,
4106                            sizeof(ULONG) * This->stackMaxSize);
4107   }
4108
4109   This->stackToVisit[This->stackSize] = nodeToPush;
4110   This->stackSize++;
4111
4112   /*
4113    * Read the root property from the storage.
4114    */
4115   readSuccessful = StorageImpl_ReadProperty(
4116                     This->parentStorage,
4117                     nodeToPush,
4118                     &rootProperty);
4119
4120   if (readSuccessful)
4121   {
4122     assert(rootProperty.sizeOfNameString!=0);
4123
4124     /*
4125      * Push the previous search node in the search stack.
4126      */
4127     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
4128   }
4129 }
4130
4131 static ULONG IEnumSTATSTGImpl_PopSearchNode(
4132   IEnumSTATSTGImpl* This,
4133   BOOL            remove)
4134 {
4135   ULONG topNode;
4136
4137   if (This->stackSize == 0)
4138     return PROPERTY_NULL;
4139
4140   topNode = This->stackToVisit[This->stackSize-1];
4141
4142   if (remove)
4143     This->stackSize--;
4144
4145   return topNode;
4146 }
4147
4148 /*
4149  * Virtual function table for the IEnumSTATSTGImpl class.
4150  */
4151 static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
4152 {
4153     IEnumSTATSTGImpl_QueryInterface,
4154     IEnumSTATSTGImpl_AddRef,
4155     IEnumSTATSTGImpl_Release,
4156     IEnumSTATSTGImpl_Next,
4157     IEnumSTATSTGImpl_Skip,
4158     IEnumSTATSTGImpl_Reset,
4159     IEnumSTATSTGImpl_Clone
4160 };
4161
4162 /******************************************************************************
4163 ** IEnumSTATSTGImpl implementation
4164 */
4165
4166 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
4167   StorageImpl* parentStorage,
4168   ULONG          firstPropertyNode)
4169 {
4170   IEnumSTATSTGImpl* newEnumeration;
4171
4172   newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
4173
4174   if (newEnumeration!=0)
4175   {
4176     /*
4177      * Set-up the virtual function table and reference count.
4178      */
4179     newEnumeration->lpVtbl    = &IEnumSTATSTGImpl_Vtbl;
4180     newEnumeration->ref       = 0;
4181
4182     /*
4183      * We want to nail-down the reference to the storage in case the
4184      * enumeration out-lives the storage in the client application.
4185      */
4186     newEnumeration->parentStorage = parentStorage;
4187     IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
4188
4189     newEnumeration->firstPropertyNode   = firstPropertyNode;
4190
4191     /*
4192      * Initialize the search stack
4193      */
4194     newEnumeration->stackSize    = 0;
4195     newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
4196     newEnumeration->stackToVisit =
4197       HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
4198
4199     /*
4200      * Make sure the current node of the iterator is the first one.
4201      */
4202     IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
4203   }
4204
4205   return newEnumeration;
4206 }
4207
4208 /*
4209  * Virtual function table for the Storage32InternalImpl class.
4210  */
4211 static const IStorageVtbl Storage32InternalImpl_Vtbl =
4212 {
4213     StorageBaseImpl_QueryInterface,
4214     StorageBaseImpl_AddRef,
4215     StorageBaseImpl_Release,
4216     StorageBaseImpl_CreateStream,
4217     StorageBaseImpl_OpenStream,
4218     StorageImpl_CreateStorage,
4219     StorageBaseImpl_OpenStorage,
4220     StorageImpl_CopyTo,
4221     StorageImpl_MoveElementTo,
4222     StorageInternalImpl_Commit,
4223     StorageInternalImpl_Revert,
4224     StorageBaseImpl_EnumElements,
4225     StorageImpl_DestroyElement,
4226     StorageBaseImpl_RenameElement,
4227     StorageImpl_SetElementTimes,
4228     StorageBaseImpl_SetClass,
4229     StorageImpl_SetStateBits,
4230     StorageBaseImpl_Stat
4231 };
4232
4233 /******************************************************************************
4234 ** Storage32InternalImpl implementation
4235 */
4236
4237 static StorageInternalImpl* StorageInternalImpl_Construct(
4238   StorageImpl* ancestorStorage,
4239   DWORD        openFlags,
4240   ULONG        rootPropertyIndex)
4241 {
4242   StorageInternalImpl* newStorage;
4243
4244   /*
4245    * Allocate space for the new storage object
4246    */
4247   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
4248
4249   if (newStorage!=0)
4250   {
4251     memset(newStorage, 0, sizeof(StorageInternalImpl));
4252
4253     /*
4254      * Initialize the stream list
4255      */
4256
4257     list_init(&newStorage->base.strmHead);
4258
4259     /*
4260      * Initialize the virtual function table.
4261      */
4262     newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
4263     newStorage->base.v_destructor = &StorageInternalImpl_Destroy;
4264     newStorage->base.openFlags = (openFlags & ~STGM_CREATE);
4265
4266     /*
4267      * Keep the ancestor storage pointer and nail a reference to it.
4268      */
4269     newStorage->base.ancestorStorage = ancestorStorage;
4270     StorageBaseImpl_AddRef((IStorage*)(newStorage->base.ancestorStorage));
4271
4272     /*
4273      * Keep the index of the root property set for this storage,
4274      */
4275     newStorage->base.rootPropertySetIndex = rootPropertyIndex;
4276
4277     return newStorage;
4278   }
4279
4280   return 0;
4281 }
4282
4283 /******************************************************************************
4284 ** StorageUtl implementation
4285 */
4286
4287 void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
4288 {
4289   WORD tmp;
4290
4291   memcpy(&tmp, buffer+offset, sizeof(WORD));
4292   *value = le16toh(tmp);
4293 }
4294
4295 void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
4296 {
4297   value = htole16(value);
4298   memcpy(buffer+offset, &value, sizeof(WORD));
4299 }
4300
4301 void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
4302 {
4303   DWORD tmp;
4304
4305   memcpy(&tmp, buffer+offset, sizeof(DWORD));
4306   *value = le32toh(tmp);
4307 }
4308
4309 void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
4310 {
4311   value = htole32(value);
4312   memcpy(buffer+offset, &value, sizeof(DWORD));
4313 }
4314
4315 void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
4316  ULARGE_INTEGER* value)
4317 {
4318 #ifdef WORDS_BIGENDIAN
4319     ULARGE_INTEGER tmp;
4320
4321     memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
4322     value->u.LowPart = htole32(tmp.u.HighPart);
4323     value->u.HighPart = htole32(tmp.u.LowPart);
4324 #else
4325     memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
4326 #endif
4327 }
4328
4329 void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
4330  const ULARGE_INTEGER *value)
4331 {
4332 #ifdef WORDS_BIGENDIAN
4333     ULARGE_INTEGER tmp;
4334
4335     tmp.u.LowPart = htole32(value->u.HighPart);
4336     tmp.u.HighPart = htole32(value->u.LowPart);
4337     memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
4338 #else
4339     memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
4340 #endif
4341 }
4342
4343 void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
4344 {
4345   StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
4346   StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
4347   StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
4348
4349   memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
4350 }
4351
4352 void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
4353 {
4354   StorageUtl_WriteDWord(buffer, offset,   value->Data1);
4355   StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
4356   StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
4357
4358   memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
4359 }
4360
4361 void StorageUtl_CopyPropertyToSTATSTG(
4362   STATSTG*     destination,
4363   StgProperty* source,
4364   int          statFlags)
4365 {
4366   /*
4367    * The copy of the string occurs only when the flag is not set
4368    */
4369   if( ((statFlags & STATFLAG_NONAME) != 0) || 
4370        (source->name == NULL) || 
4371        (source->name[0] == 0) )
4372   {
4373     destination->pwcsName = 0;
4374   }
4375   else
4376   {
4377     destination->pwcsName =
4378       CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
4379
4380     strcpyW((LPWSTR)destination->pwcsName, source->name);
4381   }
4382
4383   switch (source->propertyType)
4384   {
4385     case PROPTYPE_STORAGE:
4386     case PROPTYPE_ROOT:
4387       destination->type = STGTY_STORAGE;
4388       break;
4389     case PROPTYPE_STREAM:
4390       destination->type = STGTY_STREAM;
4391       break;
4392     default:
4393       destination->type = STGTY_STREAM;
4394       break;
4395   }
4396
4397   destination->cbSize            = source->size;
4398 /*
4399   currentReturnStruct->mtime     = {0}; TODO
4400   currentReturnStruct->ctime     = {0};
4401   currentReturnStruct->atime     = {0};
4402 */
4403   destination->grfMode           = 0;
4404   destination->grfLocksSupported = 0;
4405   destination->clsid             = source->propertyUniqueID;
4406   destination->grfStateBits      = 0;
4407   destination->reserved          = 0;
4408 }
4409
4410 /******************************************************************************
4411 ** BlockChainStream implementation
4412 */
4413
4414 BlockChainStream* BlockChainStream_Construct(
4415   StorageImpl* parentStorage,
4416   ULONG*         headOfStreamPlaceHolder,
4417   ULONG          propertyIndex)
4418 {
4419   BlockChainStream* newStream;
4420   ULONG blockIndex;
4421
4422   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
4423
4424   newStream->parentStorage           = parentStorage;
4425   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
4426   newStream->ownerPropertyIndex      = propertyIndex;
4427   newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
4428   newStream->tailIndex               = BLOCK_END_OF_CHAIN;
4429   newStream->numBlocks               = 0;
4430
4431   blockIndex = BlockChainStream_GetHeadOfChain(newStream);
4432
4433   while (blockIndex != BLOCK_END_OF_CHAIN)
4434   {
4435     newStream->numBlocks++;
4436     newStream->tailIndex = blockIndex;
4437
4438     if(FAILED(StorageImpl_GetNextBlockInChain(
4439               parentStorage,
4440               blockIndex,
4441               &blockIndex)))
4442     {
4443       HeapFree(GetProcessHeap(), 0, newStream);
4444       return NULL;
4445     }
4446   }
4447
4448   return newStream;
4449 }
4450
4451 void BlockChainStream_Destroy(BlockChainStream* This)
4452 {
4453   HeapFree(GetProcessHeap(), 0, This);
4454 }
4455
4456 /******************************************************************************
4457  *      BlockChainStream_GetHeadOfChain
4458  *
4459  * Returns the head of this stream chain.
4460  * Some special chains don't have properties, their heads are kept in
4461  * This->headOfStreamPlaceHolder.
4462  *
4463  */
4464 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
4465 {
4466   StgProperty chainProperty;
4467   BOOL      readSuccessful;
4468
4469   if (This->headOfStreamPlaceHolder != 0)
4470     return *(This->headOfStreamPlaceHolder);
4471
4472   if (This->ownerPropertyIndex != PROPERTY_NULL)
4473   {
4474     readSuccessful = StorageImpl_ReadProperty(
4475                       This->parentStorage,
4476                       This->ownerPropertyIndex,
4477                       &chainProperty);
4478
4479     if (readSuccessful)
4480     {
4481       return chainProperty.startingBlock;
4482     }
4483   }
4484
4485   return BLOCK_END_OF_CHAIN;
4486 }
4487
4488 /******************************************************************************
4489  *       BlockChainStream_GetCount
4490  *
4491  * Returns the number of blocks that comprises this chain.
4492  * This is not the size of the stream as the last block may not be full!
4493  *
4494  */
4495 static ULONG BlockChainStream_GetCount(BlockChainStream* This)
4496 {
4497   ULONG blockIndex;
4498   ULONG count = 0;
4499
4500   blockIndex = BlockChainStream_GetHeadOfChain(This);
4501
4502   while (blockIndex != BLOCK_END_OF_CHAIN)
4503   {
4504     count++;
4505
4506     if(FAILED(StorageImpl_GetNextBlockInChain(
4507                    This->parentStorage,
4508                    blockIndex,
4509                    &blockIndex)))
4510       return 0;
4511   }
4512
4513   return count;
4514 }
4515
4516 /******************************************************************************
4517  *      BlockChainStream_ReadAt
4518  *
4519  * Reads a specified number of bytes from this chain at the specified offset.
4520  * bytesRead may be NULL.
4521  * Failure will be returned if the specified number of bytes has not been read.
4522  */
4523 HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
4524   ULARGE_INTEGER offset,
4525   ULONG          size,
4526   void*          buffer,
4527   ULONG*         bytesRead)
4528 {
4529   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4530   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
4531   ULONG bytesToReadInBuffer;
4532   ULONG blockIndex;
4533   BYTE* bufferWalker;
4534   BYTE* bigBlockBuffer;
4535
4536   /*
4537    * Find the first block in the stream that contains part of the buffer.
4538    */
4539   if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4540        (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4541        (blockNoInSequence < This->lastBlockNoInSequence) )
4542   {
4543     blockIndex = BlockChainStream_GetHeadOfChain(This);
4544     This->lastBlockNoInSequence = blockNoInSequence;
4545   }
4546   else
4547   {
4548     ULONG temp = blockNoInSequence;
4549
4550     blockIndex = This->lastBlockNoInSequenceIndex;
4551     blockNoInSequence -= This->lastBlockNoInSequence;
4552     This->lastBlockNoInSequence = temp;
4553   }
4554
4555   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4556   {
4557     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
4558       return STG_E_DOCFILECORRUPT;
4559     blockNoInSequence--;
4560   }
4561
4562   if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN))
4563       return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */
4564
4565   This->lastBlockNoInSequenceIndex = blockIndex;
4566
4567   /*
4568    * Start reading the buffer.
4569    */
4570   *bytesRead   = 0;
4571   bufferWalker = buffer;
4572
4573   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4574   {
4575     /*
4576      * Calculate how many bytes we can copy from this big block.
4577      */
4578     bytesToReadInBuffer =
4579       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4580
4581     /*
4582      * Copy those bytes to the buffer
4583      */
4584     bigBlockBuffer =
4585       StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
4586     if (!bigBlockBuffer)
4587         return STG_E_READFAULT;
4588
4589     memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
4590
4591     StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4592
4593     /*
4594      * Step to the next big block.
4595      */
4596     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
4597       return STG_E_DOCFILECORRUPT;
4598
4599     bufferWalker += bytesToReadInBuffer;
4600     size         -= bytesToReadInBuffer;
4601     *bytesRead   += bytesToReadInBuffer;
4602     offsetInBlock = 0;  /* There is no offset on the next block */
4603
4604   }
4605
4606   return (size == 0) ? S_OK : STG_E_READFAULT;
4607 }
4608
4609 /******************************************************************************
4610  *      BlockChainStream_WriteAt
4611  *
4612  * Writes the specified number of bytes to this chain at the specified offset.
4613  * bytesWritten may be NULL.
4614  * Will fail if not all specified number of bytes have been written.
4615  */
4616 HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
4617   ULARGE_INTEGER    offset,
4618   ULONG             size,
4619   const void*       buffer,
4620   ULONG*            bytesWritten)
4621 {
4622   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4623   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
4624   ULONG bytesToWrite;
4625   ULONG blockIndex;
4626   const BYTE* bufferWalker;
4627   BYTE* bigBlockBuffer;
4628
4629   /*
4630    * Find the first block in the stream that contains part of the buffer.
4631    */
4632   if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4633        (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4634        (blockNoInSequence < This->lastBlockNoInSequence) )
4635   {
4636     blockIndex = BlockChainStream_GetHeadOfChain(This);
4637     This->lastBlockNoInSequence = blockNoInSequence;
4638   }
4639   else
4640   {
4641     ULONG temp = blockNoInSequence;
4642
4643     blockIndex = This->lastBlockNoInSequenceIndex;
4644     blockNoInSequence -= This->lastBlockNoInSequence;
4645     This->lastBlockNoInSequence = temp;
4646   }
4647
4648   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4649   {
4650     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4651                                               &blockIndex)))
4652       return STG_E_DOCFILECORRUPT;
4653     blockNoInSequence--;
4654   }
4655
4656   This->lastBlockNoInSequenceIndex = blockIndex;
4657
4658   /* BlockChainStream_SetSize should have already been called to ensure we have
4659    * enough blocks in the chain to write into */
4660   if (blockIndex == BLOCK_END_OF_CHAIN)
4661   {
4662     ERR("not enough blocks in chain to write data\n");
4663     return STG_E_DOCFILECORRUPT;
4664   }
4665
4666   /*
4667    * Here, I'm casting away the constness on the buffer variable
4668    * This is OK since we don't intend to modify that buffer.
4669    */
4670   *bytesWritten   = 0;
4671   bufferWalker = (const BYTE*)buffer;
4672
4673   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4674   {
4675     /*
4676      * Calculate how many bytes we can copy from this big block.
4677      */
4678     bytesToWrite =
4679       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4680
4681     /*
4682      * Copy those bytes to the buffer
4683      */
4684     bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
4685
4686     memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
4687
4688     StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4689
4690     /*
4691      * Step to the next big block.
4692      */
4693     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4694                                               &blockIndex)))
4695       return STG_E_DOCFILECORRUPT;
4696     bufferWalker  += bytesToWrite;
4697     size          -= bytesToWrite;
4698     *bytesWritten += bytesToWrite;
4699     offsetInBlock  = 0;      /* There is no offset on the next block */
4700   }
4701
4702   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
4703 }
4704
4705 /******************************************************************************
4706  *      BlockChainStream_Shrink
4707  *
4708  * Shrinks this chain in the big block depot.
4709  */
4710 static BOOL BlockChainStream_Shrink(BlockChainStream* This,
4711                                     ULARGE_INTEGER    newSize)
4712 {
4713   ULONG blockIndex, extraBlock;
4714   ULONG numBlocks;
4715   ULONG count = 1;
4716
4717   /*
4718    * Reset the last accessed block cache.
4719    */
4720   This->lastBlockNoInSequence = 0xFFFFFFFF;
4721   This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
4722
4723   /*
4724    * Figure out how many blocks are needed to contain the new size
4725    */
4726   numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4727
4728   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4729     numBlocks++;
4730
4731   blockIndex = BlockChainStream_GetHeadOfChain(This);
4732
4733   /*
4734    * Go to the new end of chain
4735    */
4736   while (count < numBlocks)
4737   {
4738     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4739                                               &blockIndex)))
4740       return FALSE;
4741     count++;
4742   }
4743
4744   /* Get the next block before marking the new end */
4745   if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4746                                             &extraBlock)))
4747     return FALSE;
4748
4749   /* Mark the new end of chain */
4750   StorageImpl_SetNextBlockInChain(
4751     This->parentStorage,
4752     blockIndex,
4753     BLOCK_END_OF_CHAIN);
4754
4755   This->tailIndex = blockIndex;
4756   This->numBlocks = numBlocks;
4757
4758   /*
4759    * Mark the extra blocks as free
4760    */
4761   while (extraBlock != BLOCK_END_OF_CHAIN)
4762   {
4763     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock,
4764                                               &blockIndex)))
4765       return FALSE;
4766     StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4767     extraBlock = blockIndex;
4768   }
4769
4770   return TRUE;
4771 }
4772
4773 /******************************************************************************
4774  *      BlockChainStream_Enlarge
4775  *
4776  * Grows this chain in the big block depot.
4777  */
4778 static BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4779                                      ULARGE_INTEGER    newSize)
4780 {
4781   ULONG blockIndex, currentBlock;
4782   ULONG newNumBlocks;
4783   ULONG oldNumBlocks = 0;
4784
4785   blockIndex = BlockChainStream_GetHeadOfChain(This);
4786
4787   /*
4788    * Empty chain. Create the head.
4789    */
4790   if (blockIndex == BLOCK_END_OF_CHAIN)
4791   {
4792     blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4793     StorageImpl_SetNextBlockInChain(This->parentStorage,
4794                                       blockIndex,
4795                                       BLOCK_END_OF_CHAIN);
4796
4797     if (This->headOfStreamPlaceHolder != 0)
4798     {
4799       *(This->headOfStreamPlaceHolder) = blockIndex;
4800     }
4801     else
4802     {
4803       StgProperty chainProp;
4804       assert(This->ownerPropertyIndex != PROPERTY_NULL);
4805
4806       StorageImpl_ReadProperty(
4807         This->parentStorage,
4808         This->ownerPropertyIndex,
4809         &chainProp);
4810
4811       chainProp.startingBlock = blockIndex;
4812
4813       StorageImpl_WriteProperty(
4814         This->parentStorage,
4815         This->ownerPropertyIndex,
4816         &chainProp);
4817     }
4818
4819     This->tailIndex = blockIndex;
4820     This->numBlocks = 1;
4821   }
4822
4823   /*
4824    * Figure out how many blocks are needed to contain this stream
4825    */
4826   newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4827
4828   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4829     newNumBlocks++;
4830
4831   /*
4832    * Go to the current end of chain
4833    */
4834   if (This->tailIndex == BLOCK_END_OF_CHAIN)
4835   {
4836     currentBlock = blockIndex;
4837
4838     while (blockIndex != BLOCK_END_OF_CHAIN)
4839     {
4840       This->numBlocks++;
4841       currentBlock = blockIndex;
4842
4843       if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
4844                                                 &blockIndex)))
4845         return FALSE;
4846     }
4847
4848     This->tailIndex = currentBlock;
4849   }
4850
4851   currentBlock = This->tailIndex;
4852   oldNumBlocks = This->numBlocks;
4853
4854   /*
4855    * Add new blocks to the chain
4856    */
4857   if (oldNumBlocks < newNumBlocks)
4858   {
4859     while (oldNumBlocks < newNumBlocks)
4860     {
4861       blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4862
4863       StorageImpl_SetNextBlockInChain(
4864         This->parentStorage,
4865         currentBlock,
4866         blockIndex);
4867
4868       StorageImpl_SetNextBlockInChain(
4869         This->parentStorage,
4870         blockIndex,
4871         BLOCK_END_OF_CHAIN);
4872
4873       currentBlock = blockIndex;
4874       oldNumBlocks++;
4875     }
4876
4877     This->tailIndex = blockIndex;
4878     This->numBlocks = newNumBlocks;
4879   }
4880
4881   return TRUE;
4882 }
4883
4884 /******************************************************************************
4885  *      BlockChainStream_SetSize
4886  *
4887  * Sets the size of this stream. The big block depot will be updated.
4888  * The file will grow if we grow the chain.
4889  *
4890  * TODO: Free the actual blocks in the file when we shrink the chain.
4891  *       Currently, the blocks are still in the file. So the file size
4892  *       doesn't shrink even if we shrink streams.
4893  */
4894 BOOL BlockChainStream_SetSize(
4895   BlockChainStream* This,
4896   ULARGE_INTEGER    newSize)
4897 {
4898   ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4899
4900   if (newSize.u.LowPart == size.u.LowPart)
4901     return TRUE;
4902
4903   if (newSize.u.LowPart < size.u.LowPart)
4904   {
4905     BlockChainStream_Shrink(This, newSize);
4906   }
4907   else
4908   {
4909     BlockChainStream_Enlarge(This, newSize);
4910   }
4911
4912   return TRUE;
4913 }
4914
4915 /******************************************************************************
4916  *      BlockChainStream_GetSize
4917  *
4918  * Returns the size of this chain.
4919  * Will return the block count if this chain doesn't have a property.
4920  */
4921 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4922 {
4923   StgProperty chainProperty;
4924
4925   if(This->headOfStreamPlaceHolder == NULL)
4926   {
4927     /*
4928      * This chain is a data stream read the property and return
4929      * the appropriate size
4930      */
4931     StorageImpl_ReadProperty(
4932       This->parentStorage,
4933       This->ownerPropertyIndex,
4934       &chainProperty);
4935
4936     return chainProperty.size;
4937   }
4938   else
4939   {
4940     /*
4941      * this chain is a chain that does not have a property, figure out the
4942      * size by making the product number of used blocks times the
4943      * size of them
4944      */
4945     ULARGE_INTEGER result;
4946     result.u.HighPart = 0;
4947
4948     result.u.LowPart  =
4949       BlockChainStream_GetCount(This) *
4950       This->parentStorage->bigBlockSize;
4951
4952     return result;
4953   }
4954 }
4955
4956 /******************************************************************************
4957 ** SmallBlockChainStream implementation
4958 */
4959
4960 SmallBlockChainStream* SmallBlockChainStream_Construct(
4961   StorageImpl* parentStorage,
4962   ULONG          propertyIndex)
4963 {
4964   SmallBlockChainStream* newStream;
4965
4966   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4967
4968   newStream->parentStorage      = parentStorage;
4969   newStream->ownerPropertyIndex = propertyIndex;
4970
4971   return newStream;
4972 }
4973
4974 void SmallBlockChainStream_Destroy(
4975   SmallBlockChainStream* This)
4976 {
4977   HeapFree(GetProcessHeap(), 0, This);
4978 }
4979
4980 /******************************************************************************
4981  *      SmallBlockChainStream_GetHeadOfChain
4982  *
4983  * Returns the head of this chain of small blocks.
4984  */
4985 static ULONG SmallBlockChainStream_GetHeadOfChain(
4986   SmallBlockChainStream* This)
4987 {
4988   StgProperty chainProperty;
4989   BOOL      readSuccessful;
4990
4991   if (This->ownerPropertyIndex)
4992   {
4993     readSuccessful = StorageImpl_ReadProperty(
4994                       This->parentStorage,
4995                       This->ownerPropertyIndex,
4996                       &chainProperty);
4997
4998     if (readSuccessful)
4999     {
5000       return chainProperty.startingBlock;
5001     }
5002
5003   }
5004
5005   return BLOCK_END_OF_CHAIN;
5006 }
5007
5008 /******************************************************************************
5009  *      SmallBlockChainStream_GetNextBlockInChain
5010  *
5011  * Returns the index of the next small block in this chain.
5012  *
5013  * Return Values:
5014  *    - BLOCK_END_OF_CHAIN: end of this chain
5015  *    - BLOCK_UNUSED: small block 'blockIndex' is free
5016  */
5017 static HRESULT SmallBlockChainStream_GetNextBlockInChain(
5018   SmallBlockChainStream* This,
5019   ULONG                  blockIndex,
5020   ULONG*                 nextBlockInChain)
5021 {
5022   ULARGE_INTEGER offsetOfBlockInDepot;
5023   DWORD  buffer;
5024   ULONG  bytesRead;
5025   HRESULT res;
5026
5027   *nextBlockInChain = BLOCK_END_OF_CHAIN;
5028
5029   offsetOfBlockInDepot.u.HighPart = 0;
5030   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
5031
5032   /*
5033    * Read those bytes in the buffer from the small block file.
5034    */
5035   res = BlockChainStream_ReadAt(
5036               This->parentStorage->smallBlockDepotChain,
5037               offsetOfBlockInDepot,
5038               sizeof(DWORD),
5039               &buffer,
5040               &bytesRead);
5041
5042   if (SUCCEEDED(res))
5043   {
5044     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
5045     return S_OK;
5046   }
5047
5048   return res;
5049 }
5050
5051 /******************************************************************************
5052  *       SmallBlockChainStream_SetNextBlockInChain
5053  *
5054  * Writes the index of the next block of the specified block in the small
5055  * block depot.
5056  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
5057  * To flag a block as free use BLOCK_UNUSED as nextBlock.
5058  */
5059 static void SmallBlockChainStream_SetNextBlockInChain(
5060   SmallBlockChainStream* This,
5061   ULONG                  blockIndex,
5062   ULONG                  nextBlock)
5063 {
5064   ULARGE_INTEGER offsetOfBlockInDepot;
5065   DWORD  buffer;
5066   ULONG  bytesWritten;
5067
5068   offsetOfBlockInDepot.u.HighPart = 0;
5069   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
5070
5071   StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
5072
5073   /*
5074    * Read those bytes in the buffer from the small block file.
5075    */
5076   BlockChainStream_WriteAt(
5077     This->parentStorage->smallBlockDepotChain,
5078     offsetOfBlockInDepot,
5079     sizeof(DWORD),
5080     &buffer,
5081     &bytesWritten);
5082 }
5083
5084 /******************************************************************************
5085  *      SmallBlockChainStream_FreeBlock
5086  *
5087  * Flag small block 'blockIndex' as free in the small block depot.
5088  */
5089 static void SmallBlockChainStream_FreeBlock(
5090   SmallBlockChainStream* This,
5091   ULONG                  blockIndex)
5092 {
5093   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
5094 }
5095
5096 /******************************************************************************
5097  *      SmallBlockChainStream_GetNextFreeBlock
5098  *
5099  * Returns the index of a free small block. The small block depot will be
5100  * enlarged if necessary. The small block chain will also be enlarged if
5101  * necessary.
5102  */
5103 static ULONG SmallBlockChainStream_GetNextFreeBlock(
5104   SmallBlockChainStream* This)
5105 {
5106   ULARGE_INTEGER offsetOfBlockInDepot;
5107   DWORD buffer;
5108   ULONG bytesRead;
5109   ULONG blockIndex = 0;
5110   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
5111   HRESULT res = S_OK;
5112   ULONG smallBlocksPerBigBlock;
5113
5114   offsetOfBlockInDepot.u.HighPart = 0;
5115
5116   /*
5117    * Scan the small block depot for a free block
5118    */
5119   while (nextBlockIndex != BLOCK_UNUSED)
5120   {
5121     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
5122
5123     res = BlockChainStream_ReadAt(
5124                 This->parentStorage->smallBlockDepotChain,
5125                 offsetOfBlockInDepot,
5126                 sizeof(DWORD),
5127                 &buffer,
5128                 &bytesRead);
5129
5130     /*
5131      * If we run out of space for the small block depot, enlarge it
5132      */
5133     if (SUCCEEDED(res))
5134     {
5135       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
5136
5137       if (nextBlockIndex != BLOCK_UNUSED)
5138         blockIndex++;
5139     }
5140     else
5141     {
5142       ULONG count =
5143         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
5144
5145       ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
5146       ULONG nextBlock, newsbdIndex;
5147       BYTE* smallBlockDepot;
5148
5149       nextBlock = sbdIndex;
5150       while (nextBlock != BLOCK_END_OF_CHAIN)
5151       {
5152         sbdIndex = nextBlock;
5153         StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock);
5154       }
5155
5156       newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5157       if (sbdIndex != BLOCK_END_OF_CHAIN)
5158         StorageImpl_SetNextBlockInChain(
5159           This->parentStorage,
5160           sbdIndex,
5161           newsbdIndex);
5162
5163       StorageImpl_SetNextBlockInChain(
5164         This->parentStorage,
5165         newsbdIndex,
5166         BLOCK_END_OF_CHAIN);
5167
5168       /*
5169        * Initialize all the small blocks to free
5170        */
5171       smallBlockDepot =
5172         StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
5173
5174       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
5175       StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
5176
5177       if (count == 0)
5178       {
5179         /*
5180          * We have just created the small block depot.
5181          */
5182         StgProperty rootProp;
5183         ULONG sbStartIndex;
5184
5185         /*
5186          * Save it in the header
5187          */
5188         This->parentStorage->smallBlockDepotStart = newsbdIndex;
5189         StorageImpl_SaveFileHeader(This->parentStorage);
5190
5191         /*
5192          * And allocate the first big block that will contain small blocks
5193          */
5194         sbStartIndex =
5195           StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5196
5197         StorageImpl_SetNextBlockInChain(
5198           This->parentStorage,
5199           sbStartIndex,
5200           BLOCK_END_OF_CHAIN);
5201
5202         StorageImpl_ReadProperty(
5203           This->parentStorage,
5204           This->parentStorage->base.rootPropertySetIndex,
5205           &rootProp);
5206
5207         rootProp.startingBlock = sbStartIndex;
5208         rootProp.size.u.HighPart = 0;
5209         rootProp.size.u.LowPart  = This->parentStorage->bigBlockSize;
5210
5211         StorageImpl_WriteProperty(
5212           This->parentStorage,
5213           This->parentStorage->base.rootPropertySetIndex,
5214           &rootProp);
5215       }
5216     }
5217   }
5218
5219   smallBlocksPerBigBlock =
5220     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
5221
5222   /*
5223    * Verify if we have to allocate big blocks to contain small blocks
5224    */
5225   if (blockIndex % smallBlocksPerBigBlock == 0)
5226   {
5227     StgProperty rootProp;
5228     ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
5229
5230     StorageImpl_ReadProperty(
5231       This->parentStorage,
5232       This->parentStorage->base.rootPropertySetIndex,
5233       &rootProp);
5234
5235     if (rootProp.size.u.LowPart <
5236        (blocksRequired * This->parentStorage->bigBlockSize))
5237     {
5238       rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;
5239
5240       BlockChainStream_SetSize(
5241         This->parentStorage->smallBlockRootChain,
5242         rootProp.size);
5243
5244       StorageImpl_WriteProperty(
5245         This->parentStorage,
5246         This->parentStorage->base.rootPropertySetIndex,
5247         &rootProp);
5248     }
5249   }
5250
5251   return blockIndex;
5252 }
5253
5254 /******************************************************************************
5255  *      SmallBlockChainStream_ReadAt
5256  *
5257  * Reads a specified number of bytes from this chain at the specified offset.
5258  * bytesRead may be NULL.
5259  * Failure will be returned if the specified number of bytes has not been read.
5260  */
5261 HRESULT SmallBlockChainStream_ReadAt(
5262   SmallBlockChainStream* This,
5263   ULARGE_INTEGER         offset,
5264   ULONG                  size,
5265   void*                  buffer,
5266   ULONG*                 bytesRead)
5267 {
5268   HRESULT rc = S_OK;
5269   ULARGE_INTEGER offsetInBigBlockFile;
5270   ULONG blockNoInSequence =
5271     offset.u.LowPart / This->parentStorage->smallBlockSize;
5272
5273   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5274   ULONG bytesToReadInBuffer;
5275   ULONG blockIndex;
5276   ULONG bytesReadFromBigBlockFile;
5277   BYTE* bufferWalker;
5278
5279   /*
5280    * This should never happen on a small block file.
5281    */
5282   assert(offset.u.HighPart==0);
5283
5284   /*
5285    * Find the first block in the stream that contains part of the buffer.
5286    */
5287   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5288
5289   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5290   {
5291     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5292     if(FAILED(rc))
5293       return rc;
5294     blockNoInSequence--;
5295   }
5296
5297   /*
5298    * Start reading the buffer.
5299    */
5300   *bytesRead   = 0;
5301   bufferWalker = buffer;
5302
5303   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5304   {
5305     /*
5306      * Calculate how many bytes we can copy from this small block.
5307      */
5308     bytesToReadInBuffer =
5309       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5310
5311     /*
5312      * Calculate the offset of the small block in the small block file.
5313      */
5314     offsetInBigBlockFile.u.HighPart  = 0;
5315     offsetInBigBlockFile.u.LowPart   =
5316       blockIndex * This->parentStorage->smallBlockSize;
5317
5318     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5319
5320     /*
5321      * Read those bytes in the buffer from the small block file.
5322      * The small block has already been identified so it shouldn't fail
5323      * unless the file is corrupt.
5324      */
5325     rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
5326       offsetInBigBlockFile,
5327       bytesToReadInBuffer,
5328       bufferWalker,
5329       &bytesReadFromBigBlockFile);
5330
5331     if (FAILED(rc))
5332       return rc;
5333
5334     /*
5335      * Step to the next big block.
5336      */
5337     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5338     if(FAILED(rc))
5339       return STG_E_DOCFILECORRUPT;
5340
5341     bufferWalker += bytesReadFromBigBlockFile;
5342     size         -= bytesReadFromBigBlockFile;
5343     *bytesRead   += bytesReadFromBigBlockFile;
5344     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
5345   }
5346
5347   return (size == 0) ? S_OK : STG_E_READFAULT;
5348 }
5349
5350 /******************************************************************************
5351  *       SmallBlockChainStream_WriteAt
5352  *
5353  * Writes the specified number of bytes to this chain at the specified offset.
5354  * bytesWritten may be NULL.
5355  * Will fail if not all specified number of bytes have been written.
5356  */
5357 HRESULT SmallBlockChainStream_WriteAt(
5358   SmallBlockChainStream* This,
5359   ULARGE_INTEGER offset,
5360   ULONG          size,
5361   const void*    buffer,
5362   ULONG*         bytesWritten)
5363 {
5364   ULARGE_INTEGER offsetInBigBlockFile;
5365   ULONG blockNoInSequence =
5366     offset.u.LowPart / This->parentStorage->smallBlockSize;
5367
5368   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5369   ULONG bytesToWriteInBuffer;
5370   ULONG blockIndex;
5371   ULONG bytesWrittenToBigBlockFile;
5372   const BYTE* bufferWalker;
5373   HRESULT res;
5374
5375   /*
5376    * This should never happen on a small block file.
5377    */
5378   assert(offset.u.HighPart==0);
5379
5380   /*
5381    * Find the first block in the stream that contains part of the buffer.
5382    */
5383   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5384
5385   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5386   {
5387     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
5388       return STG_E_DOCFILECORRUPT;
5389     blockNoInSequence--;
5390   }
5391
5392   /*
5393    * Start writing the buffer.
5394    *
5395    * Here, I'm casting away the constness on the buffer variable
5396    * This is OK since we don't intend to modify that buffer.
5397    */
5398   *bytesWritten   = 0;
5399   bufferWalker = (const BYTE*)buffer;
5400   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5401   {
5402     /*
5403      * Calculate how many bytes we can copy to this small block.
5404      */
5405     bytesToWriteInBuffer =
5406       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5407
5408     /*
5409      * Calculate the offset of the small block in the small block file.
5410      */
5411     offsetInBigBlockFile.u.HighPart  = 0;
5412     offsetInBigBlockFile.u.LowPart   =
5413       blockIndex * This->parentStorage->smallBlockSize;
5414
5415     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5416
5417     /*
5418      * Write those bytes in the buffer to the small block file.
5419      */
5420     res = BlockChainStream_WriteAt(
5421       This->parentStorage->smallBlockRootChain,
5422       offsetInBigBlockFile,
5423       bytesToWriteInBuffer,
5424       bufferWalker,
5425       &bytesWrittenToBigBlockFile);
5426     if (FAILED(res))
5427       return res;
5428
5429     /*
5430      * Step to the next big block.
5431      */
5432     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5433                                                         &blockIndex)))
5434       return FALSE;
5435     bufferWalker  += bytesWrittenToBigBlockFile;
5436     size          -= bytesWrittenToBigBlockFile;
5437     *bytesWritten += bytesWrittenToBigBlockFile;
5438     offsetInBlock  = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
5439   }
5440
5441   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
5442 }
5443
5444 /******************************************************************************
5445  *       SmallBlockChainStream_Shrink
5446  *
5447  * Shrinks this chain in the small block depot.
5448  */
5449 static BOOL SmallBlockChainStream_Shrink(
5450   SmallBlockChainStream* This,
5451   ULARGE_INTEGER newSize)
5452 {
5453   ULONG blockIndex, extraBlock;
5454   ULONG numBlocks;
5455   ULONG count = 0;
5456
5457   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5458
5459   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5460     numBlocks++;
5461
5462   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5463
5464   /*
5465    * Go to the new end of chain
5466    */
5467   while (count < numBlocks)
5468   {
5469     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5470                                                         &blockIndex)))
5471       return FALSE;
5472     count++;
5473   }
5474
5475   /*
5476    * If the count is 0, we have a special case, the head of the chain was
5477    * just freed.
5478    */
5479   if (count == 0)
5480   {
5481     StgProperty chainProp;
5482
5483     StorageImpl_ReadProperty(This->parentStorage,
5484                              This->ownerPropertyIndex,
5485                              &chainProp);
5486
5487     chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5488
5489     StorageImpl_WriteProperty(This->parentStorage,
5490                               This->ownerPropertyIndex,
5491                               &chainProp);
5492
5493     /*
5494      * We start freeing the chain at the head block.
5495      */
5496     extraBlock = blockIndex;
5497   }
5498   else
5499   {
5500     /* Get the next block before marking the new end */
5501     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5502                                                         &extraBlock)))
5503       return FALSE;
5504
5505     /* Mark the new end of chain */
5506     SmallBlockChainStream_SetNextBlockInChain(
5507       This,
5508       blockIndex,
5509       BLOCK_END_OF_CHAIN);
5510   }
5511
5512   /*
5513    * Mark the extra blocks as free
5514    */
5515   while (extraBlock != BLOCK_END_OF_CHAIN)
5516   {
5517     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
5518                                                         &blockIndex)))
5519       return FALSE;
5520     SmallBlockChainStream_FreeBlock(This, extraBlock);
5521     extraBlock = blockIndex;
5522   }
5523
5524   return TRUE;
5525 }
5526
5527 /******************************************************************************
5528  *      SmallBlockChainStream_Enlarge
5529  *
5530  * Grows this chain in the small block depot.
5531  */
5532 static BOOL SmallBlockChainStream_Enlarge(
5533   SmallBlockChainStream* This,
5534   ULARGE_INTEGER newSize)
5535 {
5536   ULONG blockIndex, currentBlock;
5537   ULONG newNumBlocks;
5538   ULONG oldNumBlocks = 0;
5539
5540   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5541
5542   /*
5543    * Empty chain
5544    */
5545   if (blockIndex == BLOCK_END_OF_CHAIN)
5546   {
5547
5548     StgProperty chainProp;
5549
5550     StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5551                                &chainProp);
5552
5553     chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
5554
5555     StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5556                                 &chainProp);
5557
5558     blockIndex = chainProp.startingBlock;
5559     SmallBlockChainStream_SetNextBlockInChain(
5560       This,
5561       blockIndex,
5562       BLOCK_END_OF_CHAIN);
5563   }
5564
5565   currentBlock = blockIndex;
5566
5567   /*
5568    * Figure out how many blocks are needed to contain this stream
5569    */
5570   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5571
5572   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5573     newNumBlocks++;
5574
5575   /*
5576    * Go to the current end of chain
5577    */
5578   while (blockIndex != BLOCK_END_OF_CHAIN)
5579   {
5580     oldNumBlocks++;
5581     currentBlock = blockIndex;
5582     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
5583       return FALSE;
5584   }
5585
5586   /*
5587    * Add new blocks to the chain
5588    */
5589   while (oldNumBlocks < newNumBlocks)
5590   {
5591     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5592     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5593
5594     SmallBlockChainStream_SetNextBlockInChain(
5595       This,
5596       blockIndex,
5597       BLOCK_END_OF_CHAIN);
5598
5599     currentBlock = blockIndex;
5600     oldNumBlocks++;
5601   }
5602
5603   return TRUE;
5604 }
5605
5606 /******************************************************************************
5607  *      SmallBlockChainStream_SetSize
5608  *
5609  * Sets the size of this stream.
5610  * The file will grow if we grow the chain.
5611  *
5612  * TODO: Free the actual blocks in the file when we shrink the chain.
5613  *       Currently, the blocks are still in the file. So the file size
5614  *       doesn't shrink even if we shrink streams.
5615  */
5616 BOOL SmallBlockChainStream_SetSize(
5617                 SmallBlockChainStream* This,
5618                 ULARGE_INTEGER    newSize)
5619 {
5620   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5621
5622   if (newSize.u.LowPart == size.u.LowPart)
5623     return TRUE;
5624
5625   if (newSize.u.LowPart < size.u.LowPart)
5626   {
5627     SmallBlockChainStream_Shrink(This, newSize);
5628   }
5629   else
5630   {
5631     SmallBlockChainStream_Enlarge(This, newSize);
5632   }
5633
5634   return TRUE;
5635 }
5636
5637 /******************************************************************************
5638  *      SmallBlockChainStream_GetSize
5639  *
5640  * Returns the size of this chain.
5641  */
5642 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5643 {
5644   StgProperty chainProperty;
5645
5646   StorageImpl_ReadProperty(
5647     This->parentStorage,
5648     This->ownerPropertyIndex,
5649     &chainProperty);
5650
5651   return chainProperty.size;
5652 }
5653
5654 /******************************************************************************
5655  *    StgCreateDocfile  [OLE32.@]
5656  * Creates a new compound file storage object
5657  *
5658  * PARAMS
5659  *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
5660  *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
5661  *  reserved  [ ?] unused?, usually 0
5662  *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
5663  *
5664  * RETURNS
5665  *  S_OK if the file was successfully created
5666  *  some STG_E_ value if error
5667  * NOTES
5668  *  if pwcsName is NULL, create file with new unique name
5669  *  the function can returns
5670  *  STG_S_CONVERTED if the specified file was successfully converted to storage format
5671  *  (unrealized now)
5672  */
5673 HRESULT WINAPI StgCreateDocfile(
5674   LPCOLESTR pwcsName,
5675   DWORD       grfMode,
5676   DWORD       reserved,
5677   IStorage  **ppstgOpen)
5678 {
5679   StorageImpl* newStorage = 0;
5680   HANDLE       hFile      = INVALID_HANDLE_VALUE;
5681   HRESULT        hr         = STG_E_INVALIDFLAG;
5682   DWORD          shareMode;
5683   DWORD          accessMode;
5684   DWORD          creationMode;
5685   DWORD          fileAttributes;
5686   WCHAR          tempFileName[MAX_PATH];
5687
5688   TRACE("(%s, %x, %d, %p)\n",
5689         debugstr_w(pwcsName), grfMode,
5690         reserved, ppstgOpen);
5691
5692   /*
5693    * Validate the parameters
5694    */
5695   if (ppstgOpen == 0)
5696     return STG_E_INVALIDPOINTER;
5697   if (reserved != 0)
5698     return STG_E_INVALIDPARAMETER;
5699
5700   /*
5701    * Validate the STGM flags
5702    */
5703   if ( FAILED( validateSTGM(grfMode) ))
5704     goto end;
5705
5706   /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
5707   switch(STGM_ACCESS_MODE(grfMode))
5708   {
5709   case STGM_WRITE:
5710   case STGM_READWRITE:
5711     break;
5712   default:
5713     goto end;
5714   }
5715
5716   /* if no share mode given then DENY_NONE is the default */     
5717   if (STGM_SHARE_MODE(grfMode) == 0)
5718     grfMode |= STGM_SHARE_DENY_NONE;
5719
5720   /* must have at least one access mode */
5721   if (STGM_ACCESS_MODE(grfMode) == 0)
5722     goto end;
5723   
5724   /* in direct mode, can only use SHARE_EXCLUSIVE */
5725   if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
5726     goto end;
5727
5728   /* but in transacted mode, any share mode is valid */
5729
5730   /*
5731    * Generate a unique name.
5732    */
5733   if (pwcsName == 0)
5734   {
5735     WCHAR tempPath[MAX_PATH];
5736     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5737
5738     memset(tempPath, 0, sizeof(tempPath));
5739     memset(tempFileName, 0, sizeof(tempFileName));
5740
5741     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5742       tempPath[0] = '.';
5743
5744     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5745       pwcsName = tempFileName;
5746     else
5747     {
5748       hr = STG_E_INSUFFICIENTMEMORY;
5749       goto end;
5750     }
5751
5752     creationMode = TRUNCATE_EXISTING;
5753   }
5754   else
5755   {
5756     creationMode = GetCreationModeFromSTGM(grfMode);
5757   }
5758
5759   /*
5760    * Interpret the STGM value grfMode
5761    */
5762   shareMode    = GetShareModeFromSTGM(grfMode);
5763   accessMode   = GetAccessModeFromSTGM(grfMode);
5764
5765   if (grfMode & STGM_DELETEONRELEASE)
5766     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5767   else
5768     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5769
5770   if (grfMode & STGM_TRANSACTED)
5771     FIXME("Transacted mode not implemented.\n");
5772
5773   /*
5774    * Initialize the "out" parameter.
5775    */
5776   *ppstgOpen = 0;
5777
5778   hFile = CreateFileW(pwcsName,
5779                         accessMode,
5780                         shareMode,
5781                         NULL,
5782                         creationMode,
5783                         fileAttributes,
5784                         0);
5785
5786   if (hFile == INVALID_HANDLE_VALUE)
5787   {
5788     if(GetLastError() == ERROR_FILE_EXISTS)
5789       hr = STG_E_FILEALREADYEXISTS;
5790     else
5791       hr = E_FAIL;
5792     goto end;
5793   }
5794
5795   /*
5796    * Allocate and initialize the new IStorage32object.
5797    */
5798   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5799
5800   if (newStorage == 0)
5801   {
5802     hr = STG_E_INSUFFICIENTMEMORY;
5803     goto end;
5804   }
5805
5806   hr = StorageImpl_Construct(
5807          newStorage,
5808          hFile,
5809         pwcsName,
5810          NULL,
5811          grfMode,
5812          TRUE,
5813          TRUE);
5814
5815   if (FAILED(hr))
5816   {
5817     HeapFree(GetProcessHeap(), 0, newStorage);
5818     goto end;
5819   }
5820
5821   /*
5822    * Get an "out" pointer for the caller.
5823    */
5824   hr = StorageBaseImpl_QueryInterface(
5825          (IStorage*)newStorage,
5826          (REFIID)&IID_IStorage,
5827          (void**)ppstgOpen);
5828 end:
5829   TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
5830
5831   return hr;
5832 }
5833
5834 /******************************************************************************
5835  *              StgCreateStorageEx        [OLE32.@]
5836  */
5837 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5838 {
5839     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5840           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5841
5842     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
5843     {
5844         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
5845         return STG_E_INVALIDPARAMETER;  
5846     }
5847
5848     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5849     {
5850         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
5851         return STG_E_INVALIDPARAMETER;  
5852     }
5853
5854     if (stgfmt == STGFMT_FILE)
5855     {
5856         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5857         return STG_E_INVALIDPARAMETER;
5858     }
5859
5860     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
5861     {
5862         FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
5863         return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); 
5864     }
5865
5866     ERR("Invalid stgfmt argument\n");
5867     return STG_E_INVALIDPARAMETER;
5868 }
5869
5870 /******************************************************************************
5871  *              StgCreatePropSetStg       [OLE32.@]
5872  */
5873 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
5874  IPropertySetStorage **ppPropSetStg)
5875 {
5876     HRESULT hr;
5877
5878     TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
5879     if (reserved)
5880         hr = STG_E_INVALIDPARAMETER;
5881     else
5882         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
5883          (void**)ppPropSetStg);
5884     return hr;
5885 }
5886
5887 /******************************************************************************
5888  *              StgOpenStorageEx      [OLE32.@]
5889  */
5890 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5891 {
5892     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5893           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5894
5895     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
5896     {
5897         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
5898         return STG_E_INVALIDPARAMETER;  
5899     }
5900
5901     switch (stgfmt)
5902     {
5903     case STGFMT_FILE:
5904         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5905         return STG_E_INVALIDPARAMETER;
5906         
5907     case STGFMT_STORAGE:
5908         break;
5909
5910     case STGFMT_DOCFILE:
5911         if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
5912         {
5913             ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
5914             return STG_E_INVALIDPARAMETER;  
5915         }
5916         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
5917         break;
5918
5919     case STGFMT_ANY:
5920         WARN("STGFMT_ANY assuming storage\n");
5921         break;
5922
5923     default:
5924         return STG_E_INVALIDPARAMETER;
5925     }
5926
5927     return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); 
5928 }
5929
5930
5931 /******************************************************************************
5932  *              StgOpenStorage        [OLE32.@]
5933  */
5934 HRESULT WINAPI StgOpenStorage(
5935   const OLECHAR *pwcsName,
5936   IStorage      *pstgPriority,
5937   DWORD          grfMode,
5938   SNB            snbExclude,
5939   DWORD          reserved,
5940   IStorage     **ppstgOpen)
5941 {
5942   StorageImpl*   newStorage = 0;
5943   HRESULT        hr = S_OK;
5944   HANDLE         hFile = 0;
5945   DWORD          shareMode;
5946   DWORD          accessMode;
5947   WCHAR          fullname[MAX_PATH];
5948
5949   TRACE("(%s, %p, %x, %p, %d, %p)\n",
5950         debugstr_w(pwcsName), pstgPriority, grfMode,
5951         snbExclude, reserved, ppstgOpen);
5952
5953   /*
5954    * Perform sanity checks
5955    */
5956   if (pwcsName == 0)
5957   {
5958     hr = STG_E_INVALIDNAME;
5959     goto end;
5960   }
5961
5962   if (ppstgOpen == 0)
5963   {
5964     hr = STG_E_INVALIDPOINTER;
5965     goto end;
5966   }
5967
5968   if (reserved)
5969   {
5970     hr = STG_E_INVALIDPARAMETER;
5971     goto end;
5972   }
5973
5974   if (grfMode & STGM_PRIORITY)
5975   {
5976     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
5977       return STG_E_INVALIDFLAG;
5978     if (grfMode & STGM_DELETEONRELEASE)
5979       return STG_E_INVALIDFUNCTION;
5980     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
5981       return STG_E_INVALIDFLAG;
5982     grfMode &= ~0xf0; /* remove the existing sharing mode */
5983     grfMode |= STGM_SHARE_DENY_NONE;
5984
5985     /* STGM_PRIORITY stops other IStorage objects on the same file from
5986      * committing until the STGM_PRIORITY IStorage is closed. it also
5987      * stops non-transacted mode StgOpenStorage calls with write access from
5988      * succeeding. obviously, both of these cannot be achieved through just
5989      * file share flags */
5990     FIXME("STGM_PRIORITY mode not implemented correctly\n");
5991   }
5992
5993   /*
5994    * Validate the sharing mode
5995    */
5996   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
5997     switch(STGM_SHARE_MODE(grfMode))
5998     {
5999       case STGM_SHARE_EXCLUSIVE:
6000       case STGM_SHARE_DENY_WRITE:
6001         break;
6002       default:
6003         hr = STG_E_INVALIDFLAG;
6004         goto end;
6005     }
6006
6007   /*
6008    * Validate the STGM flags
6009    */
6010   if ( FAILED( validateSTGM(grfMode) ) ||
6011        (grfMode&STGM_CREATE))
6012   {
6013     hr = STG_E_INVALIDFLAG;
6014     goto end;
6015   }
6016
6017   /* shared reading requires transacted mode */
6018   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
6019       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
6020      !(grfMode&STGM_TRANSACTED) )
6021   {
6022     hr = STG_E_INVALIDFLAG;
6023     goto end;
6024   }
6025
6026   /*
6027    * Interpret the STGM value grfMode
6028    */
6029   shareMode    = GetShareModeFromSTGM(grfMode);
6030   accessMode   = GetAccessModeFromSTGM(grfMode);
6031
6032   /*
6033    * Initialize the "out" parameter.
6034    */
6035   *ppstgOpen = 0;
6036
6037   hFile = CreateFileW( pwcsName,
6038                        accessMode,
6039                        shareMode,
6040                        NULL,
6041                        OPEN_EXISTING,
6042                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
6043                        0);
6044
6045   if (hFile==INVALID_HANDLE_VALUE)
6046   {
6047     DWORD last_error = GetLastError();
6048
6049     hr = E_FAIL;
6050
6051     switch (last_error)
6052     {
6053       case ERROR_FILE_NOT_FOUND:
6054         hr = STG_E_FILENOTFOUND;
6055         break;
6056
6057       case ERROR_PATH_NOT_FOUND:
6058         hr = STG_E_PATHNOTFOUND;
6059         break;
6060
6061       case ERROR_ACCESS_DENIED:
6062       case ERROR_WRITE_PROTECT:
6063         hr = STG_E_ACCESSDENIED;
6064         break;
6065
6066       case ERROR_SHARING_VIOLATION:
6067         hr = STG_E_SHAREVIOLATION;
6068         break;
6069
6070       default:
6071         hr = E_FAIL;
6072     }
6073
6074     goto end;
6075   }
6076
6077   /*
6078    * Refuse to open the file if it's too small to be a structured storage file
6079    * FIXME: verify the file when reading instead of here
6080    */
6081   if (GetFileSize(hFile, NULL) < 0x100)
6082   {
6083     CloseHandle(hFile);
6084     hr = STG_E_FILEALREADYEXISTS;
6085     goto end;
6086   }
6087
6088   /*
6089    * Allocate and initialize the new IStorage32object.
6090    */
6091   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6092
6093   if (newStorage == 0)
6094   {
6095     hr = STG_E_INSUFFICIENTMEMORY;
6096     goto end;
6097   }
6098
6099   /* Initialize the storage */
6100   hr = StorageImpl_Construct(
6101          newStorage,
6102          hFile,
6103          pwcsName,
6104          NULL,
6105          grfMode,
6106          TRUE,
6107          FALSE );
6108
6109   if (FAILED(hr))
6110   {
6111     HeapFree(GetProcessHeap(), 0, newStorage);
6112     /*
6113      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
6114      */
6115     if(hr == STG_E_INVALIDHEADER)
6116         hr = STG_E_FILEALREADYEXISTS;
6117     goto end;
6118   }
6119
6120   /* prepare the file name string given in lieu of the root property name */
6121   GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
6122   memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
6123   newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
6124
6125   /*
6126    * Get an "out" pointer for the caller.
6127    */
6128   hr = StorageBaseImpl_QueryInterface(
6129          (IStorage*)newStorage,
6130          (REFIID)&IID_IStorage,
6131          (void**)ppstgOpen);
6132
6133 end:
6134   TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
6135   return hr;
6136 }
6137
6138 /******************************************************************************
6139  *    StgCreateDocfileOnILockBytes    [OLE32.@]
6140  */
6141 HRESULT WINAPI StgCreateDocfileOnILockBytes(
6142       ILockBytes *plkbyt,
6143       DWORD grfMode,
6144       DWORD reserved,
6145       IStorage** ppstgOpen)
6146 {
6147   StorageImpl*   newStorage = 0;
6148   HRESULT        hr         = S_OK;
6149
6150   /*
6151    * Validate the parameters
6152    */
6153   if ((ppstgOpen == 0) || (plkbyt == 0))
6154     return STG_E_INVALIDPOINTER;
6155
6156   /*
6157    * Allocate and initialize the new IStorage object.
6158    */
6159   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6160
6161   if (newStorage == 0)
6162     return STG_E_INSUFFICIENTMEMORY;
6163
6164   hr = StorageImpl_Construct(
6165          newStorage,
6166          0,
6167         0,
6168          plkbyt,
6169          grfMode,
6170          FALSE,
6171          TRUE);
6172
6173   if (FAILED(hr))
6174   {
6175     HeapFree(GetProcessHeap(), 0, newStorage);
6176     return hr;
6177   }
6178
6179   /*
6180    * Get an "out" pointer for the caller.
6181    */
6182   hr = StorageBaseImpl_QueryInterface(
6183          (IStorage*)newStorage,
6184          (REFIID)&IID_IStorage,
6185          (void**)ppstgOpen);
6186
6187   return hr;
6188 }
6189
6190 /******************************************************************************
6191  *    StgOpenStorageOnILockBytes    [OLE32.@]
6192  */
6193 HRESULT WINAPI StgOpenStorageOnILockBytes(
6194       ILockBytes *plkbyt,
6195       IStorage *pstgPriority,
6196       DWORD grfMode,
6197       SNB snbExclude,
6198       DWORD reserved,
6199       IStorage **ppstgOpen)
6200 {
6201   StorageImpl* newStorage = 0;
6202   HRESULT        hr = S_OK;
6203
6204   /*
6205    * Perform a sanity check
6206    */
6207   if ((plkbyt == 0) || (ppstgOpen == 0))
6208     return STG_E_INVALIDPOINTER;
6209
6210   /*
6211    * Validate the STGM flags
6212    */
6213   if ( FAILED( validateSTGM(grfMode) ))
6214     return STG_E_INVALIDFLAG;
6215
6216   /*
6217    * Initialize the "out" parameter.
6218    */
6219   *ppstgOpen = 0;
6220
6221   /*
6222    * Allocate and initialize the new IStorage object.
6223    */
6224   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6225
6226   if (newStorage == 0)
6227     return STG_E_INSUFFICIENTMEMORY;
6228
6229   hr = StorageImpl_Construct(
6230          newStorage,
6231          0,
6232          0,
6233          plkbyt,
6234          grfMode,
6235          FALSE,
6236          FALSE);
6237
6238   if (FAILED(hr))
6239   {
6240     HeapFree(GetProcessHeap(), 0, newStorage);
6241     return hr;
6242   }
6243
6244   /*
6245    * Get an "out" pointer for the caller.
6246    */
6247   hr = StorageBaseImpl_QueryInterface(
6248          (IStorage*)newStorage,
6249          (REFIID)&IID_IStorage,
6250          (void**)ppstgOpen);
6251
6252   return hr;
6253 }
6254
6255 /******************************************************************************
6256  *              StgSetTimes [ole32.@]
6257  *              StgSetTimes [OLE32.@]
6258  *
6259  *
6260  */
6261 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6262                            FILETIME const *patime, FILETIME const *pmtime)
6263 {
6264   IStorage *stg = NULL;
6265   HRESULT r;
6266  
6267   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6268
6269   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6270                      0, 0, &stg);
6271   if( SUCCEEDED(r) )
6272   {
6273     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6274     IStorage_Release(stg);
6275   }
6276
6277   return r;
6278 }
6279
6280 /******************************************************************************
6281  *              StgIsStorageILockBytes        [OLE32.@]
6282  *
6283  * Determines if the ILockBytes contains a storage object.
6284  */
6285 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6286 {
6287   BYTE sig[8];
6288   ULARGE_INTEGER offset;
6289
6290   offset.u.HighPart = 0;
6291   offset.u.LowPart  = 0;
6292
6293   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6294
6295   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6296     return S_OK;
6297
6298   return S_FALSE;
6299 }
6300
6301 /******************************************************************************
6302  *              WriteClassStg        [OLE32.@]
6303  *
6304  * This method will store the specified CLSID in the specified storage object
6305  */
6306 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6307 {
6308   HRESULT hRes;
6309
6310   if(!pStg)
6311     return E_INVALIDARG;
6312
6313   hRes = IStorage_SetClass(pStg, rclsid);
6314
6315   return hRes;
6316 }
6317
6318 /***********************************************************************
6319  *    ReadClassStg (OLE32.@)
6320  *
6321  * This method reads the CLSID previously written to a storage object with
6322  * the WriteClassStg.
6323  *
6324  * PARAMS
6325  *  pstg    [I] IStorage pointer
6326  *  pclsid  [O] Pointer to where the CLSID is written
6327  *
6328  * RETURNS
6329  *  Success: S_OK.
6330  *  Failure: HRESULT code.
6331  */
6332 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6333
6334     STATSTG pstatstg;
6335     HRESULT hRes;
6336
6337     TRACE("(%p, %p)\n", pstg, pclsid);
6338
6339     if(!pstg || !pclsid)
6340         return E_INVALIDARG;
6341
6342    /*
6343     * read a STATSTG structure (contains the clsid) from the storage
6344     */
6345     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
6346
6347     if(SUCCEEDED(hRes))
6348         *pclsid=pstatstg.clsid;
6349
6350     return hRes;
6351 }
6352
6353 /***********************************************************************
6354  *    OleLoadFromStream (OLE32.@)
6355  *
6356  * This function loads an object from stream
6357  */
6358 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6359 {
6360     CLSID       clsid;
6361     HRESULT     res;
6362     LPPERSISTSTREAM     xstm;
6363
6364     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6365
6366     res=ReadClassStm(pStm,&clsid);
6367     if (!SUCCEEDED(res))
6368         return res;
6369     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6370     if (!SUCCEEDED(res))
6371         return res;
6372     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6373     if (!SUCCEEDED(res)) {
6374         IUnknown_Release((IUnknown*)*ppvObj);
6375         return res;
6376     }
6377     res=IPersistStream_Load(xstm,pStm);
6378     IPersistStream_Release(xstm);
6379     /* FIXME: all refcounts ok at this point? I think they should be:
6380      *          pStm    : unchanged
6381      *          ppvObj  : 1
6382      *          xstm    : 0 (released)
6383      */
6384     return res;
6385 }
6386
6387 /***********************************************************************
6388  *    OleSaveToStream (OLE32.@)
6389  *
6390  * This function saves an object with the IPersistStream interface on it
6391  * to the specified stream.
6392  */
6393 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6394 {
6395
6396     CLSID clsid;
6397     HRESULT res;
6398
6399     TRACE("(%p,%p)\n",pPStm,pStm);
6400
6401     res=IPersistStream_GetClassID(pPStm,&clsid);
6402
6403     if (SUCCEEDED(res)){
6404
6405         res=WriteClassStm(pStm,&clsid);
6406
6407         if (SUCCEEDED(res))
6408
6409             res=IPersistStream_Save(pPStm,pStm,TRUE);
6410     }
6411
6412     TRACE("Finished Save\n");
6413     return res;
6414 }
6415
6416 /****************************************************************************
6417  * This method validate a STGM parameter that can contain the values below
6418  *
6419  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6420  * The stgm values contained in 0xffff0000 are bitmasks.
6421  *
6422  * STGM_DIRECT               0x00000000
6423  * STGM_TRANSACTED           0x00010000
6424  * STGM_SIMPLE               0x08000000
6425  *
6426  * STGM_READ                 0x00000000
6427  * STGM_WRITE                0x00000001
6428  * STGM_READWRITE            0x00000002
6429  *
6430  * STGM_SHARE_DENY_NONE      0x00000040
6431  * STGM_SHARE_DENY_READ      0x00000030
6432  * STGM_SHARE_DENY_WRITE     0x00000020
6433  * STGM_SHARE_EXCLUSIVE      0x00000010
6434  *
6435  * STGM_PRIORITY             0x00040000
6436  * STGM_DELETEONRELEASE      0x04000000
6437  *
6438  * STGM_CREATE               0x00001000
6439  * STGM_CONVERT              0x00020000
6440  * STGM_FAILIFTHERE          0x00000000
6441  *
6442  * STGM_NOSCRATCH            0x00100000
6443  * STGM_NOSNAPSHOT           0x00200000
6444  */
6445 static HRESULT validateSTGM(DWORD stgm)
6446 {
6447   DWORD access = STGM_ACCESS_MODE(stgm);
6448   DWORD share  = STGM_SHARE_MODE(stgm);
6449   DWORD create = STGM_CREATE_MODE(stgm);
6450
6451   if (stgm&~STGM_KNOWN_FLAGS)
6452   {
6453     ERR("unknown flags %08x\n", stgm);
6454     return E_FAIL;
6455   }
6456
6457   switch (access)
6458   {
6459   case STGM_READ:
6460   case STGM_WRITE:
6461   case STGM_READWRITE:
6462     break;
6463   default:
6464     return E_FAIL;
6465   }
6466
6467   switch (share)
6468   {
6469   case STGM_SHARE_DENY_NONE:
6470   case STGM_SHARE_DENY_READ:
6471   case STGM_SHARE_DENY_WRITE:
6472   case STGM_SHARE_EXCLUSIVE:
6473     break;
6474   default:
6475     return E_FAIL;
6476   }
6477
6478   switch (create)
6479   {
6480   case STGM_CREATE:
6481   case STGM_FAILIFTHERE:
6482     break;
6483   default:
6484     return E_FAIL;
6485   }
6486
6487   /*
6488    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
6489    */
6490   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
6491       return E_FAIL;
6492
6493   /*
6494    * STGM_CREATE | STGM_CONVERT
6495    * if both are false, STGM_FAILIFTHERE is set to TRUE
6496    */
6497   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
6498     return E_FAIL;
6499
6500   /*
6501    * STGM_NOSCRATCH requires STGM_TRANSACTED
6502    */
6503   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
6504     return E_FAIL;
6505
6506   /*
6507    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
6508    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
6509    */
6510   if ( (stgm & STGM_NOSNAPSHOT) &&
6511         (!(stgm & STGM_TRANSACTED) ||
6512          share == STGM_SHARE_EXCLUSIVE ||
6513          share == STGM_SHARE_DENY_WRITE) )
6514     return E_FAIL;
6515
6516   return S_OK;
6517 }
6518
6519 /****************************************************************************
6520  *      GetShareModeFromSTGM
6521  *
6522  * This method will return a share mode flag from a STGM value.
6523  * The STGM value is assumed valid.
6524  */
6525 static DWORD GetShareModeFromSTGM(DWORD stgm)
6526 {
6527   switch (STGM_SHARE_MODE(stgm))
6528   {
6529   case STGM_SHARE_DENY_NONE:
6530     return FILE_SHARE_READ | FILE_SHARE_WRITE;
6531   case STGM_SHARE_DENY_READ:
6532     return FILE_SHARE_WRITE;
6533   case STGM_SHARE_DENY_WRITE:
6534     return FILE_SHARE_READ;
6535   case STGM_SHARE_EXCLUSIVE:
6536     return 0;
6537   }
6538   ERR("Invalid share mode!\n");
6539   assert(0);
6540   return 0;
6541 }
6542
6543 /****************************************************************************
6544  *      GetAccessModeFromSTGM
6545  *
6546  * This method will return an access mode flag from a STGM value.
6547  * The STGM value is assumed valid.
6548  */
6549 static DWORD GetAccessModeFromSTGM(DWORD stgm)
6550 {
6551   switch (STGM_ACCESS_MODE(stgm))
6552   {
6553   case STGM_READ:
6554     return GENERIC_READ;
6555   case STGM_WRITE:
6556   case STGM_READWRITE:
6557     return GENERIC_READ | GENERIC_WRITE;
6558   }
6559   ERR("Invalid access mode!\n");
6560   assert(0);
6561   return 0;
6562 }
6563
6564 /****************************************************************************
6565  *      GetCreationModeFromSTGM
6566  *
6567  * This method will return a creation mode flag from a STGM value.
6568  * The STGM value is assumed valid.
6569  */
6570 static DWORD GetCreationModeFromSTGM(DWORD stgm)
6571 {
6572   switch(STGM_CREATE_MODE(stgm))
6573   {
6574   case STGM_CREATE:
6575     return CREATE_ALWAYS;
6576   case STGM_CONVERT:
6577     FIXME("STGM_CONVERT not implemented!\n");
6578     return CREATE_NEW;
6579   case STGM_FAILIFTHERE:
6580     return CREATE_NEW;
6581   }
6582   ERR("Invalid create mode!\n");
6583   assert(0);
6584   return 0;
6585 }
6586
6587
6588 /*************************************************************************
6589  * OLECONVERT_LoadOLE10 [Internal]
6590  *
6591  * Loads the OLE10 STREAM to memory
6592  *
6593  * PARAMS
6594  *     pOleStream   [I] The OLESTREAM
6595  *     pData        [I] Data Structure for the OLESTREAM Data
6596  *
6597  * RETURNS
6598  *     Success:  S_OK
6599  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
6600  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
6601  *
6602  * NOTES
6603  *     This function is used by OleConvertOLESTREAMToIStorage only.
6604  *
6605  *     Memory allocated for pData must be freed by the caller
6606  */
6607 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
6608 {
6609         DWORD dwSize;
6610         HRESULT hRes = S_OK;
6611         int nTryCnt=0;
6612         int max_try = 6;
6613
6614         pData->pData = NULL;
6615         pData->pstrOleObjFileName = (CHAR *) NULL;
6616
6617         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
6618         {
6619         /* Get the OleID */
6620         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6621         if(dwSize != sizeof(pData->dwOleID))
6622         {
6623                 hRes = CONVERT10_E_OLESTREAM_GET;
6624         }
6625         else if(pData->dwOleID != OLESTREAM_ID)
6626         {
6627                 hRes = CONVERT10_E_OLESTREAM_FMT;
6628         }
6629                 else
6630                 {
6631                         hRes = S_OK;
6632                         break;
6633                 }
6634         }
6635
6636         if(hRes == S_OK)
6637         {
6638                 /* Get the TypeID...more info needed for this field */
6639                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6640                 if(dwSize != sizeof(pData->dwTypeID))
6641                 {
6642                         hRes = CONVERT10_E_OLESTREAM_GET;
6643                 }
6644         }
6645         if(hRes == S_OK)
6646         {
6647                 if(pData->dwTypeID != 0)
6648                 {
6649                         /* Get the length of the OleTypeName */
6650                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6651                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6652                         {
6653                                 hRes = CONVERT10_E_OLESTREAM_GET;
6654                         }
6655
6656                         if(hRes == S_OK)
6657                         {
6658                                 if(pData->dwOleTypeNameLength > 0)
6659                                 {
6660                                         /* Get the OleTypeName */
6661                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
6662                                         if(dwSize != pData->dwOleTypeNameLength)
6663                                         {
6664                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6665                                         }
6666                                 }
6667                         }
6668                         if(bStrem1)
6669                         {
6670                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6671                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6672                                 {
6673                                         hRes = CONVERT10_E_OLESTREAM_GET;
6674                                 }
6675                         if(hRes == S_OK)
6676                         {
6677                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6678                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6679                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
6680                                         if(pData->pstrOleObjFileName)
6681                                         {
6682                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6683                                                 if(dwSize != pData->dwOleObjFileNameLength)
6684                                                 {
6685                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6686                                                 }
6687                                         }
6688                                         else
6689                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6690                                 }
6691                         }
6692                         else
6693                         {
6694                                 /* Get the Width of the Metafile */
6695                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6696                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
6697                                 {
6698                                         hRes = CONVERT10_E_OLESTREAM_GET;
6699                                 }
6700                         if(hRes == S_OK)
6701                         {
6702                                 /* Get the Height of the Metafile */
6703                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6704                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
6705                                 {
6706                                         hRes = CONVERT10_E_OLESTREAM_GET;
6707                                 }
6708                         }
6709                         }
6710                         if(hRes == S_OK)
6711                         {
6712                                 /* Get the Length of the Data */
6713                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6714                                 if(dwSize != sizeof(pData->dwDataLength))
6715                                 {
6716                                         hRes = CONVERT10_E_OLESTREAM_GET;
6717                                 }
6718                         }
6719
6720                         if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
6721                         {
6722                                 if(!bStrem1) /* if it is a second OLE stream data */
6723                                 {
6724                                         pData->dwDataLength -= 8;
6725                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6726                                         if(dwSize != sizeof(pData->strUnknown))
6727                                         {
6728                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6729                                         }
6730                                 }
6731                         }
6732                         if(hRes == S_OK)
6733                         {
6734                                 if(pData->dwDataLength > 0)
6735                                 {
6736                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6737
6738                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
6739                                         if(pData->pData)
6740                                         {
6741                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6742                                                 if(dwSize != pData->dwDataLength)
6743                                                 {
6744                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6745                                                 }
6746                                         }
6747                                         else
6748                                         {
6749                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6750                                         }
6751                                 }
6752                         }
6753                 }
6754         }
6755         return hRes;
6756 }
6757
6758 /*************************************************************************
6759  * OLECONVERT_SaveOLE10 [Internal]
6760  *
6761  * Saves the OLE10 STREAM From memory
6762  *
6763  * PARAMS
6764  *     pData        [I] Data Structure for the OLESTREAM Data
6765  *     pOleStream   [I] The OLESTREAM to save
6766  *
6767  * RETURNS
6768  *     Success:  S_OK
6769  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
6770  *
6771  * NOTES
6772  *     This function is used by OleConvertIStorageToOLESTREAM only.
6773  *
6774  */
6775 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6776 {
6777     DWORD dwSize;
6778     HRESULT hRes = S_OK;
6779
6780
6781    /* Set the OleID */
6782     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6783     if(dwSize != sizeof(pData->dwOleID))
6784     {
6785         hRes = CONVERT10_E_OLESTREAM_PUT;
6786     }
6787
6788     if(hRes == S_OK)
6789     {
6790         /* Set the TypeID */
6791         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6792         if(dwSize != sizeof(pData->dwTypeID))
6793         {
6794             hRes = CONVERT10_E_OLESTREAM_PUT;
6795         }
6796     }
6797
6798     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6799     {
6800         /* Set the Length of the OleTypeName */
6801         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6802         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6803         {
6804             hRes = CONVERT10_E_OLESTREAM_PUT;
6805         }
6806
6807         if(hRes == S_OK)
6808         {
6809             if(pData->dwOleTypeNameLength > 0)
6810             {
6811                 /* Set the OleTypeName */
6812                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);
6813                 if(dwSize != pData->dwOleTypeNameLength)
6814                 {
6815                     hRes = CONVERT10_E_OLESTREAM_PUT;
6816                 }
6817             }
6818         }
6819
6820         if(hRes == S_OK)
6821         {
6822             /* Set the width of the Metafile */
6823             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6824             if(dwSize != sizeof(pData->dwMetaFileWidth))
6825             {
6826                 hRes = CONVERT10_E_OLESTREAM_PUT;
6827             }
6828         }
6829
6830         if(hRes == S_OK)
6831         {
6832             /* Set the height of the Metafile */
6833             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6834             if(dwSize != sizeof(pData->dwMetaFileHeight))
6835             {
6836                 hRes = CONVERT10_E_OLESTREAM_PUT;
6837             }
6838         }
6839
6840         if(hRes == S_OK)
6841         {
6842             /* Set the length of the Data */
6843             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6844             if(dwSize != sizeof(pData->dwDataLength))
6845             {
6846                 hRes = CONVERT10_E_OLESTREAM_PUT;
6847             }
6848         }
6849
6850         if(hRes == S_OK)
6851         {
6852             if(pData->dwDataLength > 0)
6853             {
6854                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6855                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
6856                 if(dwSize != pData->dwDataLength)
6857                 {
6858                     hRes = CONVERT10_E_OLESTREAM_PUT;
6859                 }
6860             }
6861         }
6862     }
6863     return hRes;
6864 }
6865
6866 /*************************************************************************
6867  * OLECONVERT_GetOLE20FromOLE10[Internal]
6868  *
6869  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6870  * opens it, and copies the content to the dest IStorage for
6871  * OleConvertOLESTREAMToIStorage
6872  *
6873  *
6874  * PARAMS
6875  *     pDestStorage  [I] The IStorage to copy the data to
6876  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
6877  *     nBufferLength [I] The size of the buffer
6878  *
6879  * RETURNS
6880  *     Nothing
6881  *
6882  * NOTES
6883  *
6884  *
6885  */
6886 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6887 {
6888     HRESULT hRes;
6889     HANDLE hFile;
6890     IStorage *pTempStorage;
6891     DWORD dwNumOfBytesWritten;
6892     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6893     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6894
6895     /* Create a temp File */
6896     GetTempPathW(MAX_PATH, wstrTempDir);
6897     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6898     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6899
6900     if(hFile != INVALID_HANDLE_VALUE)
6901     {
6902         /* Write IStorage Data to File */
6903         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6904         CloseHandle(hFile);
6905
6906         /* Open and copy temp storage to the Dest Storage */
6907         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6908         if(hRes == S_OK)
6909         {
6910             hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6911             StorageBaseImpl_Release(pTempStorage);
6912         }
6913         DeleteFileW(wstrTempFile);
6914     }
6915 }
6916
6917
6918 /*************************************************************************
6919  * OLECONVERT_WriteOLE20ToBuffer [Internal]
6920  *
6921  * Saves the OLE10 STREAM From memory
6922  *
6923  * PARAMS
6924  *     pStorage  [I] The Src IStorage to copy
6925  *     pData     [I] The Dest Memory to write to.
6926  *
6927  * RETURNS
6928  *     The size in bytes allocated for pData
6929  *
6930  * NOTES
6931  *     Memory allocated for pData must be freed by the caller
6932  *
6933  *     Used by OleConvertIStorageToOLESTREAM only.
6934  *
6935  */
6936 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6937 {
6938     HANDLE hFile;
6939     HRESULT hRes;
6940     DWORD nDataLength = 0;
6941     IStorage *pTempStorage;
6942     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6943     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6944
6945     *pData = NULL;
6946
6947     /* Create temp Storage */
6948     GetTempPathW(MAX_PATH, wstrTempDir);
6949     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6950     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6951
6952     if(hRes == S_OK)
6953     {
6954         /* Copy Src Storage to the Temp Storage */
6955         StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6956         StorageBaseImpl_Release(pTempStorage);
6957
6958         /* Open Temp Storage as a file and copy to memory */
6959         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6960         if(hFile != INVALID_HANDLE_VALUE)
6961         {
6962             nDataLength = GetFileSize(hFile, NULL);
6963             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
6964             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6965             CloseHandle(hFile);
6966         }
6967         DeleteFileW(wstrTempFile);
6968     }
6969     return nDataLength;
6970 }
6971
6972 /*************************************************************************
6973  * OLECONVERT_CreateOleStream [Internal]
6974  *
6975  * Creates the "\001OLE" stream in the IStorage if necessary.
6976  *
6977  * PARAMS
6978  *     pStorage     [I] Dest storage to create the stream in
6979  *
6980  * RETURNS
6981  *     Nothing
6982  *
6983  * NOTES
6984  *     This function is used by OleConvertOLESTREAMToIStorage only.
6985  *
6986  *     This stream is still unknown, MS Word seems to have extra data
6987  *     but since the data is stored in the OLESTREAM there should be
6988  *     no need to recreate the stream.  If the stream is manually
6989  *     deleted it will create it with this default data.
6990  *
6991  */
6992 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6993 {
6994     HRESULT hRes;
6995     IStream *pStream;
6996     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6997     BYTE pOleStreamHeader [] =
6998     {
6999         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
7000         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7001         0x00, 0x00, 0x00, 0x00
7002     };
7003
7004     /* Create stream if not present */
7005     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7006         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7007
7008     if(hRes == S_OK)
7009     {
7010         /* Write default Data */
7011         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
7012         IStream_Release(pStream);
7013     }
7014 }
7015
7016 /* write a string to a stream, preceded by its length */
7017 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
7018 {
7019     HRESULT r;
7020     LPSTR str;
7021     DWORD len = 0;
7022
7023     if( string )
7024         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
7025     r = IStream_Write( stm, &len, sizeof(len), NULL);
7026     if( FAILED( r ) )
7027         return r;
7028     if(len == 0)
7029         return r;
7030     str = CoTaskMemAlloc( len );
7031     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
7032     r = IStream_Write( stm, str, len, NULL);
7033     CoTaskMemFree( str );
7034     return r;
7035 }
7036
7037 /* read a string preceded by its length from a stream */
7038 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
7039 {
7040     HRESULT r;
7041     DWORD len, count = 0;
7042     LPSTR str;
7043     LPWSTR wstr;
7044
7045     r = IStream_Read( stm, &len, sizeof(len), &count );
7046     if( FAILED( r ) )
7047         return r;
7048     if( count != sizeof(len) )
7049         return E_OUTOFMEMORY;
7050
7051     TRACE("%d bytes\n",len);
7052     
7053     str = CoTaskMemAlloc( len );
7054     if( !str )
7055         return E_OUTOFMEMORY;
7056     count = 0;
7057     r = IStream_Read( stm, str, len, &count );
7058     if( FAILED( r ) )
7059         return r;
7060     if( count != len )
7061     {
7062         CoTaskMemFree( str );
7063         return E_OUTOFMEMORY;
7064     }
7065
7066     TRACE("Read string %s\n",debugstr_an(str,len));
7067
7068     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
7069     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
7070     if( wstr )
7071          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
7072     CoTaskMemFree( str );
7073
7074     *string = wstr;
7075
7076     return r;
7077 }
7078
7079
7080 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
7081     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
7082 {
7083     IStream *pstm;
7084     HRESULT r = S_OK;
7085     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7086
7087     static const BYTE unknown1[12] =
7088        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
7089          0xFF, 0xFF, 0xFF, 0xFF};
7090     static const BYTE unknown2[16] =
7091        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
7092          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
7093
7094     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
7095            debugstr_w(lpszUserType), debugstr_w(szClipName),
7096            debugstr_w(szProgIDName));
7097
7098     /*  Create a CompObj stream if it doesn't exist */
7099     r = IStorage_CreateStream(pstg, szwStreamName,
7100         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
7101     if( FAILED (r) )
7102         return r;
7103
7104     /* Write CompObj Structure to stream */
7105     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
7106
7107     if( SUCCEEDED( r ) )
7108         r = WriteClassStm( pstm, clsid );
7109
7110     if( SUCCEEDED( r ) )
7111         r = STREAM_WriteString( pstm, lpszUserType );
7112     if( SUCCEEDED( r ) )
7113         r = STREAM_WriteString( pstm, szClipName );
7114     if( SUCCEEDED( r ) )
7115         r = STREAM_WriteString( pstm, szProgIDName );
7116     if( SUCCEEDED( r ) )
7117         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
7118
7119     IStream_Release( pstm );
7120
7121     return r;
7122 }
7123
7124 /***********************************************************************
7125  *               WriteFmtUserTypeStg (OLE32.@)
7126  */
7127 HRESULT WINAPI WriteFmtUserTypeStg(
7128           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
7129 {
7130     HRESULT r;
7131     WCHAR szwClipName[0x40];
7132     CLSID clsid = CLSID_NULL;
7133     LPWSTR wstrProgID = NULL;
7134     DWORD n;
7135
7136     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
7137
7138     /* get the clipboard format name */
7139     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
7140     szwClipName[n]=0;
7141
7142     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
7143
7144     /* FIXME: There's room to save a CLSID and its ProgID, but
7145        the CLSID is not looked up in the registry and in all the
7146        tests I wrote it was CLSID_NULL.  Where does it come from?
7147     */
7148
7149     /* get the real program ID.  This may fail, but that's fine */
7150     ProgIDFromCLSID(&clsid, &wstrProgID);
7151
7152     TRACE("progid is %s\n",debugstr_w(wstrProgID));
7153
7154     r = STORAGE_WriteCompObj( pstg, &clsid, 
7155                               lpszUserType, szwClipName, wstrProgID );
7156
7157     CoTaskMemFree(wstrProgID);
7158
7159     return r;
7160 }
7161
7162
7163 /******************************************************************************
7164  *              ReadFmtUserTypeStg        [OLE32.@]
7165  */
7166 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
7167 {
7168     HRESULT r;
7169     IStream *stm = 0;
7170     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
7171     unsigned char unknown1[12];
7172     unsigned char unknown2[16];
7173     DWORD count;
7174     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
7175     CLSID clsid;
7176
7177     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
7178
7179     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
7180                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
7181     if( FAILED ( r ) )
7182     {
7183         WARN("Failed to open stream r = %08x\n", r);
7184         return r;
7185     }
7186
7187     /* read the various parts of the structure */
7188     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
7189     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
7190         goto end;
7191     r = ReadClassStm( stm, &clsid );
7192     if( FAILED( r ) )
7193         goto end;
7194
7195     r = STREAM_ReadString( stm, &szCLSIDName );
7196     if( FAILED( r ) )
7197         goto end;
7198
7199     r = STREAM_ReadString( stm, &szOleTypeName );
7200     if( FAILED( r ) )
7201         goto end;
7202
7203     r = STREAM_ReadString( stm, &szProgIDName );
7204     if( FAILED( r ) )
7205         goto end;
7206
7207     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7208     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7209         goto end;
7210
7211     /* ok, success... now we just need to store what we found */
7212     if( pcf )
7213         *pcf = RegisterClipboardFormatW( szOleTypeName );
7214     CoTaskMemFree( szOleTypeName );
7215
7216     if( lplpszUserType )
7217         *lplpszUserType = szCLSIDName;
7218     CoTaskMemFree( szProgIDName );
7219
7220 end:
7221     IStream_Release( stm );
7222
7223     return r;
7224 }
7225
7226
7227 /*************************************************************************
7228  * OLECONVERT_CreateCompObjStream [Internal]
7229  *
7230  * Creates a "\001CompObj" is the destination IStorage if necessary.
7231  *
7232  * PARAMS
7233  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7234  *                        if necessary.
7235  *     strOleTypeName [I] The ProgID
7236  *
7237  * RETURNS
7238  *     Success:  S_OK
7239  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7240  *
7241  * NOTES
7242  *     This function is used by OleConvertOLESTREAMToIStorage only.
7243  *
7244  *     The stream data is stored in the OLESTREAM and there should be
7245  *     no need to recreate the stream.  If the stream is manually
7246  *     deleted it will attempt to create it by querying the registry.
7247  *
7248  *
7249  */
7250 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7251 {
7252     IStream *pStream;
7253     HRESULT hStorageRes, hRes = S_OK;
7254     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7255     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7256     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7257
7258     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7259     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7260
7261     /* Initialize the CompObj structure */
7262     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7263     memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
7264     memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
7265
7266
7267     /*  Create a CompObj stream if it doesn't exist */
7268     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7269         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7270     if(hStorageRes == S_OK)
7271     {
7272         /* copy the OleTypeName to the compobj struct */
7273         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7274         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7275
7276         /* copy the OleTypeName to the compobj struct */
7277         /* Note: in the test made, these were Identical      */
7278         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7279         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7280
7281         /* Get the CLSID */
7282         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7283                              bufferW, OLESTREAM_MAX_STR_LEN );
7284         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7285
7286         if(hRes == S_OK)
7287         {
7288             HKEY hKey;
7289             LONG hErr;
7290             /* Get the CLSID Default Name from the Registry */
7291             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7292             if(hErr == ERROR_SUCCESS)
7293             {
7294                 char strTemp[OLESTREAM_MAX_STR_LEN];
7295                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7296                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7297                 if(hErr == ERROR_SUCCESS)
7298                 {
7299                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7300                 }
7301                 RegCloseKey(hKey);
7302             }
7303         }
7304
7305         /* Write CompObj Structure to stream */
7306         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7307
7308         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7309
7310         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7311         if(IStorageCompObj.dwCLSIDNameLength > 0)
7312         {
7313             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7314         }
7315         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7316         if(IStorageCompObj.dwOleTypeNameLength > 0)
7317         {
7318             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7319         }
7320         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7321         if(IStorageCompObj.dwProgIDNameLength > 0)
7322         {
7323             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7324         }
7325         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7326         IStream_Release(pStream);
7327     }
7328     return hRes;
7329 }
7330
7331
7332 /*************************************************************************
7333  * OLECONVERT_CreateOlePresStream[Internal]
7334  *
7335  * Creates the "\002OlePres000" Stream with the Metafile data
7336  *
7337  * PARAMS
7338  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7339  *     dwExtentX    [I] Width of the Metafile
7340  *     dwExtentY    [I] Height of the Metafile
7341  *     pData        [I] Metafile data
7342  *     dwDataLength [I] Size of the Metafile data
7343  *
7344  * RETURNS
7345  *     Success:  S_OK
7346  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7347  *
7348  * NOTES
7349  *     This function is used by OleConvertOLESTREAMToIStorage only.
7350  *
7351  */
7352 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7353 {
7354     HRESULT hRes;
7355     IStream *pStream;
7356     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7357     BYTE pOlePresStreamHeader [] =
7358     {
7359         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7360         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7361         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7362         0x00, 0x00, 0x00, 0x00
7363     };
7364
7365     BYTE pOlePresStreamHeaderEmpty [] =
7366     {
7367         0x00, 0x00, 0x00, 0x00,
7368         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7369         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7370         0x00, 0x00, 0x00, 0x00
7371     };
7372
7373     /* Create the OlePres000 Stream */
7374     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7375         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7376
7377     if(hRes == S_OK)
7378     {
7379         DWORD nHeaderSize;
7380         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7381
7382         memset(&OlePres, 0, sizeof(OlePres));
7383         /* Do we have any metafile data to save */
7384         if(dwDataLength > 0)
7385         {
7386             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7387             nHeaderSize = sizeof(pOlePresStreamHeader);
7388         }
7389         else
7390         {
7391             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7392             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7393         }
7394         /* Set width and height of the metafile */
7395         OlePres.dwExtentX = dwExtentX;
7396         OlePres.dwExtentY = -dwExtentY;
7397
7398         /* Set Data and Length */
7399         if(dwDataLength > sizeof(METAFILEPICT16))
7400         {
7401             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7402             OlePres.pData = &(pData[8]);
7403         }
7404         /* Save OlePres000 Data to Stream */
7405         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7406         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7407         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7408         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7409         if(OlePres.dwSize > 0)
7410         {
7411             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7412         }
7413         IStream_Release(pStream);
7414     }
7415 }
7416
7417 /*************************************************************************
7418  * OLECONVERT_CreateOle10NativeStream [Internal]
7419  *
7420  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7421  *
7422  * PARAMS
7423  *     pStorage     [I] Dest storage to create the stream in
7424  *     pData        [I] Ole10 Native Data (ex. bmp)
7425  *     dwDataLength [I] Size of the Ole10 Native Data
7426  *
7427  * RETURNS
7428  *     Nothing
7429  *
7430  * NOTES
7431  *     This function is used by OleConvertOLESTREAMToIStorage only.
7432  *
7433  *     Might need to verify the data and return appropriate error message
7434  *
7435  */
7436 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
7437 {
7438     HRESULT hRes;
7439     IStream *pStream;
7440     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7441
7442     /* Create the Ole10Native Stream */
7443     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7444         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7445
7446     if(hRes == S_OK)
7447     {
7448         /* Write info to stream */
7449         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7450         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7451         IStream_Release(pStream);
7452     }
7453
7454 }
7455
7456 /*************************************************************************
7457  * OLECONVERT_GetOLE10ProgID [Internal]
7458  *
7459  * Finds the ProgID (or OleTypeID) from the IStorage
7460  *
7461  * PARAMS
7462  *     pStorage        [I] The Src IStorage to get the ProgID
7463  *     strProgID       [I] the ProgID string to get
7464  *     dwSize          [I] the size of the string
7465  *
7466  * RETURNS
7467  *     Success:  S_OK
7468  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7469  *
7470  * NOTES
7471  *     This function is used by OleConvertIStorageToOLESTREAM only.
7472  *
7473  *
7474  */
7475 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7476 {
7477     HRESULT hRes;
7478     IStream *pStream;
7479     LARGE_INTEGER iSeekPos;
7480     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
7481     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7482
7483     /* Open the CompObj Stream */
7484     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7485         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7486     if(hRes == S_OK)
7487     {
7488
7489         /*Get the OleType from the CompObj Stream */
7490         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
7491         iSeekPos.u.HighPart = 0;
7492
7493         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7494         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
7495         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
7496         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7497         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
7498         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
7499         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7500
7501         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
7502         if(*dwSize > 0)
7503         {
7504             IStream_Read(pStream, strProgID, *dwSize, NULL);
7505         }
7506         IStream_Release(pStream);
7507     }
7508     else
7509     {
7510         STATSTG stat;
7511         LPOLESTR wstrProgID;
7512
7513         /* Get the OleType from the registry */
7514         REFCLSID clsid = &(stat.clsid);
7515         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
7516         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
7517         if(hRes == S_OK)
7518         {
7519             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
7520         }
7521
7522     }
7523     return hRes;
7524 }
7525
7526 /*************************************************************************
7527  * OLECONVERT_GetOle10PresData [Internal]
7528  *
7529  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
7530  *
7531  * PARAMS
7532  *     pStorage     [I] Src IStroage
7533  *     pOleStream   [I] Dest OleStream Mem Struct
7534  *
7535  * RETURNS
7536  *     Nothing
7537  *
7538  * NOTES
7539  *     This function is used by OleConvertIStorageToOLESTREAM only.
7540  *
7541  *     Memory allocated for pData must be freed by the caller
7542  *
7543  *
7544  */
7545 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7546 {
7547
7548     HRESULT hRes;
7549     IStream *pStream;
7550     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7551
7552     /* Initialize Default data for OLESTREAM */
7553     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7554     pOleStreamData[0].dwTypeID = 2;
7555     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7556     pOleStreamData[1].dwTypeID = 0;
7557     pOleStreamData[0].dwMetaFileWidth = 0;
7558     pOleStreamData[0].dwMetaFileHeight = 0;
7559     pOleStreamData[0].pData = NULL;
7560     pOleStreamData[1].pData = NULL;
7561
7562     /* Open Ole10Native Stream */
7563     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7564         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7565     if(hRes == S_OK)
7566     {
7567
7568         /* Read Size and Data */
7569         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
7570         if(pOleStreamData->dwDataLength > 0)
7571         {
7572             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
7573             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
7574         }
7575         IStream_Release(pStream);
7576     }
7577
7578 }
7579
7580
7581 /*************************************************************************
7582  * OLECONVERT_GetOle20PresData[Internal]
7583  *
7584  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
7585  *
7586  * PARAMS
7587  *     pStorage         [I] Src IStroage
7588  *     pOleStreamData   [I] Dest OleStream Mem Struct
7589  *
7590  * RETURNS
7591  *     Nothing
7592  *
7593  * NOTES
7594  *     This function is used by OleConvertIStorageToOLESTREAM only.
7595  *
7596  *     Memory allocated for pData must be freed by the caller
7597  */
7598 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7599 {
7600     HRESULT hRes;
7601     IStream *pStream;
7602     OLECONVERT_ISTORAGE_OLEPRES olePress;
7603     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7604
7605     /* Initialize Default data for OLESTREAM */
7606     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7607     pOleStreamData[0].dwTypeID = 2;
7608     pOleStreamData[0].dwMetaFileWidth = 0;
7609     pOleStreamData[0].dwMetaFileHeight = 0;
7610     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
7611     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7612     pOleStreamData[1].dwTypeID = 0;
7613     pOleStreamData[1].dwOleTypeNameLength = 0;
7614     pOleStreamData[1].strOleTypeName[0] = 0;
7615     pOleStreamData[1].dwMetaFileWidth = 0;
7616     pOleStreamData[1].dwMetaFileHeight = 0;
7617     pOleStreamData[1].pData = NULL;
7618     pOleStreamData[1].dwDataLength = 0;
7619
7620
7621     /* Open OlePress000 stream */
7622     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7623         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7624     if(hRes == S_OK)
7625     {
7626         LARGE_INTEGER iSeekPos;
7627         METAFILEPICT16 MetaFilePict;
7628         static const char strMetafilePictName[] = "METAFILEPICT";
7629
7630         /* Set the TypeID for a Metafile */
7631         pOleStreamData[1].dwTypeID = 5;
7632
7633         /* Set the OleTypeName to Metafile */
7634         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
7635         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
7636
7637         iSeekPos.u.HighPart = 0;
7638         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
7639
7640         /* Get Presentation Data */
7641         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7642         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
7643         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
7644         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
7645
7646         /*Set width and Height */
7647         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
7648         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
7649         if(olePress.dwSize > 0)
7650         {
7651             /* Set Length */
7652             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
7653
7654             /* Set MetaFilePict struct */
7655             MetaFilePict.mm = 8;
7656             MetaFilePict.xExt = olePress.dwExtentX;
7657             MetaFilePict.yExt = olePress.dwExtentY;
7658             MetaFilePict.hMF = 0;
7659
7660             /* Get Metafile Data */
7661             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
7662             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
7663             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
7664         }
7665         IStream_Release(pStream);
7666     }
7667 }
7668
7669 /*************************************************************************
7670  * OleConvertOLESTREAMToIStorage [OLE32.@]
7671  *
7672  * Read info on MSDN
7673  *
7674  * TODO
7675  *      DVTARGETDEVICE paramenter is not handled
7676  *      Still unsure of some mem fields for OLE 10 Stream
7677  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7678  *      and "\001OLE" streams
7679  *
7680  */
7681 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
7682     LPOLESTREAM pOleStream,
7683     LPSTORAGE pstg,
7684     const DVTARGETDEVICE* ptd)
7685 {
7686     int i;
7687     HRESULT hRes=S_OK;
7688     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7689
7690     TRACE("%p %p %p\n", pOleStream, pstg, ptd);
7691
7692     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7693
7694     if(ptd != NULL)
7695     {
7696         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
7697     }
7698
7699     if(pstg == NULL || pOleStream == NULL)
7700     {
7701         hRes = E_INVALIDARG;
7702     }
7703
7704     if(hRes == S_OK)
7705     {
7706         /* Load the OLESTREAM to Memory */
7707         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
7708     }
7709
7710     if(hRes == S_OK)
7711     {
7712         /* Load the OLESTREAM to Memory (part 2)*/
7713         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
7714     }
7715
7716     if(hRes == S_OK)
7717     {
7718
7719         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
7720         {
7721             /* Do we have the IStorage Data in the OLESTREAM */
7722             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
7723             {
7724                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7725                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
7726             }
7727             else
7728             {
7729                 /* It must be an original OLE 1.0 source */
7730                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7731             }
7732         }
7733         else
7734         {
7735             /* It must be an original OLE 1.0 source */
7736             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7737         }
7738
7739         /* Create CompObj Stream if necessary */
7740         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
7741         if(hRes == S_OK)
7742         {
7743             /*Create the Ole Stream if necessary */
7744             OLECONVERT_CreateOleStream(pstg);
7745         }
7746     }
7747
7748
7749     /* Free allocated memory */
7750     for(i=0; i < 2; i++)
7751     {
7752         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7753         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
7754         pOleStreamData[i].pstrOleObjFileName = NULL;
7755     }
7756     return hRes;
7757 }
7758
7759 /*************************************************************************
7760  * OleConvertIStorageToOLESTREAM [OLE32.@]
7761  *
7762  * Read info on MSDN
7763  *
7764  * Read info on MSDN
7765  *
7766  * TODO
7767  *      Still unsure of some mem fields for OLE 10 Stream
7768  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7769  *      and "\001OLE" streams.
7770  *
7771  */
7772 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
7773     LPSTORAGE pstg,
7774     LPOLESTREAM pOleStream)
7775 {
7776     int i;
7777     HRESULT hRes = S_OK;
7778     IStream *pStream;
7779     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7780     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7781
7782     TRACE("%p %p\n", pstg, pOleStream);
7783
7784     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7785
7786     if(pstg == NULL || pOleStream == NULL)
7787     {
7788         hRes = E_INVALIDARG;
7789     }
7790     if(hRes == S_OK)
7791     {
7792         /* Get the ProgID */
7793         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
7794         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
7795     }
7796     if(hRes == S_OK)
7797     {
7798         /* Was it originally Ole10 */
7799         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
7800         if(hRes == S_OK)
7801         {
7802             IStream_Release(pStream);
7803             /* Get Presentation Data for Ole10Native */
7804             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
7805         }
7806         else
7807         {
7808             /* Get Presentation Data (OLE20) */
7809             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
7810         }
7811
7812         /* Save OLESTREAM */
7813         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
7814         if(hRes == S_OK)
7815         {
7816             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
7817         }
7818
7819     }
7820
7821     /* Free allocated memory */
7822     for(i=0; i < 2; i++)
7823     {
7824         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7825     }
7826
7827     return hRes;
7828 }
7829
7830 /***********************************************************************
7831  *              GetConvertStg (OLE32.@)
7832  */
7833 HRESULT WINAPI GetConvertStg(IStorage *stg) {
7834     FIXME("unimplemented stub!\n");
7835     return E_FAIL;
7836 }
7837
7838 /******************************************************************************
7839  * StgIsStorageFile [OLE32.@]
7840  * Verify if the file contains a storage object
7841  *
7842  * PARAMS
7843  *  fn      [ I] Filename
7844  *
7845  * RETURNS
7846  *  S_OK    if file has magic bytes as a storage object
7847  *  S_FALSE if file is not storage
7848  */
7849 HRESULT WINAPI
7850 StgIsStorageFile(LPCOLESTR fn)
7851 {
7852         HANDLE          hf;
7853         BYTE            magic[8];
7854         DWORD           bytes_read;
7855
7856         TRACE("%s\n", debugstr_w(fn));
7857         hf = CreateFileW(fn, GENERIC_READ,
7858                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
7859                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7860
7861         if (hf == INVALID_HANDLE_VALUE)
7862                 return STG_E_FILENOTFOUND;
7863
7864         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
7865         {
7866                 WARN(" unable to read file\n");
7867                 CloseHandle(hf);
7868                 return S_FALSE;
7869         }
7870
7871         CloseHandle(hf);
7872
7873         if (bytes_read != 8) {
7874                 WARN(" too short\n");
7875                 return S_FALSE;
7876         }
7877
7878         if (!memcmp(magic,STORAGE_magic,8)) {
7879                 WARN(" -> YES\n");
7880                 return S_OK;
7881         }
7882
7883         WARN(" -> Invalid header.\n");
7884         return S_FALSE;
7885 }
7886
7887 /***********************************************************************
7888  *              WriteClassStm (OLE32.@)
7889  *
7890  * Writes a CLSID to a stream.
7891  *
7892  * PARAMS
7893  *  pStm   [I] Stream to write to.
7894  *  rclsid [I] CLSID to write.
7895  *
7896  * RETURNS
7897  *  Success: S_OK.
7898  *  Failure: HRESULT code.
7899  */
7900 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
7901 {
7902     TRACE("(%p,%p)\n",pStm,rclsid);
7903
7904     if (rclsid==NULL)
7905         return E_INVALIDARG;
7906
7907     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
7908 }
7909
7910 /***********************************************************************
7911  *              ReadClassStm (OLE32.@)
7912  *
7913  * Reads a CLSID from a stream.
7914  *
7915  * PARAMS
7916  *  pStm   [I] Stream to read from.
7917  *  rclsid [O] CLSID to read.
7918  *
7919  * RETURNS
7920  *  Success: S_OK.
7921  *  Failure: HRESULT code.
7922  */
7923 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
7924 {
7925     ULONG nbByte;
7926     HRESULT res;
7927
7928     TRACE("(%p,%p)\n",pStm,pclsid);
7929
7930     if (pclsid==NULL)
7931         return E_INVALIDARG;
7932
7933     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
7934
7935     if (FAILED(res))
7936         return res;
7937
7938     if (nbByte != sizeof(CLSID))
7939         return S_FALSE;
7940     else
7941         return S_OK;
7942 }