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