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