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