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