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