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