wined3d: Implement more GLSL instructions and a little cleanup.
[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     if (stgfmt == STGFMT_DOCFILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5833     {
5834         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
5835         return STG_E_INVALIDPARAMETER;  
5836     }
5837
5838     if (stgfmt == STGFMT_FILE)
5839     {
5840         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5841         return STG_E_INVALIDPARAMETER;
5842     }
5843
5844     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE || stgfmt == STGFMT_ANY)
5845     {
5846         if (stgfmt == STGFMT_ANY) 
5847             WARN("STGFMT_ANY assuming storage\n");
5848         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
5849         return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); 
5850     }
5851
5852     ERR("Invalid stgfmt argument\n");
5853     return STG_E_INVALIDPARAMETER;
5854 }
5855
5856
5857 /******************************************************************************
5858  *              StgOpenStorage        [OLE32.@]
5859  */
5860 HRESULT WINAPI StgOpenStorage(
5861   const OLECHAR *pwcsName,
5862   IStorage      *pstgPriority,
5863   DWORD           grfMode,
5864   SNB           snbExclude,
5865   DWORD           reserved,
5866   IStorage      **ppstgOpen)
5867 {
5868   StorageImpl* newStorage = 0;
5869   HRESULT        hr = S_OK;
5870   HANDLE       hFile = 0;
5871   DWORD          shareMode;
5872   DWORD          accessMode;
5873   WCHAR          fullname[MAX_PATH];
5874   DWORD          length;
5875
5876   TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5877         debugstr_w(pwcsName), pstgPriority, grfMode,
5878         snbExclude, reserved, ppstgOpen);
5879
5880   /*
5881    * Perform sanity checks
5882    */
5883   if (pwcsName == 0)
5884   {
5885     hr = STG_E_INVALIDNAME;
5886     goto end;
5887   }
5888
5889   if (ppstgOpen == 0)
5890   {
5891     hr = STG_E_INVALIDPOINTER;
5892     goto end;
5893   }
5894
5895   if (reserved)
5896   {
5897     hr = STG_E_INVALIDPARAMETER;
5898     goto end;
5899   }
5900
5901   if (grfMode & STGM_PRIORITY)
5902   {
5903     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
5904       return STG_E_INVALIDFLAG;
5905     if (grfMode & STGM_DELETEONRELEASE)
5906       return STG_E_INVALIDFUNCTION;
5907     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
5908       return STG_E_INVALIDFLAG;
5909     grfMode &= ~0xf0; /* remove the existing sharing mode */
5910     grfMode |= STGM_SHARE_DENY_NONE;
5911
5912     /* STGM_PRIORITY stops other IStorage objects on the same file from
5913      * committing until the STGM_PRIORITY IStorage is closed. it also
5914      * stops non-transacted mode StgOpenStorage calls with write access from
5915      * succeeding. obviously, both of these cannot be achieved through just
5916      * file share flags */
5917     FIXME("STGM_PRIORITY mode not implemented correctly\n");
5918   }
5919
5920   /*
5921    * Validate the sharing mode
5922    */
5923   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
5924     switch(STGM_SHARE_MODE(grfMode))
5925     {
5926       case STGM_SHARE_EXCLUSIVE:
5927       case STGM_SHARE_DENY_WRITE:
5928         break;
5929       default:
5930         hr = STG_E_INVALIDFLAG;
5931         goto end;
5932     }
5933
5934   /*
5935    * Validate the STGM flags
5936    */
5937   if ( FAILED( validateSTGM(grfMode) ) ||
5938        (grfMode&STGM_CREATE))
5939   {
5940     hr = STG_E_INVALIDFLAG;
5941     goto end;
5942   }
5943
5944   /* shared reading requires transacted mode */
5945   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
5946       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
5947      !(grfMode&STGM_TRANSACTED) )
5948   {
5949     hr = STG_E_INVALIDFLAG;
5950     goto end;
5951   }
5952
5953   /*
5954    * Interpret the STGM value grfMode
5955    */
5956   shareMode    = GetShareModeFromSTGM(grfMode);
5957   accessMode   = GetAccessModeFromSTGM(grfMode);
5958
5959   /*
5960    * Initialize the "out" parameter.
5961    */
5962   *ppstgOpen = 0;
5963
5964   hFile = CreateFileW( pwcsName,
5965                        accessMode,
5966                        shareMode,
5967                        NULL,
5968                        OPEN_EXISTING,
5969                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5970                        0);
5971
5972   if (hFile==INVALID_HANDLE_VALUE)
5973   {
5974     DWORD last_error = GetLastError();
5975
5976     hr = E_FAIL;
5977
5978     switch (last_error)
5979     {
5980       case ERROR_FILE_NOT_FOUND:
5981         hr = STG_E_FILENOTFOUND;
5982         break;
5983
5984       case ERROR_PATH_NOT_FOUND:
5985         hr = STG_E_PATHNOTFOUND;
5986         break;
5987
5988       case ERROR_ACCESS_DENIED:
5989       case ERROR_WRITE_PROTECT:
5990         hr = STG_E_ACCESSDENIED;
5991         break;
5992
5993       case ERROR_SHARING_VIOLATION:
5994         hr = STG_E_SHAREVIOLATION;
5995         break;
5996
5997       default:
5998         hr = E_FAIL;
5999     }
6000
6001     goto end;
6002   }
6003
6004   /*
6005    * Refuse to open the file if it's too small to be a structured storage file
6006    * FIXME: verify the file when reading instead of here
6007    */
6008   length = GetFileSize(hFile, NULL);
6009   if (length < 0x100)
6010   {
6011     CloseHandle(hFile);
6012     hr = STG_E_FILEALREADYEXISTS;
6013     goto end;
6014   }
6015
6016   /*
6017    * Allocate and initialize the new IStorage32object.
6018    */
6019   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6020
6021   if (newStorage == 0)
6022   {
6023     hr = STG_E_INSUFFICIENTMEMORY;
6024     goto end;
6025   }
6026
6027   /* if the file's length was zero, initialize the storage */
6028   hr = StorageImpl_Construct(
6029          newStorage,
6030          hFile,
6031         pwcsName,
6032          NULL,
6033          grfMode,
6034          TRUE,
6035          FALSE );
6036
6037   if (FAILED(hr))
6038   {
6039     HeapFree(GetProcessHeap(), 0, newStorage);
6040     /*
6041      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
6042      */
6043     if(hr == STG_E_INVALIDHEADER)
6044         hr = STG_E_FILEALREADYEXISTS;
6045     goto end;
6046   }
6047
6048   /* prepare the file name string given in lieu of the root property name */
6049   GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
6050   memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
6051   newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
6052
6053   /*
6054    * Get an "out" pointer for the caller.
6055    */
6056   hr = StorageBaseImpl_QueryInterface(
6057          (IStorage*)newStorage,
6058          (REFIID)&IID_IStorage,
6059          (void**)ppstgOpen);
6060
6061 end:
6062   TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
6063   return hr;
6064 }
6065
6066 /******************************************************************************
6067  *    StgCreateDocfileOnILockBytes    [OLE32.@]
6068  */
6069 HRESULT WINAPI StgCreateDocfileOnILockBytes(
6070       ILockBytes *plkbyt,
6071       DWORD grfMode,
6072       DWORD reserved,
6073       IStorage** ppstgOpen)
6074 {
6075   StorageImpl*   newStorage = 0;
6076   HRESULT        hr         = S_OK;
6077
6078   /*
6079    * Validate the parameters
6080    */
6081   if ((ppstgOpen == 0) || (plkbyt == 0))
6082     return STG_E_INVALIDPOINTER;
6083
6084   /*
6085    * Allocate and initialize the new IStorage object.
6086    */
6087   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6088
6089   if (newStorage == 0)
6090     return STG_E_INSUFFICIENTMEMORY;
6091
6092   hr = StorageImpl_Construct(
6093          newStorage,
6094          0,
6095         0,
6096          plkbyt,
6097          grfMode,
6098          FALSE,
6099          TRUE);
6100
6101   if (FAILED(hr))
6102   {
6103     HeapFree(GetProcessHeap(), 0, newStorage);
6104     return hr;
6105   }
6106
6107   /*
6108    * Get an "out" pointer for the caller.
6109    */
6110   hr = StorageBaseImpl_QueryInterface(
6111          (IStorage*)newStorage,
6112          (REFIID)&IID_IStorage,
6113          (void**)ppstgOpen);
6114
6115   return hr;
6116 }
6117
6118 /******************************************************************************
6119  *    StgOpenStorageOnILockBytes    [OLE32.@]
6120  */
6121 HRESULT WINAPI StgOpenStorageOnILockBytes(
6122       ILockBytes *plkbyt,
6123       IStorage *pstgPriority,
6124       DWORD grfMode,
6125       SNB snbExclude,
6126       DWORD reserved,
6127       IStorage **ppstgOpen)
6128 {
6129   StorageImpl* newStorage = 0;
6130   HRESULT        hr = S_OK;
6131
6132   /*
6133    * Perform a sanity check
6134    */
6135   if ((plkbyt == 0) || (ppstgOpen == 0))
6136     return STG_E_INVALIDPOINTER;
6137
6138   /*
6139    * Validate the STGM flags
6140    */
6141   if ( FAILED( validateSTGM(grfMode) ))
6142     return STG_E_INVALIDFLAG;
6143
6144   /*
6145    * Initialize the "out" parameter.
6146    */
6147   *ppstgOpen = 0;
6148
6149   /*
6150    * Allocate and initialize the new IStorage object.
6151    */
6152   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6153
6154   if (newStorage == 0)
6155     return STG_E_INSUFFICIENTMEMORY;
6156
6157   hr = StorageImpl_Construct(
6158          newStorage,
6159          0,
6160          0,
6161          plkbyt,
6162          grfMode,
6163          FALSE,
6164          FALSE);
6165
6166   if (FAILED(hr))
6167   {
6168     HeapFree(GetProcessHeap(), 0, newStorage);
6169     return hr;
6170   }
6171
6172   /*
6173    * Get an "out" pointer for the caller.
6174    */
6175   hr = StorageBaseImpl_QueryInterface(
6176          (IStorage*)newStorage,
6177          (REFIID)&IID_IStorage,
6178          (void**)ppstgOpen);
6179
6180   return hr;
6181 }
6182
6183 /******************************************************************************
6184  *              StgSetTimes [ole32.@]
6185  *              StgSetTimes [OLE32.@]
6186  *
6187  *
6188  */
6189 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6190                            FILETIME const *patime, FILETIME const *pmtime)
6191 {
6192   IStorage *stg = NULL;
6193   HRESULT r;
6194  
6195   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6196
6197   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6198                      0, 0, &stg);
6199   if( SUCCEEDED(r) )
6200   {
6201     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6202     IStorage_Release(stg);
6203   }
6204
6205   return r;
6206 }
6207
6208 /******************************************************************************
6209  *              StgIsStorageILockBytes        [OLE32.@]
6210  *
6211  * Determines if the ILockBytes contains a storage object.
6212  */
6213 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6214 {
6215   BYTE sig[8];
6216   ULARGE_INTEGER offset;
6217
6218   offset.u.HighPart = 0;
6219   offset.u.LowPart  = 0;
6220
6221   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6222
6223   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6224     return S_OK;
6225
6226   return S_FALSE;
6227 }
6228
6229 /******************************************************************************
6230  *              WriteClassStg        [OLE32.@]
6231  *
6232  * This method will store the specified CLSID in the specified storage object
6233  */
6234 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6235 {
6236   HRESULT hRes;
6237
6238   if(!pStg)
6239     return E_INVALIDARG;
6240
6241   hRes = IStorage_SetClass(pStg, rclsid);
6242
6243   return hRes;
6244 }
6245
6246 /***********************************************************************
6247  *    ReadClassStg (OLE32.@)
6248  *
6249  * This method reads the CLSID previously written to a storage object with
6250  * the WriteClassStg.
6251  *
6252  * PARAMS
6253  *  pstg    [I] IStorage pointer
6254  *  pclsid  [O] Pointer to where the CLSID is written
6255  *
6256  * RETURNS
6257  *  Success: S_OK.
6258  *  Failure: HRESULT code.
6259  */
6260 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6261
6262     STATSTG pstatstg;
6263     HRESULT hRes;
6264
6265     TRACE("(%p, %p)\n", pstg, pclsid);
6266
6267     if(!pstg || !pclsid)
6268         return E_INVALIDARG;
6269
6270    /*
6271     * read a STATSTG structure (contains the clsid) from the storage
6272     */
6273     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
6274
6275     if(SUCCEEDED(hRes))
6276         *pclsid=pstatstg.clsid;
6277
6278     return hRes;
6279 }
6280
6281 /***********************************************************************
6282  *    OleLoadFromStream (OLE32.@)
6283  *
6284  * This function loads an object from stream
6285  */
6286 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6287 {
6288     CLSID       clsid;
6289     HRESULT     res;
6290     LPPERSISTSTREAM     xstm;
6291
6292     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6293
6294     res=ReadClassStm(pStm,&clsid);
6295     if (!SUCCEEDED(res))
6296         return res;
6297     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6298     if (!SUCCEEDED(res))
6299         return res;
6300     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6301     if (!SUCCEEDED(res)) {
6302         IUnknown_Release((IUnknown*)*ppvObj);
6303         return res;
6304     }
6305     res=IPersistStream_Load(xstm,pStm);
6306     IPersistStream_Release(xstm);
6307     /* FIXME: all refcounts ok at this point? I think they should be:
6308      *          pStm    : unchanged
6309      *          ppvObj  : 1
6310      *          xstm    : 0 (released)
6311      */
6312     return res;
6313 }
6314
6315 /***********************************************************************
6316  *    OleSaveToStream (OLE32.@)
6317  *
6318  * This function saves an object with the IPersistStream interface on it
6319  * to the specified stream.
6320  */
6321 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6322 {
6323
6324     CLSID clsid;
6325     HRESULT res;
6326
6327     TRACE("(%p,%p)\n",pPStm,pStm);
6328
6329     res=IPersistStream_GetClassID(pPStm,&clsid);
6330
6331     if (SUCCEEDED(res)){
6332
6333         res=WriteClassStm(pStm,&clsid);
6334
6335         if (SUCCEEDED(res))
6336
6337             res=IPersistStream_Save(pPStm,pStm,TRUE);
6338     }
6339
6340     TRACE("Finished Save\n");
6341     return res;
6342 }
6343
6344 /****************************************************************************
6345  * This method validate a STGM parameter that can contain the values below
6346  *
6347  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6348  * The stgm values contained in 0xffff0000 are bitmasks.
6349  *
6350  * STGM_DIRECT               0x00000000
6351  * STGM_TRANSACTED           0x00010000
6352  * STGM_SIMPLE               0x08000000
6353  *
6354  * STGM_READ                 0x00000000
6355  * STGM_WRITE                0x00000001
6356  * STGM_READWRITE            0x00000002
6357  *
6358  * STGM_SHARE_DENY_NONE      0x00000040
6359  * STGM_SHARE_DENY_READ      0x00000030
6360  * STGM_SHARE_DENY_WRITE     0x00000020
6361  * STGM_SHARE_EXCLUSIVE      0x00000010
6362  *
6363  * STGM_PRIORITY             0x00040000
6364  * STGM_DELETEONRELEASE      0x04000000
6365  *
6366  * STGM_CREATE               0x00001000
6367  * STGM_CONVERT              0x00020000
6368  * STGM_FAILIFTHERE          0x00000000
6369  *
6370  * STGM_NOSCRATCH            0x00100000
6371  * STGM_NOSNAPSHOT           0x00200000
6372  */
6373 static HRESULT validateSTGM(DWORD stgm)
6374 {
6375   DWORD access = STGM_ACCESS_MODE(stgm);
6376   DWORD share  = STGM_SHARE_MODE(stgm);
6377   DWORD create = STGM_CREATE_MODE(stgm);
6378
6379   if (stgm&~STGM_KNOWN_FLAGS)
6380   {
6381     ERR("unknown flags %08lx\n", stgm);
6382     return E_FAIL;
6383   }
6384
6385   switch (access)
6386   {
6387   case STGM_READ:
6388   case STGM_WRITE:
6389   case STGM_READWRITE:
6390     break;
6391   default:
6392     return E_FAIL;
6393   }
6394
6395   switch (share)
6396   {
6397   case STGM_SHARE_DENY_NONE:
6398   case STGM_SHARE_DENY_READ:
6399   case STGM_SHARE_DENY_WRITE:
6400   case STGM_SHARE_EXCLUSIVE:
6401     break;
6402   default:
6403     return E_FAIL;
6404   }
6405
6406   switch (create)
6407   {
6408   case STGM_CREATE:
6409   case STGM_FAILIFTHERE:
6410     break;
6411   default:
6412     return E_FAIL;
6413   }
6414
6415   /*
6416    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
6417    */
6418   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
6419       return E_FAIL;
6420
6421   /*
6422    * STGM_CREATE | STGM_CONVERT
6423    * if both are false, STGM_FAILIFTHERE is set to TRUE
6424    */
6425   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
6426     return E_FAIL;
6427
6428   /*
6429    * STGM_NOSCRATCH requires STGM_TRANSACTED
6430    */
6431   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
6432     return E_FAIL;
6433
6434   /*
6435    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
6436    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
6437    */
6438   if ( (stgm & STGM_NOSNAPSHOT) &&
6439         (!(stgm & STGM_TRANSACTED) ||
6440          share == STGM_SHARE_EXCLUSIVE ||
6441          share == STGM_SHARE_DENY_WRITE) )
6442     return E_FAIL;
6443
6444   return S_OK;
6445 }
6446
6447 /****************************************************************************
6448  *      GetShareModeFromSTGM
6449  *
6450  * This method will return a share mode flag from a STGM value.
6451  * The STGM value is assumed valid.
6452  */
6453 static DWORD GetShareModeFromSTGM(DWORD stgm)
6454 {
6455   switch (STGM_SHARE_MODE(stgm))
6456   {
6457   case STGM_SHARE_DENY_NONE:
6458     return FILE_SHARE_READ | FILE_SHARE_WRITE;
6459   case STGM_SHARE_DENY_READ:
6460     return FILE_SHARE_WRITE;
6461   case STGM_SHARE_DENY_WRITE:
6462     return FILE_SHARE_READ;
6463   case STGM_SHARE_EXCLUSIVE:
6464     return 0;
6465   }
6466   ERR("Invalid share mode!\n");
6467   assert(0);
6468   return 0;
6469 }
6470
6471 /****************************************************************************
6472  *      GetAccessModeFromSTGM
6473  *
6474  * This method will return an access mode flag from a STGM value.
6475  * The STGM value is assumed valid.
6476  */
6477 static DWORD GetAccessModeFromSTGM(DWORD stgm)
6478 {
6479   switch (STGM_ACCESS_MODE(stgm))
6480   {
6481   case STGM_READ:
6482     return GENERIC_READ;
6483   case STGM_WRITE:
6484   case STGM_READWRITE:
6485     return GENERIC_READ | GENERIC_WRITE;
6486   }
6487   ERR("Invalid access mode!\n");
6488   assert(0);
6489   return 0;
6490 }
6491
6492 /****************************************************************************
6493  *      GetCreationModeFromSTGM
6494  *
6495  * This method will return a creation mode flag from a STGM value.
6496  * The STGM value is assumed valid.
6497  */
6498 static DWORD GetCreationModeFromSTGM(DWORD stgm)
6499 {
6500   switch(STGM_CREATE_MODE(stgm))
6501   {
6502   case STGM_CREATE:
6503     return CREATE_ALWAYS;
6504   case STGM_CONVERT:
6505     FIXME("STGM_CONVERT not implemented!\n");
6506     return CREATE_NEW;
6507   case STGM_FAILIFTHERE:
6508     return CREATE_NEW;
6509   }
6510   ERR("Invalid create mode!\n");
6511   assert(0);
6512   return 0;
6513 }
6514
6515
6516 /*************************************************************************
6517  * OLECONVERT_LoadOLE10 [Internal]
6518  *
6519  * Loads the OLE10 STREAM to memory
6520  *
6521  * PARAMS
6522  *     pOleStream   [I] The OLESTREAM
6523  *     pData        [I] Data Structure for the OLESTREAM Data
6524  *
6525  * RETURNS
6526  *     Success:  S_OK
6527  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
6528  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
6529  *
6530  * NOTES
6531  *     This function is used by OleConvertOLESTREAMToIStorage only.
6532  *
6533  *     Memory allocated for pData must be freed by the caller
6534  */
6535 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
6536 {
6537         DWORD dwSize;
6538         HRESULT hRes = S_OK;
6539         int nTryCnt=0;
6540         int max_try = 6;
6541
6542         pData->pData = NULL;
6543         pData->pstrOleObjFileName = (CHAR *) NULL;
6544
6545         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
6546         {
6547         /* Get the OleID */
6548         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6549         if(dwSize != sizeof(pData->dwOleID))
6550         {
6551                 hRes = CONVERT10_E_OLESTREAM_GET;
6552         }
6553         else if(pData->dwOleID != OLESTREAM_ID)
6554         {
6555                 hRes = CONVERT10_E_OLESTREAM_FMT;
6556         }
6557                 else
6558                 {
6559                         hRes = S_OK;
6560                         break;
6561                 }
6562         }
6563
6564         if(hRes == S_OK)
6565         {
6566                 /* Get the TypeID...more info needed for this field */
6567                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6568                 if(dwSize != sizeof(pData->dwTypeID))
6569                 {
6570                         hRes = CONVERT10_E_OLESTREAM_GET;
6571                 }
6572         }
6573         if(hRes == S_OK)
6574         {
6575                 if(pData->dwTypeID != 0)
6576                 {
6577                         /* Get the length of the OleTypeName */
6578                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6579                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6580                         {
6581                                 hRes = CONVERT10_E_OLESTREAM_GET;
6582                         }
6583
6584                         if(hRes == S_OK)
6585                         {
6586                                 if(pData->dwOleTypeNameLength > 0)
6587                                 {
6588                                         /* Get the OleTypeName */
6589                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
6590                                         if(dwSize != pData->dwOleTypeNameLength)
6591                                         {
6592                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6593                                         }
6594                                 }
6595                         }
6596                         if(bStrem1)
6597                         {
6598                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6599                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6600                                 {
6601                                         hRes = CONVERT10_E_OLESTREAM_GET;
6602                                 }
6603                         if(hRes == S_OK)
6604                         {
6605                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6606                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6607                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
6608                                         if(pData->pstrOleObjFileName)
6609                                         {
6610                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6611                                                 if(dwSize != pData->dwOleObjFileNameLength)
6612                                                 {
6613                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6614                                                 }
6615                                         }
6616                                         else
6617                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6618                                 }
6619                         }
6620                         else
6621                         {
6622                                 /* Get the Width of the Metafile */
6623                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6624                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
6625                                 {
6626                                         hRes = CONVERT10_E_OLESTREAM_GET;
6627                                 }
6628                         if(hRes == S_OK)
6629                         {
6630                                 /* Get the Height of the Metafile */
6631                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6632                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
6633                                 {
6634                                         hRes = CONVERT10_E_OLESTREAM_GET;
6635                                 }
6636                         }
6637                         }
6638                         if(hRes == S_OK)
6639                         {
6640                                 /* Get the Length of the Data */
6641                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6642                                 if(dwSize != sizeof(pData->dwDataLength))
6643                                 {
6644                                         hRes = CONVERT10_E_OLESTREAM_GET;
6645                                 }
6646                         }
6647
6648                         if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
6649                         {
6650                                 if(!bStrem1) /* if it is a second OLE stream data */
6651                                 {
6652                                         pData->dwDataLength -= 8;
6653                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6654                                         if(dwSize != sizeof(pData->strUnknown))
6655                                         {
6656                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6657                                         }
6658                                 }
6659                         }
6660                         if(hRes == S_OK)
6661                         {
6662                                 if(pData->dwDataLength > 0)
6663                                 {
6664                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6665
6666                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
6667                                         if(pData->pData)
6668                                         {
6669                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6670                                                 if(dwSize != pData->dwDataLength)
6671                                                 {
6672                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6673                                                 }
6674                                         }
6675                                         else
6676                                         {
6677                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6678                                         }
6679                                 }
6680                         }
6681                 }
6682         }
6683         return hRes;
6684 }
6685
6686 /*************************************************************************
6687  * OLECONVERT_SaveOLE10 [Internal]
6688  *
6689  * Saves the OLE10 STREAM From memory
6690  *
6691  * PARAMS
6692  *     pData        [I] Data Structure for the OLESTREAM Data
6693  *     pOleStream   [I] The OLESTREAM to save
6694  *
6695  * RETURNS
6696  *     Success:  S_OK
6697  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
6698  *
6699  * NOTES
6700  *     This function is used by OleConvertIStorageToOLESTREAM only.
6701  *
6702  */
6703 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6704 {
6705     DWORD dwSize;
6706     HRESULT hRes = S_OK;
6707
6708
6709    /* Set the OleID */
6710     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6711     if(dwSize != sizeof(pData->dwOleID))
6712     {
6713         hRes = CONVERT10_E_OLESTREAM_PUT;
6714     }
6715
6716     if(hRes == S_OK)
6717     {
6718         /* Set the TypeID */
6719         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6720         if(dwSize != sizeof(pData->dwTypeID))
6721         {
6722             hRes = CONVERT10_E_OLESTREAM_PUT;
6723         }
6724     }
6725
6726     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6727     {
6728         /* Set the Length of the OleTypeName */
6729         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6730         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6731         {
6732             hRes = CONVERT10_E_OLESTREAM_PUT;
6733         }
6734
6735         if(hRes == S_OK)
6736         {
6737             if(pData->dwOleTypeNameLength > 0)
6738             {
6739                 /* Set the OleTypeName */
6740                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);
6741                 if(dwSize != pData->dwOleTypeNameLength)
6742                 {
6743                     hRes = CONVERT10_E_OLESTREAM_PUT;
6744                 }
6745             }
6746         }
6747
6748         if(hRes == S_OK)
6749         {
6750             /* Set the width of the Metafile */
6751             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6752             if(dwSize != sizeof(pData->dwMetaFileWidth))
6753             {
6754                 hRes = CONVERT10_E_OLESTREAM_PUT;
6755             }
6756         }
6757
6758         if(hRes == S_OK)
6759         {
6760             /* Set the height of the Metafile */
6761             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6762             if(dwSize != sizeof(pData->dwMetaFileHeight))
6763             {
6764                 hRes = CONVERT10_E_OLESTREAM_PUT;
6765             }
6766         }
6767
6768         if(hRes == S_OK)
6769         {
6770             /* Set the length of the Data */
6771             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6772             if(dwSize != sizeof(pData->dwDataLength))
6773             {
6774                 hRes = CONVERT10_E_OLESTREAM_PUT;
6775             }
6776         }
6777
6778         if(hRes == S_OK)
6779         {
6780             if(pData->dwDataLength > 0)
6781             {
6782                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6783                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
6784                 if(dwSize != pData->dwDataLength)
6785                 {
6786                     hRes = CONVERT10_E_OLESTREAM_PUT;
6787                 }
6788             }
6789         }
6790     }
6791     return hRes;
6792 }
6793
6794 /*************************************************************************
6795  * OLECONVERT_GetOLE20FromOLE10[Internal]
6796  *
6797  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6798  * opens it, and copies the content to the dest IStorage for
6799  * OleConvertOLESTREAMToIStorage
6800  *
6801  *
6802  * PARAMS
6803  *     pDestStorage  [I] The IStorage to copy the data to
6804  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
6805  *     nBufferLength [I] The size of the buffer
6806  *
6807  * RETURNS
6808  *     Nothing
6809  *
6810  * NOTES
6811  *
6812  *
6813  */
6814 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6815 {
6816     HRESULT hRes;
6817     HANDLE hFile;
6818     IStorage *pTempStorage;
6819     DWORD dwNumOfBytesWritten;
6820     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6821     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6822
6823     /* Create a temp File */
6824     GetTempPathW(MAX_PATH, wstrTempDir);
6825     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6826     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6827
6828     if(hFile != INVALID_HANDLE_VALUE)
6829     {
6830         /* Write IStorage Data to File */
6831         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6832         CloseHandle(hFile);
6833
6834         /* Open and copy temp storage to the Dest Storage */
6835         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6836         if(hRes == S_OK)
6837         {
6838             hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6839             StorageBaseImpl_Release(pTempStorage);
6840         }
6841         DeleteFileW(wstrTempFile);
6842     }
6843 }
6844
6845
6846 /*************************************************************************
6847  * OLECONVERT_WriteOLE20ToBuffer [Internal]
6848  *
6849  * Saves the OLE10 STREAM From memory
6850  *
6851  * PARAMS
6852  *     pStorage  [I] The Src IStorage to copy
6853  *     pData     [I] The Dest Memory to write to.
6854  *
6855  * RETURNS
6856  *     The size in bytes allocated for pData
6857  *
6858  * NOTES
6859  *     Memory allocated for pData must be freed by the caller
6860  *
6861  *     Used by OleConvertIStorageToOLESTREAM only.
6862  *
6863  */
6864 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6865 {
6866     HANDLE hFile;
6867     HRESULT hRes;
6868     DWORD nDataLength = 0;
6869     IStorage *pTempStorage;
6870     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6871     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6872
6873     *pData = NULL;
6874
6875     /* Create temp Storage */
6876     GetTempPathW(MAX_PATH, wstrTempDir);
6877     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6878     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6879
6880     if(hRes == S_OK)
6881     {
6882         /* Copy Src Storage to the Temp Storage */
6883         StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6884         StorageBaseImpl_Release(pTempStorage);
6885
6886         /* Open Temp Storage as a file and copy to memory */
6887         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6888         if(hFile != INVALID_HANDLE_VALUE)
6889         {
6890             nDataLength = GetFileSize(hFile, NULL);
6891             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
6892             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6893             CloseHandle(hFile);
6894         }
6895         DeleteFileW(wstrTempFile);
6896     }
6897     return nDataLength;
6898 }
6899
6900 /*************************************************************************
6901  * OLECONVERT_CreateOleStream [Internal]
6902  *
6903  * Creates the "\001OLE" stream in the IStorage if necessary.
6904  *
6905  * PARAMS
6906  *     pStorage     [I] Dest storage to create the stream in
6907  *
6908  * RETURNS
6909  *     Nothing
6910  *
6911  * NOTES
6912  *     This function is used by OleConvertOLESTREAMToIStorage only.
6913  *
6914  *     This stream is still unknown, MS Word seems to have extra data
6915  *     but since the data is stored in the OLESTREAM there should be
6916  *     no need to recreate the stream.  If the stream is manually
6917  *     deleted it will create it with this default data.
6918  *
6919  */
6920 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6921 {
6922     HRESULT hRes;
6923     IStream *pStream;
6924     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6925     BYTE pOleStreamHeader [] =
6926     {
6927         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6928         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6929         0x00, 0x00, 0x00, 0x00
6930     };
6931
6932     /* Create stream if not present */
6933     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6934         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6935
6936     if(hRes == S_OK)
6937     {
6938         /* Write default Data */
6939         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6940         IStream_Release(pStream);
6941     }
6942 }
6943
6944 /* write a string to a stream, preceded by its length */
6945 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
6946 {
6947     HRESULT r;
6948     LPSTR str;
6949     DWORD len = 0;
6950
6951     if( string )
6952         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
6953     r = IStream_Write( stm, &len, sizeof(len), NULL);
6954     if( FAILED( r ) )
6955         return r;
6956     if(len == 0)
6957         return r;
6958     str = CoTaskMemAlloc( len );
6959     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
6960     r = IStream_Write( stm, str, len, NULL);
6961     CoTaskMemFree( str );
6962     return r;
6963 }
6964
6965 /* read a string preceded by its length from a stream */
6966 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
6967 {
6968     HRESULT r;
6969     DWORD len, count = 0;
6970     LPSTR str;
6971     LPWSTR wstr;
6972
6973     r = IStream_Read( stm, &len, sizeof(len), &count );
6974     if( FAILED( r ) )
6975         return r;
6976     if( count != sizeof(len) )
6977         return E_OUTOFMEMORY;
6978
6979     TRACE("%ld bytes\n",len);
6980     
6981     str = CoTaskMemAlloc( len );
6982     if( !str )
6983         return E_OUTOFMEMORY;
6984     count = 0;
6985     r = IStream_Read( stm, str, len, &count );
6986     if( FAILED( r ) )
6987         return r;
6988     if( count != len )
6989     {
6990         CoTaskMemFree( str );
6991         return E_OUTOFMEMORY;
6992     }
6993
6994     TRACE("Read string %s\n",debugstr_an(str,len));
6995
6996     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
6997     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
6998     if( wstr )
6999          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
7000     CoTaskMemFree( str );
7001
7002     *string = wstr;
7003
7004     return r;
7005 }
7006
7007
7008 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
7009     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
7010 {
7011     IStream *pstm;
7012     HRESULT r = S_OK;
7013     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7014
7015     static const BYTE unknown1[12] =
7016        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
7017          0xFF, 0xFF, 0xFF, 0xFF};
7018     static const BYTE unknown2[16] =
7019        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
7020          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
7021
7022     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
7023            debugstr_w(lpszUserType), debugstr_w(szClipName),
7024            debugstr_w(szProgIDName));
7025
7026     /*  Create a CompObj stream if it doesn't exist */
7027     r = IStorage_CreateStream(pstg, szwStreamName,
7028         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
7029     if( FAILED (r) )
7030         return r;
7031
7032     /* Write CompObj Structure to stream */
7033     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
7034
7035     if( SUCCEEDED( r ) )
7036         r = WriteClassStm( pstm, clsid );
7037
7038     if( SUCCEEDED( r ) )
7039         r = STREAM_WriteString( pstm, lpszUserType );
7040     if( SUCCEEDED( r ) )
7041         r = STREAM_WriteString( pstm, szClipName );
7042     if( SUCCEEDED( r ) )
7043         r = STREAM_WriteString( pstm, szProgIDName );
7044     if( SUCCEEDED( r ) )
7045         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
7046
7047     IStream_Release( pstm );
7048
7049     return r;
7050 }
7051
7052 /***********************************************************************
7053  *               WriteFmtUserTypeStg (OLE32.@)
7054  */
7055 HRESULT WINAPI WriteFmtUserTypeStg(
7056           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
7057 {
7058     HRESULT r;
7059     WCHAR szwClipName[0x40];
7060     CLSID clsid = CLSID_NULL;
7061     LPWSTR wstrProgID = NULL;
7062     DWORD n;
7063
7064     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
7065
7066     /* get the clipboard format name */
7067     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
7068     szwClipName[n]=0;
7069
7070     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
7071
7072     /* FIXME: There's room to save a CLSID and its ProgID, but
7073        the CLSID is not looked up in the registry and in all the
7074        tests I wrote it was CLSID_NULL.  Where does it come from?
7075     */
7076
7077     /* get the real program ID.  This may fail, but that's fine */
7078     ProgIDFromCLSID(&clsid, &wstrProgID);
7079
7080     TRACE("progid is %s\n",debugstr_w(wstrProgID));
7081
7082     r = STORAGE_WriteCompObj( pstg, &clsid, 
7083                               lpszUserType, szwClipName, wstrProgID );
7084
7085     CoTaskMemFree(wstrProgID);
7086
7087     return r;
7088 }
7089
7090
7091 /******************************************************************************
7092  *              ReadFmtUserTypeStg        [OLE32.@]
7093  */
7094 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
7095 {
7096     HRESULT r;
7097     IStream *stm = 0;
7098     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
7099     unsigned char unknown1[12];
7100     unsigned char unknown2[16];
7101     DWORD count;
7102     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
7103     CLSID clsid;
7104
7105     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
7106
7107     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
7108                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
7109     if( FAILED ( r ) )
7110     {
7111         WARN("Failed to open stream r = %08lx\n", r);
7112         return r;
7113     }
7114
7115     /* read the various parts of the structure */
7116     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
7117     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
7118         goto end;
7119     r = ReadClassStm( stm, &clsid );
7120     if( FAILED( r ) )
7121         goto end;
7122
7123     r = STREAM_ReadString( stm, &szCLSIDName );
7124     if( FAILED( r ) )
7125         goto end;
7126
7127     r = STREAM_ReadString( stm, &szOleTypeName );
7128     if( FAILED( r ) )
7129         goto end;
7130
7131     r = STREAM_ReadString( stm, &szProgIDName );
7132     if( FAILED( r ) )
7133         goto end;
7134
7135     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7136     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7137         goto end;
7138
7139     /* ok, success... now we just need to store what we found */
7140     if( pcf )
7141         *pcf = RegisterClipboardFormatW( szOleTypeName );
7142     CoTaskMemFree( szOleTypeName );
7143
7144     if( lplpszUserType )
7145         *lplpszUserType = szCLSIDName;
7146     CoTaskMemFree( szProgIDName );
7147
7148 end:
7149     IStream_Release( stm );
7150
7151     return r;
7152 }
7153
7154
7155 /*************************************************************************
7156  * OLECONVERT_CreateCompObjStream [Internal]
7157  *
7158  * Creates a "\001CompObj" is the destination IStorage if necessary.
7159  *
7160  * PARAMS
7161  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7162  *                        if necessary.
7163  *     strOleTypeName [I] The ProgID
7164  *
7165  * RETURNS
7166  *     Success:  S_OK
7167  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7168  *
7169  * NOTES
7170  *     This function is used by OleConvertOLESTREAMToIStorage only.
7171  *
7172  *     The stream data is stored in the OLESTREAM and there should be
7173  *     no need to recreate the stream.  If the stream is manually
7174  *     deleted it will attempt to create it by querying the registry.
7175  *
7176  *
7177  */
7178 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7179 {
7180     IStream *pStream;
7181     HRESULT hStorageRes, hRes = S_OK;
7182     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7183     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7184     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7185
7186     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7187     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7188
7189     /* Initialize the CompObj structure */
7190     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7191     memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
7192     memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
7193
7194
7195     /*  Create a CompObj stream if it doesn't exist */
7196     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7197         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7198     if(hStorageRes == S_OK)
7199     {
7200         /* copy the OleTypeName to the compobj struct */
7201         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7202         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7203
7204         /* copy the OleTypeName to the compobj struct */
7205         /* Note: in the test made, these were Identical      */
7206         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7207         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7208
7209         /* Get the CLSID */
7210         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7211                              bufferW, OLESTREAM_MAX_STR_LEN );
7212         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7213
7214         if(hRes == S_OK)
7215         {
7216             HKEY hKey;
7217             LONG hErr;
7218             /* Get the CLSID Default Name from the Registry */
7219             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7220             if(hErr == ERROR_SUCCESS)
7221             {
7222                 char strTemp[OLESTREAM_MAX_STR_LEN];
7223                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7224                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7225                 if(hErr == ERROR_SUCCESS)
7226                 {
7227                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7228                 }
7229                 RegCloseKey(hKey);
7230             }
7231         }
7232
7233         /* Write CompObj Structure to stream */
7234         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7235
7236         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7237
7238         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7239         if(IStorageCompObj.dwCLSIDNameLength > 0)
7240         {
7241             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7242         }
7243         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7244         if(IStorageCompObj.dwOleTypeNameLength > 0)
7245         {
7246             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7247         }
7248         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7249         if(IStorageCompObj.dwProgIDNameLength > 0)
7250         {
7251             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7252         }
7253         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7254         IStream_Release(pStream);
7255     }
7256     return hRes;
7257 }
7258
7259
7260 /*************************************************************************
7261  * OLECONVERT_CreateOlePresStream[Internal]
7262  *
7263  * Creates the "\002OlePres000" Stream with the Metafile data
7264  *
7265  * PARAMS
7266  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7267  *     dwExtentX    [I] Width of the Metafile
7268  *     dwExtentY    [I] Height of the Metafile
7269  *     pData        [I] Metafile data
7270  *     dwDataLength [I] Size of the Metafile data
7271  *
7272  * RETURNS
7273  *     Success:  S_OK
7274  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7275  *
7276  * NOTES
7277  *     This function is used by OleConvertOLESTREAMToIStorage only.
7278  *
7279  */
7280 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7281 {
7282     HRESULT hRes;
7283     IStream *pStream;
7284     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7285     BYTE pOlePresStreamHeader [] =
7286     {
7287         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7288         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7289         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7290         0x00, 0x00, 0x00, 0x00
7291     };
7292
7293     BYTE pOlePresStreamHeaderEmpty [] =
7294     {
7295         0x00, 0x00, 0x00, 0x00,
7296         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7297         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7298         0x00, 0x00, 0x00, 0x00
7299     };
7300
7301     /* Create the OlePres000 Stream */
7302     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7303         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7304
7305     if(hRes == S_OK)
7306     {
7307         DWORD nHeaderSize;
7308         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7309
7310         memset(&OlePres, 0, sizeof(OlePres));
7311         /* Do we have any metafile data to save */
7312         if(dwDataLength > 0)
7313         {
7314             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7315             nHeaderSize = sizeof(pOlePresStreamHeader);
7316         }
7317         else
7318         {
7319             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7320             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7321         }
7322         /* Set width and height of the metafile */
7323         OlePres.dwExtentX = dwExtentX;
7324         OlePres.dwExtentY = -dwExtentY;
7325
7326         /* Set Data and Length */
7327         if(dwDataLength > sizeof(METAFILEPICT16))
7328         {
7329             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7330             OlePres.pData = &(pData[8]);
7331         }
7332         /* Save OlePres000 Data to Stream */
7333         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7334         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7335         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7336         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7337         if(OlePres.dwSize > 0)
7338         {
7339             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7340         }
7341         IStream_Release(pStream);
7342     }
7343 }
7344
7345 /*************************************************************************
7346  * OLECONVERT_CreateOle10NativeStream [Internal]
7347  *
7348  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7349  *
7350  * PARAMS
7351  *     pStorage     [I] Dest storage to create the stream in
7352  *     pData        [I] Ole10 Native Data (ex. bmp)
7353  *     dwDataLength [I] Size of the Ole10 Native Data
7354  *
7355  * RETURNS
7356  *     Nothing
7357  *
7358  * NOTES
7359  *     This function is used by OleConvertOLESTREAMToIStorage only.
7360  *
7361  *     Might need to verify the data and return appropriate error message
7362  *
7363  */
7364 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
7365 {
7366     HRESULT hRes;
7367     IStream *pStream;
7368     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7369
7370     /* Create the Ole10Native Stream */
7371     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7372         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7373
7374     if(hRes == S_OK)
7375     {
7376         /* Write info to stream */
7377         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7378         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7379         IStream_Release(pStream);
7380     }
7381
7382 }
7383
7384 /*************************************************************************
7385  * OLECONVERT_GetOLE10ProgID [Internal]
7386  *
7387  * Finds the ProgID (or OleTypeID) from the IStorage
7388  *
7389  * PARAMS
7390  *     pStorage        [I] The Src IStorage to get the ProgID
7391  *     strProgID       [I] the ProgID string to get
7392  *     dwSize          [I] the size of the string
7393  *
7394  * RETURNS
7395  *     Success:  S_OK
7396  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7397  *
7398  * NOTES
7399  *     This function is used by OleConvertIStorageToOLESTREAM only.
7400  *
7401  *
7402  */
7403 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7404 {
7405     HRESULT hRes;
7406     IStream *pStream;
7407     LARGE_INTEGER iSeekPos;
7408     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
7409     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7410
7411     /* Open the CompObj Stream */
7412     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7413         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7414     if(hRes == S_OK)
7415     {
7416
7417         /*Get the OleType from the CompObj Stream */
7418         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
7419         iSeekPos.u.HighPart = 0;
7420
7421         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7422         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
7423         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
7424         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7425         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
7426         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
7427         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7428
7429         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
7430         if(*dwSize > 0)
7431         {
7432             IStream_Read(pStream, strProgID, *dwSize, NULL);
7433         }
7434         IStream_Release(pStream);
7435     }
7436     else
7437     {
7438         STATSTG stat;
7439         LPOLESTR wstrProgID;
7440
7441         /* Get the OleType from the registry */
7442         REFCLSID clsid = &(stat.clsid);
7443         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
7444         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
7445         if(hRes == S_OK)
7446         {
7447             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
7448         }
7449
7450     }
7451     return hRes;
7452 }
7453
7454 /*************************************************************************
7455  * OLECONVERT_GetOle10PresData [Internal]
7456  *
7457  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
7458  *
7459  * PARAMS
7460  *     pStorage     [I] Src IStroage
7461  *     pOleStream   [I] Dest OleStream Mem Struct
7462  *
7463  * RETURNS
7464  *     Nothing
7465  *
7466  * NOTES
7467  *     This function is used by OleConvertIStorageToOLESTREAM only.
7468  *
7469  *     Memory allocated for pData must be freed by the caller
7470  *
7471  *
7472  */
7473 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7474 {
7475
7476     HRESULT hRes;
7477     IStream *pStream;
7478     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7479
7480     /* Initialize Default data for OLESTREAM */
7481     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7482     pOleStreamData[0].dwTypeID = 2;
7483     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7484     pOleStreamData[1].dwTypeID = 0;
7485     pOleStreamData[0].dwMetaFileWidth = 0;
7486     pOleStreamData[0].dwMetaFileHeight = 0;
7487     pOleStreamData[0].pData = NULL;
7488     pOleStreamData[1].pData = NULL;
7489
7490     /* Open Ole10Native Stream */
7491     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7492         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7493     if(hRes == S_OK)
7494     {
7495
7496         /* Read Size and Data */
7497         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
7498         if(pOleStreamData->dwDataLength > 0)
7499         {
7500             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
7501             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
7502         }
7503         IStream_Release(pStream);
7504     }
7505
7506 }
7507
7508
7509 /*************************************************************************
7510  * OLECONVERT_GetOle20PresData[Internal]
7511  *
7512  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
7513  *
7514  * PARAMS
7515  *     pStorage         [I] Src IStroage
7516  *     pOleStreamData   [I] Dest OleStream Mem Struct
7517  *
7518  * RETURNS
7519  *     Nothing
7520  *
7521  * NOTES
7522  *     This function is used by OleConvertIStorageToOLESTREAM only.
7523  *
7524  *     Memory allocated for pData must be freed by the caller
7525  */
7526 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7527 {
7528     HRESULT hRes;
7529     IStream *pStream;
7530     OLECONVERT_ISTORAGE_OLEPRES olePress;
7531     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7532
7533     /* Initialize Default data for OLESTREAM */
7534     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7535     pOleStreamData[0].dwTypeID = 2;
7536     pOleStreamData[0].dwMetaFileWidth = 0;
7537     pOleStreamData[0].dwMetaFileHeight = 0;
7538     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
7539     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7540     pOleStreamData[1].dwTypeID = 0;
7541     pOleStreamData[1].dwOleTypeNameLength = 0;
7542     pOleStreamData[1].strOleTypeName[0] = 0;
7543     pOleStreamData[1].dwMetaFileWidth = 0;
7544     pOleStreamData[1].dwMetaFileHeight = 0;
7545     pOleStreamData[1].pData = NULL;
7546     pOleStreamData[1].dwDataLength = 0;
7547
7548
7549     /* Open OlePress000 stream */
7550     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7551         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7552     if(hRes == S_OK)
7553     {
7554         LARGE_INTEGER iSeekPos;
7555         METAFILEPICT16 MetaFilePict;
7556         static const char strMetafilePictName[] = "METAFILEPICT";
7557
7558         /* Set the TypeID for a Metafile */
7559         pOleStreamData[1].dwTypeID = 5;
7560
7561         /* Set the OleTypeName to Metafile */
7562         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
7563         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
7564
7565         iSeekPos.u.HighPart = 0;
7566         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
7567
7568         /* Get Presentation Data */
7569         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7570         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
7571         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
7572         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
7573
7574         /*Set width and Height */
7575         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
7576         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
7577         if(olePress.dwSize > 0)
7578         {
7579             /* Set Length */
7580             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
7581
7582             /* Set MetaFilePict struct */
7583             MetaFilePict.mm = 8;
7584             MetaFilePict.xExt = olePress.dwExtentX;
7585             MetaFilePict.yExt = olePress.dwExtentY;
7586             MetaFilePict.hMF = 0;
7587
7588             /* Get Metafile Data */
7589             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
7590             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
7591             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
7592         }
7593         IStream_Release(pStream);
7594     }
7595 }
7596
7597 /*************************************************************************
7598  * OleConvertOLESTREAMToIStorage [OLE32.@]
7599  *
7600  * Read info on MSDN
7601  *
7602  * TODO
7603  *      DVTARGETDEVICE paramenter is not handled
7604  *      Still unsure of some mem fields for OLE 10 Stream
7605  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7606  *      and "\001OLE" streams
7607  *
7608  */
7609 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
7610     LPOLESTREAM pOleStream,
7611     LPSTORAGE pstg,
7612     const DVTARGETDEVICE* ptd)
7613 {
7614     int i;
7615     HRESULT hRes=S_OK;
7616     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7617
7618     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7619
7620     if(ptd != NULL)
7621     {
7622         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
7623     }
7624
7625     if(pstg == NULL || pOleStream == NULL)
7626     {
7627         hRes = E_INVALIDARG;
7628     }
7629
7630     if(hRes == S_OK)
7631     {
7632         /* Load the OLESTREAM to Memory */
7633         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
7634     }
7635
7636     if(hRes == S_OK)
7637     {
7638         /* Load the OLESTREAM to Memory (part 2)*/
7639         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
7640     }
7641
7642     if(hRes == S_OK)
7643     {
7644
7645         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
7646         {
7647             /* Do we have the IStorage Data in the OLESTREAM */
7648             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
7649             {
7650                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7651                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
7652             }
7653             else
7654             {
7655                 /* It must be an original OLE 1.0 source */
7656                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7657             }
7658         }
7659         else
7660         {
7661             /* It must be an original OLE 1.0 source */
7662             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7663         }
7664
7665         /* Create CompObj Stream if necessary */
7666         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
7667         if(hRes == S_OK)
7668         {
7669             /*Create the Ole Stream if necessary */
7670             OLECONVERT_CreateOleStream(pstg);
7671         }
7672     }
7673
7674
7675     /* Free allocated memory */
7676     for(i=0; i < 2; i++)
7677     {
7678         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7679         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
7680         pOleStreamData[i].pstrOleObjFileName = NULL;
7681     }
7682     return hRes;
7683 }
7684
7685 /*************************************************************************
7686  * OleConvertIStorageToOLESTREAM [OLE32.@]
7687  *
7688  * Read info on MSDN
7689  *
7690  * Read info on MSDN
7691  *
7692  * TODO
7693  *      Still unsure of some mem fields for OLE 10 Stream
7694  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7695  *      and "\001OLE" streams.
7696  *
7697  */
7698 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
7699     LPSTORAGE pstg,
7700     LPOLESTREAM pOleStream)
7701 {
7702     int i;
7703     HRESULT hRes = S_OK;
7704     IStream *pStream;
7705     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7706     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7707
7708
7709     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7710
7711     if(pstg == NULL || pOleStream == NULL)
7712     {
7713         hRes = E_INVALIDARG;
7714     }
7715     if(hRes == S_OK)
7716     {
7717         /* Get the ProgID */
7718         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
7719         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
7720     }
7721     if(hRes == S_OK)
7722     {
7723         /* Was it originally Ole10 */
7724         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
7725         if(hRes == S_OK)
7726         {
7727             IStream_Release(pStream);
7728             /* Get Presentation Data for Ole10Native */
7729             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
7730         }
7731         else
7732         {
7733             /* Get Presentation Data (OLE20) */
7734             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
7735         }
7736
7737         /* Save OLESTREAM */
7738         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
7739         if(hRes == S_OK)
7740         {
7741             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
7742         }
7743
7744     }
7745
7746     /* Free allocated memory */
7747     for(i=0; i < 2; i++)
7748     {
7749         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7750     }
7751
7752     return hRes;
7753 }
7754
7755 /***********************************************************************
7756  *              GetConvertStg (OLE32.@)
7757  */
7758 HRESULT WINAPI GetConvertStg(IStorage *stg) {
7759     FIXME("unimplemented stub!\n");
7760     return E_FAIL;
7761 }
7762
7763 /******************************************************************************
7764  * StgIsStorageFile [OLE32.@]
7765  * Verify if the file contains a storage object
7766  *
7767  * PARAMS
7768  *  fn      [ I] Filename
7769  *
7770  * RETURNS
7771  *  S_OK    if file has magic bytes as a storage object
7772  *  S_FALSE if file is not storage
7773  */
7774 HRESULT WINAPI
7775 StgIsStorageFile(LPCOLESTR fn)
7776 {
7777         HANDLE          hf;
7778         BYTE            magic[8];
7779         DWORD           bytes_read;
7780
7781         TRACE("(\'%s\')\n", debugstr_w(fn));
7782         hf = CreateFileW(fn, GENERIC_READ,
7783                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
7784                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7785
7786         if (hf == INVALID_HANDLE_VALUE)
7787                 return STG_E_FILENOTFOUND;
7788
7789         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
7790         {
7791                 WARN(" unable to read file\n");
7792                 CloseHandle(hf);
7793                 return S_FALSE;
7794         }
7795
7796         CloseHandle(hf);
7797
7798         if (bytes_read != 8) {
7799                 WARN(" too short\n");
7800                 return S_FALSE;
7801         }
7802
7803         if (!memcmp(magic,STORAGE_magic,8)) {
7804                 WARN(" -> YES\n");
7805                 return S_OK;
7806         }
7807
7808         WARN(" -> Invalid header.\n");
7809         return S_FALSE;
7810 }