wintrust: Add a helper function to initialize chain creation parameters.
[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       else
5198         StorageImpl_SaveFileHeader(This->parentStorage);
5199     }
5200   }
5201
5202   smallBlocksPerBigBlock =
5203     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
5204
5205   /*
5206    * Verify if we have to allocate big blocks to contain small blocks
5207    */
5208   if (blockIndex % smallBlocksPerBigBlock == 0)
5209   {
5210     StgProperty rootProp;
5211     ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
5212
5213     StorageImpl_ReadProperty(
5214       This->parentStorage,
5215       This->parentStorage->base.rootPropertySetIndex,
5216       &rootProp);
5217
5218     if (rootProp.size.u.LowPart <
5219        (blocksRequired * This->parentStorage->bigBlockSize))
5220     {
5221       rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;
5222
5223       BlockChainStream_SetSize(
5224         This->parentStorage->smallBlockRootChain,
5225         rootProp.size);
5226
5227       StorageImpl_WriteProperty(
5228         This->parentStorage,
5229         This->parentStorage->base.rootPropertySetIndex,
5230         &rootProp);
5231     }
5232   }
5233
5234   return blockIndex;
5235 }
5236
5237 /******************************************************************************
5238  *      SmallBlockChainStream_ReadAt
5239  *
5240  * Reads a specified number of bytes from this chain at the specified offset.
5241  * bytesRead may be NULL.
5242  * Failure will be returned if the specified number of bytes has not been read.
5243  */
5244 HRESULT SmallBlockChainStream_ReadAt(
5245   SmallBlockChainStream* This,
5246   ULARGE_INTEGER         offset,
5247   ULONG                  size,
5248   void*                  buffer,
5249   ULONG*                 bytesRead)
5250 {
5251   HRESULT rc = S_OK;
5252   ULARGE_INTEGER offsetInBigBlockFile;
5253   ULONG blockNoInSequence =
5254     offset.u.LowPart / This->parentStorage->smallBlockSize;
5255
5256   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5257   ULONG bytesToReadInBuffer;
5258   ULONG blockIndex;
5259   ULONG bytesReadFromBigBlockFile;
5260   BYTE* bufferWalker;
5261
5262   /*
5263    * This should never happen on a small block file.
5264    */
5265   assert(offset.u.HighPart==0);
5266
5267   /*
5268    * Find the first block in the stream that contains part of the buffer.
5269    */
5270   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5271
5272   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5273   {
5274     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5275     if(FAILED(rc))
5276       return rc;
5277     blockNoInSequence--;
5278   }
5279
5280   /*
5281    * Start reading the buffer.
5282    */
5283   *bytesRead   = 0;
5284   bufferWalker = buffer;
5285
5286   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5287   {
5288     /*
5289      * Calculate how many bytes we can copy from this small block.
5290      */
5291     bytesToReadInBuffer =
5292       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5293
5294     /*
5295      * Calculate the offset of the small block in the small block file.
5296      */
5297     offsetInBigBlockFile.u.HighPart  = 0;
5298     offsetInBigBlockFile.u.LowPart   =
5299       blockIndex * This->parentStorage->smallBlockSize;
5300
5301     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5302
5303     /*
5304      * Read those bytes in the buffer from the small block file.
5305      * The small block has already been identified so it shouldn't fail
5306      * unless the file is corrupt.
5307      */
5308     rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
5309       offsetInBigBlockFile,
5310       bytesToReadInBuffer,
5311       bufferWalker,
5312       &bytesReadFromBigBlockFile);
5313
5314     if (FAILED(rc))
5315       return rc;
5316
5317     /*
5318      * Step to the next big block.
5319      */
5320     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5321     if(FAILED(rc))
5322       return STG_E_DOCFILECORRUPT;
5323
5324     bufferWalker += bytesReadFromBigBlockFile;
5325     size         -= bytesReadFromBigBlockFile;
5326     *bytesRead   += bytesReadFromBigBlockFile;
5327     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
5328   }
5329
5330   return (size == 0) ? S_OK : STG_E_READFAULT;
5331 }
5332
5333 /******************************************************************************
5334  *       SmallBlockChainStream_WriteAt
5335  *
5336  * Writes the specified number of bytes to this chain at the specified offset.
5337  * bytesWritten may be NULL.
5338  * Will fail if not all specified number of bytes have been written.
5339  */
5340 HRESULT SmallBlockChainStream_WriteAt(
5341   SmallBlockChainStream* This,
5342   ULARGE_INTEGER offset,
5343   ULONG          size,
5344   const void*    buffer,
5345   ULONG*         bytesWritten)
5346 {
5347   ULARGE_INTEGER offsetInBigBlockFile;
5348   ULONG blockNoInSequence =
5349     offset.u.LowPart / This->parentStorage->smallBlockSize;
5350
5351   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5352   ULONG bytesToWriteInBuffer;
5353   ULONG blockIndex;
5354   ULONG bytesWrittenToBigBlockFile;
5355   const BYTE* bufferWalker;
5356   HRESULT res;
5357
5358   /*
5359    * This should never happen on a small block file.
5360    */
5361   assert(offset.u.HighPart==0);
5362
5363   /*
5364    * Find the first block in the stream that contains part of the buffer.
5365    */
5366   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5367
5368   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5369   {
5370     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
5371       return STG_E_DOCFILECORRUPT;
5372     blockNoInSequence--;
5373   }
5374
5375   /*
5376    * Start writing the buffer.
5377    *
5378    * Here, I'm casting away the constness on the buffer variable
5379    * This is OK since we don't intend to modify that buffer.
5380    */
5381   *bytesWritten   = 0;
5382   bufferWalker = (const BYTE*)buffer;
5383   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5384   {
5385     /*
5386      * Calculate how many bytes we can copy to this small block.
5387      */
5388     bytesToWriteInBuffer =
5389       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5390
5391     /*
5392      * Calculate the offset of the small block in the small block file.
5393      */
5394     offsetInBigBlockFile.u.HighPart  = 0;
5395     offsetInBigBlockFile.u.LowPart   =
5396       blockIndex * This->parentStorage->smallBlockSize;
5397
5398     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5399
5400     /*
5401      * Write those bytes in the buffer to the small block file.
5402      */
5403     res = BlockChainStream_WriteAt(
5404       This->parentStorage->smallBlockRootChain,
5405       offsetInBigBlockFile,
5406       bytesToWriteInBuffer,
5407       bufferWalker,
5408       &bytesWrittenToBigBlockFile);
5409     if (FAILED(res))
5410       return res;
5411
5412     /*
5413      * Step to the next big block.
5414      */
5415     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5416                                                         &blockIndex)))
5417       return FALSE;
5418     bufferWalker  += bytesWrittenToBigBlockFile;
5419     size          -= bytesWrittenToBigBlockFile;
5420     *bytesWritten += bytesWrittenToBigBlockFile;
5421     offsetInBlock  = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
5422   }
5423
5424   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
5425 }
5426
5427 /******************************************************************************
5428  *       SmallBlockChainStream_Shrink
5429  *
5430  * Shrinks this chain in the small block depot.
5431  */
5432 static BOOL SmallBlockChainStream_Shrink(
5433   SmallBlockChainStream* This,
5434   ULARGE_INTEGER newSize)
5435 {
5436   ULONG blockIndex, extraBlock;
5437   ULONG numBlocks;
5438   ULONG count = 0;
5439
5440   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5441
5442   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5443     numBlocks++;
5444
5445   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5446
5447   /*
5448    * Go to the new end of chain
5449    */
5450   while (count < numBlocks)
5451   {
5452     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5453                                                         &blockIndex)))
5454       return FALSE;
5455     count++;
5456   }
5457
5458   /*
5459    * If the count is 0, we have a special case, the head of the chain was
5460    * just freed.
5461    */
5462   if (count == 0)
5463   {
5464     StgProperty chainProp;
5465
5466     StorageImpl_ReadProperty(This->parentStorage,
5467                              This->ownerPropertyIndex,
5468                              &chainProp);
5469
5470     chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5471
5472     StorageImpl_WriteProperty(This->parentStorage,
5473                               This->ownerPropertyIndex,
5474                               &chainProp);
5475
5476     /*
5477      * We start freeing the chain at the head block.
5478      */
5479     extraBlock = blockIndex;
5480   }
5481   else
5482   {
5483     /* Get the next block before marking the new end */
5484     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5485                                                         &extraBlock)))
5486       return FALSE;
5487
5488     /* Mark the new end of chain */
5489     SmallBlockChainStream_SetNextBlockInChain(
5490       This,
5491       blockIndex,
5492       BLOCK_END_OF_CHAIN);
5493   }
5494
5495   /*
5496    * Mark the extra blocks as free
5497    */
5498   while (extraBlock != BLOCK_END_OF_CHAIN)
5499   {
5500     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
5501                                                         &blockIndex)))
5502       return FALSE;
5503     SmallBlockChainStream_FreeBlock(This, extraBlock);
5504     extraBlock = blockIndex;
5505   }
5506
5507   return TRUE;
5508 }
5509
5510 /******************************************************************************
5511  *      SmallBlockChainStream_Enlarge
5512  *
5513  * Grows this chain in the small block depot.
5514  */
5515 static BOOL SmallBlockChainStream_Enlarge(
5516   SmallBlockChainStream* This,
5517   ULARGE_INTEGER newSize)
5518 {
5519   ULONG blockIndex, currentBlock;
5520   ULONG newNumBlocks;
5521   ULONG oldNumBlocks = 0;
5522
5523   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5524
5525   /*
5526    * Empty chain
5527    */
5528   if (blockIndex == BLOCK_END_OF_CHAIN)
5529   {
5530
5531     StgProperty chainProp;
5532
5533     StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5534                                &chainProp);
5535
5536     chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
5537
5538     StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5539                                 &chainProp);
5540
5541     blockIndex = chainProp.startingBlock;
5542     SmallBlockChainStream_SetNextBlockInChain(
5543       This,
5544       blockIndex,
5545       BLOCK_END_OF_CHAIN);
5546   }
5547
5548   currentBlock = blockIndex;
5549
5550   /*
5551    * Figure out how many blocks are needed to contain this stream
5552    */
5553   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5554
5555   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5556     newNumBlocks++;
5557
5558   /*
5559    * Go to the current end of chain
5560    */
5561   while (blockIndex != BLOCK_END_OF_CHAIN)
5562   {
5563     oldNumBlocks++;
5564     currentBlock = blockIndex;
5565     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
5566       return FALSE;
5567   }
5568
5569   /*
5570    * Add new blocks to the chain
5571    */
5572   while (oldNumBlocks < newNumBlocks)
5573   {
5574     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5575     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5576
5577     SmallBlockChainStream_SetNextBlockInChain(
5578       This,
5579       blockIndex,
5580       BLOCK_END_OF_CHAIN);
5581
5582     currentBlock = blockIndex;
5583     oldNumBlocks++;
5584   }
5585
5586   return TRUE;
5587 }
5588
5589 /******************************************************************************
5590  *      SmallBlockChainStream_SetSize
5591  *
5592  * Sets the size of this stream.
5593  * The file will grow if we grow the chain.
5594  *
5595  * TODO: Free the actual blocks in the file when we shrink the chain.
5596  *       Currently, the blocks are still in the file. So the file size
5597  *       doesn't shrink even if we shrink streams.
5598  */
5599 BOOL SmallBlockChainStream_SetSize(
5600                 SmallBlockChainStream* This,
5601                 ULARGE_INTEGER    newSize)
5602 {
5603   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5604
5605   if (newSize.u.LowPart == size.u.LowPart)
5606     return TRUE;
5607
5608   if (newSize.u.LowPart < size.u.LowPart)
5609   {
5610     SmallBlockChainStream_Shrink(This, newSize);
5611   }
5612   else
5613   {
5614     SmallBlockChainStream_Enlarge(This, newSize);
5615   }
5616
5617   return TRUE;
5618 }
5619
5620 /******************************************************************************
5621  *      SmallBlockChainStream_GetSize
5622  *
5623  * Returns the size of this chain.
5624  */
5625 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5626 {
5627   StgProperty chainProperty;
5628
5629   StorageImpl_ReadProperty(
5630     This->parentStorage,
5631     This->ownerPropertyIndex,
5632     &chainProperty);
5633
5634   return chainProperty.size;
5635 }
5636
5637 /******************************************************************************
5638  *    StgCreateDocfile  [OLE32.@]
5639  * Creates a new compound file storage object
5640  *
5641  * PARAMS
5642  *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
5643  *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
5644  *  reserved  [ ?] unused?, usually 0
5645  *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
5646  *
5647  * RETURNS
5648  *  S_OK if the file was successfully created
5649  *  some STG_E_ value if error
5650  * NOTES
5651  *  if pwcsName is NULL, create file with new unique name
5652  *  the function can returns
5653  *  STG_S_CONVERTED if the specified file was successfully converted to storage format
5654  *  (unrealized now)
5655  */
5656 HRESULT WINAPI StgCreateDocfile(
5657   LPCOLESTR pwcsName,
5658   DWORD       grfMode,
5659   DWORD       reserved,
5660   IStorage  **ppstgOpen)
5661 {
5662   StorageImpl* newStorage = 0;
5663   HANDLE       hFile      = INVALID_HANDLE_VALUE;
5664   HRESULT        hr         = STG_E_INVALIDFLAG;
5665   DWORD          shareMode;
5666   DWORD          accessMode;
5667   DWORD          creationMode;
5668   DWORD          fileAttributes;
5669   WCHAR          tempFileName[MAX_PATH];
5670
5671   TRACE("(%s, %x, %d, %p)\n",
5672         debugstr_w(pwcsName), grfMode,
5673         reserved, ppstgOpen);
5674
5675   /*
5676    * Validate the parameters
5677    */
5678   if (ppstgOpen == 0)
5679     return STG_E_INVALIDPOINTER;
5680   if (reserved != 0)
5681     return STG_E_INVALIDPARAMETER;
5682
5683   /* if no share mode given then DENY_NONE is the default */
5684   if (STGM_SHARE_MODE(grfMode) == 0)
5685       grfMode |= STGM_SHARE_DENY_NONE;
5686
5687   /*
5688    * Validate the STGM flags
5689    */
5690   if ( FAILED( validateSTGM(grfMode) ))
5691     goto end;
5692
5693   /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
5694   switch(STGM_ACCESS_MODE(grfMode))
5695   {
5696   case STGM_WRITE:
5697   case STGM_READWRITE:
5698     break;
5699   default:
5700     goto end;
5701   }
5702
5703   /* in direct mode, can only use SHARE_EXCLUSIVE */
5704   if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
5705     goto end;
5706
5707   /* but in transacted mode, any share mode is valid */
5708
5709   /*
5710    * Generate a unique name.
5711    */
5712   if (pwcsName == 0)
5713   {
5714     WCHAR tempPath[MAX_PATH];
5715     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5716
5717     memset(tempPath, 0, sizeof(tempPath));
5718     memset(tempFileName, 0, sizeof(tempFileName));
5719
5720     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5721       tempPath[0] = '.';
5722
5723     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5724       pwcsName = tempFileName;
5725     else
5726     {
5727       hr = STG_E_INSUFFICIENTMEMORY;
5728       goto end;
5729     }
5730
5731     creationMode = TRUNCATE_EXISTING;
5732   }
5733   else
5734   {
5735     creationMode = GetCreationModeFromSTGM(grfMode);
5736   }
5737
5738   /*
5739    * Interpret the STGM value grfMode
5740    */
5741   shareMode    = GetShareModeFromSTGM(grfMode);
5742   accessMode   = GetAccessModeFromSTGM(grfMode);
5743
5744   if (grfMode & STGM_DELETEONRELEASE)
5745     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5746   else
5747     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5748
5749   if (grfMode & STGM_TRANSACTED)
5750     FIXME("Transacted mode not implemented.\n");
5751
5752   /*
5753    * Initialize the "out" parameter.
5754    */
5755   *ppstgOpen = 0;
5756
5757   hFile = CreateFileW(pwcsName,
5758                         accessMode,
5759                         shareMode,
5760                         NULL,
5761                         creationMode,
5762                         fileAttributes,
5763                         0);
5764
5765   if (hFile == INVALID_HANDLE_VALUE)
5766   {
5767     if(GetLastError() == ERROR_FILE_EXISTS)
5768       hr = STG_E_FILEALREADYEXISTS;
5769     else
5770       hr = E_FAIL;
5771     goto end;
5772   }
5773
5774   /*
5775    * Allocate and initialize the new IStorage32object.
5776    */
5777   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5778
5779   if (newStorage == 0)
5780   {
5781     hr = STG_E_INSUFFICIENTMEMORY;
5782     goto end;
5783   }
5784
5785   hr = StorageImpl_Construct(
5786          newStorage,
5787          hFile,
5788         pwcsName,
5789          NULL,
5790          grfMode,
5791          TRUE,
5792          TRUE);
5793
5794   if (FAILED(hr))
5795   {
5796     HeapFree(GetProcessHeap(), 0, newStorage);
5797     goto end;
5798   }
5799
5800   /*
5801    * Get an "out" pointer for the caller.
5802    */
5803   hr = StorageBaseImpl_QueryInterface(
5804          (IStorage*)newStorage,
5805          (REFIID)&IID_IStorage,
5806          (void**)ppstgOpen);
5807 end:
5808   TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
5809
5810   return hr;
5811 }
5812
5813 /******************************************************************************
5814  *              StgCreateStorageEx        [OLE32.@]
5815  */
5816 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5817 {
5818     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5819           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5820
5821     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
5822     {
5823         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
5824         return STG_E_INVALIDPARAMETER;  
5825     }
5826
5827     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5828     {
5829         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
5830         return STG_E_INVALIDPARAMETER;  
5831     }
5832
5833     if (stgfmt == STGFMT_FILE)
5834     {
5835         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5836         return STG_E_INVALIDPARAMETER;
5837     }
5838
5839     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
5840     {
5841         FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
5842         return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); 
5843     }
5844
5845     ERR("Invalid stgfmt argument\n");
5846     return STG_E_INVALIDPARAMETER;
5847 }
5848
5849 /******************************************************************************
5850  *              StgCreatePropSetStg       [OLE32.@]
5851  */
5852 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
5853  IPropertySetStorage **ppPropSetStg)
5854 {
5855     HRESULT hr;
5856
5857     TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
5858     if (reserved)
5859         hr = STG_E_INVALIDPARAMETER;
5860     else
5861         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
5862          (void**)ppPropSetStg);
5863     return hr;
5864 }
5865
5866 /******************************************************************************
5867  *              StgOpenStorageEx      [OLE32.@]
5868  */
5869 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5870 {
5871     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5872           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5873
5874     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
5875     {
5876         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
5877         return STG_E_INVALIDPARAMETER;  
5878     }
5879
5880     switch (stgfmt)
5881     {
5882     case STGFMT_FILE:
5883         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5884         return STG_E_INVALIDPARAMETER;
5885         
5886     case STGFMT_STORAGE:
5887         break;
5888
5889     case STGFMT_DOCFILE:
5890         if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
5891         {
5892             ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
5893             return STG_E_INVALIDPARAMETER;  
5894         }
5895         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
5896         break;
5897
5898     case STGFMT_ANY:
5899         WARN("STGFMT_ANY assuming storage\n");
5900         break;
5901
5902     default:
5903         return STG_E_INVALIDPARAMETER;
5904     }
5905
5906     return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); 
5907 }
5908
5909
5910 /******************************************************************************
5911  *              StgOpenStorage        [OLE32.@]
5912  */
5913 HRESULT WINAPI StgOpenStorage(
5914   const OLECHAR *pwcsName,
5915   IStorage      *pstgPriority,
5916   DWORD          grfMode,
5917   SNB            snbExclude,
5918   DWORD          reserved,
5919   IStorage     **ppstgOpen)
5920 {
5921   StorageImpl*   newStorage = 0;
5922   HRESULT        hr = S_OK;
5923   HANDLE         hFile = 0;
5924   DWORD          shareMode;
5925   DWORD          accessMode;
5926   WCHAR          fullname[MAX_PATH];
5927
5928   TRACE("(%s, %p, %x, %p, %d, %p)\n",
5929         debugstr_w(pwcsName), pstgPriority, grfMode,
5930         snbExclude, reserved, ppstgOpen);
5931
5932   /*
5933    * Perform sanity checks
5934    */
5935   if (pwcsName == 0)
5936   {
5937     hr = STG_E_INVALIDNAME;
5938     goto end;
5939   }
5940
5941   if (ppstgOpen == 0)
5942   {
5943     hr = STG_E_INVALIDPOINTER;
5944     goto end;
5945   }
5946
5947   if (reserved)
5948   {
5949     hr = STG_E_INVALIDPARAMETER;
5950     goto end;
5951   }
5952
5953   if (grfMode & STGM_PRIORITY)
5954   {
5955     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
5956       return STG_E_INVALIDFLAG;
5957     if (grfMode & STGM_DELETEONRELEASE)
5958       return STG_E_INVALIDFUNCTION;
5959     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
5960       return STG_E_INVALIDFLAG;
5961     grfMode &= ~0xf0; /* remove the existing sharing mode */
5962     grfMode |= STGM_SHARE_DENY_NONE;
5963
5964     /* STGM_PRIORITY stops other IStorage objects on the same file from
5965      * committing until the STGM_PRIORITY IStorage is closed. it also
5966      * stops non-transacted mode StgOpenStorage calls with write access from
5967      * succeeding. obviously, both of these cannot be achieved through just
5968      * file share flags */
5969     FIXME("STGM_PRIORITY mode not implemented correctly\n");
5970   }
5971
5972   /*
5973    * Validate the sharing mode
5974    */
5975   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
5976     switch(STGM_SHARE_MODE(grfMode))
5977     {
5978       case STGM_SHARE_EXCLUSIVE:
5979       case STGM_SHARE_DENY_WRITE:
5980         break;
5981       default:
5982         hr = STG_E_INVALIDFLAG;
5983         goto end;
5984     }
5985
5986   /*
5987    * Validate the STGM flags
5988    */
5989   if ( FAILED( validateSTGM(grfMode) ) ||
5990        (grfMode&STGM_CREATE))
5991   {
5992     hr = STG_E_INVALIDFLAG;
5993     goto end;
5994   }
5995
5996   /* shared reading requires transacted mode */
5997   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
5998       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
5999      !(grfMode&STGM_TRANSACTED) )
6000   {
6001     hr = STG_E_INVALIDFLAG;
6002     goto end;
6003   }
6004
6005   /*
6006    * Interpret the STGM value grfMode
6007    */
6008   shareMode    = GetShareModeFromSTGM(grfMode);
6009   accessMode   = GetAccessModeFromSTGM(grfMode);
6010
6011   /*
6012    * Initialize the "out" parameter.
6013    */
6014   *ppstgOpen = 0;
6015
6016   hFile = CreateFileW( pwcsName,
6017                        accessMode,
6018                        shareMode,
6019                        NULL,
6020                        OPEN_EXISTING,
6021                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
6022                        0);
6023
6024   if (hFile==INVALID_HANDLE_VALUE)
6025   {
6026     DWORD last_error = GetLastError();
6027
6028     hr = E_FAIL;
6029
6030     switch (last_error)
6031     {
6032       case ERROR_FILE_NOT_FOUND:
6033         hr = STG_E_FILENOTFOUND;
6034         break;
6035
6036       case ERROR_PATH_NOT_FOUND:
6037         hr = STG_E_PATHNOTFOUND;
6038         break;
6039
6040       case ERROR_ACCESS_DENIED:
6041       case ERROR_WRITE_PROTECT:
6042         hr = STG_E_ACCESSDENIED;
6043         break;
6044
6045       case ERROR_SHARING_VIOLATION:
6046         hr = STG_E_SHAREVIOLATION;
6047         break;
6048
6049       default:
6050         hr = E_FAIL;
6051     }
6052
6053     goto end;
6054   }
6055
6056   /*
6057    * Refuse to open the file if it's too small to be a structured storage file
6058    * FIXME: verify the file when reading instead of here
6059    */
6060   if (GetFileSize(hFile, NULL) < 0x100)
6061   {
6062     CloseHandle(hFile);
6063     hr = STG_E_FILEALREADYEXISTS;
6064     goto end;
6065   }
6066
6067   /*
6068    * Allocate and initialize the new IStorage32object.
6069    */
6070   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6071
6072   if (newStorage == 0)
6073   {
6074     hr = STG_E_INSUFFICIENTMEMORY;
6075     goto end;
6076   }
6077
6078   /* Initialize the storage */
6079   hr = StorageImpl_Construct(
6080          newStorage,
6081          hFile,
6082          pwcsName,
6083          NULL,
6084          grfMode,
6085          TRUE,
6086          FALSE );
6087
6088   if (FAILED(hr))
6089   {
6090     HeapFree(GetProcessHeap(), 0, newStorage);
6091     /*
6092      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
6093      */
6094     if(hr == STG_E_INVALIDHEADER)
6095         hr = STG_E_FILEALREADYEXISTS;
6096     goto end;
6097   }
6098
6099   /* prepare the file name string given in lieu of the root property name */
6100   GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
6101   memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
6102   newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
6103
6104   /*
6105    * Get an "out" pointer for the caller.
6106    */
6107   hr = StorageBaseImpl_QueryInterface(
6108          (IStorage*)newStorage,
6109          (REFIID)&IID_IStorage,
6110          (void**)ppstgOpen);
6111
6112 end:
6113   TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
6114   return hr;
6115 }
6116
6117 /******************************************************************************
6118  *    StgCreateDocfileOnILockBytes    [OLE32.@]
6119  */
6120 HRESULT WINAPI StgCreateDocfileOnILockBytes(
6121       ILockBytes *plkbyt,
6122       DWORD grfMode,
6123       DWORD reserved,
6124       IStorage** ppstgOpen)
6125 {
6126   StorageImpl*   newStorage = 0;
6127   HRESULT        hr         = S_OK;
6128
6129   /*
6130    * Validate the parameters
6131    */
6132   if ((ppstgOpen == 0) || (plkbyt == 0))
6133     return STG_E_INVALIDPOINTER;
6134
6135   /*
6136    * Allocate and initialize the new IStorage object.
6137    */
6138   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6139
6140   if (newStorage == 0)
6141     return STG_E_INSUFFICIENTMEMORY;
6142
6143   hr = StorageImpl_Construct(
6144          newStorage,
6145          0,
6146         0,
6147          plkbyt,
6148          grfMode,
6149          FALSE,
6150          TRUE);
6151
6152   if (FAILED(hr))
6153   {
6154     HeapFree(GetProcessHeap(), 0, newStorage);
6155     return hr;
6156   }
6157
6158   /*
6159    * Get an "out" pointer for the caller.
6160    */
6161   hr = StorageBaseImpl_QueryInterface(
6162          (IStorage*)newStorage,
6163          (REFIID)&IID_IStorage,
6164          (void**)ppstgOpen);
6165
6166   return hr;
6167 }
6168
6169 /******************************************************************************
6170  *    StgOpenStorageOnILockBytes    [OLE32.@]
6171  */
6172 HRESULT WINAPI StgOpenStorageOnILockBytes(
6173       ILockBytes *plkbyt,
6174       IStorage *pstgPriority,
6175       DWORD grfMode,
6176       SNB snbExclude,
6177       DWORD reserved,
6178       IStorage **ppstgOpen)
6179 {
6180   StorageImpl* newStorage = 0;
6181   HRESULT        hr = S_OK;
6182
6183   /*
6184    * Perform a sanity check
6185    */
6186   if ((plkbyt == 0) || (ppstgOpen == 0))
6187     return STG_E_INVALIDPOINTER;
6188
6189   /*
6190    * Validate the STGM flags
6191    */
6192   if ( FAILED( validateSTGM(grfMode) ))
6193     return STG_E_INVALIDFLAG;
6194
6195   /*
6196    * Initialize the "out" parameter.
6197    */
6198   *ppstgOpen = 0;
6199
6200   /*
6201    * Allocate and initialize the new IStorage object.
6202    */
6203   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6204
6205   if (newStorage == 0)
6206     return STG_E_INSUFFICIENTMEMORY;
6207
6208   hr = StorageImpl_Construct(
6209          newStorage,
6210          0,
6211          0,
6212          plkbyt,
6213          grfMode,
6214          FALSE,
6215          FALSE);
6216
6217   if (FAILED(hr))
6218   {
6219     HeapFree(GetProcessHeap(), 0, newStorage);
6220     return hr;
6221   }
6222
6223   /*
6224    * Get an "out" pointer for the caller.
6225    */
6226   hr = StorageBaseImpl_QueryInterface(
6227          (IStorage*)newStorage,
6228          (REFIID)&IID_IStorage,
6229          (void**)ppstgOpen);
6230
6231   return hr;
6232 }
6233
6234 /******************************************************************************
6235  *              StgSetTimes [ole32.@]
6236  *              StgSetTimes [OLE32.@]
6237  *
6238  *
6239  */
6240 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6241                            FILETIME const *patime, FILETIME const *pmtime)
6242 {
6243   IStorage *stg = NULL;
6244   HRESULT r;
6245  
6246   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6247
6248   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6249                      0, 0, &stg);
6250   if( SUCCEEDED(r) )
6251   {
6252     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6253     IStorage_Release(stg);
6254   }
6255
6256   return r;
6257 }
6258
6259 /******************************************************************************
6260  *              StgIsStorageILockBytes        [OLE32.@]
6261  *
6262  * Determines if the ILockBytes contains a storage object.
6263  */
6264 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6265 {
6266   BYTE sig[8];
6267   ULARGE_INTEGER offset;
6268
6269   offset.u.HighPart = 0;
6270   offset.u.LowPart  = 0;
6271
6272   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6273
6274   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6275     return S_OK;
6276
6277   return S_FALSE;
6278 }
6279
6280 /******************************************************************************
6281  *              WriteClassStg        [OLE32.@]
6282  *
6283  * This method will store the specified CLSID in the specified storage object
6284  */
6285 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6286 {
6287   HRESULT hRes;
6288
6289   if(!pStg)
6290     return E_INVALIDARG;
6291
6292   hRes = IStorage_SetClass(pStg, rclsid);
6293
6294   return hRes;
6295 }
6296
6297 /***********************************************************************
6298  *    ReadClassStg (OLE32.@)
6299  *
6300  * This method reads the CLSID previously written to a storage object with
6301  * the WriteClassStg.
6302  *
6303  * PARAMS
6304  *  pstg    [I] IStorage pointer
6305  *  pclsid  [O] Pointer to where the CLSID is written
6306  *
6307  * RETURNS
6308  *  Success: S_OK.
6309  *  Failure: HRESULT code.
6310  */
6311 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6312
6313     STATSTG pstatstg;
6314     HRESULT hRes;
6315
6316     TRACE("(%p, %p)\n", pstg, pclsid);
6317
6318     if(!pstg || !pclsid)
6319         return E_INVALIDARG;
6320
6321    /*
6322     * read a STATSTG structure (contains the clsid) from the storage
6323     */
6324     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
6325
6326     if(SUCCEEDED(hRes))
6327         *pclsid=pstatstg.clsid;
6328
6329     return hRes;
6330 }
6331
6332 /***********************************************************************
6333  *    OleLoadFromStream (OLE32.@)
6334  *
6335  * This function loads an object from stream
6336  */
6337 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6338 {
6339     CLSID       clsid;
6340     HRESULT     res;
6341     LPPERSISTSTREAM     xstm;
6342
6343     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6344
6345     res=ReadClassStm(pStm,&clsid);
6346     if (!SUCCEEDED(res))
6347         return res;
6348     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6349     if (!SUCCEEDED(res))
6350         return res;
6351     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6352     if (!SUCCEEDED(res)) {
6353         IUnknown_Release((IUnknown*)*ppvObj);
6354         return res;
6355     }
6356     res=IPersistStream_Load(xstm,pStm);
6357     IPersistStream_Release(xstm);
6358     /* FIXME: all refcounts ok at this point? I think they should be:
6359      *          pStm    : unchanged
6360      *          ppvObj  : 1
6361      *          xstm    : 0 (released)
6362      */
6363     return res;
6364 }
6365
6366 /***********************************************************************
6367  *    OleSaveToStream (OLE32.@)
6368  *
6369  * This function saves an object with the IPersistStream interface on it
6370  * to the specified stream.
6371  */
6372 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6373 {
6374
6375     CLSID clsid;
6376     HRESULT res;
6377
6378     TRACE("(%p,%p)\n",pPStm,pStm);
6379
6380     res=IPersistStream_GetClassID(pPStm,&clsid);
6381
6382     if (SUCCEEDED(res)){
6383
6384         res=WriteClassStm(pStm,&clsid);
6385
6386         if (SUCCEEDED(res))
6387
6388             res=IPersistStream_Save(pPStm,pStm,TRUE);
6389     }
6390
6391     TRACE("Finished Save\n");
6392     return res;
6393 }
6394
6395 /****************************************************************************
6396  * This method validate a STGM parameter that can contain the values below
6397  *
6398  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6399  * The stgm values contained in 0xffff0000 are bitmasks.
6400  *
6401  * STGM_DIRECT               0x00000000
6402  * STGM_TRANSACTED           0x00010000
6403  * STGM_SIMPLE               0x08000000
6404  *
6405  * STGM_READ                 0x00000000
6406  * STGM_WRITE                0x00000001
6407  * STGM_READWRITE            0x00000002
6408  *
6409  * STGM_SHARE_DENY_NONE      0x00000040
6410  * STGM_SHARE_DENY_READ      0x00000030
6411  * STGM_SHARE_DENY_WRITE     0x00000020
6412  * STGM_SHARE_EXCLUSIVE      0x00000010
6413  *
6414  * STGM_PRIORITY             0x00040000
6415  * STGM_DELETEONRELEASE      0x04000000
6416  *
6417  * STGM_CREATE               0x00001000
6418  * STGM_CONVERT              0x00020000
6419  * STGM_FAILIFTHERE          0x00000000
6420  *
6421  * STGM_NOSCRATCH            0x00100000
6422  * STGM_NOSNAPSHOT           0x00200000
6423  */
6424 static HRESULT validateSTGM(DWORD stgm)
6425 {
6426   DWORD access = STGM_ACCESS_MODE(stgm);
6427   DWORD share  = STGM_SHARE_MODE(stgm);
6428   DWORD create = STGM_CREATE_MODE(stgm);
6429
6430   if (stgm&~STGM_KNOWN_FLAGS)
6431   {
6432     ERR("unknown flags %08x\n", stgm);
6433     return E_FAIL;
6434   }
6435
6436   switch (access)
6437   {
6438   case STGM_READ:
6439   case STGM_WRITE:
6440   case STGM_READWRITE:
6441     break;
6442   default:
6443     return E_FAIL;
6444   }
6445
6446   switch (share)
6447   {
6448   case STGM_SHARE_DENY_NONE:
6449   case STGM_SHARE_DENY_READ:
6450   case STGM_SHARE_DENY_WRITE:
6451   case STGM_SHARE_EXCLUSIVE:
6452     break;
6453   default:
6454     return E_FAIL;
6455   }
6456
6457   switch (create)
6458   {
6459   case STGM_CREATE:
6460   case STGM_FAILIFTHERE:
6461     break;
6462   default:
6463     return E_FAIL;
6464   }
6465
6466   /*
6467    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
6468    */
6469   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
6470       return E_FAIL;
6471
6472   /*
6473    * STGM_CREATE | STGM_CONVERT
6474    * if both are false, STGM_FAILIFTHERE is set to TRUE
6475    */
6476   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
6477     return E_FAIL;
6478
6479   /*
6480    * STGM_NOSCRATCH requires STGM_TRANSACTED
6481    */
6482   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
6483     return E_FAIL;
6484
6485   /*
6486    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
6487    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
6488    */
6489   if ( (stgm & STGM_NOSNAPSHOT) &&
6490         (!(stgm & STGM_TRANSACTED) ||
6491          share == STGM_SHARE_EXCLUSIVE ||
6492          share == STGM_SHARE_DENY_WRITE) )
6493     return E_FAIL;
6494
6495   return S_OK;
6496 }
6497
6498 /****************************************************************************
6499  *      GetShareModeFromSTGM
6500  *
6501  * This method will return a share mode flag from a STGM value.
6502  * The STGM value is assumed valid.
6503  */
6504 static DWORD GetShareModeFromSTGM(DWORD stgm)
6505 {
6506   switch (STGM_SHARE_MODE(stgm))
6507   {
6508   case STGM_SHARE_DENY_NONE:
6509     return FILE_SHARE_READ | FILE_SHARE_WRITE;
6510   case STGM_SHARE_DENY_READ:
6511     return FILE_SHARE_WRITE;
6512   case STGM_SHARE_DENY_WRITE:
6513     return FILE_SHARE_READ;
6514   case STGM_SHARE_EXCLUSIVE:
6515     return 0;
6516   }
6517   ERR("Invalid share mode!\n");
6518   assert(0);
6519   return 0;
6520 }
6521
6522 /****************************************************************************
6523  *      GetAccessModeFromSTGM
6524  *
6525  * This method will return an access mode flag from a STGM value.
6526  * The STGM value is assumed valid.
6527  */
6528 static DWORD GetAccessModeFromSTGM(DWORD stgm)
6529 {
6530   switch (STGM_ACCESS_MODE(stgm))
6531   {
6532   case STGM_READ:
6533     return GENERIC_READ;
6534   case STGM_WRITE:
6535   case STGM_READWRITE:
6536     return GENERIC_READ | GENERIC_WRITE;
6537   }
6538   ERR("Invalid access mode!\n");
6539   assert(0);
6540   return 0;
6541 }
6542
6543 /****************************************************************************
6544  *      GetCreationModeFromSTGM
6545  *
6546  * This method will return a creation mode flag from a STGM value.
6547  * The STGM value is assumed valid.
6548  */
6549 static DWORD GetCreationModeFromSTGM(DWORD stgm)
6550 {
6551   switch(STGM_CREATE_MODE(stgm))
6552   {
6553   case STGM_CREATE:
6554     return CREATE_ALWAYS;
6555   case STGM_CONVERT:
6556     FIXME("STGM_CONVERT not implemented!\n");
6557     return CREATE_NEW;
6558   case STGM_FAILIFTHERE:
6559     return CREATE_NEW;
6560   }
6561   ERR("Invalid create mode!\n");
6562   assert(0);
6563   return 0;
6564 }
6565
6566
6567 /*************************************************************************
6568  * OLECONVERT_LoadOLE10 [Internal]
6569  *
6570  * Loads the OLE10 STREAM to memory
6571  *
6572  * PARAMS
6573  *     pOleStream   [I] The OLESTREAM
6574  *     pData        [I] Data Structure for the OLESTREAM Data
6575  *
6576  * RETURNS
6577  *     Success:  S_OK
6578  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
6579  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
6580  *
6581  * NOTES
6582  *     This function is used by OleConvertOLESTREAMToIStorage only.
6583  *
6584  *     Memory allocated for pData must be freed by the caller
6585  */
6586 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
6587 {
6588         DWORD dwSize;
6589         HRESULT hRes = S_OK;
6590         int nTryCnt=0;
6591         int max_try = 6;
6592
6593         pData->pData = NULL;
6594         pData->pstrOleObjFileName = (CHAR *) NULL;
6595
6596         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
6597         {
6598         /* Get the OleID */
6599         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6600         if(dwSize != sizeof(pData->dwOleID))
6601         {
6602                 hRes = CONVERT10_E_OLESTREAM_GET;
6603         }
6604         else if(pData->dwOleID != OLESTREAM_ID)
6605         {
6606                 hRes = CONVERT10_E_OLESTREAM_FMT;
6607         }
6608                 else
6609                 {
6610                         hRes = S_OK;
6611                         break;
6612                 }
6613         }
6614
6615         if(hRes == S_OK)
6616         {
6617                 /* Get the TypeID...more info needed for this field */
6618                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6619                 if(dwSize != sizeof(pData->dwTypeID))
6620                 {
6621                         hRes = CONVERT10_E_OLESTREAM_GET;
6622                 }
6623         }
6624         if(hRes == S_OK)
6625         {
6626                 if(pData->dwTypeID != 0)
6627                 {
6628                         /* Get the length of the OleTypeName */
6629                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6630                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6631                         {
6632                                 hRes = CONVERT10_E_OLESTREAM_GET;
6633                         }
6634
6635                         if(hRes == S_OK)
6636                         {
6637                                 if(pData->dwOleTypeNameLength > 0)
6638                                 {
6639                                         /* Get the OleTypeName */
6640                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
6641                                         if(dwSize != pData->dwOleTypeNameLength)
6642                                         {
6643                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6644                                         }
6645                                 }
6646                         }
6647                         if(bStrem1)
6648                         {
6649                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6650                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6651                                 {
6652                                         hRes = CONVERT10_E_OLESTREAM_GET;
6653                                 }
6654                         if(hRes == S_OK)
6655                         {
6656                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6657                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6658                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
6659                                         if(pData->pstrOleObjFileName)
6660                                         {
6661                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6662                                                 if(dwSize != pData->dwOleObjFileNameLength)
6663                                                 {
6664                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6665                                                 }
6666                                         }
6667                                         else
6668                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6669                                 }
6670                         }
6671                         else
6672                         {
6673                                 /* Get the Width of the Metafile */
6674                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6675                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
6676                                 {
6677                                         hRes = CONVERT10_E_OLESTREAM_GET;
6678                                 }
6679                         if(hRes == S_OK)
6680                         {
6681                                 /* Get the Height of the Metafile */
6682                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6683                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
6684                                 {
6685                                         hRes = CONVERT10_E_OLESTREAM_GET;
6686                                 }
6687                         }
6688                         }
6689                         if(hRes == S_OK)
6690                         {
6691                                 /* Get the Length of the Data */
6692                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6693                                 if(dwSize != sizeof(pData->dwDataLength))
6694                                 {
6695                                         hRes = CONVERT10_E_OLESTREAM_GET;
6696                                 }
6697                         }
6698
6699                         if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
6700                         {
6701                                 if(!bStrem1) /* if it is a second OLE stream data */
6702                                 {
6703                                         pData->dwDataLength -= 8;
6704                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6705                                         if(dwSize != sizeof(pData->strUnknown))
6706                                         {
6707                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6708                                         }
6709                                 }
6710                         }
6711                         if(hRes == S_OK)
6712                         {
6713                                 if(pData->dwDataLength > 0)
6714                                 {
6715                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6716
6717                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
6718                                         if(pData->pData)
6719                                         {
6720                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6721                                                 if(dwSize != pData->dwDataLength)
6722                                                 {
6723                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6724                                                 }
6725                                         }
6726                                         else
6727                                         {
6728                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6729                                         }
6730                                 }
6731                         }
6732                 }
6733         }
6734         return hRes;
6735 }
6736
6737 /*************************************************************************
6738  * OLECONVERT_SaveOLE10 [Internal]
6739  *
6740  * Saves the OLE10 STREAM From memory
6741  *
6742  * PARAMS
6743  *     pData        [I] Data Structure for the OLESTREAM Data
6744  *     pOleStream   [I] The OLESTREAM to save
6745  *
6746  * RETURNS
6747  *     Success:  S_OK
6748  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
6749  *
6750  * NOTES
6751  *     This function is used by OleConvertIStorageToOLESTREAM only.
6752  *
6753  */
6754 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6755 {
6756     DWORD dwSize;
6757     HRESULT hRes = S_OK;
6758
6759
6760    /* Set the OleID */
6761     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6762     if(dwSize != sizeof(pData->dwOleID))
6763     {
6764         hRes = CONVERT10_E_OLESTREAM_PUT;
6765     }
6766
6767     if(hRes == S_OK)
6768     {
6769         /* Set the TypeID */
6770         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6771         if(dwSize != sizeof(pData->dwTypeID))
6772         {
6773             hRes = CONVERT10_E_OLESTREAM_PUT;
6774         }
6775     }
6776
6777     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6778     {
6779         /* Set the Length of the OleTypeName */
6780         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6781         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6782         {
6783             hRes = CONVERT10_E_OLESTREAM_PUT;
6784         }
6785
6786         if(hRes == S_OK)
6787         {
6788             if(pData->dwOleTypeNameLength > 0)
6789             {
6790                 /* Set the OleTypeName */
6791                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);
6792                 if(dwSize != pData->dwOleTypeNameLength)
6793                 {
6794                     hRes = CONVERT10_E_OLESTREAM_PUT;
6795                 }
6796             }
6797         }
6798
6799         if(hRes == S_OK)
6800         {
6801             /* Set the width of the Metafile */
6802             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6803             if(dwSize != sizeof(pData->dwMetaFileWidth))
6804             {
6805                 hRes = CONVERT10_E_OLESTREAM_PUT;
6806             }
6807         }
6808
6809         if(hRes == S_OK)
6810         {
6811             /* Set the height of the Metafile */
6812             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6813             if(dwSize != sizeof(pData->dwMetaFileHeight))
6814             {
6815                 hRes = CONVERT10_E_OLESTREAM_PUT;
6816             }
6817         }
6818
6819         if(hRes == S_OK)
6820         {
6821             /* Set the length of the Data */
6822             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6823             if(dwSize != sizeof(pData->dwDataLength))
6824             {
6825                 hRes = CONVERT10_E_OLESTREAM_PUT;
6826             }
6827         }
6828
6829         if(hRes == S_OK)
6830         {
6831             if(pData->dwDataLength > 0)
6832             {
6833                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6834                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
6835                 if(dwSize != pData->dwDataLength)
6836                 {
6837                     hRes = CONVERT10_E_OLESTREAM_PUT;
6838                 }
6839             }
6840         }
6841     }
6842     return hRes;
6843 }
6844
6845 /*************************************************************************
6846  * OLECONVERT_GetOLE20FromOLE10[Internal]
6847  *
6848  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6849  * opens it, and copies the content to the dest IStorage for
6850  * OleConvertOLESTREAMToIStorage
6851  *
6852  *
6853  * PARAMS
6854  *     pDestStorage  [I] The IStorage to copy the data to
6855  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
6856  *     nBufferLength [I] The size of the buffer
6857  *
6858  * RETURNS
6859  *     Nothing
6860  *
6861  * NOTES
6862  *
6863  *
6864  */
6865 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBuffer, DWORD nBufferLength)
6866 {
6867     HRESULT hRes;
6868     HANDLE hFile;
6869     IStorage *pTempStorage;
6870     DWORD dwNumOfBytesWritten;
6871     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6872     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6873
6874     /* Create a temp File */
6875     GetTempPathW(MAX_PATH, wstrTempDir);
6876     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6877     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6878
6879     if(hFile != INVALID_HANDLE_VALUE)
6880     {
6881         /* Write IStorage Data to File */
6882         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6883         CloseHandle(hFile);
6884
6885         /* Open and copy temp storage to the Dest Storage */
6886         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6887         if(hRes == S_OK)
6888         {
6889             hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6890             StorageBaseImpl_Release(pTempStorage);
6891         }
6892         DeleteFileW(wstrTempFile);
6893     }
6894 }
6895
6896
6897 /*************************************************************************
6898  * OLECONVERT_WriteOLE20ToBuffer [Internal]
6899  *
6900  * Saves the OLE10 STREAM From memory
6901  *
6902  * PARAMS
6903  *     pStorage  [I] The Src IStorage to copy
6904  *     pData     [I] The Dest Memory to write to.
6905  *
6906  * RETURNS
6907  *     The size in bytes allocated for pData
6908  *
6909  * NOTES
6910  *     Memory allocated for pData must be freed by the caller
6911  *
6912  *     Used by OleConvertIStorageToOLESTREAM only.
6913  *
6914  */
6915 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6916 {
6917     HANDLE hFile;
6918     HRESULT hRes;
6919     DWORD nDataLength = 0;
6920     IStorage *pTempStorage;
6921     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6922     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6923
6924     *pData = NULL;
6925
6926     /* Create temp Storage */
6927     GetTempPathW(MAX_PATH, wstrTempDir);
6928     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6929     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6930
6931     if(hRes == S_OK)
6932     {
6933         /* Copy Src Storage to the Temp Storage */
6934         StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6935         StorageBaseImpl_Release(pTempStorage);
6936
6937         /* Open Temp Storage as a file and copy to memory */
6938         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6939         if(hFile != INVALID_HANDLE_VALUE)
6940         {
6941             nDataLength = GetFileSize(hFile, NULL);
6942             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
6943             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6944             CloseHandle(hFile);
6945         }
6946         DeleteFileW(wstrTempFile);
6947     }
6948     return nDataLength;
6949 }
6950
6951 /*************************************************************************
6952  * OLECONVERT_CreateOleStream [Internal]
6953  *
6954  * Creates the "\001OLE" stream in the IStorage if necessary.
6955  *
6956  * PARAMS
6957  *     pStorage     [I] Dest storage to create the stream in
6958  *
6959  * RETURNS
6960  *     Nothing
6961  *
6962  * NOTES
6963  *     This function is used by OleConvertOLESTREAMToIStorage only.
6964  *
6965  *     This stream is still unknown, MS Word seems to have extra data
6966  *     but since the data is stored in the OLESTREAM there should be
6967  *     no need to recreate the stream.  If the stream is manually
6968  *     deleted it will create it with this default data.
6969  *
6970  */
6971 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6972 {
6973     HRESULT hRes;
6974     IStream *pStream;
6975     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6976     BYTE pOleStreamHeader [] =
6977     {
6978         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6979         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6980         0x00, 0x00, 0x00, 0x00
6981     };
6982
6983     /* Create stream if not present */
6984     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6985         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6986
6987     if(hRes == S_OK)
6988     {
6989         /* Write default Data */
6990         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6991         IStream_Release(pStream);
6992     }
6993 }
6994
6995 /* write a string to a stream, preceded by its length */
6996 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
6997 {
6998     HRESULT r;
6999     LPSTR str;
7000     DWORD len = 0;
7001
7002     if( string )
7003         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
7004     r = IStream_Write( stm, &len, sizeof(len), NULL);
7005     if( FAILED( r ) )
7006         return r;
7007     if(len == 0)
7008         return r;
7009     str = CoTaskMemAlloc( len );
7010     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
7011     r = IStream_Write( stm, str, len, NULL);
7012     CoTaskMemFree( str );
7013     return r;
7014 }
7015
7016 /* read a string preceded by its length from a stream */
7017 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
7018 {
7019     HRESULT r;
7020     DWORD len, count = 0;
7021     LPSTR str;
7022     LPWSTR wstr;
7023
7024     r = IStream_Read( stm, &len, sizeof(len), &count );
7025     if( FAILED( r ) )
7026         return r;
7027     if( count != sizeof(len) )
7028         return E_OUTOFMEMORY;
7029
7030     TRACE("%d bytes\n",len);
7031     
7032     str = CoTaskMemAlloc( len );
7033     if( !str )
7034         return E_OUTOFMEMORY;
7035     count = 0;
7036     r = IStream_Read( stm, str, len, &count );
7037     if( FAILED( r ) )
7038         return r;
7039     if( count != len )
7040     {
7041         CoTaskMemFree( str );
7042         return E_OUTOFMEMORY;
7043     }
7044
7045     TRACE("Read string %s\n",debugstr_an(str,len));
7046
7047     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
7048     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
7049     if( wstr )
7050          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
7051     CoTaskMemFree( str );
7052
7053     *string = wstr;
7054
7055     return r;
7056 }
7057
7058
7059 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
7060     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
7061 {
7062     IStream *pstm;
7063     HRESULT r = S_OK;
7064     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7065
7066     static const BYTE unknown1[12] =
7067        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
7068          0xFF, 0xFF, 0xFF, 0xFF};
7069     static const BYTE unknown2[16] =
7070        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
7071          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
7072
7073     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
7074            debugstr_w(lpszUserType), debugstr_w(szClipName),
7075            debugstr_w(szProgIDName));
7076
7077     /*  Create a CompObj stream if it doesn't exist */
7078     r = IStorage_CreateStream(pstg, szwStreamName,
7079         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
7080     if( FAILED (r) )
7081         return r;
7082
7083     /* Write CompObj Structure to stream */
7084     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
7085
7086     if( SUCCEEDED( r ) )
7087         r = WriteClassStm( pstm, clsid );
7088
7089     if( SUCCEEDED( r ) )
7090         r = STREAM_WriteString( pstm, lpszUserType );
7091     if( SUCCEEDED( r ) )
7092         r = STREAM_WriteString( pstm, szClipName );
7093     if( SUCCEEDED( r ) )
7094         r = STREAM_WriteString( pstm, szProgIDName );
7095     if( SUCCEEDED( r ) )
7096         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
7097
7098     IStream_Release( pstm );
7099
7100     return r;
7101 }
7102
7103 /***********************************************************************
7104  *               WriteFmtUserTypeStg (OLE32.@)
7105  */
7106 HRESULT WINAPI WriteFmtUserTypeStg(
7107           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
7108 {
7109     HRESULT r;
7110     WCHAR szwClipName[0x40];
7111     CLSID clsid = CLSID_NULL;
7112     LPWSTR wstrProgID = NULL;
7113     DWORD n;
7114
7115     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
7116
7117     /* get the clipboard format name */
7118     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
7119     szwClipName[n]=0;
7120
7121     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
7122
7123     /* FIXME: There's room to save a CLSID and its ProgID, but
7124        the CLSID is not looked up in the registry and in all the
7125        tests I wrote it was CLSID_NULL.  Where does it come from?
7126     */
7127
7128     /* get the real program ID.  This may fail, but that's fine */
7129     ProgIDFromCLSID(&clsid, &wstrProgID);
7130
7131     TRACE("progid is %s\n",debugstr_w(wstrProgID));
7132
7133     r = STORAGE_WriteCompObj( pstg, &clsid, 
7134                               lpszUserType, szwClipName, wstrProgID );
7135
7136     CoTaskMemFree(wstrProgID);
7137
7138     return r;
7139 }
7140
7141
7142 /******************************************************************************
7143  *              ReadFmtUserTypeStg        [OLE32.@]
7144  */
7145 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
7146 {
7147     HRESULT r;
7148     IStream *stm = 0;
7149     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
7150     unsigned char unknown1[12];
7151     unsigned char unknown2[16];
7152     DWORD count;
7153     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
7154     CLSID clsid;
7155
7156     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
7157
7158     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
7159                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
7160     if( FAILED ( r ) )
7161     {
7162         WARN("Failed to open stream r = %08x\n", r);
7163         return r;
7164     }
7165
7166     /* read the various parts of the structure */
7167     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
7168     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
7169         goto end;
7170     r = ReadClassStm( stm, &clsid );
7171     if( FAILED( r ) )
7172         goto end;
7173
7174     r = STREAM_ReadString( stm, &szCLSIDName );
7175     if( FAILED( r ) )
7176         goto end;
7177
7178     r = STREAM_ReadString( stm, &szOleTypeName );
7179     if( FAILED( r ) )
7180         goto end;
7181
7182     r = STREAM_ReadString( stm, &szProgIDName );
7183     if( FAILED( r ) )
7184         goto end;
7185
7186     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7187     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7188         goto end;
7189
7190     /* ok, success... now we just need to store what we found */
7191     if( pcf )
7192         *pcf = RegisterClipboardFormatW( szOleTypeName );
7193     CoTaskMemFree( szOleTypeName );
7194
7195     if( lplpszUserType )
7196         *lplpszUserType = szCLSIDName;
7197     CoTaskMemFree( szProgIDName );
7198
7199 end:
7200     IStream_Release( stm );
7201
7202     return r;
7203 }
7204
7205
7206 /*************************************************************************
7207  * OLECONVERT_CreateCompObjStream [Internal]
7208  *
7209  * Creates a "\001CompObj" is the destination IStorage if necessary.
7210  *
7211  * PARAMS
7212  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7213  *                        if necessary.
7214  *     strOleTypeName [I] The ProgID
7215  *
7216  * RETURNS
7217  *     Success:  S_OK
7218  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7219  *
7220  * NOTES
7221  *     This function is used by OleConvertOLESTREAMToIStorage only.
7222  *
7223  *     The stream data is stored in the OLESTREAM and there should be
7224  *     no need to recreate the stream.  If the stream is manually
7225  *     deleted it will attempt to create it by querying the registry.
7226  *
7227  *
7228  */
7229 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7230 {
7231     IStream *pStream;
7232     HRESULT hStorageRes, hRes = S_OK;
7233     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7234     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7235     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7236
7237     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7238     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7239
7240     /* Initialize the CompObj structure */
7241     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7242     memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
7243     memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
7244
7245
7246     /*  Create a CompObj stream if it doesn't exist */
7247     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7248         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7249     if(hStorageRes == S_OK)
7250     {
7251         /* copy the OleTypeName to the compobj struct */
7252         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7253         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7254
7255         /* copy the OleTypeName to the compobj struct */
7256         /* Note: in the test made, these were Identical      */
7257         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7258         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7259
7260         /* Get the CLSID */
7261         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7262                              bufferW, OLESTREAM_MAX_STR_LEN );
7263         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7264
7265         if(hRes == S_OK)
7266         {
7267             HKEY hKey;
7268             LONG hErr;
7269             /* Get the CLSID Default Name from the Registry */
7270             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7271             if(hErr == ERROR_SUCCESS)
7272             {
7273                 char strTemp[OLESTREAM_MAX_STR_LEN];
7274                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7275                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7276                 if(hErr == ERROR_SUCCESS)
7277                 {
7278                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7279                 }
7280                 RegCloseKey(hKey);
7281             }
7282         }
7283
7284         /* Write CompObj Structure to stream */
7285         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7286
7287         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7288
7289         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7290         if(IStorageCompObj.dwCLSIDNameLength > 0)
7291         {
7292             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7293         }
7294         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7295         if(IStorageCompObj.dwOleTypeNameLength > 0)
7296         {
7297             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7298         }
7299         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7300         if(IStorageCompObj.dwProgIDNameLength > 0)
7301         {
7302             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7303         }
7304         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7305         IStream_Release(pStream);
7306     }
7307     return hRes;
7308 }
7309
7310
7311 /*************************************************************************
7312  * OLECONVERT_CreateOlePresStream[Internal]
7313  *
7314  * Creates the "\002OlePres000" Stream with the Metafile data
7315  *
7316  * PARAMS
7317  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7318  *     dwExtentX    [I] Width of the Metafile
7319  *     dwExtentY    [I] Height of the Metafile
7320  *     pData        [I] Metafile data
7321  *     dwDataLength [I] Size of the Metafile data
7322  *
7323  * RETURNS
7324  *     Success:  S_OK
7325  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7326  *
7327  * NOTES
7328  *     This function is used by OleConvertOLESTREAMToIStorage only.
7329  *
7330  */
7331 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7332 {
7333     HRESULT hRes;
7334     IStream *pStream;
7335     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7336     BYTE pOlePresStreamHeader [] =
7337     {
7338         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7339         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7340         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7341         0x00, 0x00, 0x00, 0x00
7342     };
7343
7344     BYTE pOlePresStreamHeaderEmpty [] =
7345     {
7346         0x00, 0x00, 0x00, 0x00,
7347         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7348         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7349         0x00, 0x00, 0x00, 0x00
7350     };
7351
7352     /* Create the OlePres000 Stream */
7353     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7354         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7355
7356     if(hRes == S_OK)
7357     {
7358         DWORD nHeaderSize;
7359         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7360
7361         memset(&OlePres, 0, sizeof(OlePres));
7362         /* Do we have any metafile data to save */
7363         if(dwDataLength > 0)
7364         {
7365             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7366             nHeaderSize = sizeof(pOlePresStreamHeader);
7367         }
7368         else
7369         {
7370             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7371             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7372         }
7373         /* Set width and height of the metafile */
7374         OlePres.dwExtentX = dwExtentX;
7375         OlePres.dwExtentY = -dwExtentY;
7376
7377         /* Set Data and Length */
7378         if(dwDataLength > sizeof(METAFILEPICT16))
7379         {
7380             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7381             OlePres.pData = &(pData[8]);
7382         }
7383         /* Save OlePres000 Data to Stream */
7384         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7385         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7386         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7387         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7388         if(OlePres.dwSize > 0)
7389         {
7390             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7391         }
7392         IStream_Release(pStream);
7393     }
7394 }
7395
7396 /*************************************************************************
7397  * OLECONVERT_CreateOle10NativeStream [Internal]
7398  *
7399  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7400  *
7401  * PARAMS
7402  *     pStorage     [I] Dest storage to create the stream in
7403  *     pData        [I] Ole10 Native Data (ex. bmp)
7404  *     dwDataLength [I] Size of the Ole10 Native Data
7405  *
7406  * RETURNS
7407  *     Nothing
7408  *
7409  * NOTES
7410  *     This function is used by OleConvertOLESTREAMToIStorage only.
7411  *
7412  *     Might need to verify the data and return appropriate error message
7413  *
7414  */
7415 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
7416 {
7417     HRESULT hRes;
7418     IStream *pStream;
7419     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7420
7421     /* Create the Ole10Native Stream */
7422     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7423         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7424
7425     if(hRes == S_OK)
7426     {
7427         /* Write info to stream */
7428         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7429         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7430         IStream_Release(pStream);
7431     }
7432
7433 }
7434
7435 /*************************************************************************
7436  * OLECONVERT_GetOLE10ProgID [Internal]
7437  *
7438  * Finds the ProgID (or OleTypeID) from the IStorage
7439  *
7440  * PARAMS
7441  *     pStorage        [I] The Src IStorage to get the ProgID
7442  *     strProgID       [I] the ProgID string to get
7443  *     dwSize          [I] the size of the string
7444  *
7445  * RETURNS
7446  *     Success:  S_OK
7447  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7448  *
7449  * NOTES
7450  *     This function is used by OleConvertIStorageToOLESTREAM only.
7451  *
7452  *
7453  */
7454 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7455 {
7456     HRESULT hRes;
7457     IStream *pStream;
7458     LARGE_INTEGER iSeekPos;
7459     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
7460     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7461
7462     /* Open the CompObj Stream */
7463     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7464         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7465     if(hRes == S_OK)
7466     {
7467
7468         /*Get the OleType from the CompObj Stream */
7469         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
7470         iSeekPos.u.HighPart = 0;
7471
7472         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7473         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
7474         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
7475         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7476         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
7477         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
7478         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7479
7480         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
7481         if(*dwSize > 0)
7482         {
7483             IStream_Read(pStream, strProgID, *dwSize, NULL);
7484         }
7485         IStream_Release(pStream);
7486     }
7487     else
7488     {
7489         STATSTG stat;
7490         LPOLESTR wstrProgID;
7491
7492         /* Get the OleType from the registry */
7493         REFCLSID clsid = &(stat.clsid);
7494         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
7495         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
7496         if(hRes == S_OK)
7497         {
7498             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
7499         }
7500
7501     }
7502     return hRes;
7503 }
7504
7505 /*************************************************************************
7506  * OLECONVERT_GetOle10PresData [Internal]
7507  *
7508  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
7509  *
7510  * PARAMS
7511  *     pStorage     [I] Src IStroage
7512  *     pOleStream   [I] Dest OleStream Mem Struct
7513  *
7514  * RETURNS
7515  *     Nothing
7516  *
7517  * NOTES
7518  *     This function is used by OleConvertIStorageToOLESTREAM only.
7519  *
7520  *     Memory allocated for pData must be freed by the caller
7521  *
7522  *
7523  */
7524 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7525 {
7526
7527     HRESULT hRes;
7528     IStream *pStream;
7529     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7530
7531     /* Initialize Default data for OLESTREAM */
7532     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7533     pOleStreamData[0].dwTypeID = 2;
7534     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7535     pOleStreamData[1].dwTypeID = 0;
7536     pOleStreamData[0].dwMetaFileWidth = 0;
7537     pOleStreamData[0].dwMetaFileHeight = 0;
7538     pOleStreamData[0].pData = NULL;
7539     pOleStreamData[1].pData = NULL;
7540
7541     /* Open Ole10Native Stream */
7542     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7543         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7544     if(hRes == S_OK)
7545     {
7546
7547         /* Read Size and Data */
7548         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
7549         if(pOleStreamData->dwDataLength > 0)
7550         {
7551             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
7552             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
7553         }
7554         IStream_Release(pStream);
7555     }
7556
7557 }
7558
7559
7560 /*************************************************************************
7561  * OLECONVERT_GetOle20PresData[Internal]
7562  *
7563  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
7564  *
7565  * PARAMS
7566  *     pStorage         [I] Src IStroage
7567  *     pOleStreamData   [I] Dest OleStream Mem Struct
7568  *
7569  * RETURNS
7570  *     Nothing
7571  *
7572  * NOTES
7573  *     This function is used by OleConvertIStorageToOLESTREAM only.
7574  *
7575  *     Memory allocated for pData must be freed by the caller
7576  */
7577 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7578 {
7579     HRESULT hRes;
7580     IStream *pStream;
7581     OLECONVERT_ISTORAGE_OLEPRES olePress;
7582     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7583
7584     /* Initialize Default data for OLESTREAM */
7585     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7586     pOleStreamData[0].dwTypeID = 2;
7587     pOleStreamData[0].dwMetaFileWidth = 0;
7588     pOleStreamData[0].dwMetaFileHeight = 0;
7589     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
7590     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7591     pOleStreamData[1].dwTypeID = 0;
7592     pOleStreamData[1].dwOleTypeNameLength = 0;
7593     pOleStreamData[1].strOleTypeName[0] = 0;
7594     pOleStreamData[1].dwMetaFileWidth = 0;
7595     pOleStreamData[1].dwMetaFileHeight = 0;
7596     pOleStreamData[1].pData = NULL;
7597     pOleStreamData[1].dwDataLength = 0;
7598
7599
7600     /* Open OlePress000 stream */
7601     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7602         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7603     if(hRes == S_OK)
7604     {
7605         LARGE_INTEGER iSeekPos;
7606         METAFILEPICT16 MetaFilePict;
7607         static const char strMetafilePictName[] = "METAFILEPICT";
7608
7609         /* Set the TypeID for a Metafile */
7610         pOleStreamData[1].dwTypeID = 5;
7611
7612         /* Set the OleTypeName to Metafile */
7613         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
7614         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
7615
7616         iSeekPos.u.HighPart = 0;
7617         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
7618
7619         /* Get Presentation Data */
7620         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7621         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
7622         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
7623         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
7624
7625         /*Set width and Height */
7626         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
7627         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
7628         if(olePress.dwSize > 0)
7629         {
7630             /* Set Length */
7631             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
7632
7633             /* Set MetaFilePict struct */
7634             MetaFilePict.mm = 8;
7635             MetaFilePict.xExt = olePress.dwExtentX;
7636             MetaFilePict.yExt = olePress.dwExtentY;
7637             MetaFilePict.hMF = 0;
7638
7639             /* Get Metafile Data */
7640             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
7641             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
7642             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
7643         }
7644         IStream_Release(pStream);
7645     }
7646 }
7647
7648 /*************************************************************************
7649  * OleConvertOLESTREAMToIStorage [OLE32.@]
7650  *
7651  * Read info on MSDN
7652  *
7653  * TODO
7654  *      DVTARGETDEVICE paramenter is not handled
7655  *      Still unsure of some mem fields for OLE 10 Stream
7656  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7657  *      and "\001OLE" streams
7658  *
7659  */
7660 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
7661     LPOLESTREAM pOleStream,
7662     LPSTORAGE pstg,
7663     const DVTARGETDEVICE* ptd)
7664 {
7665     int i;
7666     HRESULT hRes=S_OK;
7667     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7668
7669     TRACE("%p %p %p\n", pOleStream, pstg, ptd);
7670
7671     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7672
7673     if(ptd != NULL)
7674     {
7675         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
7676     }
7677
7678     if(pstg == NULL || pOleStream == NULL)
7679     {
7680         hRes = E_INVALIDARG;
7681     }
7682
7683     if(hRes == S_OK)
7684     {
7685         /* Load the OLESTREAM to Memory */
7686         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
7687     }
7688
7689     if(hRes == S_OK)
7690     {
7691         /* Load the OLESTREAM to Memory (part 2)*/
7692         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
7693     }
7694
7695     if(hRes == S_OK)
7696     {
7697
7698         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
7699         {
7700             /* Do we have the IStorage Data in the OLESTREAM */
7701             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
7702             {
7703                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7704                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
7705             }
7706             else
7707             {
7708                 /* It must be an original OLE 1.0 source */
7709                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7710             }
7711         }
7712         else
7713         {
7714             /* It must be an original OLE 1.0 source */
7715             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7716         }
7717
7718         /* Create CompObj Stream if necessary */
7719         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
7720         if(hRes == S_OK)
7721         {
7722             /*Create the Ole Stream if necessary */
7723             OLECONVERT_CreateOleStream(pstg);
7724         }
7725     }
7726
7727
7728     /* Free allocated memory */
7729     for(i=0; i < 2; i++)
7730     {
7731         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7732         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
7733         pOleStreamData[i].pstrOleObjFileName = NULL;
7734     }
7735     return hRes;
7736 }
7737
7738 /*************************************************************************
7739  * OleConvertIStorageToOLESTREAM [OLE32.@]
7740  *
7741  * Read info on MSDN
7742  *
7743  * Read info on MSDN
7744  *
7745  * TODO
7746  *      Still unsure of some mem fields for OLE 10 Stream
7747  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7748  *      and "\001OLE" streams.
7749  *
7750  */
7751 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
7752     LPSTORAGE pstg,
7753     LPOLESTREAM pOleStream)
7754 {
7755     int i;
7756     HRESULT hRes = S_OK;
7757     IStream *pStream;
7758     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7759     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7760
7761     TRACE("%p %p\n", pstg, pOleStream);
7762
7763     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7764
7765     if(pstg == NULL || pOleStream == NULL)
7766     {
7767         hRes = E_INVALIDARG;
7768     }
7769     if(hRes == S_OK)
7770     {
7771         /* Get the ProgID */
7772         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
7773         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
7774     }
7775     if(hRes == S_OK)
7776     {
7777         /* Was it originally Ole10 */
7778         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
7779         if(hRes == S_OK)
7780         {
7781             IStream_Release(pStream);
7782             /* Get Presentation Data for Ole10Native */
7783             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
7784         }
7785         else
7786         {
7787             /* Get Presentation Data (OLE20) */
7788             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
7789         }
7790
7791         /* Save OLESTREAM */
7792         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
7793         if(hRes == S_OK)
7794         {
7795             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
7796         }
7797
7798     }
7799
7800     /* Free allocated memory */
7801     for(i=0; i < 2; i++)
7802     {
7803         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7804     }
7805
7806     return hRes;
7807 }
7808
7809 /***********************************************************************
7810  *              GetConvertStg (OLE32.@)
7811  */
7812 HRESULT WINAPI GetConvertStg(IStorage *stg) {
7813     FIXME("unimplemented stub!\n");
7814     return E_FAIL;
7815 }
7816
7817 /******************************************************************************
7818  * StgIsStorageFile [OLE32.@]
7819  * Verify if the file contains a storage object
7820  *
7821  * PARAMS
7822  *  fn      [ I] Filename
7823  *
7824  * RETURNS
7825  *  S_OK    if file has magic bytes as a storage object
7826  *  S_FALSE if file is not storage
7827  */
7828 HRESULT WINAPI
7829 StgIsStorageFile(LPCOLESTR fn)
7830 {
7831         HANDLE          hf;
7832         BYTE            magic[8];
7833         DWORD           bytes_read;
7834
7835         TRACE("%s\n", debugstr_w(fn));
7836         hf = CreateFileW(fn, GENERIC_READ,
7837                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
7838                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7839
7840         if (hf == INVALID_HANDLE_VALUE)
7841                 return STG_E_FILENOTFOUND;
7842
7843         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
7844         {
7845                 WARN(" unable to read file\n");
7846                 CloseHandle(hf);
7847                 return S_FALSE;
7848         }
7849
7850         CloseHandle(hf);
7851
7852         if (bytes_read != 8) {
7853                 WARN(" too short\n");
7854                 return S_FALSE;
7855         }
7856
7857         if (!memcmp(magic,STORAGE_magic,8)) {
7858                 WARN(" -> YES\n");
7859                 return S_OK;
7860         }
7861
7862         WARN(" -> Invalid header.\n");
7863         return S_FALSE;
7864 }
7865
7866 /***********************************************************************
7867  *              WriteClassStm (OLE32.@)
7868  *
7869  * Writes a CLSID to a stream.
7870  *
7871  * PARAMS
7872  *  pStm   [I] Stream to write to.
7873  *  rclsid [I] CLSID to write.
7874  *
7875  * RETURNS
7876  *  Success: S_OK.
7877  *  Failure: HRESULT code.
7878  */
7879 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
7880 {
7881     TRACE("(%p,%p)\n",pStm,rclsid);
7882
7883     if (!pStm || !rclsid)
7884         return E_INVALIDARG;
7885
7886     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
7887 }
7888
7889 /***********************************************************************
7890  *              ReadClassStm (OLE32.@)
7891  *
7892  * Reads a CLSID from a stream.
7893  *
7894  * PARAMS
7895  *  pStm   [I] Stream to read from.
7896  *  rclsid [O] CLSID to read.
7897  *
7898  * RETURNS
7899  *  Success: S_OK.
7900  *  Failure: HRESULT code.
7901  */
7902 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
7903 {
7904     ULONG nbByte;
7905     HRESULT res;
7906
7907     TRACE("(%p,%p)\n",pStm,pclsid);
7908
7909     if (!pStm || !pclsid)
7910         return E_INVALIDARG;
7911
7912     /* clear the output args */
7913     memcpy(pclsid, &CLSID_NULL, sizeof(*pclsid));
7914
7915     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
7916
7917     if (FAILED(res))
7918         return res;
7919
7920     if (nbByte != sizeof(CLSID))
7921         return STG_E_READFAULT;
7922     else
7923         return S_OK;
7924 }