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