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