wined3d: Update the device palette if the primary palette is changed.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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_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 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 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 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 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 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 ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
3648   IEnumSTATSTG* iface)
3649 {
3650   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3651   return InterlockedIncrement(&This->ref);
3652 }
3653
3654 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 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 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 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 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     ULARGE_INTEGER fileSize =
4816       BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4817
4818     ULONG diff = newSize.u.LowPart - size.u.LowPart;
4819
4820     /*
4821      * Make sure the file stays a multiple of blocksize
4822      */
4823     if ((diff % This->parentStorage->bigBlockSize) != 0)
4824       diff += (This->parentStorage->bigBlockSize -
4825                 (diff % This->parentStorage->bigBlockSize) );
4826
4827     fileSize.u.LowPart += diff;
4828     BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4829
4830     BlockChainStream_Enlarge(This, newSize);
4831   }
4832
4833   return TRUE;
4834 }
4835
4836 /******************************************************************************
4837  *      BlockChainStream_GetSize
4838  *
4839  * Returns the size of this chain.
4840  * Will return the block count if this chain doesn't have a property.
4841  */
4842 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4843 {
4844   StgProperty chainProperty;
4845
4846   if(This->headOfStreamPlaceHolder == NULL)
4847   {
4848     /*
4849      * This chain is a data stream read the property and return
4850      * the appropriate size
4851      */
4852     StorageImpl_ReadProperty(
4853       This->parentStorage,
4854       This->ownerPropertyIndex,
4855       &chainProperty);
4856
4857     return chainProperty.size;
4858   }
4859   else
4860   {
4861     /*
4862      * this chain is a chain that does not have a property, figure out the
4863      * size by making the product number of used blocks times the
4864      * size of them
4865      */
4866     ULARGE_INTEGER result;
4867     result.u.HighPart = 0;
4868
4869     result.u.LowPart  =
4870       BlockChainStream_GetCount(This) *
4871       This->parentStorage->bigBlockSize;
4872
4873     return result;
4874   }
4875 }
4876
4877 /******************************************************************************
4878 ** SmallBlockChainStream implementation
4879 */
4880
4881 SmallBlockChainStream* SmallBlockChainStream_Construct(
4882   StorageImpl* parentStorage,
4883   ULONG          propertyIndex)
4884 {
4885   SmallBlockChainStream* newStream;
4886
4887   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4888
4889   newStream->parentStorage      = parentStorage;
4890   newStream->ownerPropertyIndex = propertyIndex;
4891
4892   return newStream;
4893 }
4894
4895 void SmallBlockChainStream_Destroy(
4896   SmallBlockChainStream* This)
4897 {
4898   HeapFree(GetProcessHeap(), 0, This);
4899 }
4900
4901 /******************************************************************************
4902  *      SmallBlockChainStream_GetHeadOfChain
4903  *
4904  * Returns the head of this chain of small blocks.
4905  */
4906 ULONG SmallBlockChainStream_GetHeadOfChain(
4907   SmallBlockChainStream* This)
4908 {
4909   StgProperty chainProperty;
4910   BOOL      readSuccessful;
4911
4912   if (This->ownerPropertyIndex)
4913   {
4914     readSuccessful = StorageImpl_ReadProperty(
4915                       This->parentStorage,
4916                       This->ownerPropertyIndex,
4917                       &chainProperty);
4918
4919     if (readSuccessful)
4920     {
4921       return chainProperty.startingBlock;
4922     }
4923
4924   }
4925
4926   return BLOCK_END_OF_CHAIN;
4927 }
4928
4929 /******************************************************************************
4930  *      SmallBlockChainStream_GetNextBlockInChain
4931  *
4932  * Returns the index of the next small block in this chain.
4933  *
4934  * Return Values:
4935  *    - BLOCK_END_OF_CHAIN: end of this chain
4936  *    - BLOCK_UNUSED: small block 'blockIndex' is free
4937  */
4938 HRESULT SmallBlockChainStream_GetNextBlockInChain(
4939   SmallBlockChainStream* This,
4940   ULONG                  blockIndex,
4941   ULONG*                 nextBlockInChain)
4942 {
4943   ULARGE_INTEGER offsetOfBlockInDepot;
4944   DWORD  buffer;
4945   ULONG  bytesRead;
4946   BOOL success;
4947
4948   *nextBlockInChain = BLOCK_END_OF_CHAIN;
4949
4950   offsetOfBlockInDepot.u.HighPart = 0;
4951   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
4952
4953   /*
4954    * Read those bytes in the buffer from the small block file.
4955    */
4956   success = BlockChainStream_ReadAt(
4957               This->parentStorage->smallBlockDepotChain,
4958               offsetOfBlockInDepot,
4959               sizeof(DWORD),
4960               &buffer,
4961               &bytesRead);
4962
4963   if (success)
4964   {
4965     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
4966     return S_OK;
4967   }
4968
4969   return STG_E_READFAULT;
4970 }
4971
4972 /******************************************************************************
4973  *       SmallBlockChainStream_SetNextBlockInChain
4974  *
4975  * Writes the index of the next block of the specified block in the small
4976  * block depot.
4977  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4978  * To flag a block as free use BLOCK_UNUSED as nextBlock.
4979  */
4980 void SmallBlockChainStream_SetNextBlockInChain(
4981   SmallBlockChainStream* This,
4982   ULONG                  blockIndex,
4983   ULONG                  nextBlock)
4984 {
4985   ULARGE_INTEGER offsetOfBlockInDepot;
4986   DWORD  buffer;
4987   ULONG  bytesWritten;
4988
4989   offsetOfBlockInDepot.u.HighPart = 0;
4990   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
4991
4992   StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
4993
4994   /*
4995    * Read those bytes in the buffer from the small block file.
4996    */
4997   BlockChainStream_WriteAt(
4998     This->parentStorage->smallBlockDepotChain,
4999     offsetOfBlockInDepot,
5000     sizeof(DWORD),
5001     &buffer,
5002     &bytesWritten);
5003 }
5004
5005 /******************************************************************************
5006  *      SmallBlockChainStream_FreeBlock
5007  *
5008  * Flag small block 'blockIndex' as free in the small block depot.
5009  */
5010 void SmallBlockChainStream_FreeBlock(
5011   SmallBlockChainStream* This,
5012   ULONG                  blockIndex)
5013 {
5014   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
5015 }
5016
5017 /******************************************************************************
5018  *      SmallBlockChainStream_GetNextFreeBlock
5019  *
5020  * Returns the index of a free small block. The small block depot will be
5021  * enlarged if necessary. The small block chain will also be enlarged if
5022  * necessary.
5023  */
5024 ULONG SmallBlockChainStream_GetNextFreeBlock(
5025   SmallBlockChainStream* This)
5026 {
5027   ULARGE_INTEGER offsetOfBlockInDepot;
5028   DWORD buffer;
5029   ULONG bytesRead;
5030   ULONG blockIndex = 0;
5031   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
5032   BOOL success = TRUE;
5033   ULONG smallBlocksPerBigBlock;
5034
5035   offsetOfBlockInDepot.u.HighPart = 0;
5036
5037   /*
5038    * Scan the small block depot for a free block
5039    */
5040   while (nextBlockIndex != BLOCK_UNUSED)
5041   {
5042     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
5043
5044     success = BlockChainStream_ReadAt(
5045                 This->parentStorage->smallBlockDepotChain,
5046                 offsetOfBlockInDepot,
5047                 sizeof(DWORD),
5048                 &buffer,
5049                 &bytesRead);
5050
5051     /*
5052      * If we run out of space for the small block depot, enlarge it
5053      */
5054     if (success)
5055     {
5056       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
5057
5058       if (nextBlockIndex != BLOCK_UNUSED)
5059         blockIndex++;
5060     }
5061     else
5062     {
5063       ULONG count =
5064         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
5065
5066       ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
5067       ULONG nextBlock, newsbdIndex;
5068       BYTE* smallBlockDepot;
5069
5070       nextBlock = sbdIndex;
5071       while (nextBlock != BLOCK_END_OF_CHAIN)
5072       {
5073         sbdIndex = nextBlock;
5074         StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock);
5075       }
5076
5077       newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5078       if (sbdIndex != BLOCK_END_OF_CHAIN)
5079         StorageImpl_SetNextBlockInChain(
5080           This->parentStorage,
5081           sbdIndex,
5082           newsbdIndex);
5083
5084       StorageImpl_SetNextBlockInChain(
5085         This->parentStorage,
5086         newsbdIndex,
5087         BLOCK_END_OF_CHAIN);
5088
5089       /*
5090        * Initialize all the small blocks to free
5091        */
5092       smallBlockDepot =
5093         StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
5094
5095       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
5096       StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
5097
5098       if (count == 0)
5099       {
5100         /*
5101          * We have just created the small block depot.
5102          */
5103         StgProperty rootProp;
5104         ULONG sbStartIndex;
5105
5106         /*
5107          * Save it in the header
5108          */
5109         This->parentStorage->smallBlockDepotStart = newsbdIndex;
5110         StorageImpl_SaveFileHeader(This->parentStorage);
5111
5112         /*
5113          * And allocate the first big block that will contain small blocks
5114          */
5115         sbStartIndex =
5116           StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5117
5118         StorageImpl_SetNextBlockInChain(
5119           This->parentStorage,
5120           sbStartIndex,
5121           BLOCK_END_OF_CHAIN);
5122
5123         StorageImpl_ReadProperty(
5124           This->parentStorage,
5125           This->parentStorage->base.rootPropertySetIndex,
5126           &rootProp);
5127
5128         rootProp.startingBlock = sbStartIndex;
5129         rootProp.size.u.HighPart = 0;
5130         rootProp.size.u.LowPart  = This->parentStorage->bigBlockSize;
5131
5132         StorageImpl_WriteProperty(
5133           This->parentStorage,
5134           This->parentStorage->base.rootPropertySetIndex,
5135           &rootProp);
5136       }
5137     }
5138   }
5139
5140   smallBlocksPerBigBlock =
5141     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
5142
5143   /*
5144    * Verify if we have to allocate big blocks to contain small blocks
5145    */
5146   if (blockIndex % smallBlocksPerBigBlock == 0)
5147   {
5148     StgProperty rootProp;
5149     ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
5150
5151     StorageImpl_ReadProperty(
5152       This->parentStorage,
5153       This->parentStorage->base.rootPropertySetIndex,
5154       &rootProp);
5155
5156     if (rootProp.size.u.LowPart <
5157        (blocksRequired * This->parentStorage->bigBlockSize))
5158     {
5159       rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;
5160
5161       BlockChainStream_SetSize(
5162         This->parentStorage->smallBlockRootChain,
5163         rootProp.size);
5164
5165       StorageImpl_WriteProperty(
5166         This->parentStorage,
5167         This->parentStorage->base.rootPropertySetIndex,
5168         &rootProp);
5169     }
5170   }
5171
5172   return blockIndex;
5173 }
5174
5175 /******************************************************************************
5176  *      SmallBlockChainStream_ReadAt
5177  *
5178  * Reads a specified number of bytes from this chain at the specified offset.
5179  * bytesRead may be NULL.
5180  * Failure will be returned if the specified number of bytes has not been read.
5181  */
5182 HRESULT SmallBlockChainStream_ReadAt(
5183   SmallBlockChainStream* This,
5184   ULARGE_INTEGER         offset,
5185   ULONG                  size,
5186   void*                  buffer,
5187   ULONG*                 bytesRead)
5188 {
5189   HRESULT rc = S_OK;
5190   ULARGE_INTEGER offsetInBigBlockFile;
5191   ULONG blockNoInSequence =
5192     offset.u.LowPart / This->parentStorage->smallBlockSize;
5193
5194   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5195   ULONG bytesToReadInBuffer;
5196   ULONG blockIndex;
5197   ULONG bytesReadFromBigBlockFile;
5198   BYTE* bufferWalker;
5199
5200   /*
5201    * This should never happen on a small block file.
5202    */
5203   assert(offset.u.HighPart==0);
5204
5205   /*
5206    * Find the first block in the stream that contains part of the buffer.
5207    */
5208   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5209
5210   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5211   {
5212     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5213     if(FAILED(rc))
5214       return rc;
5215     blockNoInSequence--;
5216   }
5217
5218   /*
5219    * Start reading the buffer.
5220    */
5221   *bytesRead   = 0;
5222   bufferWalker = buffer;
5223
5224   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5225   {
5226     /*
5227      * Calculate how many bytes we can copy from this small block.
5228      */
5229     bytesToReadInBuffer =
5230       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5231
5232     /*
5233      * Calculate the offset of the small block in the small block file.
5234      */
5235     offsetInBigBlockFile.u.HighPart  = 0;
5236     offsetInBigBlockFile.u.LowPart   =
5237       blockIndex * This->parentStorage->smallBlockSize;
5238
5239     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5240
5241     /*
5242      * Read those bytes in the buffer from the small block file.
5243      * The small block has already been identified so it shouldn't fail
5244      * unless the file is corrupt.
5245      */
5246     if (!BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
5247       offsetInBigBlockFile,
5248       bytesToReadInBuffer,
5249       bufferWalker,
5250       &bytesReadFromBigBlockFile))
5251       return STG_E_DOCFILECORRUPT;
5252
5253     assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
5254
5255     /*
5256      * Step to the next big block.
5257      */
5258     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5259     if(FAILED(rc))
5260       return rc;
5261
5262     bufferWalker += bytesToReadInBuffer;
5263     size         -= bytesToReadInBuffer;
5264     *bytesRead   += bytesToReadInBuffer;
5265     offsetInBlock = 0;  /* There is no offset on the next block */
5266   }
5267
5268   return rc;
5269 }
5270
5271 /******************************************************************************
5272  *       SmallBlockChainStream_WriteAt
5273  *
5274  * Writes the specified number of bytes to this chain at the specified offset.
5275  * bytesWritten may be NULL.
5276  * Will fail if not all specified number of bytes have been written.
5277  */
5278 BOOL SmallBlockChainStream_WriteAt(
5279   SmallBlockChainStream* This,
5280   ULARGE_INTEGER offset,
5281   ULONG          size,
5282   const void*    buffer,
5283   ULONG*         bytesWritten)
5284 {
5285   ULARGE_INTEGER offsetInBigBlockFile;
5286   ULONG blockNoInSequence =
5287     offset.u.LowPart / This->parentStorage->smallBlockSize;
5288
5289   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5290   ULONG bytesToWriteInBuffer;
5291   ULONG blockIndex;
5292   ULONG bytesWrittenFromBigBlockFile;
5293   const BYTE* bufferWalker;
5294
5295   /*
5296    * This should never happen on a small block file.
5297    */
5298   assert(offset.u.HighPart==0);
5299
5300   /*
5301    * Find the first block in the stream that contains part of the buffer.
5302    */
5303   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5304
5305   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5306   {
5307     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
5308       return FALSE;
5309     blockNoInSequence--;
5310   }
5311
5312   /*
5313    * Start writing the buffer.
5314    *
5315    * Here, I'm casting away the constness on the buffer variable
5316    * This is OK since we don't intend to modify that buffer.
5317    */
5318   *bytesWritten   = 0;
5319   bufferWalker = (const BYTE*)buffer;
5320   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5321   {
5322     /*
5323      * Calculate how many bytes we can copy to this small block.
5324      */
5325     bytesToWriteInBuffer =
5326       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5327
5328     /*
5329      * Calculate the offset of the small block in the small block file.
5330      */
5331     offsetInBigBlockFile.u.HighPart  = 0;
5332     offsetInBigBlockFile.u.LowPart   =
5333       blockIndex * This->parentStorage->smallBlockSize;
5334
5335     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5336
5337     /*
5338      * Write those bytes in the buffer to the small block file.
5339      */
5340     BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
5341       offsetInBigBlockFile,
5342       bytesToWriteInBuffer,
5343       bufferWalker,
5344       &bytesWrittenFromBigBlockFile);
5345
5346     assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
5347
5348     /*
5349      * Step to the next big block.
5350      */
5351     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5352                                                         &blockIndex)))
5353       return FALSE;
5354     bufferWalker  += bytesToWriteInBuffer;
5355     size          -= bytesToWriteInBuffer;
5356     *bytesWritten += bytesToWriteInBuffer;
5357     offsetInBlock  = 0;     /* There is no offset on the next block */
5358   }
5359
5360   return (size == 0);
5361 }
5362
5363 /******************************************************************************
5364  *       SmallBlockChainStream_Shrink
5365  *
5366  * Shrinks this chain in the small block depot.
5367  */
5368 BOOL SmallBlockChainStream_Shrink(
5369   SmallBlockChainStream* This,
5370   ULARGE_INTEGER newSize)
5371 {
5372   ULONG blockIndex, extraBlock;
5373   ULONG numBlocks;
5374   ULONG count = 0;
5375
5376   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5377
5378   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5379     numBlocks++;
5380
5381   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5382
5383   /*
5384    * Go to the new end of chain
5385    */
5386   while (count < numBlocks)
5387   {
5388     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5389                                                         &blockIndex)))
5390       return FALSE;
5391     count++;
5392   }
5393
5394   /*
5395    * If the count is 0, we have a special case, the head of the chain was
5396    * just freed.
5397    */
5398   if (count == 0)
5399   {
5400     StgProperty chainProp;
5401
5402     StorageImpl_ReadProperty(This->parentStorage,
5403                              This->ownerPropertyIndex,
5404                              &chainProp);
5405
5406     chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5407
5408     StorageImpl_WriteProperty(This->parentStorage,
5409                               This->ownerPropertyIndex,
5410                               &chainProp);
5411
5412     /*
5413      * We start freeing the chain at the head block.
5414      */
5415     extraBlock = blockIndex;
5416   }
5417   else
5418   {
5419     /* Get the next block before marking the new end */
5420     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5421                                                         &extraBlock)))
5422       return FALSE;
5423
5424     /* Mark the new end of chain */
5425     SmallBlockChainStream_SetNextBlockInChain(
5426       This,
5427       blockIndex,
5428       BLOCK_END_OF_CHAIN);
5429   }
5430
5431   /*
5432    * Mark the extra blocks as free
5433    */
5434   while (extraBlock != BLOCK_END_OF_CHAIN)
5435   {
5436     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
5437                                                         &blockIndex)))
5438       return FALSE;
5439     SmallBlockChainStream_FreeBlock(This, extraBlock);
5440     extraBlock = blockIndex;
5441   }
5442
5443   return TRUE;
5444 }
5445
5446 /******************************************************************************
5447  *      SmallBlockChainStream_Enlarge
5448  *
5449  * Grows this chain in the small block depot.
5450  */
5451 BOOL SmallBlockChainStream_Enlarge(
5452   SmallBlockChainStream* This,
5453   ULARGE_INTEGER newSize)
5454 {
5455   ULONG blockIndex, currentBlock;
5456   ULONG newNumBlocks;
5457   ULONG oldNumBlocks = 0;
5458
5459   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5460
5461   /*
5462    * Empty chain
5463    */
5464   if (blockIndex == BLOCK_END_OF_CHAIN)
5465   {
5466
5467     StgProperty chainProp;
5468
5469     StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5470                                &chainProp);
5471
5472     chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
5473
5474     StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5475                                 &chainProp);
5476
5477     blockIndex = chainProp.startingBlock;
5478     SmallBlockChainStream_SetNextBlockInChain(
5479       This,
5480       blockIndex,
5481       BLOCK_END_OF_CHAIN);
5482   }
5483
5484   currentBlock = blockIndex;
5485
5486   /*
5487    * Figure out how many blocks are needed to contain this stream
5488    */
5489   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5490
5491   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5492     newNumBlocks++;
5493
5494   /*
5495    * Go to the current end of chain
5496    */
5497   while (blockIndex != BLOCK_END_OF_CHAIN)
5498   {
5499     oldNumBlocks++;
5500     currentBlock = blockIndex;
5501     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
5502       return FALSE;
5503   }
5504
5505   /*
5506    * Add new blocks to the chain
5507    */
5508   while (oldNumBlocks < newNumBlocks)
5509   {
5510     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5511     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5512
5513     SmallBlockChainStream_SetNextBlockInChain(
5514       This,
5515       blockIndex,
5516       BLOCK_END_OF_CHAIN);
5517
5518     currentBlock = blockIndex;
5519     oldNumBlocks++;
5520   }
5521
5522   return TRUE;
5523 }
5524
5525 /******************************************************************************
5526  *      SmallBlockChainStream_GetCount
5527  *
5528  * Returns the number of blocks that comprises this chain.
5529  * This is not the size of this chain as the last block may not be full!
5530  */
5531 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
5532 {
5533   ULONG blockIndex;
5534   ULONG count = 0;
5535
5536   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5537
5538   while (blockIndex != BLOCK_END_OF_CHAIN)
5539   {
5540     count++;
5541
5542     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
5543       return 0;
5544   }
5545
5546   return count;
5547 }
5548
5549 /******************************************************************************
5550  *      SmallBlockChainStream_SetSize
5551  *
5552  * Sets the size of this stream.
5553  * The file will grow if we grow the chain.
5554  *
5555  * TODO: Free the actual blocks in the file when we shrink the chain.
5556  *       Currently, the blocks are still in the file. So the file size
5557  *       doesn't shrink even if we shrink streams.
5558  */
5559 BOOL SmallBlockChainStream_SetSize(
5560                 SmallBlockChainStream* This,
5561                 ULARGE_INTEGER    newSize)
5562 {
5563   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5564
5565   if (newSize.u.LowPart == size.u.LowPart)
5566     return TRUE;
5567
5568   if (newSize.u.LowPart < size.u.LowPart)
5569   {
5570     SmallBlockChainStream_Shrink(This, newSize);
5571   }
5572   else
5573   {
5574     SmallBlockChainStream_Enlarge(This, newSize);
5575   }
5576
5577   return TRUE;
5578 }
5579
5580 /******************************************************************************
5581  *      SmallBlockChainStream_GetSize
5582  *
5583  * Returns the size of this chain.
5584  */
5585 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5586 {
5587   StgProperty chainProperty;
5588
5589   StorageImpl_ReadProperty(
5590     This->parentStorage,
5591     This->ownerPropertyIndex,
5592     &chainProperty);
5593
5594   return chainProperty.size;
5595 }
5596
5597 /******************************************************************************
5598  *    StgCreateDocfile  [OLE32.@]
5599  * Creates a new compound file storage object
5600  *
5601  * PARAMS
5602  *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
5603  *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
5604  *  reserved  [ ?] unused?, usually 0
5605  *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
5606  *
5607  * RETURNS
5608  *  S_OK if the file was successfully created
5609  *  some STG_E_ value if error
5610  * NOTES
5611  *  if pwcsName is NULL, create file with new unique name
5612  *  the function can returns
5613  *  STG_S_CONVERTED if the specified file was successfully converted to storage format
5614  *  (unrealized now)
5615  */
5616 HRESULT WINAPI StgCreateDocfile(
5617   LPCOLESTR pwcsName,
5618   DWORD       grfMode,
5619   DWORD       reserved,
5620   IStorage  **ppstgOpen)
5621 {
5622   StorageImpl* newStorage = 0;
5623   HANDLE       hFile      = INVALID_HANDLE_VALUE;
5624   HRESULT        hr         = STG_E_INVALIDFLAG;
5625   DWORD          shareMode;
5626   DWORD          accessMode;
5627   DWORD          creationMode;
5628   DWORD          fileAttributes;
5629   WCHAR          tempFileName[MAX_PATH];
5630
5631   TRACE("(%s, %lx, %ld, %p)\n",
5632         debugstr_w(pwcsName), grfMode,
5633         reserved, ppstgOpen);
5634
5635   /*
5636    * Validate the parameters
5637    */
5638   if (ppstgOpen == 0)
5639     return STG_E_INVALIDPOINTER;
5640   if (reserved != 0)
5641     return STG_E_INVALIDPARAMETER;
5642
5643   /*
5644    * Validate the STGM flags
5645    */
5646   if ( FAILED( validateSTGM(grfMode) ))
5647     goto end;
5648
5649   /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
5650   switch(STGM_ACCESS_MODE(grfMode))
5651   {
5652   case STGM_WRITE:
5653   case STGM_READWRITE:
5654     break;
5655   default:
5656     goto end;
5657   }
5658
5659   /* if no share mode given then DENY_NONE is the default */     
5660   if (STGM_SHARE_MODE(grfMode) == 0)
5661     grfMode |= STGM_SHARE_DENY_NONE;
5662
5663   /* must have at least one access mode */
5664   if (STGM_ACCESS_MODE(grfMode) == 0)
5665     goto end;
5666   
5667   /* in direct mode, can only use SHARE_EXCLUSIVE */
5668   if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
5669     goto end;
5670
5671   /* but in transacted mode, any share mode is valid */
5672
5673   /*
5674    * Generate a unique name.
5675    */
5676   if (pwcsName == 0)
5677   {
5678     WCHAR tempPath[MAX_PATH];
5679     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5680
5681     if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
5682       goto end;
5683
5684     memset(tempPath, 0, sizeof(tempPath));
5685     memset(tempFileName, 0, sizeof(tempFileName));
5686
5687     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5688       tempPath[0] = '.';
5689
5690     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5691       pwcsName = tempFileName;
5692     else
5693     {
5694       hr = STG_E_INSUFFICIENTMEMORY;
5695       goto end;
5696     }
5697
5698     creationMode = TRUNCATE_EXISTING;
5699   }
5700   else
5701   {
5702     creationMode = GetCreationModeFromSTGM(grfMode);
5703   }
5704
5705   /*
5706    * Interpret the STGM value grfMode
5707    */
5708   shareMode    = GetShareModeFromSTGM(grfMode);
5709   accessMode   = GetAccessModeFromSTGM(grfMode);
5710
5711   if (grfMode & STGM_DELETEONRELEASE)
5712     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5713   else
5714     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5715
5716   if (grfMode & STGM_TRANSACTED)
5717     FIXME("Transacted mode not implemented.\n");
5718
5719   /*
5720    * Initialize the "out" parameter.
5721    */
5722   *ppstgOpen = 0;
5723
5724   hFile = CreateFileW(pwcsName,
5725                         accessMode,
5726                         shareMode,
5727                         NULL,
5728                         creationMode,
5729                         fileAttributes,
5730                         0);
5731
5732   if (hFile == INVALID_HANDLE_VALUE)
5733   {
5734     if(GetLastError() == ERROR_FILE_EXISTS)
5735       hr = STG_E_FILEALREADYEXISTS;
5736     else
5737       hr = E_FAIL;
5738     goto end;
5739   }
5740
5741   /*
5742    * Allocate and initialize the new IStorage32object.
5743    */
5744   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5745
5746   if (newStorage == 0)
5747   {
5748     hr = STG_E_INSUFFICIENTMEMORY;
5749     goto end;
5750   }
5751
5752   hr = StorageImpl_Construct(
5753          newStorage,
5754          hFile,
5755         pwcsName,
5756          NULL,
5757          grfMode,
5758          TRUE,
5759          TRUE);
5760
5761   if (FAILED(hr))
5762   {
5763     HeapFree(GetProcessHeap(), 0, newStorage);
5764     goto end;
5765   }
5766
5767   /*
5768    * Get an "out" pointer for the caller.
5769    */
5770   hr = StorageBaseImpl_QueryInterface(
5771          (IStorage*)newStorage,
5772          (REFIID)&IID_IStorage,
5773          (void**)ppstgOpen);
5774 end:
5775   TRACE("<-- %p  r = %08lx\n", *ppstgOpen, hr);
5776
5777   return hr;
5778 }
5779
5780 /******************************************************************************
5781  *              StgCreateStorageEx        [OLE32.@]
5782  */
5783 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5784 {
5785     TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5786           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5787
5788     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
5789     {
5790         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
5791         return STG_E_INVALIDPARAMETER;  
5792     }
5793
5794     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5795     {
5796         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
5797         return STG_E_INVALIDPARAMETER;  
5798     }
5799
5800     if (stgfmt == STGFMT_FILE)
5801     {
5802         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5803         return STG_E_INVALIDPARAMETER;
5804     }
5805
5806     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
5807     {
5808         FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
5809         return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); 
5810     }
5811
5812     ERR("Invalid stgfmt argument\n");
5813     return STG_E_INVALIDPARAMETER;
5814 }
5815
5816 /******************************************************************************
5817  *              StgCreatePropSetStg       [OLE32.@]
5818  */
5819 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
5820  IPropertySetStorage **ppPropSetStg)
5821 {
5822     HRESULT hr;
5823
5824     TRACE("(%p, 0x%lx, %p)\n", pstg, reserved, ppPropSetStg);
5825     if (reserved)
5826         hr = STG_E_INVALIDPARAMETER;
5827     else
5828         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
5829          (void**)ppPropSetStg);
5830     return hr;
5831 }
5832
5833 /******************************************************************************
5834  *              StgOpenStorageEx      [OLE32.@]
5835  */
5836 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5837 {
5838     TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5839           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5840
5841     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
5842     {
5843         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
5844         return STG_E_INVALIDPARAMETER;  
5845     }
5846
5847     if (stgfmt == STGFMT_DOCFILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5848     {
5849         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
5850         return STG_E_INVALIDPARAMETER;  
5851     }
5852
5853     if (stgfmt == STGFMT_FILE)
5854     {
5855         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5856         return STG_E_INVALIDPARAMETER;
5857     }
5858
5859     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE || stgfmt == STGFMT_ANY)
5860     {
5861         if (stgfmt == STGFMT_ANY) 
5862             WARN("STGFMT_ANY assuming storage\n");
5863         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
5864         return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); 
5865     }
5866
5867     ERR("Invalid stgfmt argument\n");
5868     return STG_E_INVALIDPARAMETER;
5869 }
5870
5871
5872 /******************************************************************************
5873  *              StgOpenStorage        [OLE32.@]
5874  */
5875 HRESULT WINAPI StgOpenStorage(
5876   const OLECHAR *pwcsName,
5877   IStorage      *pstgPriority,
5878   DWORD           grfMode,
5879   SNB           snbExclude,
5880   DWORD           reserved,
5881   IStorage      **ppstgOpen)
5882 {
5883   StorageImpl* newStorage = 0;
5884   HRESULT        hr = S_OK;
5885   HANDLE       hFile = 0;
5886   DWORD          shareMode;
5887   DWORD          accessMode;
5888   WCHAR          fullname[MAX_PATH];
5889   DWORD          length;
5890
5891   TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5892         debugstr_w(pwcsName), pstgPriority, grfMode,
5893         snbExclude, reserved, ppstgOpen);
5894
5895   /*
5896    * Perform sanity checks
5897    */
5898   if (pwcsName == 0)
5899   {
5900     hr = STG_E_INVALIDNAME;
5901     goto end;
5902   }
5903
5904   if (ppstgOpen == 0)
5905   {
5906     hr = STG_E_INVALIDPOINTER;
5907     goto end;
5908   }
5909
5910   if (reserved)
5911   {
5912     hr = STG_E_INVALIDPARAMETER;
5913     goto end;
5914   }
5915
5916   if (grfMode & STGM_PRIORITY)
5917   {
5918     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
5919       return STG_E_INVALIDFLAG;
5920     if (grfMode & STGM_DELETEONRELEASE)
5921       return STG_E_INVALIDFUNCTION;
5922     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
5923       return STG_E_INVALIDFLAG;
5924     grfMode &= ~0xf0; /* remove the existing sharing mode */
5925     grfMode |= STGM_SHARE_DENY_NONE;
5926
5927     /* STGM_PRIORITY stops other IStorage objects on the same file from
5928      * committing until the STGM_PRIORITY IStorage is closed. it also
5929      * stops non-transacted mode StgOpenStorage calls with write access from
5930      * succeeding. obviously, both of these cannot be achieved through just
5931      * file share flags */
5932     FIXME("STGM_PRIORITY mode not implemented correctly\n");
5933   }
5934
5935   /*
5936    * Validate the sharing mode
5937    */
5938   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
5939     switch(STGM_SHARE_MODE(grfMode))
5940     {
5941       case STGM_SHARE_EXCLUSIVE:
5942       case STGM_SHARE_DENY_WRITE:
5943         break;
5944       default:
5945         hr = STG_E_INVALIDFLAG;
5946         goto end;
5947     }
5948
5949   /*
5950    * Validate the STGM flags
5951    */
5952   if ( FAILED( validateSTGM(grfMode) ) ||
5953        (grfMode&STGM_CREATE))
5954   {
5955     hr = STG_E_INVALIDFLAG;
5956     goto end;
5957   }
5958
5959   /* shared reading requires transacted mode */
5960   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
5961       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
5962      !(grfMode&STGM_TRANSACTED) )
5963   {
5964     hr = STG_E_INVALIDFLAG;
5965     goto end;
5966   }
5967
5968   /*
5969    * Interpret the STGM value grfMode
5970    */
5971   shareMode    = GetShareModeFromSTGM(grfMode);
5972   accessMode   = GetAccessModeFromSTGM(grfMode);
5973
5974   /*
5975    * Initialize the "out" parameter.
5976    */
5977   *ppstgOpen = 0;
5978
5979   hFile = CreateFileW( pwcsName,
5980                        accessMode,
5981                        shareMode,
5982                        NULL,
5983                        OPEN_EXISTING,
5984                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5985                        0);
5986
5987   if (hFile==INVALID_HANDLE_VALUE)
5988   {
5989     DWORD last_error = GetLastError();
5990
5991     hr = E_FAIL;
5992
5993     switch (last_error)
5994     {
5995       case ERROR_FILE_NOT_FOUND:
5996         hr = STG_E_FILENOTFOUND;
5997         break;
5998
5999       case ERROR_PATH_NOT_FOUND:
6000         hr = STG_E_PATHNOTFOUND;
6001         break;
6002
6003       case ERROR_ACCESS_DENIED:
6004       case ERROR_WRITE_PROTECT:
6005         hr = STG_E_ACCESSDENIED;
6006         break;
6007
6008       case ERROR_SHARING_VIOLATION:
6009         hr = STG_E_SHAREVIOLATION;
6010         break;
6011
6012       default:
6013         hr = E_FAIL;
6014     }
6015
6016     goto end;
6017   }
6018
6019   /*
6020    * Refuse to open the file if it's too small to be a structured storage file
6021    * FIXME: verify the file when reading instead of here
6022    */
6023   length = GetFileSize(hFile, NULL);
6024   if (length < 0x100)
6025   {
6026     CloseHandle(hFile);
6027     hr = STG_E_FILEALREADYEXISTS;
6028     goto end;
6029   }
6030
6031   /*
6032    * Allocate and initialize the new IStorage32object.
6033    */
6034   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6035
6036   if (newStorage == 0)
6037   {
6038     hr = STG_E_INSUFFICIENTMEMORY;
6039     goto end;
6040   }
6041
6042   /* if the file's length was zero, initialize the storage */
6043   hr = StorageImpl_Construct(
6044          newStorage,
6045          hFile,
6046         pwcsName,
6047          NULL,
6048          grfMode,
6049          TRUE,
6050          FALSE );
6051
6052   if (FAILED(hr))
6053   {
6054     HeapFree(GetProcessHeap(), 0, newStorage);
6055     /*
6056      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
6057      */
6058     if(hr == STG_E_INVALIDHEADER)
6059         hr = STG_E_FILEALREADYEXISTS;
6060     goto end;
6061   }
6062
6063   /* prepare the file name string given in lieu of the root property name */
6064   GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
6065   memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
6066   newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
6067
6068   /*
6069    * Get an "out" pointer for the caller.
6070    */
6071   hr = StorageBaseImpl_QueryInterface(
6072          (IStorage*)newStorage,
6073          (REFIID)&IID_IStorage,
6074          (void**)ppstgOpen);
6075
6076 end:
6077   TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
6078   return hr;
6079 }
6080
6081 /******************************************************************************
6082  *    StgCreateDocfileOnILockBytes    [OLE32.@]
6083  */
6084 HRESULT WINAPI StgCreateDocfileOnILockBytes(
6085       ILockBytes *plkbyt,
6086       DWORD grfMode,
6087       DWORD reserved,
6088       IStorage** ppstgOpen)
6089 {
6090   StorageImpl*   newStorage = 0;
6091   HRESULT        hr         = S_OK;
6092
6093   /*
6094    * Validate the parameters
6095    */
6096   if ((ppstgOpen == 0) || (plkbyt == 0))
6097     return STG_E_INVALIDPOINTER;
6098
6099   /*
6100    * Allocate and initialize the new IStorage object.
6101    */
6102   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6103
6104   if (newStorage == 0)
6105     return STG_E_INSUFFICIENTMEMORY;
6106
6107   hr = StorageImpl_Construct(
6108          newStorage,
6109          0,
6110         0,
6111          plkbyt,
6112          grfMode,
6113          FALSE,
6114          TRUE);
6115
6116   if (FAILED(hr))
6117   {
6118     HeapFree(GetProcessHeap(), 0, newStorage);
6119     return hr;
6120   }
6121
6122   /*
6123    * Get an "out" pointer for the caller.
6124    */
6125   hr = StorageBaseImpl_QueryInterface(
6126          (IStorage*)newStorage,
6127          (REFIID)&IID_IStorage,
6128          (void**)ppstgOpen);
6129
6130   return hr;
6131 }
6132
6133 /******************************************************************************
6134  *    StgOpenStorageOnILockBytes    [OLE32.@]
6135  */
6136 HRESULT WINAPI StgOpenStorageOnILockBytes(
6137       ILockBytes *plkbyt,
6138       IStorage *pstgPriority,
6139       DWORD grfMode,
6140       SNB snbExclude,
6141       DWORD reserved,
6142       IStorage **ppstgOpen)
6143 {
6144   StorageImpl* newStorage = 0;
6145   HRESULT        hr = S_OK;
6146
6147   /*
6148    * Perform a sanity check
6149    */
6150   if ((plkbyt == 0) || (ppstgOpen == 0))
6151     return STG_E_INVALIDPOINTER;
6152
6153   /*
6154    * Validate the STGM flags
6155    */
6156   if ( FAILED( validateSTGM(grfMode) ))
6157     return STG_E_INVALIDFLAG;
6158
6159   /*
6160    * Initialize the "out" parameter.
6161    */
6162   *ppstgOpen = 0;
6163
6164   /*
6165    * Allocate and initialize the new IStorage object.
6166    */
6167   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6168
6169   if (newStorage == 0)
6170     return STG_E_INSUFFICIENTMEMORY;
6171
6172   hr = StorageImpl_Construct(
6173          newStorage,
6174          0,
6175          0,
6176          plkbyt,
6177          grfMode,
6178          FALSE,
6179          FALSE);
6180
6181   if (FAILED(hr))
6182   {
6183     HeapFree(GetProcessHeap(), 0, newStorage);
6184     return hr;
6185   }
6186
6187   /*
6188    * Get an "out" pointer for the caller.
6189    */
6190   hr = StorageBaseImpl_QueryInterface(
6191          (IStorage*)newStorage,
6192          (REFIID)&IID_IStorage,
6193          (void**)ppstgOpen);
6194
6195   return hr;
6196 }
6197
6198 /******************************************************************************
6199  *              StgSetTimes [ole32.@]
6200  *              StgSetTimes [OLE32.@]
6201  *
6202  *
6203  */
6204 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6205                            FILETIME const *patime, FILETIME const *pmtime)
6206 {
6207   IStorage *stg = NULL;
6208   HRESULT r;
6209  
6210   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6211
6212   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6213                      0, 0, &stg);
6214   if( SUCCEEDED(r) )
6215   {
6216     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6217     IStorage_Release(stg);
6218   }
6219
6220   return r;
6221 }
6222
6223 /******************************************************************************
6224  *              StgIsStorageILockBytes        [OLE32.@]
6225  *
6226  * Determines if the ILockBytes contains a storage object.
6227  */
6228 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6229 {
6230   BYTE sig[8];
6231   ULARGE_INTEGER offset;
6232
6233   offset.u.HighPart = 0;
6234   offset.u.LowPart  = 0;
6235
6236   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6237
6238   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6239     return S_OK;
6240
6241   return S_FALSE;
6242 }
6243
6244 /******************************************************************************
6245  *              WriteClassStg        [OLE32.@]
6246  *
6247  * This method will store the specified CLSID in the specified storage object
6248  */
6249 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6250 {
6251   HRESULT hRes;
6252
6253   if(!pStg)
6254     return E_INVALIDARG;
6255
6256   hRes = IStorage_SetClass(pStg, rclsid);
6257
6258   return hRes;
6259 }
6260
6261 /***********************************************************************
6262  *    ReadClassStg (OLE32.@)
6263  *
6264  * This method reads the CLSID previously written to a storage object with
6265  * the WriteClassStg.
6266  *
6267  * PARAMS
6268  *  pstg    [I] IStorage pointer
6269  *  pclsid  [O] Pointer to where the CLSID is written
6270  *
6271  * RETURNS
6272  *  Success: S_OK.
6273  *  Failure: HRESULT code.
6274  */
6275 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6276
6277     STATSTG pstatstg;
6278     HRESULT hRes;
6279
6280     TRACE("(%p, %p)\n", pstg, pclsid);
6281
6282     if(!pstg || !pclsid)
6283         return E_INVALIDARG;
6284
6285    /*
6286     * read a STATSTG structure (contains the clsid) from the storage
6287     */
6288     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
6289
6290     if(SUCCEEDED(hRes))
6291         *pclsid=pstatstg.clsid;
6292
6293     return hRes;
6294 }
6295
6296 /***********************************************************************
6297  *    OleLoadFromStream (OLE32.@)
6298  *
6299  * This function loads an object from stream
6300  */
6301 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6302 {
6303     CLSID       clsid;
6304     HRESULT     res;
6305     LPPERSISTSTREAM     xstm;
6306
6307     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6308
6309     res=ReadClassStm(pStm,&clsid);
6310     if (!SUCCEEDED(res))
6311         return res;
6312     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6313     if (!SUCCEEDED(res))
6314         return res;
6315     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6316     if (!SUCCEEDED(res)) {
6317         IUnknown_Release((IUnknown*)*ppvObj);
6318         return res;
6319     }
6320     res=IPersistStream_Load(xstm,pStm);
6321     IPersistStream_Release(xstm);
6322     /* FIXME: all refcounts ok at this point? I think they should be:
6323      *          pStm    : unchanged
6324      *          ppvObj  : 1
6325      *          xstm    : 0 (released)
6326      */
6327     return res;
6328 }
6329
6330 /***********************************************************************
6331  *    OleSaveToStream (OLE32.@)
6332  *
6333  * This function saves an object with the IPersistStream interface on it
6334  * to the specified stream.
6335  */
6336 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6337 {
6338
6339     CLSID clsid;
6340     HRESULT res;
6341
6342     TRACE("(%p,%p)\n",pPStm,pStm);
6343
6344     res=IPersistStream_GetClassID(pPStm,&clsid);
6345
6346     if (SUCCEEDED(res)){
6347
6348         res=WriteClassStm(pStm,&clsid);
6349
6350         if (SUCCEEDED(res))
6351
6352             res=IPersistStream_Save(pPStm,pStm,TRUE);
6353     }
6354
6355     TRACE("Finished Save\n");
6356     return res;
6357 }
6358
6359 /****************************************************************************
6360  * This method validate a STGM parameter that can contain the values below
6361  *
6362  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6363  * The stgm values contained in 0xffff0000 are bitmasks.
6364  *
6365  * STGM_DIRECT               0x00000000
6366  * STGM_TRANSACTED           0x00010000
6367  * STGM_SIMPLE               0x08000000
6368  *
6369  * STGM_READ                 0x00000000
6370  * STGM_WRITE                0x00000001
6371  * STGM_READWRITE            0x00000002
6372  *
6373  * STGM_SHARE_DENY_NONE      0x00000040
6374  * STGM_SHARE_DENY_READ      0x00000030
6375  * STGM_SHARE_DENY_WRITE     0x00000020
6376  * STGM_SHARE_EXCLUSIVE      0x00000010
6377  *
6378  * STGM_PRIORITY             0x00040000
6379  * STGM_DELETEONRELEASE      0x04000000
6380  *
6381  * STGM_CREATE               0x00001000
6382  * STGM_CONVERT              0x00020000
6383  * STGM_FAILIFTHERE          0x00000000
6384  *
6385  * STGM_NOSCRATCH            0x00100000
6386  * STGM_NOSNAPSHOT           0x00200000
6387  */
6388 static HRESULT validateSTGM(DWORD stgm)
6389 {
6390   DWORD access = STGM_ACCESS_MODE(stgm);
6391   DWORD share  = STGM_SHARE_MODE(stgm);
6392   DWORD create = STGM_CREATE_MODE(stgm);
6393
6394   if (stgm&~STGM_KNOWN_FLAGS)
6395   {
6396     ERR("unknown flags %08lx\n", stgm);
6397     return E_FAIL;
6398   }
6399
6400   switch (access)
6401   {
6402   case STGM_READ:
6403   case STGM_WRITE:
6404   case STGM_READWRITE:
6405     break;
6406   default:
6407     return E_FAIL;
6408   }
6409
6410   switch (share)
6411   {
6412   case STGM_SHARE_DENY_NONE:
6413   case STGM_SHARE_DENY_READ:
6414   case STGM_SHARE_DENY_WRITE:
6415   case STGM_SHARE_EXCLUSIVE:
6416     break;
6417   default:
6418     return E_FAIL;
6419   }
6420
6421   switch (create)
6422   {
6423   case STGM_CREATE:
6424   case STGM_FAILIFTHERE:
6425     break;
6426   default:
6427     return E_FAIL;
6428   }
6429
6430   /*
6431    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
6432    */
6433   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
6434       return E_FAIL;
6435
6436   /*
6437    * STGM_CREATE | STGM_CONVERT
6438    * if both are false, STGM_FAILIFTHERE is set to TRUE
6439    */
6440   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
6441     return E_FAIL;
6442
6443   /*
6444    * STGM_NOSCRATCH requires STGM_TRANSACTED
6445    */
6446   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
6447     return E_FAIL;
6448
6449   /*
6450    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
6451    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
6452    */
6453   if ( (stgm & STGM_NOSNAPSHOT) &&
6454         (!(stgm & STGM_TRANSACTED) ||
6455          share == STGM_SHARE_EXCLUSIVE ||
6456          share == STGM_SHARE_DENY_WRITE) )
6457     return E_FAIL;
6458
6459   return S_OK;
6460 }
6461
6462 /****************************************************************************
6463  *      GetShareModeFromSTGM
6464  *
6465  * This method will return a share mode flag from a STGM value.
6466  * The STGM value is assumed valid.
6467  */
6468 static DWORD GetShareModeFromSTGM(DWORD stgm)
6469 {
6470   switch (STGM_SHARE_MODE(stgm))
6471   {
6472   case STGM_SHARE_DENY_NONE:
6473     return FILE_SHARE_READ | FILE_SHARE_WRITE;
6474   case STGM_SHARE_DENY_READ:
6475     return FILE_SHARE_WRITE;
6476   case STGM_SHARE_DENY_WRITE:
6477     return FILE_SHARE_READ;
6478   case STGM_SHARE_EXCLUSIVE:
6479     return 0;
6480   }
6481   ERR("Invalid share mode!\n");
6482   assert(0);
6483   return 0;
6484 }
6485
6486 /****************************************************************************
6487  *      GetAccessModeFromSTGM
6488  *
6489  * This method will return an access mode flag from a STGM value.
6490  * The STGM value is assumed valid.
6491  */
6492 static DWORD GetAccessModeFromSTGM(DWORD stgm)
6493 {
6494   switch (STGM_ACCESS_MODE(stgm))
6495   {
6496   case STGM_READ:
6497     return GENERIC_READ;
6498   case STGM_WRITE:
6499   case STGM_READWRITE:
6500     return GENERIC_READ | GENERIC_WRITE;
6501   }
6502   ERR("Invalid access mode!\n");
6503   assert(0);
6504   return 0;
6505 }
6506
6507 /****************************************************************************
6508  *      GetCreationModeFromSTGM
6509  *
6510  * This method will return a creation mode flag from a STGM value.
6511  * The STGM value is assumed valid.
6512  */
6513 static DWORD GetCreationModeFromSTGM(DWORD stgm)
6514 {
6515   switch(STGM_CREATE_MODE(stgm))
6516   {
6517   case STGM_CREATE:
6518     return CREATE_ALWAYS;
6519   case STGM_CONVERT:
6520     FIXME("STGM_CONVERT not implemented!\n");
6521     return CREATE_NEW;
6522   case STGM_FAILIFTHERE:
6523     return CREATE_NEW;
6524   }
6525   ERR("Invalid create mode!\n");
6526   assert(0);
6527   return 0;
6528 }
6529
6530
6531 /*************************************************************************
6532  * OLECONVERT_LoadOLE10 [Internal]
6533  *
6534  * Loads the OLE10 STREAM to memory
6535  *
6536  * PARAMS
6537  *     pOleStream   [I] The OLESTREAM
6538  *     pData        [I] Data Structure for the OLESTREAM Data
6539  *
6540  * RETURNS
6541  *     Success:  S_OK
6542  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
6543  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
6544  *
6545  * NOTES
6546  *     This function is used by OleConvertOLESTREAMToIStorage only.
6547  *
6548  *     Memory allocated for pData must be freed by the caller
6549  */
6550 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
6551 {
6552         DWORD dwSize;
6553         HRESULT hRes = S_OK;
6554         int nTryCnt=0;
6555         int max_try = 6;
6556
6557         pData->pData = NULL;
6558         pData->pstrOleObjFileName = (CHAR *) NULL;
6559
6560         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
6561         {
6562         /* Get the OleID */
6563         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6564         if(dwSize != sizeof(pData->dwOleID))
6565         {
6566                 hRes = CONVERT10_E_OLESTREAM_GET;
6567         }
6568         else if(pData->dwOleID != OLESTREAM_ID)
6569         {
6570                 hRes = CONVERT10_E_OLESTREAM_FMT;
6571         }
6572                 else
6573                 {
6574                         hRes = S_OK;
6575                         break;
6576                 }
6577         }
6578
6579         if(hRes == S_OK)
6580         {
6581                 /* Get the TypeID...more info needed for this field */
6582                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6583                 if(dwSize != sizeof(pData->dwTypeID))
6584                 {
6585                         hRes = CONVERT10_E_OLESTREAM_GET;
6586                 }
6587         }
6588         if(hRes == S_OK)
6589         {
6590                 if(pData->dwTypeID != 0)
6591                 {
6592                         /* Get the length of the OleTypeName */
6593                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6594                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6595                         {
6596                                 hRes = CONVERT10_E_OLESTREAM_GET;
6597                         }
6598
6599                         if(hRes == S_OK)
6600                         {
6601                                 if(pData->dwOleTypeNameLength > 0)
6602                                 {
6603                                         /* Get the OleTypeName */
6604                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
6605                                         if(dwSize != pData->dwOleTypeNameLength)
6606                                         {
6607                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6608                                         }
6609                                 }
6610                         }
6611                         if(bStrem1)
6612                         {
6613                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6614                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6615                                 {
6616                                         hRes = CONVERT10_E_OLESTREAM_GET;
6617                                 }
6618                         if(hRes == S_OK)
6619                         {
6620                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6621                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6622                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
6623                                         if(pData->pstrOleObjFileName)
6624                                         {
6625                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6626                                                 if(dwSize != pData->dwOleObjFileNameLength)
6627                                                 {
6628                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6629                                                 }
6630                                         }
6631                                         else
6632                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6633                                 }
6634                         }
6635                         else
6636                         {
6637                                 /* Get the Width of the Metafile */
6638                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6639                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
6640                                 {
6641                                         hRes = CONVERT10_E_OLESTREAM_GET;
6642                                 }
6643                         if(hRes == S_OK)
6644                         {
6645                                 /* Get the Height of the Metafile */
6646                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6647                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
6648                                 {
6649                                         hRes = CONVERT10_E_OLESTREAM_GET;
6650                                 }
6651                         }
6652                         }
6653                         if(hRes == S_OK)
6654                         {
6655                                 /* Get the Length of the Data */
6656                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6657                                 if(dwSize != sizeof(pData->dwDataLength))
6658                                 {
6659                                         hRes = CONVERT10_E_OLESTREAM_GET;
6660                                 }
6661                         }
6662
6663                         if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
6664                         {
6665                                 if(!bStrem1) /* if it is a second OLE stream data */
6666                                 {
6667                                         pData->dwDataLength -= 8;
6668                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6669                                         if(dwSize != sizeof(pData->strUnknown))
6670                                         {
6671                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6672                                         }
6673                                 }
6674                         }
6675                         if(hRes == S_OK)
6676                         {
6677                                 if(pData->dwDataLength > 0)
6678                                 {
6679                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6680
6681                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
6682                                         if(pData->pData)
6683                                         {
6684                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6685                                                 if(dwSize != pData->dwDataLength)
6686                                                 {
6687                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6688                                                 }
6689                                         }
6690                                         else
6691                                         {
6692                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6693                                         }
6694                                 }
6695                         }
6696                 }
6697         }
6698         return hRes;
6699 }
6700
6701 /*************************************************************************
6702  * OLECONVERT_SaveOLE10 [Internal]
6703  *
6704  * Saves the OLE10 STREAM From memory
6705  *
6706  * PARAMS
6707  *     pData        [I] Data Structure for the OLESTREAM Data
6708  *     pOleStream   [I] The OLESTREAM to save
6709  *
6710  * RETURNS
6711  *     Success:  S_OK
6712  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
6713  *
6714  * NOTES
6715  *     This function is used by OleConvertIStorageToOLESTREAM only.
6716  *
6717  */
6718 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6719 {
6720     DWORD dwSize;
6721     HRESULT hRes = S_OK;
6722
6723
6724    /* Set the OleID */
6725     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6726     if(dwSize != sizeof(pData->dwOleID))
6727     {
6728         hRes = CONVERT10_E_OLESTREAM_PUT;
6729     }
6730
6731     if(hRes == S_OK)
6732     {
6733         /* Set the TypeID */
6734         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6735         if(dwSize != sizeof(pData->dwTypeID))
6736         {
6737             hRes = CONVERT10_E_OLESTREAM_PUT;
6738         }
6739     }
6740
6741     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6742     {
6743         /* Set the Length of the OleTypeName */
6744         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6745         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6746         {
6747             hRes = CONVERT10_E_OLESTREAM_PUT;
6748         }
6749
6750         if(hRes == S_OK)
6751         {
6752             if(pData->dwOleTypeNameLength > 0)
6753             {
6754                 /* Set the OleTypeName */
6755                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);
6756                 if(dwSize != pData->dwOleTypeNameLength)
6757                 {
6758                     hRes = CONVERT10_E_OLESTREAM_PUT;
6759                 }
6760             }
6761         }
6762
6763         if(hRes == S_OK)
6764         {
6765             /* Set the width of the Metafile */
6766             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6767             if(dwSize != sizeof(pData->dwMetaFileWidth))
6768             {
6769                 hRes = CONVERT10_E_OLESTREAM_PUT;
6770             }
6771         }
6772
6773         if(hRes == S_OK)
6774         {
6775             /* Set the height of the Metafile */
6776             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6777             if(dwSize != sizeof(pData->dwMetaFileHeight))
6778             {
6779                 hRes = CONVERT10_E_OLESTREAM_PUT;
6780             }
6781         }
6782
6783         if(hRes == S_OK)
6784         {
6785             /* Set the length of the Data */
6786             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6787             if(dwSize != sizeof(pData->dwDataLength))
6788             {
6789                 hRes = CONVERT10_E_OLESTREAM_PUT;
6790             }
6791         }
6792
6793         if(hRes == S_OK)
6794         {
6795             if(pData->dwDataLength > 0)
6796             {
6797                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6798                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
6799                 if(dwSize != pData->dwDataLength)
6800                 {
6801                     hRes = CONVERT10_E_OLESTREAM_PUT;
6802                 }
6803             }
6804         }
6805     }
6806     return hRes;
6807 }
6808
6809 /*************************************************************************
6810  * OLECONVERT_GetOLE20FromOLE10[Internal]
6811  *
6812  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6813  * opens it, and copies the content to the dest IStorage for
6814  * OleConvertOLESTREAMToIStorage
6815  *
6816  *
6817  * PARAMS
6818  *     pDestStorage  [I] The IStorage to copy the data to
6819  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
6820  *     nBufferLength [I] The size of the buffer
6821  *
6822  * RETURNS
6823  *     Nothing
6824  *
6825  * NOTES
6826  *
6827  *
6828  */
6829 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6830 {
6831     HRESULT hRes;
6832     HANDLE hFile;
6833     IStorage *pTempStorage;
6834     DWORD dwNumOfBytesWritten;
6835     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6836     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6837
6838     /* Create a temp File */
6839     GetTempPathW(MAX_PATH, wstrTempDir);
6840     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6841     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6842
6843     if(hFile != INVALID_HANDLE_VALUE)
6844     {
6845         /* Write IStorage Data to File */
6846         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6847         CloseHandle(hFile);
6848
6849         /* Open and copy temp storage to the Dest Storage */
6850         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6851         if(hRes == S_OK)
6852         {
6853             hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6854             StorageBaseImpl_Release(pTempStorage);
6855         }
6856         DeleteFileW(wstrTempFile);
6857     }
6858 }
6859
6860
6861 /*************************************************************************
6862  * OLECONVERT_WriteOLE20ToBuffer [Internal]
6863  *
6864  * Saves the OLE10 STREAM From memory
6865  *
6866  * PARAMS
6867  *     pStorage  [I] The Src IStorage to copy
6868  *     pData     [I] The Dest Memory to write to.
6869  *
6870  * RETURNS
6871  *     The size in bytes allocated for pData
6872  *
6873  * NOTES
6874  *     Memory allocated for pData must be freed by the caller
6875  *
6876  *     Used by OleConvertIStorageToOLESTREAM only.
6877  *
6878  */
6879 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6880 {
6881     HANDLE hFile;
6882     HRESULT hRes;
6883     DWORD nDataLength = 0;
6884     IStorage *pTempStorage;
6885     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6886     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6887
6888     *pData = NULL;
6889
6890     /* Create temp Storage */
6891     GetTempPathW(MAX_PATH, wstrTempDir);
6892     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6893     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6894
6895     if(hRes == S_OK)
6896     {
6897         /* Copy Src Storage to the Temp Storage */
6898         StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6899         StorageBaseImpl_Release(pTempStorage);
6900
6901         /* Open Temp Storage as a file and copy to memory */
6902         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6903         if(hFile != INVALID_HANDLE_VALUE)
6904         {
6905             nDataLength = GetFileSize(hFile, NULL);
6906             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
6907             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6908             CloseHandle(hFile);
6909         }
6910         DeleteFileW(wstrTempFile);
6911     }
6912     return nDataLength;
6913 }
6914
6915 /*************************************************************************
6916  * OLECONVERT_CreateOleStream [Internal]
6917  *
6918  * Creates the "\001OLE" stream in the IStorage if necessary.
6919  *
6920  * PARAMS
6921  *     pStorage     [I] Dest storage to create the stream in
6922  *
6923  * RETURNS
6924  *     Nothing
6925  *
6926  * NOTES
6927  *     This function is used by OleConvertOLESTREAMToIStorage only.
6928  *
6929  *     This stream is still unknown, MS Word seems to have extra data
6930  *     but since the data is stored in the OLESTREAM there should be
6931  *     no need to recreate the stream.  If the stream is manually
6932  *     deleted it will create it with this default data.
6933  *
6934  */
6935 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6936 {
6937     HRESULT hRes;
6938     IStream *pStream;
6939     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6940     BYTE pOleStreamHeader [] =
6941     {
6942         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6943         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6944         0x00, 0x00, 0x00, 0x00
6945     };
6946
6947     /* Create stream if not present */
6948     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6949         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6950
6951     if(hRes == S_OK)
6952     {
6953         /* Write default Data */
6954         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6955         IStream_Release(pStream);
6956     }
6957 }
6958
6959 /* write a string to a stream, preceded by its length */
6960 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
6961 {
6962     HRESULT r;
6963     LPSTR str;
6964     DWORD len = 0;
6965
6966     if( string )
6967         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
6968     r = IStream_Write( stm, &len, sizeof(len), NULL);
6969     if( FAILED( r ) )
6970         return r;
6971     if(len == 0)
6972         return r;
6973     str = CoTaskMemAlloc( len );
6974     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
6975     r = IStream_Write( stm, str, len, NULL);
6976     CoTaskMemFree( str );
6977     return r;
6978 }
6979
6980 /* read a string preceded by its length from a stream */
6981 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
6982 {
6983     HRESULT r;
6984     DWORD len, count = 0;
6985     LPSTR str;
6986     LPWSTR wstr;
6987
6988     r = IStream_Read( stm, &len, sizeof(len), &count );
6989     if( FAILED( r ) )
6990         return r;
6991     if( count != sizeof(len) )
6992         return E_OUTOFMEMORY;
6993
6994     TRACE("%ld bytes\n",len);
6995     
6996     str = CoTaskMemAlloc( len );
6997     if( !str )
6998         return E_OUTOFMEMORY;
6999     count = 0;
7000     r = IStream_Read( stm, str, len, &count );
7001     if( FAILED( r ) )
7002         return r;
7003     if( count != len )
7004     {
7005         CoTaskMemFree( str );
7006         return E_OUTOFMEMORY;
7007     }
7008
7009     TRACE("Read string %s\n",debugstr_an(str,len));
7010
7011     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
7012     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
7013     if( wstr )
7014          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
7015     CoTaskMemFree( str );
7016
7017     *string = wstr;
7018
7019     return r;
7020 }
7021
7022
7023 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
7024     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
7025 {
7026     IStream *pstm;
7027     HRESULT r = S_OK;
7028     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7029
7030     static const BYTE unknown1[12] =
7031        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
7032          0xFF, 0xFF, 0xFF, 0xFF};
7033     static const BYTE unknown2[16] =
7034        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
7035          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
7036
7037     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
7038            debugstr_w(lpszUserType), debugstr_w(szClipName),
7039            debugstr_w(szProgIDName));
7040
7041     /*  Create a CompObj stream if it doesn't exist */
7042     r = IStorage_CreateStream(pstg, szwStreamName,
7043         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
7044     if( FAILED (r) )
7045         return r;
7046
7047     /* Write CompObj Structure to stream */
7048     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
7049
7050     if( SUCCEEDED( r ) )
7051         r = WriteClassStm( pstm, clsid );
7052
7053     if( SUCCEEDED( r ) )
7054         r = STREAM_WriteString( pstm, lpszUserType );
7055     if( SUCCEEDED( r ) )
7056         r = STREAM_WriteString( pstm, szClipName );
7057     if( SUCCEEDED( r ) )
7058         r = STREAM_WriteString( pstm, szProgIDName );
7059     if( SUCCEEDED( r ) )
7060         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
7061
7062     IStream_Release( pstm );
7063
7064     return r;
7065 }
7066
7067 /***********************************************************************
7068  *               WriteFmtUserTypeStg (OLE32.@)
7069  */
7070 HRESULT WINAPI WriteFmtUserTypeStg(
7071           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
7072 {
7073     HRESULT r;
7074     WCHAR szwClipName[0x40];
7075     CLSID clsid = CLSID_NULL;
7076     LPWSTR wstrProgID = NULL;
7077     DWORD n;
7078
7079     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
7080
7081     /* get the clipboard format name */
7082     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
7083     szwClipName[n]=0;
7084
7085     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
7086
7087     /* FIXME: There's room to save a CLSID and its ProgID, but
7088        the CLSID is not looked up in the registry and in all the
7089        tests I wrote it was CLSID_NULL.  Where does it come from?
7090     */
7091
7092     /* get the real program ID.  This may fail, but that's fine */
7093     ProgIDFromCLSID(&clsid, &wstrProgID);
7094
7095     TRACE("progid is %s\n",debugstr_w(wstrProgID));
7096
7097     r = STORAGE_WriteCompObj( pstg, &clsid, 
7098                               lpszUserType, szwClipName, wstrProgID );
7099
7100     CoTaskMemFree(wstrProgID);
7101
7102     return r;
7103 }
7104
7105
7106 /******************************************************************************
7107  *              ReadFmtUserTypeStg        [OLE32.@]
7108  */
7109 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
7110 {
7111     HRESULT r;
7112     IStream *stm = 0;
7113     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
7114     unsigned char unknown1[12];
7115     unsigned char unknown2[16];
7116     DWORD count;
7117     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
7118     CLSID clsid;
7119
7120     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
7121
7122     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
7123                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
7124     if( FAILED ( r ) )
7125     {
7126         WARN("Failed to open stream r = %08lx\n", r);
7127         return r;
7128     }
7129
7130     /* read the various parts of the structure */
7131     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
7132     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
7133         goto end;
7134     r = ReadClassStm( stm, &clsid );
7135     if( FAILED( r ) )
7136         goto end;
7137
7138     r = STREAM_ReadString( stm, &szCLSIDName );
7139     if( FAILED( r ) )
7140         goto end;
7141
7142     r = STREAM_ReadString( stm, &szOleTypeName );
7143     if( FAILED( r ) )
7144         goto end;
7145
7146     r = STREAM_ReadString( stm, &szProgIDName );
7147     if( FAILED( r ) )
7148         goto end;
7149
7150     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7151     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7152         goto end;
7153
7154     /* ok, success... now we just need to store what we found */
7155     if( pcf )
7156         *pcf = RegisterClipboardFormatW( szOleTypeName );
7157     CoTaskMemFree( szOleTypeName );
7158
7159     if( lplpszUserType )
7160         *lplpszUserType = szCLSIDName;
7161     CoTaskMemFree( szProgIDName );
7162
7163 end:
7164     IStream_Release( stm );
7165
7166     return r;
7167 }
7168
7169
7170 /*************************************************************************
7171  * OLECONVERT_CreateCompObjStream [Internal]
7172  *
7173  * Creates a "\001CompObj" is the destination IStorage if necessary.
7174  *
7175  * PARAMS
7176  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7177  *                        if necessary.
7178  *     strOleTypeName [I] The ProgID
7179  *
7180  * RETURNS
7181  *     Success:  S_OK
7182  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7183  *
7184  * NOTES
7185  *     This function is used by OleConvertOLESTREAMToIStorage only.
7186  *
7187  *     The stream data is stored in the OLESTREAM and there should be
7188  *     no need to recreate the stream.  If the stream is manually
7189  *     deleted it will attempt to create it by querying the registry.
7190  *
7191  *
7192  */
7193 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7194 {
7195     IStream *pStream;
7196     HRESULT hStorageRes, hRes = S_OK;
7197     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7198     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7199     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7200
7201     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7202     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7203
7204     /* Initialize the CompObj structure */
7205     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7206     memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
7207     memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
7208
7209
7210     /*  Create a CompObj stream if it doesn't exist */
7211     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7212         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7213     if(hStorageRes == S_OK)
7214     {
7215         /* copy the OleTypeName to the compobj struct */
7216         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7217         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7218
7219         /* copy the OleTypeName to the compobj struct */
7220         /* Note: in the test made, these were Identical      */
7221         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7222         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7223
7224         /* Get the CLSID */
7225         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7226                              bufferW, OLESTREAM_MAX_STR_LEN );
7227         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7228
7229         if(hRes == S_OK)
7230         {
7231             HKEY hKey;
7232             LONG hErr;
7233             /* Get the CLSID Default Name from the Registry */
7234             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7235             if(hErr == ERROR_SUCCESS)
7236             {
7237                 char strTemp[OLESTREAM_MAX_STR_LEN];
7238                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7239                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7240                 if(hErr == ERROR_SUCCESS)
7241                 {
7242                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7243                 }
7244                 RegCloseKey(hKey);
7245             }
7246         }
7247
7248         /* Write CompObj Structure to stream */
7249         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7250
7251         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7252
7253         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7254         if(IStorageCompObj.dwCLSIDNameLength > 0)
7255         {
7256             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7257         }
7258         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7259         if(IStorageCompObj.dwOleTypeNameLength > 0)
7260         {
7261             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7262         }
7263         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7264         if(IStorageCompObj.dwProgIDNameLength > 0)
7265         {
7266             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7267         }
7268         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7269         IStream_Release(pStream);
7270     }
7271     return hRes;
7272 }
7273
7274
7275 /*************************************************************************
7276  * OLECONVERT_CreateOlePresStream[Internal]
7277  *
7278  * Creates the "\002OlePres000" Stream with the Metafile data
7279  *
7280  * PARAMS
7281  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7282  *     dwExtentX    [I] Width of the Metafile
7283  *     dwExtentY    [I] Height of the Metafile
7284  *     pData        [I] Metafile data
7285  *     dwDataLength [I] Size of the Metafile data
7286  *
7287  * RETURNS
7288  *     Success:  S_OK
7289  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7290  *
7291  * NOTES
7292  *     This function is used by OleConvertOLESTREAMToIStorage only.
7293  *
7294  */
7295 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7296 {
7297     HRESULT hRes;
7298     IStream *pStream;
7299     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7300     BYTE pOlePresStreamHeader [] =
7301     {
7302         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7303         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7304         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7305         0x00, 0x00, 0x00, 0x00
7306     };
7307
7308     BYTE pOlePresStreamHeaderEmpty [] =
7309     {
7310         0x00, 0x00, 0x00, 0x00,
7311         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7312         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7313         0x00, 0x00, 0x00, 0x00
7314     };
7315
7316     /* Create the OlePres000 Stream */
7317     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7318         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7319
7320     if(hRes == S_OK)
7321     {
7322         DWORD nHeaderSize;
7323         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7324
7325         memset(&OlePres, 0, sizeof(OlePres));
7326         /* Do we have any metafile data to save */
7327         if(dwDataLength > 0)
7328         {
7329             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7330             nHeaderSize = sizeof(pOlePresStreamHeader);
7331         }
7332         else
7333         {
7334             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7335             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7336         }
7337         /* Set width and height of the metafile */
7338         OlePres.dwExtentX = dwExtentX;
7339         OlePres.dwExtentY = -dwExtentY;
7340
7341         /* Set Data and Length */
7342         if(dwDataLength > sizeof(METAFILEPICT16))
7343         {
7344             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7345             OlePres.pData = &(pData[8]);
7346         }
7347         /* Save OlePres000 Data to Stream */
7348         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7349         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7350         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7351         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7352         if(OlePres.dwSize > 0)
7353         {
7354             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7355         }
7356         IStream_Release(pStream);
7357     }
7358 }
7359
7360 /*************************************************************************
7361  * OLECONVERT_CreateOle10NativeStream [Internal]
7362  *
7363  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7364  *
7365  * PARAMS
7366  *     pStorage     [I] Dest storage to create the stream in
7367  *     pData        [I] Ole10 Native Data (ex. bmp)
7368  *     dwDataLength [I] Size of the Ole10 Native Data
7369  *
7370  * RETURNS
7371  *     Nothing
7372  *
7373  * NOTES
7374  *     This function is used by OleConvertOLESTREAMToIStorage only.
7375  *
7376  *     Might need to verify the data and return appropriate error message
7377  *
7378  */
7379 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
7380 {
7381     HRESULT hRes;
7382     IStream *pStream;
7383     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7384
7385     /* Create the Ole10Native Stream */
7386     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7387         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7388
7389     if(hRes == S_OK)
7390     {
7391         /* Write info to stream */
7392         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7393         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7394         IStream_Release(pStream);
7395     }
7396
7397 }
7398
7399 /*************************************************************************
7400  * OLECONVERT_GetOLE10ProgID [Internal]
7401  *
7402  * Finds the ProgID (or OleTypeID) from the IStorage
7403  *
7404  * PARAMS
7405  *     pStorage        [I] The Src IStorage to get the ProgID
7406  *     strProgID       [I] the ProgID string to get
7407  *     dwSize          [I] the size of the string
7408  *
7409  * RETURNS
7410  *     Success:  S_OK
7411  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7412  *
7413  * NOTES
7414  *     This function is used by OleConvertIStorageToOLESTREAM only.
7415  *
7416  *
7417  */
7418 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7419 {
7420     HRESULT hRes;
7421     IStream *pStream;
7422     LARGE_INTEGER iSeekPos;
7423     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
7424     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7425
7426     /* Open the CompObj Stream */
7427     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7428         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7429     if(hRes == S_OK)
7430     {
7431
7432         /*Get the OleType from the CompObj Stream */
7433         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
7434         iSeekPos.u.HighPart = 0;
7435
7436         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7437         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
7438         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
7439         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7440         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
7441         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
7442         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7443
7444         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
7445         if(*dwSize > 0)
7446         {
7447             IStream_Read(pStream, strProgID, *dwSize, NULL);
7448         }
7449         IStream_Release(pStream);
7450     }
7451     else
7452     {
7453         STATSTG stat;
7454         LPOLESTR wstrProgID;
7455
7456         /* Get the OleType from the registry */
7457         REFCLSID clsid = &(stat.clsid);
7458         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
7459         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
7460         if(hRes == S_OK)
7461         {
7462             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
7463         }
7464
7465     }
7466     return hRes;
7467 }
7468
7469 /*************************************************************************
7470  * OLECONVERT_GetOle10PresData [Internal]
7471  *
7472  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
7473  *
7474  * PARAMS
7475  *     pStorage     [I] Src IStroage
7476  *     pOleStream   [I] Dest OleStream Mem Struct
7477  *
7478  * RETURNS
7479  *     Nothing
7480  *
7481  * NOTES
7482  *     This function is used by OleConvertIStorageToOLESTREAM only.
7483  *
7484  *     Memory allocated for pData must be freed by the caller
7485  *
7486  *
7487  */
7488 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7489 {
7490
7491     HRESULT hRes;
7492     IStream *pStream;
7493     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7494
7495     /* Initialize Default data for OLESTREAM */
7496     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7497     pOleStreamData[0].dwTypeID = 2;
7498     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7499     pOleStreamData[1].dwTypeID = 0;
7500     pOleStreamData[0].dwMetaFileWidth = 0;
7501     pOleStreamData[0].dwMetaFileHeight = 0;
7502     pOleStreamData[0].pData = NULL;
7503     pOleStreamData[1].pData = NULL;
7504
7505     /* Open Ole10Native Stream */
7506     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7507         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7508     if(hRes == S_OK)
7509     {
7510
7511         /* Read Size and Data */
7512         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
7513         if(pOleStreamData->dwDataLength > 0)
7514         {
7515             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
7516             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
7517         }
7518         IStream_Release(pStream);
7519     }
7520
7521 }
7522
7523
7524 /*************************************************************************
7525  * OLECONVERT_GetOle20PresData[Internal]
7526  *
7527  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
7528  *
7529  * PARAMS
7530  *     pStorage         [I] Src IStroage
7531  *     pOleStreamData   [I] Dest OleStream Mem Struct
7532  *
7533  * RETURNS
7534  *     Nothing
7535  *
7536  * NOTES
7537  *     This function is used by OleConvertIStorageToOLESTREAM only.
7538  *
7539  *     Memory allocated for pData must be freed by the caller
7540  */
7541 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7542 {
7543     HRESULT hRes;
7544     IStream *pStream;
7545     OLECONVERT_ISTORAGE_OLEPRES olePress;
7546     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7547
7548     /* Initialize Default data for OLESTREAM */
7549     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7550     pOleStreamData[0].dwTypeID = 2;
7551     pOleStreamData[0].dwMetaFileWidth = 0;
7552     pOleStreamData[0].dwMetaFileHeight = 0;
7553     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
7554     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7555     pOleStreamData[1].dwTypeID = 0;
7556     pOleStreamData[1].dwOleTypeNameLength = 0;
7557     pOleStreamData[1].strOleTypeName[0] = 0;
7558     pOleStreamData[1].dwMetaFileWidth = 0;
7559     pOleStreamData[1].dwMetaFileHeight = 0;
7560     pOleStreamData[1].pData = NULL;
7561     pOleStreamData[1].dwDataLength = 0;
7562
7563
7564     /* Open OlePress000 stream */
7565     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7566         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7567     if(hRes == S_OK)
7568     {
7569         LARGE_INTEGER iSeekPos;
7570         METAFILEPICT16 MetaFilePict;
7571         static const char strMetafilePictName[] = "METAFILEPICT";
7572
7573         /* Set the TypeID for a Metafile */
7574         pOleStreamData[1].dwTypeID = 5;
7575
7576         /* Set the OleTypeName to Metafile */
7577         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
7578         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
7579
7580         iSeekPos.u.HighPart = 0;
7581         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
7582
7583         /* Get Presentation Data */
7584         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7585         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
7586         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
7587         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
7588
7589         /*Set width and Height */
7590         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
7591         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
7592         if(olePress.dwSize > 0)
7593         {
7594             /* Set Length */
7595             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
7596
7597             /* Set MetaFilePict struct */
7598             MetaFilePict.mm = 8;
7599             MetaFilePict.xExt = olePress.dwExtentX;
7600             MetaFilePict.yExt = olePress.dwExtentY;
7601             MetaFilePict.hMF = 0;
7602
7603             /* Get Metafile Data */
7604             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
7605             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
7606             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
7607         }
7608         IStream_Release(pStream);
7609     }
7610 }
7611
7612 /*************************************************************************
7613  * OleConvertOLESTREAMToIStorage [OLE32.@]
7614  *
7615  * Read info on MSDN
7616  *
7617  * TODO
7618  *      DVTARGETDEVICE paramenter is not handled
7619  *      Still unsure of some mem fields for OLE 10 Stream
7620  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7621  *      and "\001OLE" streams
7622  *
7623  */
7624 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
7625     LPOLESTREAM pOleStream,
7626     LPSTORAGE pstg,
7627     const DVTARGETDEVICE* ptd)
7628 {
7629     int i;
7630     HRESULT hRes=S_OK;
7631     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7632
7633     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7634
7635     if(ptd != NULL)
7636     {
7637         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
7638     }
7639
7640     if(pstg == NULL || pOleStream == NULL)
7641     {
7642         hRes = E_INVALIDARG;
7643     }
7644
7645     if(hRes == S_OK)
7646     {
7647         /* Load the OLESTREAM to Memory */
7648         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
7649     }
7650
7651     if(hRes == S_OK)
7652     {
7653         /* Load the OLESTREAM to Memory (part 2)*/
7654         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
7655     }
7656
7657     if(hRes == S_OK)
7658     {
7659
7660         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
7661         {
7662             /* Do we have the IStorage Data in the OLESTREAM */
7663             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
7664             {
7665                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7666                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
7667             }
7668             else
7669             {
7670                 /* It must be an original OLE 1.0 source */
7671                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7672             }
7673         }
7674         else
7675         {
7676             /* It must be an original OLE 1.0 source */
7677             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7678         }
7679
7680         /* Create CompObj Stream if necessary */
7681         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
7682         if(hRes == S_OK)
7683         {
7684             /*Create the Ole Stream if necessary */
7685             OLECONVERT_CreateOleStream(pstg);
7686         }
7687     }
7688
7689
7690     /* Free allocated memory */
7691     for(i=0; i < 2; i++)
7692     {
7693         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7694         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
7695         pOleStreamData[i].pstrOleObjFileName = NULL;
7696     }
7697     return hRes;
7698 }
7699
7700 /*************************************************************************
7701  * OleConvertIStorageToOLESTREAM [OLE32.@]
7702  *
7703  * Read info on MSDN
7704  *
7705  * Read info on MSDN
7706  *
7707  * TODO
7708  *      Still unsure of some mem fields for OLE 10 Stream
7709  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7710  *      and "\001OLE" streams.
7711  *
7712  */
7713 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
7714     LPSTORAGE pstg,
7715     LPOLESTREAM pOleStream)
7716 {
7717     int i;
7718     HRESULT hRes = S_OK;
7719     IStream *pStream;
7720     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7721     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7722
7723
7724     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7725
7726     if(pstg == NULL || pOleStream == NULL)
7727     {
7728         hRes = E_INVALIDARG;
7729     }
7730     if(hRes == S_OK)
7731     {
7732         /* Get the ProgID */
7733         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
7734         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
7735     }
7736     if(hRes == S_OK)
7737     {
7738         /* Was it originally Ole10 */
7739         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
7740         if(hRes == S_OK)
7741         {
7742             IStream_Release(pStream);
7743             /* Get Presentation Data for Ole10Native */
7744             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
7745         }
7746         else
7747         {
7748             /* Get Presentation Data (OLE20) */
7749             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
7750         }
7751
7752         /* Save OLESTREAM */
7753         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
7754         if(hRes == S_OK)
7755         {
7756             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
7757         }
7758
7759     }
7760
7761     /* Free allocated memory */
7762     for(i=0; i < 2; i++)
7763     {
7764         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7765     }
7766
7767     return hRes;
7768 }
7769
7770 /***********************************************************************
7771  *              GetConvertStg (OLE32.@)
7772  */
7773 HRESULT WINAPI GetConvertStg(IStorage *stg) {
7774     FIXME("unimplemented stub!\n");
7775     return E_FAIL;
7776 }
7777
7778 /******************************************************************************
7779  * StgIsStorageFile [OLE32.@]
7780  * Verify if the file contains a storage object
7781  *
7782  * PARAMS
7783  *  fn      [ I] Filename
7784  *
7785  * RETURNS
7786  *  S_OK    if file has magic bytes as a storage object
7787  *  S_FALSE if file is not storage
7788  */
7789 HRESULT WINAPI
7790 StgIsStorageFile(LPCOLESTR fn)
7791 {
7792         HANDLE          hf;
7793         BYTE            magic[8];
7794         DWORD           bytes_read;
7795
7796         TRACE("(\'%s\')\n", debugstr_w(fn));
7797         hf = CreateFileW(fn, GENERIC_READ,
7798                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
7799                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7800
7801         if (hf == INVALID_HANDLE_VALUE)
7802                 return STG_E_FILENOTFOUND;
7803
7804         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
7805         {
7806                 WARN(" unable to read file\n");
7807                 CloseHandle(hf);
7808                 return S_FALSE;
7809         }
7810
7811         CloseHandle(hf);
7812
7813         if (bytes_read != 8) {
7814                 WARN(" too short\n");
7815                 return S_FALSE;
7816         }
7817
7818         if (!memcmp(magic,STORAGE_magic,8)) {
7819                 WARN(" -> YES\n");
7820                 return S_OK;
7821         }
7822
7823         WARN(" -> Invalid header.\n");
7824         return S_FALSE;
7825 }