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