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