ole32: Fix stream ref counting.
[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 to Destroy the old property we must zeroed it's 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 tweek 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 it's 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 it's 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  * Stategy: This implementation is build this way for simplicity not for speed.
1656  *          I always delete the top most 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 reside in the usage of another
1660  *          enumeration stategy 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 it's 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 it's 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 it's 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
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   /*
3004    * Get a pointer to the big block of data containing the header.
3005    */
3006   headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
3007
3008   /*
3009    * Extract the information from the header.
3010    */
3011   if (headerBigBlock!=0)
3012   {
3013     /*
3014      * Check for the "magic number" signature and return an error if it is not
3015      * found.
3016      */
3017     if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
3018     {
3019       StorageImpl_ReleaseBigBlock(This, headerBigBlock);
3020       return STG_E_OLDFORMAT;
3021     }
3022
3023     if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
3024     {
3025       StorageImpl_ReleaseBigBlock(This, headerBigBlock);
3026       return STG_E_INVALIDHEADER;
3027     }
3028
3029     StorageUtl_ReadWord(
3030       headerBigBlock,
3031       OFFSET_BIGBLOCKSIZEBITS,
3032       &This->bigBlockSizeBits);
3033
3034     StorageUtl_ReadWord(
3035       headerBigBlock,
3036       OFFSET_SMALLBLOCKSIZEBITS,
3037       &This->smallBlockSizeBits);
3038
3039     StorageUtl_ReadDWord(
3040       headerBigBlock,
3041       OFFSET_BBDEPOTCOUNT,
3042       &This->bigBlockDepotCount);
3043
3044     StorageUtl_ReadDWord(
3045       headerBigBlock,
3046       OFFSET_ROOTSTARTBLOCK,
3047       &This->rootStartBlock);
3048
3049     StorageUtl_ReadDWord(
3050       headerBigBlock,
3051       OFFSET_SBDEPOTSTART,
3052       &This->smallBlockDepotStart);
3053
3054     StorageUtl_ReadDWord(
3055       headerBigBlock,
3056       OFFSET_EXTBBDEPOTSTART,
3057       &This->extBigBlockDepotStart);
3058
3059     StorageUtl_ReadDWord(
3060       headerBigBlock,
3061       OFFSET_EXTBBDEPOTCOUNT,
3062       &This->extBigBlockDepotCount);
3063
3064     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3065     {
3066       StorageUtl_ReadDWord(
3067         headerBigBlock,
3068         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3069         &(This->bigBlockDepotStart[index]));
3070     }
3071
3072     /*
3073      * Make the bitwise arithmetic to get the size of the blocks in bytes.
3074      */
3075     if ((1 << 2) == 4)
3076     {
3077       This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
3078       This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
3079     }
3080     else
3081     {
3082       This->bigBlockSize   = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
3083       This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
3084     }
3085
3086     /*
3087      * Right now, the code is making some assumptions about the size of the
3088      * blocks, just make sure they are what we're expecting.
3089      */
3090     if (This->bigBlockSize != DEF_BIG_BLOCK_SIZE ||
3091         This->smallBlockSize != DEF_SMALL_BLOCK_SIZE)
3092     {
3093         WARN("Broken OLE storage file\n");
3094         hr = STG_E_INVALIDHEADER;
3095     }
3096     else
3097         hr = S_OK;
3098
3099     /*
3100      * Release the block.
3101      */
3102     StorageImpl_ReleaseBigBlock(This, headerBigBlock);
3103   }
3104
3105   return hr;
3106 }
3107
3108 /******************************************************************************
3109  *      Storage32Impl_SaveFileHeader
3110  *
3111  * This method will save to the file the header, i.e. big block -1.
3112  */
3113 void StorageImpl_SaveFileHeader(
3114           StorageImpl* This)
3115 {
3116   BYTE   headerBigBlock[BIG_BLOCK_SIZE];
3117   int    index;
3118   BOOL success;
3119
3120   /*
3121    * Get a pointer to the big block of data containing the header.
3122    */
3123   success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
3124
3125   /*
3126    * If the block read failed, the file is probably new.
3127    */
3128   if (!success)
3129   {
3130     /*
3131      * Initialize for all unknown fields.
3132      */
3133     memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
3134
3135     /*
3136      * Initialize the magic number.
3137      */
3138     memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
3139
3140     /*
3141      * And a bunch of things we don't know what they mean
3142      */
3143     StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
3144     StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
3145     StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
3146     StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
3147   }
3148
3149   /*
3150    * Write the information to the header.
3151    */
3152   StorageUtl_WriteWord(
3153     headerBigBlock,
3154     OFFSET_BIGBLOCKSIZEBITS,
3155     This->bigBlockSizeBits);
3156
3157   StorageUtl_WriteWord(
3158     headerBigBlock,
3159     OFFSET_SMALLBLOCKSIZEBITS,
3160     This->smallBlockSizeBits);
3161
3162   StorageUtl_WriteDWord(
3163     headerBigBlock,
3164     OFFSET_BBDEPOTCOUNT,
3165     This->bigBlockDepotCount);
3166
3167   StorageUtl_WriteDWord(
3168     headerBigBlock,
3169     OFFSET_ROOTSTARTBLOCK,
3170     This->rootStartBlock);
3171
3172   StorageUtl_WriteDWord(
3173     headerBigBlock,
3174     OFFSET_SBDEPOTSTART,
3175     This->smallBlockDepotStart);
3176
3177   StorageUtl_WriteDWord(
3178     headerBigBlock,
3179     OFFSET_SBDEPOTCOUNT,
3180     This->smallBlockDepotChain ?
3181      BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
3182
3183   StorageUtl_WriteDWord(
3184     headerBigBlock,
3185     OFFSET_EXTBBDEPOTSTART,
3186     This->extBigBlockDepotStart);
3187
3188   StorageUtl_WriteDWord(
3189     headerBigBlock,
3190     OFFSET_EXTBBDEPOTCOUNT,
3191     This->extBigBlockDepotCount);
3192
3193   for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3194   {
3195     StorageUtl_WriteDWord(
3196       headerBigBlock,
3197       OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3198       (This->bigBlockDepotStart[index]));
3199   }
3200
3201   /*
3202    * Write the big block back to the file.
3203    */
3204   StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
3205 }
3206
3207 /******************************************************************************
3208  *      Storage32Impl_ReadProperty
3209  *
3210  * This method will read the specified property from the property chain.
3211  */
3212 BOOL StorageImpl_ReadProperty(
3213   StorageImpl* This,
3214   ULONG          index,
3215   StgProperty*   buffer)
3216 {
3217   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
3218   ULARGE_INTEGER offsetInPropSet;
3219   BOOL         readSuccessful;
3220   ULONG          bytesRead;
3221
3222   offsetInPropSet.u.HighPart = 0;
3223   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3224
3225   readSuccessful = BlockChainStream_ReadAt(
3226                     This->rootBlockChain,
3227                     offsetInPropSet,
3228                     PROPSET_BLOCK_SIZE,
3229                     currentProperty,
3230                     &bytesRead);
3231
3232   if (readSuccessful)
3233   {
3234     /* replace the name of root entry (often "Root Entry") by the file name */
3235     WCHAR *propName = (index == This->base.rootPropertySetIndex) ?
3236                         This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME;
3237
3238     memset(buffer->name, 0, sizeof(buffer->name));
3239     memcpy(
3240       buffer->name,
3241       propName,
3242       PROPERTY_NAME_BUFFER_LEN );
3243     TRACE("storage name: %s\n", debugstr_w(buffer->name));
3244
3245     memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
3246
3247     StorageUtl_ReadWord(
3248       currentProperty,
3249       OFFSET_PS_NAMELENGTH,
3250       &buffer->sizeOfNameString);
3251
3252     StorageUtl_ReadDWord(
3253       currentProperty,
3254       OFFSET_PS_PREVIOUSPROP,
3255       &buffer->previousProperty);
3256
3257     StorageUtl_ReadDWord(
3258       currentProperty,
3259       OFFSET_PS_NEXTPROP,
3260       &buffer->nextProperty);
3261
3262     StorageUtl_ReadDWord(
3263       currentProperty,
3264       OFFSET_PS_DIRPROP,
3265       &buffer->dirProperty);
3266
3267     StorageUtl_ReadGUID(
3268       currentProperty,
3269       OFFSET_PS_GUID,
3270       &buffer->propertyUniqueID);
3271
3272     StorageUtl_ReadDWord(
3273       currentProperty,
3274       OFFSET_PS_TSS1,
3275       &buffer->timeStampS1);
3276
3277     StorageUtl_ReadDWord(
3278       currentProperty,
3279       OFFSET_PS_TSD1,
3280       &buffer->timeStampD1);
3281
3282     StorageUtl_ReadDWord(
3283       currentProperty,
3284       OFFSET_PS_TSS2,
3285       &buffer->timeStampS2);
3286
3287     StorageUtl_ReadDWord(
3288       currentProperty,
3289       OFFSET_PS_TSD2,
3290       &buffer->timeStampD2);
3291
3292     StorageUtl_ReadDWord(
3293       currentProperty,
3294       OFFSET_PS_STARTBLOCK,
3295       &buffer->startingBlock);
3296
3297     StorageUtl_ReadDWord(
3298       currentProperty,
3299       OFFSET_PS_SIZE,
3300       &buffer->size.u.LowPart);
3301
3302     buffer->size.u.HighPart = 0;
3303   }
3304
3305   return readSuccessful;
3306 }
3307
3308 /*********************************************************************
3309  * Write the specified property into the property chain
3310  */
3311 BOOL StorageImpl_WriteProperty(
3312   StorageImpl* This,
3313   ULONG          index,
3314   StgProperty*   buffer)
3315 {
3316   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
3317   ULARGE_INTEGER offsetInPropSet;
3318   BOOL         writeSuccessful;
3319   ULONG          bytesWritten;
3320
3321   offsetInPropSet.u.HighPart = 0;
3322   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3323
3324   memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
3325
3326   memcpy(
3327     currentProperty + OFFSET_PS_NAME,
3328     buffer->name,
3329     PROPERTY_NAME_BUFFER_LEN );
3330
3331   memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
3332
3333   StorageUtl_WriteWord(
3334     currentProperty,
3335       OFFSET_PS_NAMELENGTH,
3336       buffer->sizeOfNameString);
3337
3338   StorageUtl_WriteDWord(
3339     currentProperty,
3340       OFFSET_PS_PREVIOUSPROP,
3341       buffer->previousProperty);
3342
3343   StorageUtl_WriteDWord(
3344     currentProperty,
3345       OFFSET_PS_NEXTPROP,
3346       buffer->nextProperty);
3347
3348   StorageUtl_WriteDWord(
3349     currentProperty,
3350       OFFSET_PS_DIRPROP,
3351       buffer->dirProperty);
3352
3353   StorageUtl_WriteGUID(
3354     currentProperty,
3355       OFFSET_PS_GUID,
3356       &buffer->propertyUniqueID);
3357
3358   StorageUtl_WriteDWord(
3359     currentProperty,
3360       OFFSET_PS_TSS1,
3361       buffer->timeStampS1);
3362
3363   StorageUtl_WriteDWord(
3364     currentProperty,
3365       OFFSET_PS_TSD1,
3366       buffer->timeStampD1);
3367
3368   StorageUtl_WriteDWord(
3369     currentProperty,
3370       OFFSET_PS_TSS2,
3371       buffer->timeStampS2);
3372
3373   StorageUtl_WriteDWord(
3374     currentProperty,
3375       OFFSET_PS_TSD2,
3376       buffer->timeStampD2);
3377
3378   StorageUtl_WriteDWord(
3379     currentProperty,
3380       OFFSET_PS_STARTBLOCK,
3381       buffer->startingBlock);
3382
3383   StorageUtl_WriteDWord(
3384     currentProperty,
3385       OFFSET_PS_SIZE,
3386       buffer->size.u.LowPart);
3387
3388   writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
3389                                             offsetInPropSet,
3390                                             PROPSET_BLOCK_SIZE,
3391                                             currentProperty,
3392                                             &bytesWritten);
3393   return writeSuccessful;
3394 }
3395
3396 BOOL StorageImpl_ReadBigBlock(
3397   StorageImpl* This,
3398   ULONG          blockIndex,
3399   void*          buffer)
3400 {
3401   void* bigBlockBuffer;
3402
3403   bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
3404
3405   if (bigBlockBuffer!=0)
3406   {
3407     memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
3408
3409     StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3410
3411     return TRUE;
3412   }
3413
3414   return FALSE;
3415 }
3416
3417 BOOL StorageImpl_WriteBigBlock(
3418   StorageImpl* This,
3419   ULONG          blockIndex,
3420   void*          buffer)
3421 {
3422   void* bigBlockBuffer;
3423
3424   bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
3425
3426   if (bigBlockBuffer!=0)
3427   {
3428     memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
3429
3430     StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3431
3432     return TRUE;
3433   }
3434
3435   return FALSE;
3436 }
3437
3438 void* StorageImpl_GetROBigBlock(
3439   StorageImpl* This,
3440   ULONG          blockIndex)
3441 {
3442   return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
3443 }
3444
3445 void* StorageImpl_GetBigBlock(
3446   StorageImpl* This,
3447   ULONG          blockIndex)
3448 {
3449   return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
3450 }
3451
3452 void StorageImpl_ReleaseBigBlock(
3453   StorageImpl* This,
3454   void*          pBigBlock)
3455 {
3456   BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
3457 }
3458
3459 /******************************************************************************
3460  *              Storage32Impl_SmallBlocksToBigBlocks
3461  *
3462  * This method will convert a small block chain to a big block chain.
3463  * The small block chain will be destroyed.
3464  */
3465 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3466                       StorageImpl* This,
3467                       SmallBlockChainStream** ppsbChain)
3468 {
3469   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3470   ULARGE_INTEGER size, offset;
3471   ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
3472   ULONG propertyIndex;
3473   BOOL successWrite;
3474   HRESULT successRead;
3475   StgProperty chainProperty;
3476   BYTE *buffer;
3477   BlockChainStream *bbTempChain = NULL;
3478   BlockChainStream *bigBlockChain = NULL;
3479
3480   /*
3481    * Create a temporary big block chain that doesn't have
3482    * an associated property. This temporary chain will be
3483    * used to copy data from small blocks to big blocks.
3484    */
3485   bbTempChain = BlockChainStream_Construct(This,
3486                                            &bbHeadOfChain,
3487                                            PROPERTY_NULL);
3488   if(!bbTempChain) return NULL;
3489   /*
3490    * Grow the big block chain.
3491    */
3492   size = SmallBlockChainStream_GetSize(*ppsbChain);
3493   BlockChainStream_SetSize(bbTempChain, size);
3494
3495   /*
3496    * Copy the contents of the small block chain to the big block chain
3497    * by small block size increments.
3498    */
3499   offset.u.LowPart = 0;
3500   offset.u.HighPart = 0;
3501   cbTotalRead = 0;
3502   cbTotalWritten = 0;
3503
3504   buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3505   do
3506   {
3507     successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3508                                                offset,
3509                                                DEF_SMALL_BLOCK_SIZE,
3510                                                buffer,
3511                                                &cbRead);
3512     if (FAILED(successRead))
3513         break;
3514
3515     if (cbRead > 0)
3516     {
3517         cbTotalRead += cbRead;
3518
3519         successWrite = BlockChainStream_WriteAt(bbTempChain,
3520                                             offset,
3521                                             cbRead,
3522                                             buffer,
3523                                             &cbWritten);
3524
3525         if (!successWrite)
3526             break;
3527
3528         cbTotalWritten += cbWritten;
3529         offset.u.LowPart += This->smallBlockSize;
3530     }
3531   } while (cbRead > 0);
3532   HeapFree(GetProcessHeap(),0,buffer);
3533
3534   assert(cbTotalRead == cbTotalWritten);
3535
3536   /*
3537    * Destroy the small block chain.
3538    */
3539   propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3540   size.u.HighPart = 0;
3541   size.u.LowPart  = 0;
3542   SmallBlockChainStream_SetSize(*ppsbChain, size);
3543   SmallBlockChainStream_Destroy(*ppsbChain);
3544   *ppsbChain = 0;
3545
3546   /*
3547    * Change the property information. This chain is now a big block chain
3548    * and it doesn't reside in the small blocks chain anymore.
3549    */
3550   StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3551
3552   chainProperty.startingBlock = bbHeadOfChain;
3553
3554   StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3555
3556   /*
3557    * Destroy the temporary propertyless big block chain.
3558    * Create a new big block chain associated with this property.
3559    */
3560   BlockChainStream_Destroy(bbTempChain);
3561   bigBlockChain = BlockChainStream_Construct(This,
3562                                              NULL,
3563                                              propertyIndex);
3564
3565   return bigBlockChain;
3566 }
3567
3568 void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
3569 {
3570   StorageInternalImpl* This = (StorageInternalImpl*) iface;
3571
3572   StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);
3573   HeapFree(GetProcessHeap(), 0, This);
3574 }
3575
3576 /******************************************************************************
3577 **
3578 ** Storage32InternalImpl_Commit
3579 **
3580 ** The non-root storages cannot be opened in transacted mode thus this function
3581 ** does nothing.
3582 */
3583 HRESULT WINAPI StorageInternalImpl_Commit(
3584   IStorage*            iface,
3585   DWORD                  grfCommitFlags)  /* [in] */
3586 {
3587   return S_OK;
3588 }
3589
3590 /******************************************************************************
3591 **
3592 ** Storage32InternalImpl_Revert
3593 **
3594 ** The non-root storages cannot be opened in transacted mode thus this function
3595 ** does nothing.
3596 */
3597 HRESULT WINAPI StorageInternalImpl_Revert(
3598   IStorage*            iface)
3599 {
3600   return S_OK;
3601 }
3602
3603 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3604 {
3605   IStorage_Release((IStorage*)This->parentStorage);
3606   HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3607   HeapFree(GetProcessHeap(), 0, This);
3608 }
3609
3610 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3611   IEnumSTATSTG*     iface,
3612   REFIID            riid,
3613   void**            ppvObject)
3614 {
3615   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3616
3617   /*
3618    * Perform a sanity check on the parameters.
3619    */
3620   if (ppvObject==0)
3621     return E_INVALIDARG;
3622
3623   /*
3624    * Initialize the return parameter.
3625    */
3626   *ppvObject = 0;
3627
3628   /*
3629    * Compare the riid with the interface IDs implemented by this object.
3630    */
3631   if (IsEqualGUID(&IID_IUnknown, riid) ||
3632       IsEqualGUID(&IID_IStorage, riid))
3633   {
3634     *ppvObject = (IEnumSTATSTG*)This;
3635     IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
3636     return S_OK;
3637   }
3638
3639   return E_NOINTERFACE;
3640 }
3641
3642 ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
3643   IEnumSTATSTG* iface)
3644 {
3645   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3646   return InterlockedIncrement(&This->ref);
3647 }
3648
3649 ULONG   WINAPI IEnumSTATSTGImpl_Release(
3650   IEnumSTATSTG* iface)
3651 {
3652   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3653
3654   ULONG newRef;
3655
3656   newRef = InterlockedDecrement(&This->ref);
3657
3658   /*
3659    * If the reference count goes down to 0, perform suicide.
3660    */
3661   if (newRef==0)
3662   {
3663     IEnumSTATSTGImpl_Destroy(This);
3664   }
3665
3666   return newRef;
3667 }
3668
3669 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3670   IEnumSTATSTG* iface,
3671   ULONG             celt,
3672   STATSTG*          rgelt,
3673   ULONG*            pceltFetched)
3674 {
3675   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3676
3677   StgProperty currentProperty;
3678   STATSTG*    currentReturnStruct = rgelt;
3679   ULONG       objectFetched       = 0;
3680   ULONG      currentSearchNode;
3681
3682   /*
3683    * Perform a sanity check on the parameters.
3684    */
3685   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3686     return E_INVALIDARG;
3687
3688   /*
3689    * To avoid the special case, get another pointer to a ULONG value if
3690    * the caller didn't supply one.
3691    */
3692   if (pceltFetched==0)
3693     pceltFetched = &objectFetched;
3694
3695   /*
3696    * Start the iteration, we will iterate until we hit the end of the
3697    * linked list or until we hit the number of items to iterate through
3698    */
3699   *pceltFetched = 0;
3700
3701   /*
3702    * Start with the node at the top of the stack.
3703    */
3704   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3705
3706   while ( ( *pceltFetched < celt) &&
3707           ( currentSearchNode!=PROPERTY_NULL) )
3708   {
3709     /*
3710      * Remove the top node from the stack
3711      */
3712     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3713
3714     /*
3715      * Read the property from the storage.
3716      */
3717     StorageImpl_ReadProperty(This->parentStorage,
3718       currentSearchNode,
3719       &currentProperty);
3720
3721     /*
3722      * Copy the information to the return buffer.
3723      */
3724     StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3725       &currentProperty,
3726       STATFLAG_DEFAULT);
3727
3728     /*
3729      * Step to the next item in the iteration
3730      */
3731     (*pceltFetched)++;
3732     currentReturnStruct++;
3733
3734     /*
3735      * Push the next search node in the search stack.
3736      */
3737     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3738
3739     /*
3740      * continue the iteration.
3741      */
3742     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3743   }
3744
3745   if (*pceltFetched == celt)
3746     return S_OK;
3747
3748   return S_FALSE;
3749 }
3750
3751
3752 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3753   IEnumSTATSTG* iface,
3754   ULONG             celt)
3755 {
3756   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3757
3758   StgProperty currentProperty;
3759   ULONG       objectFetched       = 0;
3760   ULONG       currentSearchNode;
3761
3762   /*
3763    * Start with the node at the top of the stack.
3764    */
3765   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3766
3767   while ( (objectFetched < celt) &&
3768           (currentSearchNode!=PROPERTY_NULL) )
3769   {
3770     /*
3771      * Remove the top node from the stack
3772      */
3773     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3774
3775     /*
3776      * Read the property from the storage.
3777      */
3778     StorageImpl_ReadProperty(This->parentStorage,
3779       currentSearchNode,
3780       &currentProperty);
3781
3782     /*
3783      * Step to the next item in the iteration
3784      */
3785     objectFetched++;
3786
3787     /*
3788      * Push the next search node in the search stack.
3789      */
3790     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3791
3792     /*
3793      * continue the iteration.
3794      */
3795     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3796   }
3797
3798   if (objectFetched == celt)
3799     return S_OK;
3800
3801   return S_FALSE;
3802 }
3803
3804 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3805   IEnumSTATSTG* iface)
3806 {
3807   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3808
3809   StgProperty rootProperty;
3810   BOOL      readSuccessful;
3811
3812   /*
3813    * Re-initialize the search stack to an empty stack
3814    */
3815   This->stackSize = 0;
3816
3817   /*
3818    * Read the root property from the storage.
3819    */
3820   readSuccessful = StorageImpl_ReadProperty(
3821                     This->parentStorage,
3822                     This->firstPropertyNode,
3823                     &rootProperty);
3824
3825   if (readSuccessful)
3826   {
3827     assert(rootProperty.sizeOfNameString!=0);
3828
3829     /*
3830      * Push the search node in the search stack.
3831      */
3832     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3833   }
3834
3835   return S_OK;
3836 }
3837
3838 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3839   IEnumSTATSTG* iface,
3840   IEnumSTATSTG**    ppenum)
3841 {
3842   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3843
3844   IEnumSTATSTGImpl* newClone;
3845
3846   /*
3847    * Perform a sanity check on the parameters.
3848    */
3849   if (ppenum==0)
3850     return E_INVALIDARG;
3851
3852   newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3853                This->firstPropertyNode);
3854
3855
3856   /*
3857    * The new clone enumeration must point to the same current node as
3858    * the ole one.
3859    */
3860   newClone->stackSize    = This->stackSize    ;
3861   newClone->stackMaxSize = This->stackMaxSize ;
3862   newClone->stackToVisit =
3863     HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3864
3865   memcpy(
3866     newClone->stackToVisit,
3867     This->stackToVisit,
3868     sizeof(ULONG) * newClone->stackSize);
3869
3870   *ppenum = (IEnumSTATSTG*)newClone;
3871
3872   /*
3873    * Don't forget to nail down a reference to the clone before
3874    * returning it.
3875    */
3876   IEnumSTATSTGImpl_AddRef(*ppenum);
3877
3878   return S_OK;
3879 }
3880
3881 INT IEnumSTATSTGImpl_FindParentProperty(
3882   IEnumSTATSTGImpl *This,
3883   ULONG             childProperty,
3884   StgProperty      *currentProperty,
3885   ULONG            *thisNodeId)
3886 {
3887   ULONG currentSearchNode;
3888   ULONG foundNode;
3889
3890   /*
3891    * To avoid the special case, get another pointer to a ULONG value if
3892    * the caller didn't supply one.
3893    */
3894   if (thisNodeId==0)
3895     thisNodeId = &foundNode;
3896
3897   /*
3898    * Start with the node at the top of the stack.
3899    */
3900   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3901
3902
3903   while (currentSearchNode!=PROPERTY_NULL)
3904   {
3905     /*
3906      * Store the current node in the returned parameters
3907      */
3908     *thisNodeId = currentSearchNode;
3909
3910     /*
3911      * Remove the top node from the stack
3912      */
3913     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3914
3915     /*
3916      * Read the property from the storage.
3917      */
3918     StorageImpl_ReadProperty(
3919       This->parentStorage,
3920       currentSearchNode,
3921       currentProperty);
3922
3923     if (currentProperty->previousProperty == childProperty)
3924       return PROPERTY_RELATION_PREVIOUS;
3925
3926     else if (currentProperty->nextProperty == childProperty)
3927       return PROPERTY_RELATION_NEXT;
3928
3929     else if (currentProperty->dirProperty == childProperty)
3930       return PROPERTY_RELATION_DIR;
3931
3932     /*
3933      * Push the next search node in the search stack.
3934      */
3935     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3936
3937     /*
3938      * continue the iteration.
3939      */
3940     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3941   }
3942
3943   return PROPERTY_NULL;
3944 }
3945
3946 ULONG IEnumSTATSTGImpl_FindProperty(
3947   IEnumSTATSTGImpl* This,
3948   const OLECHAR*  lpszPropName,
3949   StgProperty*      currentProperty)
3950 {
3951   ULONG currentSearchNode;
3952
3953   /*
3954    * Start with the node at the top of the stack.
3955    */
3956   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3957
3958   while (currentSearchNode!=PROPERTY_NULL)
3959   {
3960     /*
3961      * Remove the top node from the stack
3962      */
3963     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3964
3965     /*
3966      * Read the property from the storage.
3967      */
3968     StorageImpl_ReadProperty(This->parentStorage,
3969       currentSearchNode,
3970       currentProperty);
3971
3972     if ( propertyNameCmp(
3973           (const OLECHAR*)currentProperty->name,
3974           (const OLECHAR*)lpszPropName) == 0)
3975       return currentSearchNode;
3976
3977     /*
3978      * Push the next search node in the search stack.
3979      */
3980     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3981
3982     /*
3983      * continue the iteration.
3984      */
3985     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3986   }
3987
3988   return PROPERTY_NULL;
3989 }
3990
3991 void IEnumSTATSTGImpl_PushSearchNode(
3992   IEnumSTATSTGImpl* This,
3993   ULONG             nodeToPush)
3994 {
3995   StgProperty rootProperty;
3996   BOOL      readSuccessful;
3997
3998   /*
3999    * First, make sure we're not trying to push an unexisting node.
4000    */
4001   if (nodeToPush==PROPERTY_NULL)
4002     return;
4003
4004   /*
4005    * First push the node to the stack
4006    */
4007   if (This->stackSize == This->stackMaxSize)
4008   {
4009     This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
4010
4011     This->stackToVisit = HeapReAlloc(
4012                            GetProcessHeap(),
4013                            0,
4014                            This->stackToVisit,
4015                            sizeof(ULONG) * This->stackMaxSize);
4016   }
4017
4018   This->stackToVisit[This->stackSize] = nodeToPush;
4019   This->stackSize++;
4020
4021   /*
4022    * Read the root property from the storage.
4023    */
4024   readSuccessful = StorageImpl_ReadProperty(
4025                     This->parentStorage,
4026                     nodeToPush,
4027                     &rootProperty);
4028
4029   if (readSuccessful)
4030   {
4031     assert(rootProperty.sizeOfNameString!=0);
4032
4033     /*
4034      * Push the previous search node in the search stack.
4035      */
4036     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
4037   }
4038 }
4039
4040 ULONG IEnumSTATSTGImpl_PopSearchNode(
4041   IEnumSTATSTGImpl* This,
4042   BOOL            remove)
4043 {
4044   ULONG topNode;
4045
4046   if (This->stackSize == 0)
4047     return PROPERTY_NULL;
4048
4049   topNode = This->stackToVisit[This->stackSize-1];
4050
4051   if (remove)
4052     This->stackSize--;
4053
4054   return topNode;
4055 }
4056
4057 /*
4058  * Virtual function table for the IEnumSTATSTGImpl class.
4059  */
4060 static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
4061 {
4062     IEnumSTATSTGImpl_QueryInterface,
4063     IEnumSTATSTGImpl_AddRef,
4064     IEnumSTATSTGImpl_Release,
4065     IEnumSTATSTGImpl_Next,
4066     IEnumSTATSTGImpl_Skip,
4067     IEnumSTATSTGImpl_Reset,
4068     IEnumSTATSTGImpl_Clone
4069 };
4070
4071 /******************************************************************************
4072 ** IEnumSTATSTGImpl implementation
4073 */
4074
4075 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
4076   StorageImpl* parentStorage,
4077   ULONG          firstPropertyNode)
4078 {
4079   IEnumSTATSTGImpl* newEnumeration;
4080
4081   newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
4082
4083   if (newEnumeration!=0)
4084   {
4085     /*
4086      * Set-up the virtual function table and reference count.
4087      */
4088     newEnumeration->lpVtbl    = &IEnumSTATSTGImpl_Vtbl;
4089     newEnumeration->ref       = 0;
4090
4091     /*
4092      * We want to nail-down the reference to the storage in case the
4093      * enumeration out-lives the storage in the client application.
4094      */
4095     newEnumeration->parentStorage = parentStorage;
4096     IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
4097
4098     newEnumeration->firstPropertyNode   = firstPropertyNode;
4099
4100     /*
4101      * Initialize the search stack
4102      */
4103     newEnumeration->stackSize    = 0;
4104     newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
4105     newEnumeration->stackToVisit =
4106       HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
4107
4108     /*
4109      * Make sure the current node of the iterator is the first one.
4110      */
4111     IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
4112   }
4113
4114   return newEnumeration;
4115 }
4116
4117 /*
4118  * Virtual function table for the Storage32InternalImpl class.
4119  */
4120 static const IStorageVtbl Storage32InternalImpl_Vtbl =
4121 {
4122     StorageBaseImpl_QueryInterface,
4123     StorageBaseImpl_AddRef,
4124     StorageBaseImpl_Release,
4125     StorageBaseImpl_CreateStream,
4126     StorageBaseImpl_OpenStream,
4127     StorageImpl_CreateStorage,
4128     StorageBaseImpl_OpenStorage,
4129     StorageImpl_CopyTo,
4130     StorageImpl_MoveElementTo,
4131     StorageInternalImpl_Commit,
4132     StorageInternalImpl_Revert,
4133     StorageBaseImpl_EnumElements,
4134     StorageImpl_DestroyElement,
4135     StorageBaseImpl_RenameElement,
4136     StorageImpl_SetElementTimes,
4137     StorageBaseImpl_SetClass,
4138     StorageImpl_SetStateBits,
4139     StorageBaseImpl_Stat
4140 };
4141
4142 /******************************************************************************
4143 ** Storage32InternalImpl implementation
4144 */
4145
4146 StorageInternalImpl* StorageInternalImpl_Construct(
4147   StorageImpl* ancestorStorage,
4148   DWORD        openFlags,
4149   ULONG        rootPropertyIndex)
4150 {
4151   StorageInternalImpl* newStorage;
4152
4153   /*
4154    * Allocate space for the new storage object
4155    */
4156   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
4157
4158   if (newStorage!=0)
4159   {
4160     memset(newStorage, 0, sizeof(StorageInternalImpl));
4161
4162     /*
4163      * Initialize the stream list
4164      */
4165
4166     list_init(&newStorage->base.strmHead);
4167
4168     /*
4169      * Initialize the virtual function table.
4170      */
4171     newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
4172     newStorage->base.v_destructor = &StorageInternalImpl_Destroy;
4173     newStorage->base.openFlags = openFlags;
4174
4175     /*
4176      * Keep the ancestor storage pointer and nail a reference to it.
4177      */
4178     newStorage->base.ancestorStorage = ancestorStorage;
4179     StorageBaseImpl_AddRef((IStorage*)(newStorage->base.ancestorStorage));
4180
4181     /*
4182      * Keep the index of the root property set for this storage,
4183      */
4184     newStorage->base.rootPropertySetIndex = rootPropertyIndex;
4185
4186     return newStorage;
4187   }
4188
4189   return 0;
4190 }
4191
4192 /******************************************************************************
4193 ** StorageUtl implementation
4194 */
4195
4196 void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
4197 {
4198   WORD tmp;
4199
4200   memcpy(&tmp, buffer+offset, sizeof(WORD));
4201   *value = le16toh(tmp);
4202 }
4203
4204 void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
4205 {
4206   value = htole16(value);
4207   memcpy(buffer+offset, &value, sizeof(WORD));
4208 }
4209
4210 void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
4211 {
4212   DWORD tmp;
4213
4214   memcpy(&tmp, buffer+offset, sizeof(DWORD));
4215   *value = le32toh(tmp);
4216 }
4217
4218 void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
4219 {
4220   value = htole32(value);
4221   memcpy(buffer+offset, &value, sizeof(DWORD));
4222 }
4223
4224 void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
4225  ULARGE_INTEGER* value)
4226 {
4227 #ifdef WORDS_BIGENDIAN
4228     ULARGE_INTEGER tmp;
4229
4230     memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
4231     value->u.LowPart = htole32(tmp.u.HighPart);
4232     value->u.HighPart = htole32(tmp.u.LowPart);
4233 #else
4234     memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
4235 #endif
4236 }
4237
4238 void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
4239  const ULARGE_INTEGER *value)
4240 {
4241 #ifdef WORDS_BIGENDIAN
4242     ULARGE_INTEGER tmp;
4243
4244     tmp.u.LowPart = htole32(value->u.HighPart);
4245     tmp.u.HighPart = htole32(value->u.LowPart);
4246     memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
4247 #else
4248     memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
4249 #endif
4250 }
4251
4252 void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
4253 {
4254   StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
4255   StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
4256   StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
4257
4258   memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
4259 }
4260
4261 void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
4262 {
4263   StorageUtl_WriteDWord(buffer, offset,   value->Data1);
4264   StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
4265   StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
4266
4267   memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
4268 }
4269
4270 void StorageUtl_CopyPropertyToSTATSTG(
4271   STATSTG*     destination,
4272   StgProperty* source,
4273   int          statFlags)
4274 {
4275   /*
4276    * The copy of the string occurs only when the flag is not set
4277    */
4278   if( ((statFlags & STATFLAG_NONAME) != 0) || 
4279        (source->name == NULL) || 
4280        (source->name[0] == 0) )
4281   {
4282     destination->pwcsName = 0;
4283   }
4284   else
4285   {
4286     destination->pwcsName =
4287       CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
4288
4289     strcpyW((LPWSTR)destination->pwcsName, source->name);
4290   }
4291
4292   switch (source->propertyType)
4293   {
4294     case PROPTYPE_STORAGE:
4295     case PROPTYPE_ROOT:
4296       destination->type = STGTY_STORAGE;
4297       break;
4298     case PROPTYPE_STREAM:
4299       destination->type = STGTY_STREAM;
4300       break;
4301     default:
4302       destination->type = STGTY_STREAM;
4303       break;
4304   }
4305
4306   destination->cbSize            = source->size;
4307 /*
4308   currentReturnStruct->mtime     = {0}; TODO
4309   currentReturnStruct->ctime     = {0};
4310   currentReturnStruct->atime     = {0};
4311 */
4312   destination->grfMode           = 0;
4313   destination->grfLocksSupported = 0;
4314   destination->clsid             = source->propertyUniqueID;
4315   destination->grfStateBits      = 0;
4316   destination->reserved          = 0;
4317 }
4318
4319 /******************************************************************************
4320 ** BlockChainStream implementation
4321 */
4322
4323 BlockChainStream* BlockChainStream_Construct(
4324   StorageImpl* parentStorage,
4325   ULONG*         headOfStreamPlaceHolder,
4326   ULONG          propertyIndex)
4327 {
4328   BlockChainStream* newStream;
4329   ULONG blockIndex;
4330
4331   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
4332
4333   newStream->parentStorage           = parentStorage;
4334   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
4335   newStream->ownerPropertyIndex      = propertyIndex;
4336   newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
4337   newStream->tailIndex               = BLOCK_END_OF_CHAIN;
4338   newStream->numBlocks               = 0;
4339
4340   blockIndex = BlockChainStream_GetHeadOfChain(newStream);
4341
4342   while (blockIndex != BLOCK_END_OF_CHAIN)
4343   {
4344     newStream->numBlocks++;
4345     newStream->tailIndex = blockIndex;
4346
4347     if(FAILED(StorageImpl_GetNextBlockInChain(
4348               parentStorage,
4349               blockIndex,
4350               &blockIndex)))
4351     {
4352       HeapFree(GetProcessHeap(), 0, newStream);
4353       return NULL;
4354     }
4355   }
4356
4357   return newStream;
4358 }
4359
4360 void BlockChainStream_Destroy(BlockChainStream* This)
4361 {
4362   HeapFree(GetProcessHeap(), 0, This);
4363 }
4364
4365 /******************************************************************************
4366  *      BlockChainStream_GetHeadOfChain
4367  *
4368  * Returns the head of this stream chain.
4369  * Some special chains don't have properties, their heads are kept in
4370  * This->headOfStreamPlaceHolder.
4371  *
4372  */
4373 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
4374 {
4375   StgProperty chainProperty;
4376   BOOL      readSuccessful;
4377
4378   if (This->headOfStreamPlaceHolder != 0)
4379     return *(This->headOfStreamPlaceHolder);
4380
4381   if (This->ownerPropertyIndex != PROPERTY_NULL)
4382   {
4383     readSuccessful = StorageImpl_ReadProperty(
4384                       This->parentStorage,
4385                       This->ownerPropertyIndex,
4386                       &chainProperty);
4387
4388     if (readSuccessful)
4389     {
4390       return chainProperty.startingBlock;
4391     }
4392   }
4393
4394   return BLOCK_END_OF_CHAIN;
4395 }
4396
4397 /******************************************************************************
4398  *       BlockChainStream_GetCount
4399  *
4400  * Returns the number of blocks that comprises this chain.
4401  * This is not the size of the stream as the last block may not be full!
4402  *
4403  */
4404 ULONG BlockChainStream_GetCount(BlockChainStream* This)
4405 {
4406   ULONG blockIndex;
4407   ULONG count = 0;
4408
4409   blockIndex = BlockChainStream_GetHeadOfChain(This);
4410
4411   while (blockIndex != BLOCK_END_OF_CHAIN)
4412   {
4413     count++;
4414
4415     if(FAILED(StorageImpl_GetNextBlockInChain(
4416                    This->parentStorage,
4417                    blockIndex,
4418                    &blockIndex)))
4419       return 0;
4420   }
4421
4422   return count;
4423 }
4424
4425 /******************************************************************************
4426  *      BlockChainStream_ReadAt
4427  *
4428  * Reads a specified number of bytes from this chain at the specified offset.
4429  * bytesRead may be NULL.
4430  * Failure will be returned if the specified number of bytes has not been read.
4431  */
4432 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
4433   ULARGE_INTEGER offset,
4434   ULONG          size,
4435   void*          buffer,
4436   ULONG*         bytesRead)
4437 {
4438   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4439   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
4440   ULONG bytesToReadInBuffer;
4441   ULONG blockIndex;
4442   BYTE* bufferWalker;
4443   BYTE* bigBlockBuffer;
4444
4445   /*
4446    * Find the first block in the stream that contains part of the buffer.
4447    */
4448   if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4449        (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4450        (blockNoInSequence < This->lastBlockNoInSequence) )
4451   {
4452     blockIndex = BlockChainStream_GetHeadOfChain(This);
4453     This->lastBlockNoInSequence = blockNoInSequence;
4454   }
4455   else
4456   {
4457     ULONG temp = blockNoInSequence;
4458
4459     blockIndex = This->lastBlockNoInSequenceIndex;
4460     blockNoInSequence -= This->lastBlockNoInSequence;
4461     This->lastBlockNoInSequence = temp;
4462   }
4463
4464   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4465   {
4466     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
4467       return FALSE;
4468     blockNoInSequence--;
4469   }
4470
4471   if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN))
4472       return FALSE; /* We failed to find the starting block */
4473
4474   This->lastBlockNoInSequenceIndex = blockIndex;
4475
4476   /*
4477    * Start reading the buffer.
4478    */
4479   *bytesRead   = 0;
4480   bufferWalker = buffer;
4481
4482   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4483   {
4484     /*
4485      * Calculate how many bytes we can copy from this big block.
4486      */
4487     bytesToReadInBuffer =
4488       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4489
4490     /*
4491      * Copy those bytes to the buffer
4492      */
4493     bigBlockBuffer =
4494       StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
4495
4496     memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
4497
4498     StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4499
4500     /*
4501      * Step to the next big block.
4502      */
4503     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
4504       return FALSE;
4505
4506     bufferWalker += bytesToReadInBuffer;
4507     size         -= bytesToReadInBuffer;
4508     *bytesRead   += bytesToReadInBuffer;
4509     offsetInBlock = 0;  /* There is no offset on the next block */
4510
4511   }
4512
4513   return (size == 0);
4514 }
4515
4516 /******************************************************************************
4517  *      BlockChainStream_WriteAt
4518  *
4519  * Writes the specified number of bytes to this chain at the specified offset.
4520  * bytesWritten may be NULL.
4521  * Will fail if not all specified number of bytes have been written.
4522  */
4523 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
4524   ULARGE_INTEGER    offset,
4525   ULONG             size,
4526   const void*       buffer,
4527   ULONG*            bytesWritten)
4528 {
4529   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4530   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
4531   ULONG bytesToWrite;
4532   ULONG blockIndex;
4533   const BYTE* bufferWalker;
4534   BYTE* bigBlockBuffer;
4535
4536   /*
4537    * Find the first block in the stream that contains part of the buffer.
4538    */
4539   if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4540        (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4541        (blockNoInSequence < This->lastBlockNoInSequence) )
4542   {
4543     blockIndex = BlockChainStream_GetHeadOfChain(This);
4544     This->lastBlockNoInSequence = blockNoInSequence;
4545   }
4546   else
4547   {
4548     ULONG temp = blockNoInSequence;
4549
4550     blockIndex = This->lastBlockNoInSequenceIndex;
4551     blockNoInSequence -= This->lastBlockNoInSequence;
4552     This->lastBlockNoInSequence = temp;
4553   }
4554
4555   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4556   {
4557     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4558                                               &blockIndex)))
4559       return FALSE;
4560     blockNoInSequence--;
4561   }
4562
4563   This->lastBlockNoInSequenceIndex = blockIndex;
4564
4565   /*
4566    * Here, I'm casting away the constness on the buffer variable
4567    * This is OK since we don't intend to modify that buffer.
4568    */
4569   *bytesWritten   = 0;
4570   bufferWalker = (const BYTE*)buffer;
4571
4572   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4573   {
4574     /*
4575      * Calculate how many bytes we can copy from this big block.
4576      */
4577     bytesToWrite =
4578       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4579
4580     /*
4581      * Copy those bytes to the buffer
4582      */
4583     bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
4584
4585     memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
4586
4587     StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4588
4589     /*
4590      * Step to the next big block.
4591      */
4592     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4593                                               &blockIndex)))
4594       return FALSE;
4595     bufferWalker  += bytesToWrite;
4596     size          -= bytesToWrite;
4597     *bytesWritten += bytesToWrite;
4598     offsetInBlock  = 0;      /* There is no offset on the next block */
4599   }
4600
4601   return (size == 0);
4602 }
4603
4604 /******************************************************************************
4605  *      BlockChainStream_Shrink
4606  *
4607  * Shrinks this chain in the big block depot.
4608  */
4609 BOOL BlockChainStream_Shrink(BlockChainStream* This,
4610                                ULARGE_INTEGER    newSize)
4611 {
4612   ULONG blockIndex, extraBlock;
4613   ULONG numBlocks;
4614   ULONG count = 1;
4615
4616   /*
4617    * Reset the last accessed block cache.
4618    */
4619   This->lastBlockNoInSequence = 0xFFFFFFFF;
4620   This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
4621
4622   /*
4623    * Figure out how many blocks are needed to contain the new size
4624    */
4625   numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4626
4627   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4628     numBlocks++;
4629
4630   blockIndex = BlockChainStream_GetHeadOfChain(This);
4631
4632   /*
4633    * Go to the new end of chain
4634    */
4635   while (count < numBlocks)
4636   {
4637     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4638                                               &blockIndex)))
4639       return FALSE;
4640     count++;
4641   }
4642
4643   /* Get the next block before marking the new end */
4644   if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4645                                             &extraBlock)))
4646     return FALSE;
4647
4648   /* Mark the new end of chain */
4649   StorageImpl_SetNextBlockInChain(
4650     This->parentStorage,
4651     blockIndex,
4652     BLOCK_END_OF_CHAIN);
4653
4654   This->tailIndex = blockIndex;
4655   This->numBlocks = numBlocks;
4656
4657   /*
4658    * Mark the extra blocks as free
4659    */
4660   while (extraBlock != BLOCK_END_OF_CHAIN)
4661   {
4662     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock,
4663                                               &blockIndex)))
4664       return FALSE;
4665     StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4666     extraBlock = blockIndex;
4667   }
4668
4669   return TRUE;
4670 }
4671
4672 /******************************************************************************
4673  *      BlockChainStream_Enlarge
4674  *
4675  * Grows this chain in the big block depot.
4676  */
4677 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4678                                 ULARGE_INTEGER    newSize)
4679 {
4680   ULONG blockIndex, currentBlock;
4681   ULONG newNumBlocks;
4682   ULONG oldNumBlocks = 0;
4683
4684   blockIndex = BlockChainStream_GetHeadOfChain(This);
4685
4686   /*
4687    * Empty chain. Create the head.
4688    */
4689   if (blockIndex == BLOCK_END_OF_CHAIN)
4690   {
4691     blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4692     StorageImpl_SetNextBlockInChain(This->parentStorage,
4693                                       blockIndex,
4694                                       BLOCK_END_OF_CHAIN);
4695
4696     if (This->headOfStreamPlaceHolder != 0)
4697     {
4698       *(This->headOfStreamPlaceHolder) = blockIndex;
4699     }
4700     else
4701     {
4702       StgProperty chainProp;
4703       assert(This->ownerPropertyIndex != PROPERTY_NULL);
4704
4705       StorageImpl_ReadProperty(
4706         This->parentStorage,
4707         This->ownerPropertyIndex,
4708         &chainProp);
4709
4710       chainProp.startingBlock = blockIndex;
4711
4712       StorageImpl_WriteProperty(
4713         This->parentStorage,
4714         This->ownerPropertyIndex,
4715         &chainProp);
4716     }
4717
4718     This->tailIndex = blockIndex;
4719     This->numBlocks = 1;
4720   }
4721
4722   /*
4723    * Figure out how many blocks are needed to contain this stream
4724    */
4725   newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4726
4727   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4728     newNumBlocks++;
4729
4730   /*
4731    * Go to the current end of chain
4732    */
4733   if (This->tailIndex == BLOCK_END_OF_CHAIN)
4734   {
4735     currentBlock = blockIndex;
4736
4737     while (blockIndex != BLOCK_END_OF_CHAIN)
4738     {
4739       This->numBlocks++;
4740       currentBlock = blockIndex;
4741
4742       if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
4743                                                 &blockIndex)))
4744         return FALSE;
4745     }
4746
4747     This->tailIndex = currentBlock;
4748   }
4749
4750   currentBlock = This->tailIndex;
4751   oldNumBlocks = This->numBlocks;
4752
4753   /*
4754    * Add new blocks to the chain
4755    */
4756   if (oldNumBlocks < newNumBlocks)
4757   {
4758     while (oldNumBlocks < newNumBlocks)
4759     {
4760       blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4761
4762       StorageImpl_SetNextBlockInChain(
4763         This->parentStorage,
4764         currentBlock,
4765         blockIndex);
4766
4767       StorageImpl_SetNextBlockInChain(
4768         This->parentStorage,
4769         blockIndex,
4770         BLOCK_END_OF_CHAIN);
4771
4772       currentBlock = blockIndex;
4773       oldNumBlocks++;
4774     }
4775
4776     This->tailIndex = blockIndex;
4777     This->numBlocks = newNumBlocks;
4778   }
4779
4780   return TRUE;
4781 }
4782
4783 /******************************************************************************
4784  *      BlockChainStream_SetSize
4785  *
4786  * Sets the size of this stream. The big block depot will be updated.
4787  * The file will grow if we grow the chain.
4788  *
4789  * TODO: Free the actual blocks in the file when we shrink the chain.
4790  *       Currently, the blocks are still in the file. So the file size
4791  *       doesn't shrink even if we shrink streams.
4792  */
4793 BOOL BlockChainStream_SetSize(
4794   BlockChainStream* This,
4795   ULARGE_INTEGER    newSize)
4796 {
4797   ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4798
4799   if (newSize.u.LowPart == size.u.LowPart)
4800     return TRUE;
4801
4802   if (newSize.u.LowPart < size.u.LowPart)
4803   {
4804     BlockChainStream_Shrink(This, newSize);
4805   }
4806   else
4807   {
4808     ULARGE_INTEGER fileSize =
4809       BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4810
4811     ULONG diff = newSize.u.LowPart - size.u.LowPart;
4812
4813     /*
4814      * Make sure the file stays a multiple of blocksize
4815      */
4816     if ((diff % This->parentStorage->bigBlockSize) != 0)
4817       diff += (This->parentStorage->bigBlockSize -
4818                 (diff % This->parentStorage->bigBlockSize) );
4819
4820     fileSize.u.LowPart += diff;
4821     BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4822
4823     BlockChainStream_Enlarge(This, newSize);
4824   }
4825
4826   return TRUE;
4827 }
4828
4829 /******************************************************************************
4830  *      BlockChainStream_GetSize
4831  *
4832  * Returns the size of this chain.
4833  * Will return the block count if this chain doesn't have a property.
4834  */
4835 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4836 {
4837   StgProperty chainProperty;
4838
4839   if(This->headOfStreamPlaceHolder == NULL)
4840   {
4841     /*
4842      * This chain is a data stream read the property and return
4843      * the appropriate size
4844      */
4845     StorageImpl_ReadProperty(
4846       This->parentStorage,
4847       This->ownerPropertyIndex,
4848       &chainProperty);
4849
4850     return chainProperty.size;
4851   }
4852   else
4853   {
4854     /*
4855      * this chain is a chain that does not have a property, figure out the
4856      * size by making the product number of used blocks times the
4857      * size of them
4858      */
4859     ULARGE_INTEGER result;
4860     result.u.HighPart = 0;
4861
4862     result.u.LowPart  =
4863       BlockChainStream_GetCount(This) *
4864       This->parentStorage->bigBlockSize;
4865
4866     return result;
4867   }
4868 }
4869
4870 /******************************************************************************
4871 ** SmallBlockChainStream implementation
4872 */
4873
4874 SmallBlockChainStream* SmallBlockChainStream_Construct(
4875   StorageImpl* parentStorage,
4876   ULONG          propertyIndex)
4877 {
4878   SmallBlockChainStream* newStream;
4879
4880   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4881
4882   newStream->parentStorage      = parentStorage;
4883   newStream->ownerPropertyIndex = propertyIndex;
4884
4885   return newStream;
4886 }
4887
4888 void SmallBlockChainStream_Destroy(
4889   SmallBlockChainStream* This)
4890 {
4891   HeapFree(GetProcessHeap(), 0, This);
4892 }
4893
4894 /******************************************************************************
4895  *      SmallBlockChainStream_GetHeadOfChain
4896  *
4897  * Returns the head of this chain of small blocks.
4898  */
4899 ULONG SmallBlockChainStream_GetHeadOfChain(
4900   SmallBlockChainStream* This)
4901 {
4902   StgProperty chainProperty;
4903   BOOL      readSuccessful;
4904
4905   if (This->ownerPropertyIndex)
4906   {
4907     readSuccessful = StorageImpl_ReadProperty(
4908                       This->parentStorage,
4909                       This->ownerPropertyIndex,
4910                       &chainProperty);
4911
4912     if (readSuccessful)
4913     {
4914       return chainProperty.startingBlock;
4915     }
4916
4917   }
4918
4919   return BLOCK_END_OF_CHAIN;
4920 }
4921
4922 /******************************************************************************
4923  *      SmallBlockChainStream_GetNextBlockInChain
4924  *
4925  * Returns the index of the next small block in this chain.
4926  *
4927  * Return Values:
4928  *    - BLOCK_END_OF_CHAIN: end of this chain
4929  *    - BLOCK_UNUSED: small block 'blockIndex' is free
4930  */
4931 HRESULT SmallBlockChainStream_GetNextBlockInChain(
4932   SmallBlockChainStream* This,
4933   ULONG                  blockIndex,
4934   ULONG*                 nextBlockInChain)
4935 {
4936   ULARGE_INTEGER offsetOfBlockInDepot;
4937   DWORD  buffer;
4938   ULONG  bytesRead;
4939   BOOL success;
4940
4941   *nextBlockInChain = BLOCK_END_OF_CHAIN;
4942
4943   offsetOfBlockInDepot.u.HighPart = 0;
4944   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
4945
4946   /*
4947    * Read those bytes in the buffer from the small block file.
4948    */
4949   success = BlockChainStream_ReadAt(
4950               This->parentStorage->smallBlockDepotChain,
4951               offsetOfBlockInDepot,
4952               sizeof(DWORD),
4953               &buffer,
4954               &bytesRead);
4955
4956   if (success)
4957   {
4958     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
4959     return S_OK;
4960   }
4961
4962   return STG_E_READFAULT;
4963 }
4964
4965 /******************************************************************************
4966  *       SmallBlockChainStream_SetNextBlockInChain
4967  *
4968  * Writes the index of the next block of the specified block in the small
4969  * block depot.
4970  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4971  * To flag a block as free use BLOCK_UNUSED as nextBlock.
4972  */
4973 void SmallBlockChainStream_SetNextBlockInChain(
4974   SmallBlockChainStream* This,
4975   ULONG                  blockIndex,
4976   ULONG                  nextBlock)
4977 {
4978   ULARGE_INTEGER offsetOfBlockInDepot;
4979   DWORD  buffer;
4980   ULONG  bytesWritten;
4981
4982   offsetOfBlockInDepot.u.HighPart = 0;
4983   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
4984
4985   StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
4986
4987   /*
4988    * Read those bytes in the buffer from the small block file.
4989    */
4990   BlockChainStream_WriteAt(
4991     This->parentStorage->smallBlockDepotChain,
4992     offsetOfBlockInDepot,
4993     sizeof(DWORD),
4994     &buffer,
4995     &bytesWritten);
4996 }
4997
4998 /******************************************************************************
4999  *      SmallBlockChainStream_FreeBlock
5000  *
5001  * Flag small block 'blockIndex' as free in the small block depot.
5002  */
5003 void SmallBlockChainStream_FreeBlock(
5004   SmallBlockChainStream* This,
5005   ULONG                  blockIndex)
5006 {
5007   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
5008 }
5009
5010 /******************************************************************************
5011  *      SmallBlockChainStream_GetNextFreeBlock
5012  *
5013  * Returns the index of a free small block. The small block depot will be
5014  * enlarged if necessary. The small block chain will also be enlarged if
5015  * necessary.
5016  */
5017 ULONG SmallBlockChainStream_GetNextFreeBlock(
5018   SmallBlockChainStream* This)
5019 {
5020   ULARGE_INTEGER offsetOfBlockInDepot;
5021   DWORD buffer;
5022   ULONG bytesRead;
5023   ULONG blockIndex = 0;
5024   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
5025   BOOL success = TRUE;
5026   ULONG smallBlocksPerBigBlock;
5027
5028   offsetOfBlockInDepot.u.HighPart = 0;
5029
5030   /*
5031    * Scan the small block depot for a free block
5032    */
5033   while (nextBlockIndex != BLOCK_UNUSED)
5034   {
5035     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
5036
5037     success = BlockChainStream_ReadAt(
5038                 This->parentStorage->smallBlockDepotChain,
5039                 offsetOfBlockInDepot,
5040                 sizeof(DWORD),
5041                 &buffer,
5042                 &bytesRead);
5043
5044     /*
5045      * If we run out of space for the small block depot, enlarge it
5046      */
5047     if (success)
5048     {
5049       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
5050
5051       if (nextBlockIndex != BLOCK_UNUSED)
5052         blockIndex++;
5053     }
5054     else
5055     {
5056       ULONG count =
5057         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
5058
5059       ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
5060       ULONG nextBlock, newsbdIndex;
5061       BYTE* smallBlockDepot;
5062
5063       nextBlock = sbdIndex;
5064       while (nextBlock != BLOCK_END_OF_CHAIN)
5065       {
5066         sbdIndex = nextBlock;
5067         StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock);
5068       }
5069
5070       newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5071       if (sbdIndex != BLOCK_END_OF_CHAIN)
5072         StorageImpl_SetNextBlockInChain(
5073           This->parentStorage,
5074           sbdIndex,
5075           newsbdIndex);
5076
5077       StorageImpl_SetNextBlockInChain(
5078         This->parentStorage,
5079         newsbdIndex,
5080         BLOCK_END_OF_CHAIN);
5081
5082       /*
5083        * Initialize all the small blocks to free
5084        */
5085       smallBlockDepot =
5086         StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
5087
5088       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
5089       StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
5090
5091       if (count == 0)
5092       {
5093         /*
5094          * We have just created the small block depot.
5095          */
5096         StgProperty rootProp;
5097         ULONG sbStartIndex;
5098
5099         /*
5100          * Save it in the header
5101          */
5102         This->parentStorage->smallBlockDepotStart = newsbdIndex;
5103         StorageImpl_SaveFileHeader(This->parentStorage);
5104
5105         /*
5106          * And allocate the first big block that will contain small blocks
5107          */
5108         sbStartIndex =
5109           StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5110
5111         StorageImpl_SetNextBlockInChain(
5112           This->parentStorage,
5113           sbStartIndex,
5114           BLOCK_END_OF_CHAIN);
5115
5116         StorageImpl_ReadProperty(
5117           This->parentStorage,
5118           This->parentStorage->base.rootPropertySetIndex,
5119           &rootProp);
5120
5121         rootProp.startingBlock = sbStartIndex;
5122         rootProp.size.u.HighPart = 0;
5123         rootProp.size.u.LowPart  = This->parentStorage->bigBlockSize;
5124
5125         StorageImpl_WriteProperty(
5126           This->parentStorage,
5127           This->parentStorage->base.rootPropertySetIndex,
5128           &rootProp);
5129       }
5130     }
5131   }
5132
5133   smallBlocksPerBigBlock =
5134     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
5135
5136   /*
5137    * Verify if we have to allocate big blocks to contain small blocks
5138    */
5139   if (blockIndex % smallBlocksPerBigBlock == 0)
5140   {
5141     StgProperty rootProp;
5142     ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
5143
5144     StorageImpl_ReadProperty(
5145       This->parentStorage,
5146       This->parentStorage->base.rootPropertySetIndex,
5147       &rootProp);
5148
5149     if (rootProp.size.u.LowPart <
5150        (blocksRequired * This->parentStorage->bigBlockSize))
5151     {
5152       rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;
5153
5154       BlockChainStream_SetSize(
5155         This->parentStorage->smallBlockRootChain,
5156         rootProp.size);
5157
5158       StorageImpl_WriteProperty(
5159         This->parentStorage,
5160         This->parentStorage->base.rootPropertySetIndex,
5161         &rootProp);
5162     }
5163   }
5164
5165   return blockIndex;
5166 }
5167
5168 /******************************************************************************
5169  *      SmallBlockChainStream_ReadAt
5170  *
5171  * Reads a specified number of bytes from this chain at the specified offset.
5172  * bytesRead may be NULL.
5173  * Failure will be returned if the specified number of bytes has not been read.
5174  */
5175 HRESULT SmallBlockChainStream_ReadAt(
5176   SmallBlockChainStream* This,
5177   ULARGE_INTEGER         offset,
5178   ULONG                  size,
5179   void*                  buffer,
5180   ULONG*                 bytesRead)
5181 {
5182   HRESULT rc = S_OK;
5183   ULARGE_INTEGER offsetInBigBlockFile;
5184   ULONG blockNoInSequence =
5185     offset.u.LowPart / This->parentStorage->smallBlockSize;
5186
5187   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5188   ULONG bytesToReadInBuffer;
5189   ULONG blockIndex;
5190   ULONG bytesReadFromBigBlockFile;
5191   BYTE* bufferWalker;
5192
5193   /*
5194    * This should never happen on a small block file.
5195    */
5196   assert(offset.u.HighPart==0);
5197
5198   /*
5199    * Find the first block in the stream that contains part of the buffer.
5200    */
5201   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5202
5203   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5204   {
5205     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5206     if(FAILED(rc))
5207       return rc;
5208     blockNoInSequence--;
5209   }
5210
5211   /*
5212    * Start reading the buffer.
5213    */
5214   *bytesRead   = 0;
5215   bufferWalker = buffer;
5216
5217   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5218   {
5219     /*
5220      * Calculate how many bytes we can copy from this small block.
5221      */
5222     bytesToReadInBuffer =
5223       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5224
5225     /*
5226      * Calculate the offset of the small block in the small block file.
5227      */
5228     offsetInBigBlockFile.u.HighPart  = 0;
5229     offsetInBigBlockFile.u.LowPart   =
5230       blockIndex * This->parentStorage->smallBlockSize;
5231
5232     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5233
5234     /*
5235      * Read those bytes in the buffer from the small block file.
5236      * The small block has already been identified so it shouldn't fail
5237      * unless the file is corrupt.
5238      */
5239     if (!BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
5240       offsetInBigBlockFile,
5241       bytesToReadInBuffer,
5242       bufferWalker,
5243       &bytesReadFromBigBlockFile))
5244       return STG_E_DOCFILECORRUPT;
5245
5246     assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
5247
5248     /*
5249      * Step to the next big block.
5250      */
5251     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5252     if(FAILED(rc))
5253       return rc;
5254
5255     bufferWalker += bytesToReadInBuffer;
5256     size         -= bytesToReadInBuffer;
5257     *bytesRead   += bytesToReadInBuffer;
5258     offsetInBlock = 0;  /* There is no offset on the next block */
5259   }
5260
5261   return rc;
5262 }
5263
5264 /******************************************************************************
5265  *       SmallBlockChainStream_WriteAt
5266  *
5267  * Writes the specified number of bytes to this chain at the specified offset.
5268  * bytesWritten may be NULL.
5269  * Will fail if not all specified number of bytes have been written.
5270  */
5271 BOOL SmallBlockChainStream_WriteAt(
5272   SmallBlockChainStream* This,
5273   ULARGE_INTEGER offset,
5274   ULONG          size,
5275   const void*    buffer,
5276   ULONG*         bytesWritten)
5277 {
5278   ULARGE_INTEGER offsetInBigBlockFile;
5279   ULONG blockNoInSequence =
5280     offset.u.LowPart / This->parentStorage->smallBlockSize;
5281
5282   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5283   ULONG bytesToWriteInBuffer;
5284   ULONG blockIndex;
5285   ULONG bytesWrittenFromBigBlockFile;
5286   const BYTE* bufferWalker;
5287
5288   /*
5289    * This should never happen on a small block file.
5290    */
5291   assert(offset.u.HighPart==0);
5292
5293   /*
5294    * Find the first block in the stream that contains part of the buffer.
5295    */
5296   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5297
5298   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5299   {
5300     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
5301       return FALSE;
5302     blockNoInSequence--;
5303   }
5304
5305   /*
5306    * Start writing the buffer.
5307    *
5308    * Here, I'm casting away the constness on the buffer variable
5309    * This is OK since we don't intend to modify that buffer.
5310    */
5311   *bytesWritten   = 0;
5312   bufferWalker = (const BYTE*)buffer;
5313   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5314   {
5315     /*
5316      * Calculate how many bytes we can copy to this small block.
5317      */
5318     bytesToWriteInBuffer =
5319       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5320
5321     /*
5322      * Calculate the offset of the small block in the small block file.
5323      */
5324     offsetInBigBlockFile.u.HighPart  = 0;
5325     offsetInBigBlockFile.u.LowPart   =
5326       blockIndex * This->parentStorage->smallBlockSize;
5327
5328     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5329
5330     /*
5331      * Write those bytes in the buffer to the small block file.
5332      */
5333     BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
5334       offsetInBigBlockFile,
5335       bytesToWriteInBuffer,
5336       bufferWalker,
5337       &bytesWrittenFromBigBlockFile);
5338
5339     assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
5340
5341     /*
5342      * Step to the next big block.
5343      */
5344     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5345                                                         &blockIndex)))
5346       return FALSE;
5347     bufferWalker  += bytesToWriteInBuffer;
5348     size          -= bytesToWriteInBuffer;
5349     *bytesWritten += bytesToWriteInBuffer;
5350     offsetInBlock  = 0;     /* There is no offset on the next block */
5351   }
5352
5353   return (size == 0);
5354 }
5355
5356 /******************************************************************************
5357  *       SmallBlockChainStream_Shrink
5358  *
5359  * Shrinks this chain in the small block depot.
5360  */
5361 BOOL SmallBlockChainStream_Shrink(
5362   SmallBlockChainStream* This,
5363   ULARGE_INTEGER newSize)
5364 {
5365   ULONG blockIndex, extraBlock;
5366   ULONG numBlocks;
5367   ULONG count = 0;
5368
5369   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5370
5371   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5372     numBlocks++;
5373
5374   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5375
5376   /*
5377    * Go to the new end of chain
5378    */
5379   while (count < numBlocks)
5380   {
5381     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5382                                                         &blockIndex)))
5383       return FALSE;
5384     count++;
5385   }
5386
5387   /*
5388    * If the count is 0, we have a special case, the head of the chain was
5389    * just freed.
5390    */
5391   if (count == 0)
5392   {
5393     StgProperty chainProp;
5394
5395     StorageImpl_ReadProperty(This->parentStorage,
5396                              This->ownerPropertyIndex,
5397                              &chainProp);
5398
5399     chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5400
5401     StorageImpl_WriteProperty(This->parentStorage,
5402                               This->ownerPropertyIndex,
5403                               &chainProp);
5404
5405     /*
5406      * We start freeing the chain at the head block.
5407      */
5408     extraBlock = blockIndex;
5409   }
5410   else
5411   {
5412     /* Get the next block before marking the new end */
5413     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5414                                                         &extraBlock)))
5415       return FALSE;
5416
5417     /* Mark the new end of chain */
5418     SmallBlockChainStream_SetNextBlockInChain(
5419       This,
5420       blockIndex,
5421       BLOCK_END_OF_CHAIN);
5422   }
5423
5424   /*
5425    * Mark the extra blocks as free
5426    */
5427   while (extraBlock != BLOCK_END_OF_CHAIN)
5428   {
5429     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
5430                                                         &blockIndex)))
5431       return FALSE;
5432     SmallBlockChainStream_FreeBlock(This, extraBlock);
5433     extraBlock = blockIndex;
5434   }
5435
5436   return TRUE;
5437 }
5438
5439 /******************************************************************************
5440  *      SmallBlockChainStream_Enlarge
5441  *
5442  * Grows this chain in the small block depot.
5443  */
5444 BOOL SmallBlockChainStream_Enlarge(
5445   SmallBlockChainStream* This,
5446   ULARGE_INTEGER newSize)
5447 {
5448   ULONG blockIndex, currentBlock;
5449   ULONG newNumBlocks;
5450   ULONG oldNumBlocks = 0;
5451
5452   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5453
5454   /*
5455    * Empty chain
5456    */
5457   if (blockIndex == BLOCK_END_OF_CHAIN)
5458   {
5459
5460     StgProperty chainProp;
5461
5462     StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5463                                &chainProp);
5464
5465     chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
5466
5467     StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5468                                 &chainProp);
5469
5470     blockIndex = chainProp.startingBlock;
5471     SmallBlockChainStream_SetNextBlockInChain(
5472       This,
5473       blockIndex,
5474       BLOCK_END_OF_CHAIN);
5475   }
5476
5477   currentBlock = blockIndex;
5478
5479   /*
5480    * Figure out how many blocks are needed to contain this stream
5481    */
5482   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5483
5484   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5485     newNumBlocks++;
5486
5487   /*
5488    * Go to the current end of chain
5489    */
5490   while (blockIndex != BLOCK_END_OF_CHAIN)
5491   {
5492     oldNumBlocks++;
5493     currentBlock = blockIndex;
5494     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
5495       return FALSE;
5496   }
5497
5498   /*
5499    * Add new blocks to the chain
5500    */
5501   while (oldNumBlocks < newNumBlocks)
5502   {
5503     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5504     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5505
5506     SmallBlockChainStream_SetNextBlockInChain(
5507       This,
5508       blockIndex,
5509       BLOCK_END_OF_CHAIN);
5510
5511     currentBlock = blockIndex;
5512     oldNumBlocks++;
5513   }
5514
5515   return TRUE;
5516 }
5517
5518 /******************************************************************************
5519  *      SmallBlockChainStream_GetCount
5520  *
5521  * Returns the number of blocks that comprises this chain.
5522  * This is not the size of this chain as the last block may not be full!
5523  */
5524 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
5525 {
5526   ULONG blockIndex;
5527   ULONG count = 0;
5528
5529   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5530
5531   while (blockIndex != BLOCK_END_OF_CHAIN)
5532   {
5533     count++;
5534
5535     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
5536       return 0;
5537   }
5538
5539   return count;
5540 }
5541
5542 /******************************************************************************
5543  *      SmallBlockChainStream_SetSize
5544  *
5545  * Sets the size of this stream.
5546  * The file will grow if we grow the chain.
5547  *
5548  * TODO: Free the actual blocks in the file when we shrink the chain.
5549  *       Currently, the blocks are still in the file. So the file size
5550  *       doesn't shrink even if we shrink streams.
5551  */
5552 BOOL SmallBlockChainStream_SetSize(
5553                 SmallBlockChainStream* This,
5554                 ULARGE_INTEGER    newSize)
5555 {
5556   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5557
5558   if (newSize.u.LowPart == size.u.LowPart)
5559     return TRUE;
5560
5561   if (newSize.u.LowPart < size.u.LowPart)
5562   {
5563     SmallBlockChainStream_Shrink(This, newSize);
5564   }
5565   else
5566   {
5567     SmallBlockChainStream_Enlarge(This, newSize);
5568   }
5569
5570   return TRUE;
5571 }
5572
5573 /******************************************************************************
5574  *      SmallBlockChainStream_GetSize
5575  *
5576  * Returns the size of this chain.
5577  */
5578 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5579 {
5580   StgProperty chainProperty;
5581
5582   StorageImpl_ReadProperty(
5583     This->parentStorage,
5584     This->ownerPropertyIndex,
5585     &chainProperty);
5586
5587   return chainProperty.size;
5588 }
5589
5590 /******************************************************************************
5591  *    StgCreateDocfile  [OLE32.@]
5592  */
5593 HRESULT WINAPI StgCreateDocfile(
5594   LPCOLESTR pwcsName,
5595   DWORD       grfMode,
5596   DWORD       reserved,
5597   IStorage  **ppstgOpen)
5598 {
5599   StorageImpl* newStorage = 0;
5600   HANDLE       hFile      = INVALID_HANDLE_VALUE;
5601   HRESULT        hr         = STG_E_INVALIDFLAG;
5602   DWORD          shareMode;
5603   DWORD          accessMode;
5604   DWORD          creationMode;
5605   DWORD          fileAttributes;
5606   WCHAR          tempFileName[MAX_PATH];
5607
5608   TRACE("(%s, %lx, %ld, %p)\n",
5609         debugstr_w(pwcsName), grfMode,
5610         reserved, ppstgOpen);
5611
5612   /*
5613    * Validate the parameters
5614    */
5615   if (ppstgOpen == 0)
5616     return STG_E_INVALIDPOINTER;
5617   if (reserved != 0)
5618     return STG_E_INVALIDPARAMETER;
5619
5620   /*
5621    * Validate the STGM flags
5622    */
5623   if ( FAILED( validateSTGM(grfMode) ))
5624     goto end;
5625
5626   /* StgCreateDocFile always opens for write */
5627   switch(STGM_ACCESS_MODE(grfMode))
5628   {
5629   case STGM_WRITE:
5630   case STGM_READWRITE:
5631     break;
5632   default:
5633     goto end;
5634   }
5635
5636   /* can't share write */
5637   switch(STGM_SHARE_MODE(grfMode))
5638   {
5639   case STGM_SHARE_EXCLUSIVE:
5640   case STGM_SHARE_DENY_WRITE:
5641     break;
5642   default:
5643     goto end;
5644   }
5645
5646   /* shared reading requires transacted mode */
5647   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
5648      !(grfMode&STGM_TRANSACTED) )
5649     goto end;
5650
5651   /*
5652    * Generate a unique name.
5653    */
5654   if (pwcsName == 0)
5655   {
5656     WCHAR tempPath[MAX_PATH];
5657     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5658
5659     if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
5660       goto end;
5661
5662     memset(tempPath, 0, sizeof(tempPath));
5663     memset(tempFileName, 0, sizeof(tempFileName));
5664
5665     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5666       tempPath[0] = '.';
5667
5668     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5669       pwcsName = tempFileName;
5670     else
5671     {
5672       hr = STG_E_INSUFFICIENTMEMORY;
5673       goto end;
5674     }
5675
5676     creationMode = TRUNCATE_EXISTING;
5677   }
5678   else
5679   {
5680     creationMode = GetCreationModeFromSTGM(grfMode);
5681   }
5682
5683   /*
5684    * Interpret the STGM value grfMode
5685    */
5686   shareMode    = GetShareModeFromSTGM(grfMode);
5687   accessMode   = GetAccessModeFromSTGM(grfMode);
5688
5689   if (grfMode & STGM_DELETEONRELEASE)
5690     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5691   else
5692     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5693
5694   if (grfMode & STGM_TRANSACTED)
5695     FIXME("Transacted mode not implemented.\n");
5696
5697   /*
5698    * Initialize the "out" parameter.
5699    */
5700   *ppstgOpen = 0;
5701
5702   hFile = CreateFileW(pwcsName,
5703                         accessMode,
5704                         shareMode,
5705                         NULL,
5706                         creationMode,
5707                         fileAttributes,
5708                         0);
5709
5710   if (hFile == INVALID_HANDLE_VALUE)
5711   {
5712     if(GetLastError() == ERROR_FILE_EXISTS)
5713       hr = STG_E_FILEALREADYEXISTS;
5714     else
5715       hr = E_FAIL;
5716     goto end;
5717   }
5718
5719   /*
5720    * Allocate and initialize the new IStorage32object.
5721    */
5722   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5723
5724   if (newStorage == 0)
5725   {
5726     hr = STG_E_INSUFFICIENTMEMORY;
5727     goto end;
5728   }
5729
5730   hr = StorageImpl_Construct(
5731          newStorage,
5732          hFile,
5733         pwcsName,
5734          NULL,
5735          grfMode,
5736          TRUE,
5737          TRUE);
5738
5739   if (FAILED(hr))
5740   {
5741     HeapFree(GetProcessHeap(), 0, newStorage);
5742     goto end;
5743   }
5744
5745   /*
5746    * Get an "out" pointer for the caller.
5747    */
5748   hr = StorageBaseImpl_QueryInterface(
5749          (IStorage*)newStorage,
5750          (REFIID)&IID_IStorage,
5751          (void**)ppstgOpen);
5752 end:
5753   TRACE("<-- %p  r = %08lx\n", *ppstgOpen, hr);
5754
5755   return hr;
5756 }
5757
5758 /******************************************************************************
5759  *              StgCreateStorageEx        [OLE32.@]
5760  */
5761 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5762 {
5763     TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5764           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5765
5766     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
5767     {
5768         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
5769         return STG_E_INVALIDPARAMETER;  
5770     }
5771
5772     if (stgfmt != STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5773     {
5774         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
5775         return STG_E_INVALIDPARAMETER;  
5776     }
5777
5778     if (stgfmt == STGFMT_FILE)
5779     {
5780         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5781         return STG_E_INVALIDPARAMETER;
5782     }
5783
5784     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
5785     {
5786         FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
5787         return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); 
5788     }
5789
5790     ERR("Invalid stgfmt argument\n");
5791     return STG_E_INVALIDPARAMETER;
5792 }
5793
5794 /******************************************************************************
5795  *              StgCreatePropSetStg       [OLE32.@]
5796  */
5797 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
5798  IPropertySetStorage **ppPropSetStg)
5799 {
5800     HRESULT hr;
5801
5802     TRACE("(%p, 0x%lx, %p)\n", pstg, reserved, ppPropSetStg);
5803     if (reserved)
5804         hr = STG_E_INVALIDPARAMETER;
5805     else
5806         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
5807          (void**)ppPropSetStg);
5808     return hr;
5809 }
5810
5811 /******************************************************************************
5812  *              StgOpenStorageEx      [OLE32.@]
5813  */
5814 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5815 {
5816     TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5817           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5818
5819     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
5820     {
5821         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
5822         return STG_E_INVALIDPARAMETER;  
5823     }
5824
5825     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5826     {
5827         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
5828         return STG_E_INVALIDPARAMETER;  
5829     }
5830
5831     if (stgfmt == STGFMT_FILE)
5832     {
5833         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5834         return STG_E_INVALIDPARAMETER;
5835     }
5836
5837     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE || stgfmt == STGFMT_ANY)
5838     {
5839         if (stgfmt == STGFMT_ANY) 
5840             WARN("STGFMT_ANY assuming storage\n");
5841         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
5842         return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); 
5843     }
5844
5845     ERR("Invalid stgfmt argument\n");
5846     return STG_E_INVALIDPARAMETER;
5847 }
5848
5849
5850 /******************************************************************************
5851  *              StgOpenStorage        [OLE32.@]
5852  */
5853 HRESULT WINAPI StgOpenStorage(
5854   const OLECHAR *pwcsName,
5855   IStorage      *pstgPriority,
5856   DWORD           grfMode,
5857   SNB           snbExclude,
5858   DWORD           reserved,
5859   IStorage      **ppstgOpen)
5860 {
5861   StorageImpl* newStorage = 0;
5862   HRESULT        hr = S_OK;
5863   HANDLE       hFile = 0;
5864   DWORD          shareMode;
5865   DWORD          accessMode;
5866   WCHAR          fullname[MAX_PATH];
5867   DWORD          length;
5868
5869   TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5870         debugstr_w(pwcsName), pstgPriority, grfMode,
5871         snbExclude, reserved, ppstgOpen);
5872
5873   /*
5874    * Perform sanity checks
5875    */
5876   if (pwcsName == 0)
5877   {
5878     hr = STG_E_INVALIDNAME;
5879     goto end;
5880   }
5881
5882   if (ppstgOpen == 0)
5883   {
5884     hr = STG_E_INVALIDPOINTER;
5885     goto end;
5886   }
5887
5888   if (reserved)
5889   {
5890     hr = STG_E_INVALIDPARAMETER;
5891     goto end;
5892   }
5893
5894   /*
5895    * Validate the sharing mode
5896    */
5897   if (!(grfMode & STGM_TRANSACTED))
5898     switch(STGM_SHARE_MODE(grfMode))
5899     {
5900       case STGM_SHARE_EXCLUSIVE:
5901       case STGM_SHARE_DENY_WRITE:
5902         break;
5903       default:
5904         hr = STG_E_INVALIDFLAG;
5905         goto end;
5906     }
5907
5908   /*
5909    * Validate the STGM flags
5910    */
5911   if ( FAILED( validateSTGM(grfMode) ) ||
5912        (grfMode&STGM_CREATE))
5913   {
5914     hr = STG_E_INVALIDFLAG;
5915     goto end;
5916   }
5917
5918   /* shared reading requires transacted mode */
5919   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
5920       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
5921      !(grfMode&STGM_TRANSACTED) )
5922   {
5923     hr = STG_E_INVALIDFLAG;
5924     goto end;
5925   }
5926
5927   /*
5928    * Interpret the STGM value grfMode
5929    */
5930   shareMode    = GetShareModeFromSTGM(grfMode);
5931   accessMode   = GetAccessModeFromSTGM(grfMode);
5932
5933   /*
5934    * Initialize the "out" parameter.
5935    */
5936   *ppstgOpen = 0;
5937
5938   hFile = CreateFileW( pwcsName,
5939                        accessMode,
5940                        shareMode,
5941                        NULL,
5942                        OPEN_EXISTING,
5943                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5944                        0);
5945
5946   if (hFile==INVALID_HANDLE_VALUE)
5947   {
5948     DWORD last_error = GetLastError();
5949
5950     hr = E_FAIL;
5951
5952     switch (last_error)
5953     {
5954       case ERROR_FILE_NOT_FOUND:
5955         hr = STG_E_FILENOTFOUND;
5956         break;
5957
5958       case ERROR_PATH_NOT_FOUND:
5959         hr = STG_E_PATHNOTFOUND;
5960         break;
5961
5962       case ERROR_ACCESS_DENIED:
5963       case ERROR_WRITE_PROTECT:
5964         hr = STG_E_ACCESSDENIED;
5965         break;
5966
5967       case ERROR_SHARING_VIOLATION:
5968         hr = STG_E_SHAREVIOLATION;
5969         break;
5970
5971       default:
5972         hr = E_FAIL;
5973     }
5974
5975     goto end;
5976   }
5977
5978   /*
5979    * Refuse to open the file if it's too small to be a structured storage file
5980    * FIXME: verify the file when reading instead of here
5981    */
5982   length = GetFileSize(hFile, NULL);
5983   if (length < 0x100)
5984   {
5985     CloseHandle(hFile);
5986     hr = STG_E_FILEALREADYEXISTS;
5987     goto end;
5988   }
5989
5990   /*
5991    * Allocate and initialize the new IStorage32object.
5992    */
5993   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5994
5995   if (newStorage == 0)
5996   {
5997     hr = STG_E_INSUFFICIENTMEMORY;
5998     goto end;
5999   }
6000
6001   /* if the file's length was zero, initialize the storage */
6002   hr = StorageImpl_Construct(
6003          newStorage,
6004          hFile,
6005         pwcsName,
6006          NULL,
6007          grfMode,
6008          TRUE,
6009          FALSE );
6010
6011   if (FAILED(hr))
6012   {
6013     HeapFree(GetProcessHeap(), 0, newStorage);
6014     /*
6015      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
6016      */
6017     if(hr == STG_E_INVALIDHEADER)
6018         hr = STG_E_FILEALREADYEXISTS;
6019     goto end;
6020   }
6021
6022   /* prepare the file name string given in lieu of the root property name */
6023   GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
6024   memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
6025   newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
6026
6027   /*
6028    * Get an "out" pointer for the caller.
6029    */
6030   hr = StorageBaseImpl_QueryInterface(
6031          (IStorage*)newStorage,
6032          (REFIID)&IID_IStorage,
6033          (void**)ppstgOpen);
6034
6035 end:
6036   TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
6037   return hr;
6038 }
6039
6040 /******************************************************************************
6041  *    StgCreateDocfileOnILockBytes    [OLE32.@]
6042  */
6043 HRESULT WINAPI StgCreateDocfileOnILockBytes(
6044       ILockBytes *plkbyt,
6045       DWORD grfMode,
6046       DWORD reserved,
6047       IStorage** ppstgOpen)
6048 {
6049   StorageImpl*   newStorage = 0;
6050   HRESULT        hr         = S_OK;
6051
6052   /*
6053    * Validate the parameters
6054    */
6055   if ((ppstgOpen == 0) || (plkbyt == 0))
6056     return STG_E_INVALIDPOINTER;
6057
6058   /*
6059    * Allocate and initialize the new IStorage object.
6060    */
6061   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6062
6063   if (newStorage == 0)
6064     return STG_E_INSUFFICIENTMEMORY;
6065
6066   hr = StorageImpl_Construct(
6067          newStorage,
6068          0,
6069         0,
6070          plkbyt,
6071          grfMode,
6072          FALSE,
6073          TRUE);
6074
6075   if (FAILED(hr))
6076   {
6077     HeapFree(GetProcessHeap(), 0, newStorage);
6078     return hr;
6079   }
6080
6081   /*
6082    * Get an "out" pointer for the caller.
6083    */
6084   hr = StorageBaseImpl_QueryInterface(
6085          (IStorage*)newStorage,
6086          (REFIID)&IID_IStorage,
6087          (void**)ppstgOpen);
6088
6089   return hr;
6090 }
6091
6092 /******************************************************************************
6093  *    StgOpenStorageOnILockBytes    [OLE32.@]
6094  */
6095 HRESULT WINAPI StgOpenStorageOnILockBytes(
6096       ILockBytes *plkbyt,
6097       IStorage *pstgPriority,
6098       DWORD grfMode,
6099       SNB snbExclude,
6100       DWORD reserved,
6101       IStorage **ppstgOpen)
6102 {
6103   StorageImpl* newStorage = 0;
6104   HRESULT        hr = S_OK;
6105
6106   /*
6107    * Perform a sanity check
6108    */
6109   if ((plkbyt == 0) || (ppstgOpen == 0))
6110     return STG_E_INVALIDPOINTER;
6111
6112   /*
6113    * Validate the STGM flags
6114    */
6115   if ( FAILED( validateSTGM(grfMode) ))
6116     return STG_E_INVALIDFLAG;
6117
6118   /*
6119    * Initialize the "out" parameter.
6120    */
6121   *ppstgOpen = 0;
6122
6123   /*
6124    * Allocate and initialize the new IStorage object.
6125    */
6126   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6127
6128   if (newStorage == 0)
6129     return STG_E_INSUFFICIENTMEMORY;
6130
6131   hr = StorageImpl_Construct(
6132          newStorage,
6133          0,
6134          0,
6135          plkbyt,
6136          grfMode,
6137          FALSE,
6138          FALSE);
6139
6140   if (FAILED(hr))
6141   {
6142     HeapFree(GetProcessHeap(), 0, newStorage);
6143     return hr;
6144   }
6145
6146   /*
6147    * Get an "out" pointer for the caller.
6148    */
6149   hr = StorageBaseImpl_QueryInterface(
6150          (IStorage*)newStorage,
6151          (REFIID)&IID_IStorage,
6152          (void**)ppstgOpen);
6153
6154   return hr;
6155 }
6156
6157 /******************************************************************************
6158  *              StgSetTimes [ole32.@]
6159  *              StgSetTimes [OLE32.@]
6160  *
6161  *
6162  */
6163 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6164                            FILETIME const *patime, FILETIME const *pmtime)
6165 {
6166   IStorage *stg = NULL;
6167   HRESULT r;
6168  
6169   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6170
6171   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6172                      0, 0, &stg);
6173   if( SUCCEEDED(r) )
6174   {
6175     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6176     IStorage_Release(stg);
6177   }
6178
6179   return r;
6180 }
6181
6182 /******************************************************************************
6183  *              StgIsStorageILockBytes        [OLE32.@]
6184  *
6185  * Determines if the ILockBytes contains a storage object.
6186  */
6187 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6188 {
6189   BYTE sig[8];
6190   ULARGE_INTEGER offset;
6191
6192   offset.u.HighPart = 0;
6193   offset.u.LowPart  = 0;
6194
6195   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6196
6197   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6198     return S_OK;
6199
6200   return S_FALSE;
6201 }
6202
6203 /******************************************************************************
6204  *              WriteClassStg        [OLE32.@]
6205  *
6206  * This method will store the specified CLSID in the specified storage object
6207  */
6208 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6209 {
6210   HRESULT hRes;
6211
6212   if(!pStg)
6213     return E_INVALIDARG;
6214
6215   hRes = IStorage_SetClass(pStg, rclsid);
6216
6217   return hRes;
6218 }
6219
6220 /***********************************************************************
6221  *    ReadClassStg (OLE32.@)
6222  *
6223  * This method reads the CLSID previously written to a storage object with
6224  * the WriteClassStg.
6225  *
6226  * PARAMS
6227  *  pstg    [I] IStorage pointer
6228  *  pclsid  [O] Pointer to where the CLSID is written
6229  *
6230  * RETURNS
6231  *  Success: S_OK.
6232  *  Failure: HRESULT code.
6233  */
6234 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6235
6236     STATSTG pstatstg;
6237     HRESULT hRes;
6238
6239     TRACE("(%p, %p)\n", pstg, pclsid);
6240
6241     if(!pstg || !pclsid)
6242         return E_INVALIDARG;
6243
6244    /*
6245     * read a STATSTG structure (contains the clsid) from the storage
6246     */
6247     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
6248
6249     if(SUCCEEDED(hRes))
6250         *pclsid=pstatstg.clsid;
6251
6252     return hRes;
6253 }
6254
6255 /***********************************************************************
6256  *    OleLoadFromStream (OLE32.@)
6257  *
6258  * This function loads an object from stream
6259  */
6260 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6261 {
6262     CLSID       clsid;
6263     HRESULT     res;
6264     LPPERSISTSTREAM     xstm;
6265
6266     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6267
6268     res=ReadClassStm(pStm,&clsid);
6269     if (!SUCCEEDED(res))
6270         return res;
6271     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6272     if (!SUCCEEDED(res))
6273         return res;
6274     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6275     if (!SUCCEEDED(res)) {
6276         IUnknown_Release((IUnknown*)*ppvObj);
6277         return res;
6278     }
6279     res=IPersistStream_Load(xstm,pStm);
6280     IPersistStream_Release(xstm);
6281     /* FIXME: all refcounts ok at this point? I think they should be:
6282      *          pStm    : unchanged
6283      *          ppvObj  : 1
6284      *          xstm    : 0 (released)
6285      */
6286     return res;
6287 }
6288
6289 /***********************************************************************
6290  *    OleSaveToStream (OLE32.@)
6291  *
6292  * This function saves an object with the IPersistStream interface on it
6293  * to the specified stream.
6294  */
6295 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6296 {
6297
6298     CLSID clsid;
6299     HRESULT res;
6300
6301     TRACE("(%p,%p)\n",pPStm,pStm);
6302
6303     res=IPersistStream_GetClassID(pPStm,&clsid);
6304
6305     if (SUCCEEDED(res)){
6306
6307         res=WriteClassStm(pStm,&clsid);
6308
6309         if (SUCCEEDED(res))
6310
6311             res=IPersistStream_Save(pPStm,pStm,TRUE);
6312     }
6313
6314     TRACE("Finished Save\n");
6315     return res;
6316 }
6317
6318 /****************************************************************************
6319  * This method validate a STGM parameter that can contain the values below
6320  *
6321  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6322  * The stgm values contained in 0xffff0000 are bitmasks.
6323  *
6324  * STGM_DIRECT               0x00000000
6325  * STGM_TRANSACTED           0x00010000
6326  * STGM_SIMPLE               0x08000000
6327  *
6328  * STGM_READ                 0x00000000
6329  * STGM_WRITE                0x00000001
6330  * STGM_READWRITE            0x00000002
6331  *
6332  * STGM_SHARE_DENY_NONE      0x00000040
6333  * STGM_SHARE_DENY_READ      0x00000030
6334  * STGM_SHARE_DENY_WRITE     0x00000020
6335  * STGM_SHARE_EXCLUSIVE      0x00000010
6336  *
6337  * STGM_PRIORITY             0x00040000
6338  * STGM_DELETEONRELEASE      0x04000000
6339  *
6340  * STGM_CREATE               0x00001000
6341  * STGM_CONVERT              0x00020000
6342  * STGM_FAILIFTHERE          0x00000000
6343  *
6344  * STGM_NOSCRATCH            0x00100000
6345  * STGM_NOSNAPSHOT           0x00200000
6346  */
6347 static HRESULT validateSTGM(DWORD stgm)
6348 {
6349   DWORD access = STGM_ACCESS_MODE(stgm);
6350   DWORD share  = STGM_SHARE_MODE(stgm);
6351   DWORD create = STGM_CREATE_MODE(stgm);
6352
6353   if (stgm&~STGM_KNOWN_FLAGS)
6354   {
6355     ERR("unknown flags %08lx\n", stgm);
6356     return E_FAIL;
6357   }
6358
6359   switch (access)
6360   {
6361   case STGM_READ:
6362   case STGM_WRITE:
6363   case STGM_READWRITE:
6364     break;
6365   default:
6366     return E_FAIL;
6367   }
6368
6369   switch (share)
6370   {
6371   case STGM_SHARE_DENY_NONE:
6372   case STGM_SHARE_DENY_READ:
6373   case STGM_SHARE_DENY_WRITE:
6374   case STGM_SHARE_EXCLUSIVE:
6375     break;
6376   default:
6377     return E_FAIL;
6378   }
6379
6380   switch (create)
6381   {
6382   case STGM_CREATE:
6383   case STGM_FAILIFTHERE:
6384     break;
6385   default:
6386     return E_FAIL;
6387   }
6388
6389   /*
6390    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
6391    */
6392   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
6393       return E_FAIL;
6394
6395   /*
6396    * STGM_CREATE | STGM_CONVERT
6397    * if both are false, STGM_FAILIFTHERE is set to TRUE
6398    */
6399   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
6400     return E_FAIL;
6401
6402   /*
6403    * STGM_NOSCRATCH requires STGM_TRANSACTED
6404    */
6405   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
6406     return E_FAIL;
6407
6408   /*
6409    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
6410    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
6411    */
6412   if ( (stgm & STGM_NOSNAPSHOT) &&
6413         (!(stgm & STGM_TRANSACTED) ||
6414          share == STGM_SHARE_EXCLUSIVE ||
6415          share == STGM_SHARE_DENY_WRITE) )
6416     return E_FAIL;
6417
6418   return S_OK;
6419 }
6420
6421 /****************************************************************************
6422  *      GetShareModeFromSTGM
6423  *
6424  * This method will return a share mode flag from a STGM value.
6425  * The STGM value is assumed valid.
6426  */
6427 static DWORD GetShareModeFromSTGM(DWORD stgm)
6428 {
6429   switch (STGM_SHARE_MODE(stgm))
6430   {
6431   case STGM_SHARE_DENY_NONE:
6432     return FILE_SHARE_READ | FILE_SHARE_WRITE;
6433   case STGM_SHARE_DENY_READ:
6434     return FILE_SHARE_WRITE;
6435   case STGM_SHARE_DENY_WRITE:
6436     return FILE_SHARE_READ;
6437   case STGM_SHARE_EXCLUSIVE:
6438     return 0;
6439   }
6440   ERR("Invalid share mode!\n");
6441   assert(0);
6442   return 0;
6443 }
6444
6445 /****************************************************************************
6446  *      GetAccessModeFromSTGM
6447  *
6448  * This method will return an access mode flag from a STGM value.
6449  * The STGM value is assumed valid.
6450  */
6451 static DWORD GetAccessModeFromSTGM(DWORD stgm)
6452 {
6453   switch (STGM_ACCESS_MODE(stgm))
6454   {
6455   case STGM_READ:
6456     return GENERIC_READ;
6457   case STGM_WRITE:
6458   case STGM_READWRITE:
6459     return GENERIC_READ | GENERIC_WRITE;
6460   }
6461   ERR("Invalid access mode!\n");
6462   assert(0);
6463   return 0;
6464 }
6465
6466 /****************************************************************************
6467  *      GetCreationModeFromSTGM
6468  *
6469  * This method will return a creation mode flag from a STGM value.
6470  * The STGM value is assumed valid.
6471  */
6472 static DWORD GetCreationModeFromSTGM(DWORD stgm)
6473 {
6474   switch(STGM_CREATE_MODE(stgm))
6475   {
6476   case STGM_CREATE:
6477     return CREATE_ALWAYS;
6478   case STGM_CONVERT:
6479     FIXME("STGM_CONVERT not implemented!\n");
6480     return CREATE_NEW;
6481   case STGM_FAILIFTHERE:
6482     return CREATE_NEW;
6483   }
6484   ERR("Invalid create mode!\n");
6485   assert(0);
6486   return 0;
6487 }
6488
6489
6490 /*************************************************************************
6491  * OLECONVERT_LoadOLE10 [Internal]
6492  *
6493  * Loads the OLE10 STREAM to memory
6494  *
6495  * PARAMS
6496  *     pOleStream   [I] The OLESTREAM
6497  *     pData        [I] Data Structure for the OLESTREAM Data
6498  *
6499  * RETURNS
6500  *     Success:  S_OK
6501  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
6502  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
6503  *
6504  * NOTES
6505  *     This function is used by OleConvertOLESTREAMToIStorage only.
6506  *
6507  *     Memory allocated for pData must be freed by the caller
6508  */
6509 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
6510 {
6511         DWORD dwSize;
6512         HRESULT hRes = S_OK;
6513         int nTryCnt=0;
6514         int max_try = 6;
6515
6516         pData->pData = NULL;
6517         pData->pstrOleObjFileName = (CHAR *) NULL;
6518
6519         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
6520         {
6521         /* Get the OleID */
6522         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6523         if(dwSize != sizeof(pData->dwOleID))
6524         {
6525                 hRes = CONVERT10_E_OLESTREAM_GET;
6526         }
6527         else if(pData->dwOleID != OLESTREAM_ID)
6528         {
6529                 hRes = CONVERT10_E_OLESTREAM_FMT;
6530         }
6531                 else
6532                 {
6533                         hRes = S_OK;
6534                         break;
6535                 }
6536         }
6537
6538         if(hRes == S_OK)
6539         {
6540                 /* Get the TypeID...more info needed for this field */
6541                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6542                 if(dwSize != sizeof(pData->dwTypeID))
6543                 {
6544                         hRes = CONVERT10_E_OLESTREAM_GET;
6545                 }
6546         }
6547         if(hRes == S_OK)
6548         {
6549                 if(pData->dwTypeID != 0)
6550                 {
6551                         /* Get the length of the OleTypeName */
6552                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6553                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6554                         {
6555                                 hRes = CONVERT10_E_OLESTREAM_GET;
6556                         }
6557
6558                         if(hRes == S_OK)
6559                         {
6560                                 if(pData->dwOleTypeNameLength > 0)
6561                                 {
6562                                         /* Get the OleTypeName */
6563                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
6564                                         if(dwSize != pData->dwOleTypeNameLength)
6565                                         {
6566                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6567                                         }
6568                                 }
6569                         }
6570                         if(bStrem1)
6571                         {
6572                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6573                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6574                                 {
6575                                         hRes = CONVERT10_E_OLESTREAM_GET;
6576                                 }
6577                         if(hRes == S_OK)
6578                         {
6579                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6580                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6581                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
6582                                         if(pData->pstrOleObjFileName)
6583                                         {
6584                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6585                                                 if(dwSize != pData->dwOleObjFileNameLength)
6586                                                 {
6587                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6588                                                 }
6589                                         }
6590                                         else
6591                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6592                                 }
6593                         }
6594                         else
6595                         {
6596                                 /* Get the Width of the Metafile */
6597                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6598                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
6599                                 {
6600                                         hRes = CONVERT10_E_OLESTREAM_GET;
6601                                 }
6602                         if(hRes == S_OK)
6603                         {
6604                                 /* Get the Height of the Metafile */
6605                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6606                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
6607                                 {
6608                                         hRes = CONVERT10_E_OLESTREAM_GET;
6609                                 }
6610                         }
6611                         }
6612                         if(hRes == S_OK)
6613                         {
6614                                 /* Get the Length of the Data */
6615                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6616                                 if(dwSize != sizeof(pData->dwDataLength))
6617                                 {
6618                                         hRes = CONVERT10_E_OLESTREAM_GET;
6619                                 }
6620                         }
6621
6622                         if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
6623                         {
6624                                 if(!bStrem1) /* if it is a second OLE stream data */
6625                                 {
6626                                         pData->dwDataLength -= 8;
6627                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6628                                         if(dwSize != sizeof(pData->strUnknown))
6629                                         {
6630                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6631                                         }
6632                                 }
6633                         }
6634                         if(hRes == S_OK)
6635                         {
6636                                 if(pData->dwDataLength > 0)
6637                                 {
6638                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6639
6640                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
6641                                         if(pData->pData)
6642                                         {
6643                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6644                                                 if(dwSize != pData->dwDataLength)
6645                                                 {
6646                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6647                                                 }
6648                                         }
6649                                         else
6650                                         {
6651                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6652                                         }
6653                                 }
6654                         }
6655                 }
6656         }
6657         return hRes;
6658 }
6659
6660 /*************************************************************************
6661  * OLECONVERT_SaveOLE10 [Internal]
6662  *
6663  * Saves the OLE10 STREAM From memory
6664  *
6665  * PARAMS
6666  *     pData        [I] Data Structure for the OLESTREAM Data
6667  *     pOleStream   [I] The OLESTREAM to save
6668  *
6669  * RETURNS
6670  *     Success:  S_OK
6671  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
6672  *
6673  * NOTES
6674  *     This function is used by OleConvertIStorageToOLESTREAM only.
6675  *
6676  */
6677 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6678 {
6679     DWORD dwSize;
6680     HRESULT hRes = S_OK;
6681
6682
6683    /* Set the OleID */
6684     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6685     if(dwSize != sizeof(pData->dwOleID))
6686     {
6687         hRes = CONVERT10_E_OLESTREAM_PUT;
6688     }
6689
6690     if(hRes == S_OK)
6691     {
6692         /* Set the TypeID */
6693         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6694         if(dwSize != sizeof(pData->dwTypeID))
6695         {
6696             hRes = CONVERT10_E_OLESTREAM_PUT;
6697         }
6698     }
6699
6700     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6701     {
6702         /* Set the Length of the OleTypeName */
6703         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6704         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6705         {
6706             hRes = CONVERT10_E_OLESTREAM_PUT;
6707         }
6708
6709         if(hRes == S_OK)
6710         {
6711             if(pData->dwOleTypeNameLength > 0)
6712             {
6713                 /* Set the OleTypeName */
6714                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);
6715                 if(dwSize != pData->dwOleTypeNameLength)
6716                 {
6717                     hRes = CONVERT10_E_OLESTREAM_PUT;
6718                 }
6719             }
6720         }
6721
6722         if(hRes == S_OK)
6723         {
6724             /* Set the width of the Metafile */
6725             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6726             if(dwSize != sizeof(pData->dwMetaFileWidth))
6727             {
6728                 hRes = CONVERT10_E_OLESTREAM_PUT;
6729             }
6730         }
6731
6732         if(hRes == S_OK)
6733         {
6734             /* Set the height of the Metafile */
6735             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6736             if(dwSize != sizeof(pData->dwMetaFileHeight))
6737             {
6738                 hRes = CONVERT10_E_OLESTREAM_PUT;
6739             }
6740         }
6741
6742         if(hRes == S_OK)
6743         {
6744             /* Set the length of the Data */
6745             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6746             if(dwSize != sizeof(pData->dwDataLength))
6747             {
6748                 hRes = CONVERT10_E_OLESTREAM_PUT;
6749             }
6750         }
6751
6752         if(hRes == S_OK)
6753         {
6754             if(pData->dwDataLength > 0)
6755             {
6756                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6757                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
6758                 if(dwSize != pData->dwDataLength)
6759                 {
6760                     hRes = CONVERT10_E_OLESTREAM_PUT;
6761                 }
6762             }
6763         }
6764     }
6765     return hRes;
6766 }
6767
6768 /*************************************************************************
6769  * OLECONVERT_GetOLE20FromOLE10[Internal]
6770  *
6771  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6772  * opens it, and copies the content to the dest IStorage for
6773  * OleConvertOLESTREAMToIStorage
6774  *
6775  *
6776  * PARAMS
6777  *     pDestStorage  [I] The IStorage to copy the data to
6778  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
6779  *     nBufferLength [I] The size of the buffer
6780  *
6781  * RETURNS
6782  *     Nothing
6783  *
6784  * NOTES
6785  *
6786  *
6787  */
6788 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6789 {
6790     HRESULT hRes;
6791     HANDLE hFile;
6792     IStorage *pTempStorage;
6793     DWORD dwNumOfBytesWritten;
6794     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6795     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6796
6797     /* Create a temp File */
6798     GetTempPathW(MAX_PATH, wstrTempDir);
6799     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6800     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6801
6802     if(hFile != INVALID_HANDLE_VALUE)
6803     {
6804         /* Write IStorage Data to File */
6805         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6806         CloseHandle(hFile);
6807
6808         /* Open and copy temp storage to the Dest Storage */
6809         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6810         if(hRes == S_OK)
6811         {
6812             hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6813             StorageBaseImpl_Release(pTempStorage);
6814         }
6815         DeleteFileW(wstrTempFile);
6816     }
6817 }
6818
6819
6820 /*************************************************************************
6821  * OLECONVERT_WriteOLE20ToBuffer [Internal]
6822  *
6823  * Saves the OLE10 STREAM From memory
6824  *
6825  * PARAMS
6826  *     pStorage  [I] The Src IStorage to copy
6827  *     pData     [I] The Dest Memory to write to.
6828  *
6829  * RETURNS
6830  *     The size in bytes allocated for pData
6831  *
6832  * NOTES
6833  *     Memory allocated for pData must be freed by the caller
6834  *
6835  *     Used by OleConvertIStorageToOLESTREAM only.
6836  *
6837  */
6838 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6839 {
6840     HANDLE hFile;
6841     HRESULT hRes;
6842     DWORD nDataLength = 0;
6843     IStorage *pTempStorage;
6844     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6845     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6846
6847     *pData = NULL;
6848
6849     /* Create temp Storage */
6850     GetTempPathW(MAX_PATH, wstrTempDir);
6851     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6852     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6853
6854     if(hRes == S_OK)
6855     {
6856         /* Copy Src Storage to the Temp Storage */
6857         StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6858         StorageBaseImpl_Release(pTempStorage);
6859
6860         /* Open Temp Storage as a file and copy to memory */
6861         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6862         if(hFile != INVALID_HANDLE_VALUE)
6863         {
6864             nDataLength = GetFileSize(hFile, NULL);
6865             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
6866             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6867             CloseHandle(hFile);
6868         }
6869         DeleteFileW(wstrTempFile);
6870     }
6871     return nDataLength;
6872 }
6873
6874 /*************************************************************************
6875  * OLECONVERT_CreateOleStream [Internal]
6876  *
6877  * Creates the "\001OLE" stream in the IStorage if necessary.
6878  *
6879  * PARAMS
6880  *     pStorage     [I] Dest storage to create the stream in
6881  *
6882  * RETURNS
6883  *     Nothing
6884  *
6885  * NOTES
6886  *     This function is used by OleConvertOLESTREAMToIStorage only.
6887  *
6888  *     This stream is still unknown, MS Word seems to have extra data
6889  *     but since the data is stored in the OLESTREAM there should be
6890  *     no need to recreate the stream.  If the stream is manually
6891  *     deleted it will create it with this default data.
6892  *
6893  */
6894 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6895 {
6896     HRESULT hRes;
6897     IStream *pStream;
6898     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6899     BYTE pOleStreamHeader [] =
6900     {
6901         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6902         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6903         0x00, 0x00, 0x00, 0x00
6904     };
6905
6906     /* Create stream if not present */
6907     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6908         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6909
6910     if(hRes == S_OK)
6911     {
6912         /* Write default Data */
6913         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6914         IStream_Release(pStream);
6915     }
6916 }
6917
6918 /* write a string to a stream, preceded by its length */
6919 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
6920 {
6921     HRESULT r;
6922     LPSTR str;
6923     DWORD len = 0;
6924
6925     if( string )
6926         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
6927     r = IStream_Write( stm, &len, sizeof(len), NULL);
6928     if( FAILED( r ) )
6929         return r;
6930     if(len == 0)
6931         return r;
6932     str = CoTaskMemAlloc( len );
6933     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
6934     r = IStream_Write( stm, str, len, NULL);
6935     CoTaskMemFree( str );
6936     return r;
6937 }
6938
6939 /* read a string preceded by its length from a stream */
6940 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
6941 {
6942     HRESULT r;
6943     DWORD len, count = 0;
6944     LPSTR str;
6945     LPWSTR wstr;
6946
6947     r = IStream_Read( stm, &len, sizeof(len), &count );
6948     if( FAILED( r ) )
6949         return r;
6950     if( count != sizeof(len) )
6951         return E_OUTOFMEMORY;
6952
6953     TRACE("%ld bytes\n",len);
6954     
6955     str = CoTaskMemAlloc( len );
6956     if( !str )
6957         return E_OUTOFMEMORY;
6958     count = 0;
6959     r = IStream_Read( stm, str, len, &count );
6960     if( FAILED( r ) )
6961         return r;
6962     if( count != len )
6963     {
6964         CoTaskMemFree( str );
6965         return E_OUTOFMEMORY;
6966     }
6967
6968     TRACE("Read string %s\n",debugstr_an(str,len));
6969
6970     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
6971     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
6972     if( wstr )
6973          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
6974     CoTaskMemFree( str );
6975
6976     *string = wstr;
6977
6978     return r;
6979 }
6980
6981
6982 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
6983     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
6984 {
6985     IStream *pstm;
6986     HRESULT r = S_OK;
6987     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6988
6989     static const BYTE unknown1[12] =
6990        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
6991          0xFF, 0xFF, 0xFF, 0xFF};
6992     static const BYTE unknown2[16] =
6993        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
6994          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
6995
6996     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
6997            debugstr_w(lpszUserType), debugstr_w(szClipName),
6998            debugstr_w(szProgIDName));
6999
7000     /*  Create a CompObj stream if it doesn't exist */
7001     r = IStorage_CreateStream(pstg, szwStreamName,
7002         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
7003     if( FAILED (r) )
7004         return r;
7005
7006     /* Write CompObj Structure to stream */
7007     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
7008
7009     if( SUCCEEDED( r ) )
7010         r = WriteClassStm( pstm, clsid );
7011
7012     if( SUCCEEDED( r ) )
7013         r = STREAM_WriteString( pstm, lpszUserType );
7014     if( SUCCEEDED( r ) )
7015         r = STREAM_WriteString( pstm, szClipName );
7016     if( SUCCEEDED( r ) )
7017         r = STREAM_WriteString( pstm, szProgIDName );
7018     if( SUCCEEDED( r ) )
7019         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
7020
7021     IStream_Release( pstm );
7022
7023     return r;
7024 }
7025
7026 /***********************************************************************
7027  *               WriteFmtUserTypeStg (OLE32.@)
7028  */
7029 HRESULT WINAPI WriteFmtUserTypeStg(
7030           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
7031 {
7032     HRESULT r;
7033     WCHAR szwClipName[0x40];
7034     CLSID clsid = CLSID_NULL;
7035     LPWSTR wstrProgID = NULL;
7036     DWORD n;
7037
7038     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
7039
7040     /* get the clipboard format name */
7041     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
7042     szwClipName[n]=0;
7043
7044     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
7045
7046     /* FIXME: There's room to save a CLSID and its ProgID, but
7047        the CLSID is not looked up in the registry and in all the
7048        tests I wrote it was CLSID_NULL.  Where does it come from?
7049     */
7050
7051     /* get the real program ID.  This may fail, but that's fine */
7052     ProgIDFromCLSID(&clsid, &wstrProgID);
7053
7054     TRACE("progid is %s\n",debugstr_w(wstrProgID));
7055
7056     r = STORAGE_WriteCompObj( pstg, &clsid, 
7057                               lpszUserType, szwClipName, wstrProgID );
7058
7059     CoTaskMemFree(wstrProgID);
7060
7061     return r;
7062 }
7063
7064
7065 /******************************************************************************
7066  *              ReadFmtUserTypeStg        [OLE32.@]
7067  */
7068 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
7069 {
7070     HRESULT r;
7071     IStream *stm = 0;
7072     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
7073     unsigned char unknown1[12];
7074     unsigned char unknown2[16];
7075     DWORD count;
7076     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
7077     CLSID clsid;
7078
7079     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
7080
7081     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
7082                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
7083     if( FAILED ( r ) )
7084     {
7085         WARN("Failed to open stream r = %08lx\n", r);
7086         return r;
7087     }
7088
7089     /* read the various parts of the structure */
7090     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
7091     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
7092         goto end;
7093     r = ReadClassStm( stm, &clsid );
7094     if( FAILED( r ) )
7095         goto end;
7096
7097     r = STREAM_ReadString( stm, &szCLSIDName );
7098     if( FAILED( r ) )
7099         goto end;
7100
7101     r = STREAM_ReadString( stm, &szOleTypeName );
7102     if( FAILED( r ) )
7103         goto end;
7104
7105     r = STREAM_ReadString( stm, &szProgIDName );
7106     if( FAILED( r ) )
7107         goto end;
7108
7109     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7110     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7111         goto end;
7112
7113     /* ok, success... now we just need to store what we found */
7114     if( pcf )
7115         *pcf = RegisterClipboardFormatW( szOleTypeName );
7116     CoTaskMemFree( szOleTypeName );
7117
7118     if( lplpszUserType )
7119         *lplpszUserType = szCLSIDName;
7120     CoTaskMemFree( szProgIDName );
7121
7122 end:
7123     IStream_Release( stm );
7124
7125     return r;
7126 }
7127
7128
7129 /*************************************************************************
7130  * OLECONVERT_CreateCompObjStream [Internal]
7131  *
7132  * Creates a "\001CompObj" is the destination IStorage if necessary.
7133  *
7134  * PARAMS
7135  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7136  *                        if necessary.
7137  *     strOleTypeName [I] The ProgID
7138  *
7139  * RETURNS
7140  *     Success:  S_OK
7141  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7142  *
7143  * NOTES
7144  *     This function is used by OleConvertOLESTREAMToIStorage only.
7145  *
7146  *     The stream data is stored in the OLESTREAM and there should be
7147  *     no need to recreate the stream.  If the stream is manually
7148  *     deleted it will attempt to create it by querying the registry.
7149  *
7150  *
7151  */
7152 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7153 {
7154     IStream *pStream;
7155     HRESULT hStorageRes, hRes = S_OK;
7156     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7157     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7158     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7159
7160     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7161     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7162
7163     /* Initialize the CompObj structure */
7164     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7165     memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
7166     memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
7167
7168
7169     /*  Create a CompObj stream if it doesn't exist */
7170     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7171         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7172     if(hStorageRes == S_OK)
7173     {
7174         /* copy the OleTypeName to the compobj struct */
7175         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7176         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7177
7178         /* copy the OleTypeName to the compobj struct */
7179         /* Note: in the test made, these were Identical      */
7180         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7181         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7182
7183         /* Get the CLSID */
7184         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7185                              bufferW, OLESTREAM_MAX_STR_LEN );
7186         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7187
7188         if(hRes == S_OK)
7189         {
7190             HKEY hKey;
7191             LONG hErr;
7192             /* Get the CLSID Default Name from the Registry */
7193             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7194             if(hErr == ERROR_SUCCESS)
7195             {
7196                 char strTemp[OLESTREAM_MAX_STR_LEN];
7197                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7198                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7199                 if(hErr == ERROR_SUCCESS)
7200                 {
7201                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7202                 }
7203                 RegCloseKey(hKey);
7204             }
7205         }
7206
7207         /* Write CompObj Structure to stream */
7208         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7209
7210         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7211
7212         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7213         if(IStorageCompObj.dwCLSIDNameLength > 0)
7214         {
7215             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7216         }
7217         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7218         if(IStorageCompObj.dwOleTypeNameLength > 0)
7219         {
7220             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7221         }
7222         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7223         if(IStorageCompObj.dwProgIDNameLength > 0)
7224         {
7225             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7226         }
7227         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7228         IStream_Release(pStream);
7229     }
7230     return hRes;
7231 }
7232
7233
7234 /*************************************************************************
7235  * OLECONVERT_CreateOlePresStream[Internal]
7236  *
7237  * Creates the "\002OlePres000" Stream with the Metafile data
7238  *
7239  * PARAMS
7240  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7241  *     dwExtentX    [I] Width of the Metafile
7242  *     dwExtentY    [I] Height of the Metafile
7243  *     pData        [I] Metafile data
7244  *     dwDataLength [I] Size of the Metafile data
7245  *
7246  * RETURNS
7247  *     Success:  S_OK
7248  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7249  *
7250  * NOTES
7251  *     This function is used by OleConvertOLESTREAMToIStorage only.
7252  *
7253  */
7254 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7255 {
7256     HRESULT hRes;
7257     IStream *pStream;
7258     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7259     BYTE pOlePresStreamHeader [] =
7260     {
7261         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7262         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7263         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7264         0x00, 0x00, 0x00, 0x00
7265     };
7266
7267     BYTE pOlePresStreamHeaderEmpty [] =
7268     {
7269         0x00, 0x00, 0x00, 0x00,
7270         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7271         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7272         0x00, 0x00, 0x00, 0x00
7273     };
7274
7275     /* Create the OlePres000 Stream */
7276     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7277         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7278
7279     if(hRes == S_OK)
7280     {
7281         DWORD nHeaderSize;
7282         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7283
7284         memset(&OlePres, 0, sizeof(OlePres));
7285         /* Do we have any metafile data to save */
7286         if(dwDataLength > 0)
7287         {
7288             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7289             nHeaderSize = sizeof(pOlePresStreamHeader);
7290         }
7291         else
7292         {
7293             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7294             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7295         }
7296         /* Set width and height of the metafile */
7297         OlePres.dwExtentX = dwExtentX;
7298         OlePres.dwExtentY = -dwExtentY;
7299
7300         /* Set Data and Length */
7301         if(dwDataLength > sizeof(METAFILEPICT16))
7302         {
7303             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7304             OlePres.pData = &(pData[8]);
7305         }
7306         /* Save OlePres000 Data to Stream */
7307         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7308         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7309         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7310         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7311         if(OlePres.dwSize > 0)
7312         {
7313             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7314         }
7315         IStream_Release(pStream);
7316     }
7317 }
7318
7319 /*************************************************************************
7320  * OLECONVERT_CreateOle10NativeStream [Internal]
7321  *
7322  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7323  *
7324  * PARAMS
7325  *     pStorage     [I] Dest storage to create the stream in
7326  *     pData        [I] Ole10 Native Data (ex. bmp)
7327  *     dwDataLength [I] Size of the Ole10 Native Data
7328  *
7329  * RETURNS
7330  *     Nothing
7331  *
7332  * NOTES
7333  *     This function is used by OleConvertOLESTREAMToIStorage only.
7334  *
7335  *     Might need to verify the data and return appropriate error message
7336  *
7337  */
7338 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
7339 {
7340     HRESULT hRes;
7341     IStream *pStream;
7342     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7343
7344     /* Create the Ole10Native Stream */
7345     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7346         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7347
7348     if(hRes == S_OK)
7349     {
7350         /* Write info to stream */
7351         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7352         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7353         IStream_Release(pStream);
7354     }
7355
7356 }
7357
7358 /*************************************************************************
7359  * OLECONVERT_GetOLE10ProgID [Internal]
7360  *
7361  * Finds the ProgID (or OleTypeID) from the IStorage
7362  *
7363  * PARAMS
7364  *     pStorage        [I] The Src IStorage to get the ProgID
7365  *     strProgID       [I] the ProgID string to get
7366  *     dwSize          [I] the size of the string
7367  *
7368  * RETURNS
7369  *     Success:  S_OK
7370  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7371  *
7372  * NOTES
7373  *     This function is used by OleConvertIStorageToOLESTREAM only.
7374  *
7375  *
7376  */
7377 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7378 {
7379     HRESULT hRes;
7380     IStream *pStream;
7381     LARGE_INTEGER iSeekPos;
7382     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
7383     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7384
7385     /* Open the CompObj Stream */
7386     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7387         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7388     if(hRes == S_OK)
7389     {
7390
7391         /*Get the OleType from the CompObj Stream */
7392         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
7393         iSeekPos.u.HighPart = 0;
7394
7395         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7396         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
7397         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
7398         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7399         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
7400         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
7401         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7402
7403         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
7404         if(*dwSize > 0)
7405         {
7406             IStream_Read(pStream, strProgID, *dwSize, NULL);
7407         }
7408         IStream_Release(pStream);
7409     }
7410     else
7411     {
7412         STATSTG stat;
7413         LPOLESTR wstrProgID;
7414
7415         /* Get the OleType from the registry */
7416         REFCLSID clsid = &(stat.clsid);
7417         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
7418         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
7419         if(hRes == S_OK)
7420         {
7421             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
7422         }
7423
7424     }
7425     return hRes;
7426 }
7427
7428 /*************************************************************************
7429  * OLECONVERT_GetOle10PresData [Internal]
7430  *
7431  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
7432  *
7433  * PARAMS
7434  *     pStorage     [I] Src IStroage
7435  *     pOleStream   [I] Dest OleStream Mem Struct
7436  *
7437  * RETURNS
7438  *     Nothing
7439  *
7440  * NOTES
7441  *     This function is used by OleConvertIStorageToOLESTREAM only.
7442  *
7443  *     Memory allocated for pData must be freed by the caller
7444  *
7445  *
7446  */
7447 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7448 {
7449
7450     HRESULT hRes;
7451     IStream *pStream;
7452     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7453
7454     /* Initialize Default data for OLESTREAM */
7455     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7456     pOleStreamData[0].dwTypeID = 2;
7457     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7458     pOleStreamData[1].dwTypeID = 0;
7459     pOleStreamData[0].dwMetaFileWidth = 0;
7460     pOleStreamData[0].dwMetaFileHeight = 0;
7461     pOleStreamData[0].pData = NULL;
7462     pOleStreamData[1].pData = NULL;
7463
7464     /* Open Ole10Native Stream */
7465     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7466         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7467     if(hRes == S_OK)
7468     {
7469
7470         /* Read Size and Data */
7471         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
7472         if(pOleStreamData->dwDataLength > 0)
7473         {
7474             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
7475             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
7476         }
7477         IStream_Release(pStream);
7478     }
7479
7480 }
7481
7482
7483 /*************************************************************************
7484  * OLECONVERT_GetOle20PresData[Internal]
7485  *
7486  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
7487  *
7488  * PARAMS
7489  *     pStorage         [I] Src IStroage
7490  *     pOleStreamData   [I] Dest OleStream Mem Struct
7491  *
7492  * RETURNS
7493  *     Nothing
7494  *
7495  * NOTES
7496  *     This function is used by OleConvertIStorageToOLESTREAM only.
7497  *
7498  *     Memory allocated for pData must be freed by the caller
7499  */
7500 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7501 {
7502     HRESULT hRes;
7503     IStream *pStream;
7504     OLECONVERT_ISTORAGE_OLEPRES olePress;
7505     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7506
7507     /* Initialize Default data for OLESTREAM */
7508     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7509     pOleStreamData[0].dwTypeID = 2;
7510     pOleStreamData[0].dwMetaFileWidth = 0;
7511     pOleStreamData[0].dwMetaFileHeight = 0;
7512     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
7513     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7514     pOleStreamData[1].dwTypeID = 0;
7515     pOleStreamData[1].dwOleTypeNameLength = 0;
7516     pOleStreamData[1].strOleTypeName[0] = 0;
7517     pOleStreamData[1].dwMetaFileWidth = 0;
7518     pOleStreamData[1].dwMetaFileHeight = 0;
7519     pOleStreamData[1].pData = NULL;
7520     pOleStreamData[1].dwDataLength = 0;
7521
7522
7523     /* Open OlePress000 stream */
7524     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7525         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7526     if(hRes == S_OK)
7527     {
7528         LARGE_INTEGER iSeekPos;
7529         METAFILEPICT16 MetaFilePict;
7530         static const char strMetafilePictName[] = "METAFILEPICT";
7531
7532         /* Set the TypeID for a Metafile */
7533         pOleStreamData[1].dwTypeID = 5;
7534
7535         /* Set the OleTypeName to Metafile */
7536         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
7537         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
7538
7539         iSeekPos.u.HighPart = 0;
7540         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
7541
7542         /* Get Presentation Data */
7543         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7544         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
7545         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
7546         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
7547
7548         /*Set width and Height */
7549         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
7550         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
7551         if(olePress.dwSize > 0)
7552         {
7553             /* Set Length */
7554             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
7555
7556             /* Set MetaFilePict struct */
7557             MetaFilePict.mm = 8;
7558             MetaFilePict.xExt = olePress.dwExtentX;
7559             MetaFilePict.yExt = olePress.dwExtentY;
7560             MetaFilePict.hMF = 0;
7561
7562             /* Get Metafile Data */
7563             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
7564             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
7565             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
7566         }
7567         IStream_Release(pStream);
7568     }
7569 }
7570
7571 /*************************************************************************
7572  * OleConvertOLESTREAMToIStorage [OLE32.@]
7573  *
7574  * Read info on MSDN
7575  *
7576  * TODO
7577  *      DVTARGETDEVICE paramenter is not handled
7578  *      Still unsure of some mem fields for OLE 10 Stream
7579  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7580  *      and "\001OLE" streams
7581  *
7582  */
7583 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
7584     LPOLESTREAM pOleStream,
7585     LPSTORAGE pstg,
7586     const DVTARGETDEVICE* ptd)
7587 {
7588     int i;
7589     HRESULT hRes=S_OK;
7590     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7591
7592     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7593
7594     if(ptd != NULL)
7595     {
7596         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
7597     }
7598
7599     if(pstg == NULL || pOleStream == NULL)
7600     {
7601         hRes = E_INVALIDARG;
7602     }
7603
7604     if(hRes == S_OK)
7605     {
7606         /* Load the OLESTREAM to Memory */
7607         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
7608     }
7609
7610     if(hRes == S_OK)
7611     {
7612         /* Load the OLESTREAM to Memory (part 2)*/
7613         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
7614     }
7615
7616     if(hRes == S_OK)
7617     {
7618
7619         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
7620         {
7621             /* Do we have the IStorage Data in the OLESTREAM */
7622             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
7623             {
7624                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7625                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
7626             }
7627             else
7628             {
7629                 /* It must be an original OLE 1.0 source */
7630                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7631             }
7632         }
7633         else
7634         {
7635             /* It must be an original OLE 1.0 source */
7636             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7637         }
7638
7639         /* Create CompObj Stream if necessary */
7640         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
7641         if(hRes == S_OK)
7642         {
7643             /*Create the Ole Stream if necessary */
7644             OLECONVERT_CreateOleStream(pstg);
7645         }
7646     }
7647
7648
7649     /* Free allocated memory */
7650     for(i=0; i < 2; i++)
7651     {
7652         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7653         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
7654         pOleStreamData[i].pstrOleObjFileName = NULL;
7655     }
7656     return hRes;
7657 }
7658
7659 /*************************************************************************
7660  * OleConvertIStorageToOLESTREAM [OLE32.@]
7661  *
7662  * Read info on MSDN
7663  *
7664  * Read info on MSDN
7665  *
7666  * TODO
7667  *      Still unsure of some mem fields for OLE 10 Stream
7668  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7669  *      and "\001OLE" streams.
7670  *
7671  */
7672 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
7673     LPSTORAGE pstg,
7674     LPOLESTREAM pOleStream)
7675 {
7676     int i;
7677     HRESULT hRes = S_OK;
7678     IStream *pStream;
7679     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7680     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7681
7682
7683     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7684
7685     if(pstg == NULL || pOleStream == NULL)
7686     {
7687         hRes = E_INVALIDARG;
7688     }
7689     if(hRes == S_OK)
7690     {
7691         /* Get the ProgID */
7692         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
7693         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
7694     }
7695     if(hRes == S_OK)
7696     {
7697         /* Was it originally Ole10 */
7698         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
7699         if(hRes == S_OK)
7700         {
7701             IStream_Release(pStream);
7702             /* Get Presentation Data for Ole10Native */
7703             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
7704         }
7705         else
7706         {
7707             /* Get Presentation Data (OLE20) */
7708             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
7709         }
7710
7711         /* Save OLESTREAM */
7712         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
7713         if(hRes == S_OK)
7714         {
7715             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
7716         }
7717
7718     }
7719
7720     /* Free allocated memory */
7721     for(i=0; i < 2; i++)
7722     {
7723         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7724     }
7725
7726     return hRes;
7727 }
7728
7729 /***********************************************************************
7730  *              GetConvertStg (OLE32.@)
7731  */
7732 HRESULT WINAPI GetConvertStg(IStorage *stg) {
7733     FIXME("unimplemented stub!\n");
7734     return E_FAIL;
7735 }
7736
7737 /******************************************************************************
7738  * StgIsStorageFile [OLE32.@]
7739  */
7740 HRESULT WINAPI
7741 StgIsStorageFile(LPCOLESTR fn)
7742 {
7743         HANDLE          hf;
7744         BYTE            magic[8];
7745         DWORD           bytes_read;
7746
7747         TRACE("(\'%s\')\n", debugstr_w(fn));
7748         hf = CreateFileW(fn, GENERIC_READ,
7749                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
7750                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7751
7752         if (hf == INVALID_HANDLE_VALUE)
7753                 return STG_E_FILENOTFOUND;
7754
7755         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
7756         {
7757                 WARN(" unable to read file\n");
7758                 CloseHandle(hf);
7759                 return S_FALSE;
7760         }
7761
7762         CloseHandle(hf);
7763
7764         if (bytes_read != 8) {
7765                 WARN(" too short\n");
7766                 return S_FALSE;
7767         }
7768
7769         if (!memcmp(magic,STORAGE_magic,8)) {
7770                 WARN(" -> YES\n");
7771                 return S_OK;
7772         }
7773
7774         WARN(" -> Invalid header.\n");
7775         return S_FALSE;
7776 }