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