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