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