- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / ole / 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 <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17
18 #include "windows.h"
19 #include "winerror.h"
20 #include "file.h"
21 #include "ole.h"
22 #include "ole2.h"
23 #include "objbase.h"
24 #include "crtdll.h"
25 #include "tchar.h"
26 #include "heap.h"
27
28 #include "winnt.h"
29 #include "winbase.h"
30 #include "debug.h"
31
32 #include "storage32.h"
33
34 #define FILE_BEGIN 0
35
36 static const char rootPropertyName[] = "Root Entry";
37
38 /***********************************************************************
39  * Forward declaration of internal functions used by the method DestroyElement
40  */
41 static HRESULT deleteStorageProperty(
42   Storage32Impl *parentStorage,
43   OLECHAR32     *propertyToDeleteName);
44
45 static HRESULT deleteStreamProperty(
46   Storage32Impl *parentStorage,
47   ULONG         foundPropertyIndexToDelete,
48   StgProperty   propertyToDelete);
49
50 static HRESULT findPlaceholder(
51   Storage32Impl *storage,
52   ULONG         propertyIndexToStore,
53   ULONG         storagePropertyIndex,
54   INT32         typeOfRelation);
55
56 static HRESULT adjustPropertyChain( 
57   Storage32Impl *This,
58   StgProperty   propertyToDelete,
59   StgProperty   parentProperty,
60   ULONG         parentPropertyId,
61   INT32         typeOfRelation);
62
63 /***********************************************************************
64  * Declaration of the functions used to manipulate StgProperty
65  */
66
67 static ULONG getFreeProperty(
68   Storage32Impl *storage);
69
70 static void updatePropertyChain(
71   Storage32Impl *storage,
72   ULONG       newPropertyIndex,
73   StgProperty newProperty);
74
75 static LONG propertyNameCmp(
76   OLECHAR32 *newProperty,
77   OLECHAR32 *currentProperty);
78
79
80 /***********************************************************************
81  * Declaration of miscellaneous functions...
82  */
83 static HRESULT validateSTGM(DWORD stgmValue); 
84
85 static DWORD GetShareModeFromSTGM(DWORD stgm);
86 static DWORD GetAccessModeFromSTGM(DWORD stgm);
87 static DWORD GetCreationModeFromSTGM(DWORD stgm);
88
89 /*
90  * Virtual function table for the IStorage32Impl class.
91  */
92 static ICOM_VTABLE(IStorage32) Storage32Impl_Vtbl =
93 {
94     Storage32BaseImpl_QueryInterface,
95     Storage32BaseImpl_AddRef,
96     Storage32BaseImpl_Release,
97     Storage32BaseImpl_CreateStream,
98     Storage32BaseImpl_OpenStream,
99     Storage32Impl_CreateStorage,
100     Storage32BaseImpl_OpenStorage,
101     Storage32Impl_CopyTo,
102     Storage32Impl_MoveElementTo,
103     Storage32Impl_Commit,
104     Storage32Impl_Revert,
105     Storage32BaseImpl_EnumElements,
106     Storage32Impl_DestroyElement,
107     Storage32BaseImpl_RenameElement,
108     Storage32Impl_SetElementTimes,
109     Storage32BaseImpl_SetClass,
110     Storage32Impl_SetStateBits,
111     Storage32BaseImpl_Stat
112 };
113
114 /*
115  * Virtual function table for the Storage32InternalImpl class.
116  */
117 static ICOM_VTABLE(IStorage32) Storage32InternalImpl_Vtbl =
118   {
119     Storage32BaseImpl_QueryInterface,
120     Storage32BaseImpl_AddRef,
121     Storage32BaseImpl_Release,
122     Storage32BaseImpl_CreateStream,
123     Storage32BaseImpl_OpenStream,
124     Storage32Impl_CreateStorage,
125     Storage32BaseImpl_OpenStorage,
126     Storage32Impl_CopyTo,
127     Storage32Impl_MoveElementTo,
128     Storage32InternalImpl_Commit,
129     Storage32InternalImpl_Revert,
130     Storage32BaseImpl_EnumElements,
131     Storage32Impl_DestroyElement,
132     Storage32BaseImpl_RenameElement,
133     Storage32Impl_SetElementTimes,
134     Storage32BaseImpl_SetClass,
135     Storage32Impl_SetStateBits,
136     Storage32BaseImpl_Stat
137 };
138
139 /*
140  * Virtual function table for the IEnumSTATSTGImpl class.
141  */
142 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
143 {
144     IEnumSTATSTGImpl_QueryInterface,
145     IEnumSTATSTGImpl_AddRef,
146     IEnumSTATSTGImpl_Release,
147     IEnumSTATSTGImpl_Next,
148     IEnumSTATSTGImpl_Skip,
149     IEnumSTATSTGImpl_Reset,
150     IEnumSTATSTGImpl_Clone
151 };
152
153
154
155
156
157 /************************************************************************
158 ** Storage32BaseImpl implementatiion
159 */
160
161 /************************************************************************
162  * Storage32BaseImpl_QueryInterface (IUnknown)
163  *
164  * This method implements the common QueryInterface for all IStorage32
165  * implementations contained in this file.
166  * 
167  * See Windows documentation for more details on IUnknown methods.
168  */
169 HRESULT WINAPI Storage32BaseImpl_QueryInterface(
170   IStorage32*        iface,
171   REFIID             riid,
172   void**             ppvObject)
173 {
174   ICOM_THIS(Storage32BaseImpl,iface);
175   /*
176    * Perform a sanity check on the parameters.
177    */
178   if ( (This==0) || (ppvObject==0) )
179     return E_INVALIDARG;
180   
181   /*
182    * Initialize the return parameter.
183    */
184   *ppvObject = 0;
185   
186   /*
187    * Compare the riid with the interface IDs implemented by this object.
188    */
189   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
190   {
191     *ppvObject = (IStorage32*)This;
192   }
193   else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0) 
194   {
195     *ppvObject = (IStorage32*)This;
196   }
197   
198   /*
199    * Check that we obtained an interface.
200    */
201   if ((*ppvObject)==0)
202     return E_NOINTERFACE;
203   
204   /*
205    * Query Interface always increases the reference count by one when it is
206    * successful
207    */
208   Storage32BaseImpl_AddRef(iface);
209
210   return S_OK;
211 }
212         
213 /************************************************************************
214  * Storage32BaseImpl_AddRef (IUnknown)
215  *
216  * This method implements the common AddRef for all IStorage32
217  * implementations contained in this file.
218  * 
219  * See Windows documentation for more details on IUnknown methods.
220  */
221 ULONG WINAPI Storage32BaseImpl_AddRef( 
222             IStorage32* iface)
223 {
224   ICOM_THIS(Storage32BaseImpl,iface);
225   This->ref++;
226
227   return This->ref;
228 }
229         
230 /************************************************************************
231  * Storage32BaseImpl_Release (IUnknown)
232  *
233  * This method implements the common Release for all IStorage32
234  * implementations contained in this file.
235  * 
236  * See Windows documentation for more details on IUnknown methods.
237  */
238 ULONG WINAPI Storage32BaseImpl_Release( 
239       IStorage32* iface)
240 {
241   ICOM_THIS(Storage32BaseImpl,iface);
242   /*
243    * Decrease the reference count on this object.
244    */
245   This->ref--;
246
247   /*
248    * If the reference count goes down to 0, perform suicide.
249    */
250   if (This->ref==0)
251   {
252     /*
253      * Since we are using a system of base-classes, we want to call the 
254      * destructor of the appropriate derived class. To do this, we are 
255      * using virtual functions to implement the destructor.
256      */
257     This->v_destructor(This);
258
259     return 0;
260   }
261   
262   return This->ref;
263 }
264
265 /************************************************************************
266  * Storage32BaseImpl_OpenStream (IStorage)
267  *
268  * This method will open the specified stream object from the current storage.
269  *
270  * See Windows documentation for more details on IStorage methods.
271  */
272 HRESULT WINAPI Storage32BaseImpl_OpenStream( 
273   IStorage32*        iface,
274   const OLECHAR32*   pwcsName,  /* [string][in] */
275   void*              reserved1, /* [unique][in] */
276   DWORD              grfMode,   /* [in]  */        
277   DWORD              reserved2, /* [in]  */        
278   IStream32**        ppstm)     /* [out] */       
279 {
280   ICOM_THIS(Storage32BaseImpl,iface);
281   IEnumSTATSTGImpl* propertyEnumeration;
282   StgStreamImpl*    newStream;
283   StgProperty       currentProperty;
284   ULONG             foundPropertyIndex;
285
286   /*
287    * Perform a sanity check on the parameters.
288    */
289   if ( (pwcsName==NULL) || (ppstm==0) )
290     return E_INVALIDARG;
291   
292   /*
293    * Initialize the out parameter
294    */
295   *ppstm = 0;
296   
297   /*
298    * Validate the STGM flags
299    */
300   if ( FAILED( validateSTGM(grfMode) ))
301     return STG_E_INVALIDFLAG;
302
303   /*
304    * As documented.
305    */
306   if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
307         (grfMode & STGM_DELETEONRELEASE) ||
308         (grfMode & STGM_TRANSACTED) )
309     return STG_E_INVALIDFUNCTION;
310
311   /*
312    * Create a property enumeration to search the properties
313    */
314   propertyEnumeration = IEnumSTATSTGImpl_Construct(
315     This->ancestorStorage, 
316     This->rootPropertySetIndex);
317   
318   /*
319    * Search the enumeration for the property with the given name
320    */
321   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
322     propertyEnumeration,
323     pwcsName,
324     &currentProperty);
325   
326   /*
327    * Delete the property enumeration since we don't need it anymore
328    */
329   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
330   
331   /*
332    * If it was found, construct the stream object and return a pointer to it.
333    */
334   if ( (foundPropertyIndex!=PROPERTY_NULL) && 
335        (currentProperty.propertyType==PROPTYPE_STREAM) )
336   {
337     newStream = StgStreamImpl_Construct(This, foundPropertyIndex);
338     
339     if (newStream!=0)
340     {
341       *ppstm = (IStream32*)newStream;
342
343       /*
344        * Since we are returning a pointer to the interface, we have to 
345        * nail down the reference.
346        */
347       StgStreamImpl_AddRef(*ppstm);
348       
349       return S_OK;
350     }
351     
352     return E_OUTOFMEMORY;
353   }
354   
355   return STG_E_FILENOTFOUND;
356 }
357
358 /************************************************************************
359  * Storage32BaseImpl_OpenStorage (IStorage)
360  *
361  * This method will open a new storage object from the current storage.
362  * 
363  * See Windows documentation for more details on IStorage methods.
364  */        
365 HRESULT WINAPI Storage32BaseImpl_OpenStorage( 
366   IStorage32*        iface,
367   const OLECHAR32*   pwcsName,      /* [string][unique][in] */ 
368   IStorage32*        pstgPriority,  /* [unique][in] */         
369   DWORD              grfMode,       /* [in] */                 
370   SNB32              snbExclude,    /* [unique][in] */         
371   DWORD              reserved,      /* [in] */                 
372   IStorage32**       ppstg)         /* [out] */                        
373 {
374   ICOM_THIS(Storage32BaseImpl,iface);
375   Storage32InternalImpl* newStorage;
376   IEnumSTATSTGImpl*      propertyEnumeration;
377   StgProperty            currentProperty;
378   ULONG                  foundPropertyIndex;
379   
380   /*
381    * Perform a sanity check on the parameters.
382    */
383   if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
384     return E_INVALIDARG;
385   
386   /*
387    * Validate the STGM flags
388    */
389   if ( FAILED( validateSTGM(grfMode) ))
390     return STG_E_INVALIDFLAG;
391
392   /*
393    * As documented.
394    */
395   if ( !(grfMode & STGM_SHARE_EXCLUSIVE) || 
396         (grfMode & STGM_DELETEONRELEASE) ||
397         (grfMode & STGM_PRIORITY) )
398     return STG_E_INVALIDFUNCTION;
399
400   /*
401    * Initialize the out parameter
402    */
403   *ppstg = 0;
404   
405   /*
406    * Create a property enumeration to search the properties
407    */
408   propertyEnumeration = IEnumSTATSTGImpl_Construct(
409                           This->ancestorStorage, 
410                           This->rootPropertySetIndex);
411   
412   /*
413    * Search the enumeration for the property with the given name
414    */
415   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
416                          propertyEnumeration,
417                          pwcsName,
418                          &currentProperty);
419   
420   /*
421    * Delete the property enumeration since we don't need it anymore
422    */
423   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
424   
425   /*
426    * If it was found, construct the stream object and return a pointer to it.
427    */
428   if ( (foundPropertyIndex!=PROPERTY_NULL) && 
429        (currentProperty.propertyType==PROPTYPE_STORAGE) )
430   {
431     /*
432      * Construct a new Storage object
433      */
434     newStorage = Storage32InternalImpl_Construct(
435                    This->ancestorStorage,
436                    foundPropertyIndex);
437     
438     if (newStorage != 0)
439     {
440       *ppstg = (IStorage32*)newStorage;
441
442       /*
443        * Since we are returning a pointer to the interface, 
444        * we have to nail down the reference.
445        */
446       Storage32BaseImpl_AddRef(*ppstg);
447       
448       return S_OK;
449     }
450     
451     return STG_E_INSUFFICIENTMEMORY;
452   }
453   
454   return STG_E_FILENOTFOUND;
455 }
456
457 /************************************************************************
458  * Storage32BaseImpl_EnumElements (IStorage)
459  *
460  * This method will create an enumerator object that can be used to 
461  * retrieve informatino about all the properties in the storage object.
462  * 
463  * See Windows documentation for more details on IStorage methods.
464  */        
465 HRESULT WINAPI Storage32BaseImpl_EnumElements( 
466   IStorage32*        iface,
467   DWORD              reserved1, /* [in] */                  
468   void*              reserved2, /* [size_is][unique][in] */ 
469   DWORD              reserved3, /* [in] */                  
470   IEnumSTATSTG**     ppenum)    /* [out] */                 
471 {
472   ICOM_THIS(Storage32BaseImpl,iface);
473   IEnumSTATSTGImpl* newEnum;
474
475   /*
476    * Perform a sanity check on the parameters.
477    */
478   if ( (This==0) || (ppenum==0))
479     return E_INVALIDARG;
480   
481   /*
482    * Construct the enumerator.
483    */
484   newEnum = IEnumSTATSTGImpl_Construct(
485               This->ancestorStorage,
486               This->rootPropertySetIndex);
487
488   if (newEnum!=0)
489   {
490     *ppenum = (IEnumSTATSTG*)newEnum;
491
492     /*
493      * Don't forget to nail down a reference to the new object before
494      * returning it.
495      */
496     IEnumSTATSTGImpl_AddRef(*ppenum);
497     
498     return S_OK;
499   }
500
501   return E_OUTOFMEMORY;
502 }
503
504 /************************************************************************
505  * Storage32BaseImpl_Stat (IStorage)
506  *
507  * This method will retrieve information about this storage object.
508  * 
509  * See Windows documentation for more details on IStorage methods.
510  */        
511 HRESULT WINAPI Storage32BaseImpl_Stat( 
512   IStorage32*        iface,
513   STATSTG*           pstatstg,     /* [out] */ 
514   DWORD              grfStatFlag)  /* [in] */  
515 {
516   ICOM_THIS(Storage32BaseImpl,iface);
517   StgProperty    curProperty;
518   BOOL32         readSucessful;
519
520   /*
521    * Perform a sanity check on the parameters.
522    */
523   if ( (This==0) || (pstatstg==0))
524     return E_INVALIDARG;
525
526   /*
527    * Read the information from the property.
528    */
529   readSucessful = Storage32Impl_ReadProperty(
530                     This->ancestorStorage,
531                     This->rootPropertySetIndex,
532                     &curProperty);
533
534   if (readSucessful)
535   {
536     StorageUtl_CopyPropertyToSTATSTG(
537       pstatstg, 
538       &curProperty, 
539       grfStatFlag);
540     
541     return S_OK;
542   }
543   
544   return E_FAIL;
545 }
546
547 /************************************************************************
548  * Storage32BaseImpl_RenameElement (IStorage)
549  *
550  * This method will rename the specified element. 
551  *
552  * See Windows documentation for more details on IStorage methods.
553  * 
554  * Implementation notes: The method used to rename consists of creating a clone 
555  *    of the deleted StgProperty object setting it with the new name and to 
556  *    perform a DestroyElement of the old StgProperty.
557  */
558 HRESULT WINAPI Storage32BaseImpl_RenameElement(
559             IStorage32*        iface,
560             const OLECHAR32*   pwcsOldName,  /* [in] */
561             const OLECHAR32*   pwcsNewName)  /* [in] */
562 {
563   ICOM_THIS(Storage32BaseImpl,iface);
564   IEnumSTATSTGImpl* propertyEnumeration;
565   StgProperty       currentProperty;
566   ULONG             foundPropertyIndex;
567
568   /*
569    * Create a property enumeration to search the properties
570    */
571   propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
572                                                    This->rootPropertySetIndex);
573
574   /*
575    * Search the enumeration for the new property name
576    */
577   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
578                                                      pwcsNewName,
579                                                      &currentProperty);
580
581   if (foundPropertyIndex != PROPERTY_NULL)
582   {
583     /*
584      * There is already a property with the new name
585      */
586     IEnumSTATSTGImpl_Destroy(propertyEnumeration);
587     return STG_E_FILEALREADYEXISTS;
588   }
589
590   IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
591
592   /*
593    * Search the enumeration for the old property name
594    */
595   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
596                                                      pwcsOldName,
597                                                      &currentProperty);
598
599   /*
600    * Delete the property enumeration since we don't need it anymore
601    */
602   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
603
604   if (foundPropertyIndex != PROPERTY_NULL)
605   {
606     StgProperty renamedProperty;
607     ULONG       renamedPropertyIndex;
608
609     /*
610      * Setup a new property for the renamed property
611      */
612     renamedProperty.sizeOfNameString = 
613       ( lstrlen32W(pwcsNewName)+1 ) * sizeof(WCHAR);
614   
615     if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
616       return STG_E_INVALIDNAME;
617   
618     lstrcpy32W(renamedProperty.name, pwcsNewName);
619  
620     renamedProperty.propertyType  = currentProperty.propertyType;
621     renamedProperty.startingBlock = currentProperty.startingBlock;
622     renamedProperty.size.LowPart  = currentProperty.size.LowPart;
623     renamedProperty.size.HighPart = currentProperty.size.HighPart;
624   
625     renamedProperty.previousProperty = PROPERTY_NULL;
626     renamedProperty.nextProperty     = PROPERTY_NULL;
627   
628     /*
629      * Bring the dirProperty link in case it is a storage and in which
630      * case the renamed storage elements don't require to be reorganized.
631      */
632     renamedProperty.dirProperty = currentProperty.dirProperty;
633   
634     /* call CoFileTime to get the current time 
635     renamedProperty.timeStampS1
636     renamedProperty.timeStampD1
637     renamedProperty.timeStampS2
638     renamedProperty.timeStampD2
639     renamedProperty.propertyUniqueID 
640     */
641   
642     /* 
643      * Obtain a free property in the property chain
644      */
645     renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
646   
647     /*
648      * Save the new property into the new property spot
649      */  
650     Storage32Impl_WriteProperty(
651       This->ancestorStorage,
652       renamedPropertyIndex, 
653       &renamedProperty);
654   
655     /* 
656      * Find a spot in the property chain for our newly created property.
657      */
658     updatePropertyChain(
659       (Storage32Impl*)This,
660       renamedPropertyIndex, 
661       renamedProperty);
662
663     /*
664      * At this point the renamed property has been inserted in the tree, 
665      * now, before to Destroy the old property we must zeroed it's dirProperty 
666      * otherwise the DestroyProperty below will zap it all and we do not want 
667      * this to happen.
668      * Also, we fake that the old property is a storage so the DestroyProperty
669      * will not do a SetSize(0) on the stream data.
670      * 
671      * This means that we need to tweek the StgProperty if it is a stream or a
672      * non empty storage.
673      */
674     currentProperty.dirProperty  = PROPERTY_NULL;
675     currentProperty.propertyType = PROPTYPE_STORAGE;
676     Storage32Impl_WriteProperty(
677       This->ancestorStorage,
678       foundPropertyIndex, 
679       &currentProperty);
680
681     /* 
682      * Invoke Destroy to get rid of the ole property and automatically redo 
683      * the linking of it's previous and next members... 
684      */ 
685     Storage32Impl_DestroyElement((IStorage32*)This->ancestorStorage, pwcsOldName); 
686
687   }
688   else
689   {
690     /*
691      * There is no property with the old name
692      */
693     return STG_E_FILENOTFOUND;
694   }
695
696   return S_OK;
697 }
698
699 /************************************************************************
700  * Storage32BaseImpl_CreateStream (IStorage)
701  *
702  * This method will create a stream object within this storage 
703  *
704  * See Windows documentation for more details on IStorage methods.
705  */
706 HRESULT WINAPI Storage32BaseImpl_CreateStream(
707             IStorage32*        iface,
708             const OLECHAR32*   pwcsName,  /* [string][in] */
709             DWORD              grfMode,   /* [in] */
710             DWORD              reserved1, /* [in] */
711             DWORD              reserved2, /* [in] */
712             IStream32**        ppstm)     /* [out] */
713 {
714   ICOM_THIS(Storage32BaseImpl,iface);
715   IEnumSTATSTGImpl* propertyEnumeration;
716   StgStreamImpl*    newStream;
717   StgProperty       currentProperty, newStreamProperty;
718   ULONG             foundPropertyIndex, newPropertyIndex;
719
720   /*
721    * Validate parameters
722    */
723   if (ppstm == 0)
724     return STG_E_INVALIDPOINTER;
725
726   if (pwcsName == 0)
727     return STG_E_INVALIDNAME;
728
729   /*
730    * Validate the STGM flags
731    */
732   if ( FAILED( validateSTGM(grfMode) ))
733     return STG_E_INVALIDFLAG;
734
735   /*
736    * As documented.
737    */
738   if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
739         (grfMode & STGM_DELETEONRELEASE) ||
740         (grfMode & STGM_TRANSACTED) )
741     return STG_E_INVALIDFUNCTION;
742
743   /*
744    * Initialize the out parameter
745    */
746   *ppstm = 0;
747
748   /*
749    * Create a property enumeration to search the properties
750    */
751   propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
752                                                    This->rootPropertySetIndex);
753
754   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
755                                                      pwcsName,
756                                                      &currentProperty);
757
758   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
759
760   if (foundPropertyIndex != PROPERTY_NULL)
761   {
762     /*
763      * An element with this name already exists 
764      */
765     if (grfMode & STGM_CREATE)
766       Storage32Impl_DestroyElement((IStorage32*)This->ancestorStorage, pwcsName); 
767     else 
768       return STG_E_FILEALREADYEXISTS;
769   }
770
771   /* 
772    * memset the empty property 
773    */
774   memset(&newStreamProperty, 0, sizeof(StgProperty));
775
776   newStreamProperty.sizeOfNameString =
777       ( lstrlen32W(pwcsName)+1 ) * sizeof(WCHAR);
778
779   if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
780     return STG_E_INVALIDNAME;
781
782   lstrcpy32W(newStreamProperty.name, pwcsName);
783
784   newStreamProperty.propertyType  = PROPTYPE_STREAM;
785   newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
786   newStreamProperty.size.LowPart  = 0;
787   newStreamProperty.size.HighPart = 0;
788
789   newStreamProperty.previousProperty = PROPERTY_NULL;
790   newStreamProperty.nextProperty     = PROPERTY_NULL;
791   newStreamProperty.dirProperty      = PROPERTY_NULL;
792
793   /* call CoFileTime to get the current time 
794   newStreamProperty.timeStampS1
795   newStreamProperty.timeStampD1
796   newStreamProperty.timeStampS2
797   newStreamProperty.timeStampD2
798   */
799
800   /*  newStreamProperty.propertyUniqueID */
801
802   /*
803    * Get a free property or create a new one 
804    */
805   newPropertyIndex = getFreeProperty(This->ancestorStorage);
806
807   /*
808    * Save the new property into the new property spot
809    */  
810   Storage32Impl_WriteProperty(
811     This->ancestorStorage,
812     newPropertyIndex, 
813     &newStreamProperty);
814
815   /* 
816    * Find a spot in the property chain for our newly created property.
817    */
818   updatePropertyChain(
819     (Storage32Impl*)This,
820     newPropertyIndex, 
821     newStreamProperty);
822
823   /* 
824    * Open the stream to return it.
825    */
826   newStream = StgStreamImpl_Construct(This, newPropertyIndex);
827
828   if (newStream != 0)
829   {
830     *ppstm = (IStream32*)newStream;
831
832     /*
833      * Since we are returning a pointer to the interface, we have to nail down
834      * the reference.
835      */
836     StgStreamImpl_AddRef(*ppstm);
837   }
838   else
839   {
840     return STG_E_INSUFFICIENTMEMORY;
841   }
842
843   return S_OK;
844 }
845
846 /************************************************************************
847  * Storage32BaseImpl_SetClass (IStorage)
848  *
849  * This method will write the specified CLSID in the property of this 
850  * storage.
851  *
852  * See Windows documentation for more details on IStorage methods.
853  */
854 HRESULT WINAPI Storage32BaseImpl_SetClass(
855   IStorage32*        iface,
856   REFCLSID           clsid) /* [in] */
857 {
858   ICOM_THIS(Storage32BaseImpl,iface);
859   HRESULT hRes = E_FAIL;
860   StgProperty curProperty;
861   BOOL32 success;
862   
863   success = Storage32Impl_ReadProperty(This->ancestorStorage,
864                                        This->rootPropertySetIndex,
865                                        &curProperty);
866   if (success)
867   {
868     curProperty.propertyUniqueID = *clsid;
869
870     success =  Storage32Impl_WriteProperty(This->ancestorStorage,
871                                            This->rootPropertySetIndex,
872                                            &curProperty);
873     if (success)
874       hRes = S_OK;
875   }
876
877   return hRes;
878 }
879
880 /************************************************************************
881 ** Storage32Impl implementation
882 */
883         
884 /************************************************************************
885  * Storage32Impl_CreateStorage (IStorage)
886  *
887  * This method will create the storage object within the provided storage.
888  *
889  * See Windows documentation for more details on IStorage methods.
890  */
891 HRESULT WINAPI Storage32Impl_CreateStorage( 
892   IStorage32*      iface,
893   const OLECHAR32  *pwcsName, /* [string][in] */ 
894   DWORD            grfMode,   /* [in] */ 
895   DWORD            reserved1, /* [in] */ 
896   DWORD            reserved2, /* [in] */ 
897   IStorage32       **ppstg)   /* [out] */ 
898 {
899   Storage32Impl* const This=(Storage32Impl*)iface;
900
901   IEnumSTATSTGImpl *propertyEnumeration;
902   StgProperty      currentProperty;
903   StgProperty      newProperty;
904   ULONG            foundPropertyIndex;
905   ULONG            newPropertyIndex;
906   HRESULT          hr;
907
908   /*
909    * Validate parameters
910    */
911   if (ppstg == 0)
912     return STG_E_INVALIDPOINTER;
913
914   if (pwcsName == 0)
915     return STG_E_INVALIDNAME;
916
917   /*
918    * Validate the STGM flags
919    */
920   if ( FAILED( validateSTGM(grfMode) ) ||
921        (grfMode & STGM_DELETEONRELEASE) )
922     return STG_E_INVALIDFLAG;
923
924   /*
925    * Initialize the out parameter
926    */
927   *ppstg = 0;
928
929   /*
930    * Create a property enumeration and search the properties
931    */
932   propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
933                                                     This->rootPropertySetIndex);
934
935   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
936                                                      pwcsName,
937                                                      &currentProperty);
938   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
939
940   if (foundPropertyIndex != PROPERTY_NULL)
941   {
942     /*
943      * An element with this name already exists 
944      */
945     if (grfMode & STGM_CREATE)
946       Storage32Impl_DestroyElement((IStorage32*)This->ancestorStorage, pwcsName); 
947     else 
948       return STG_E_FILEALREADYEXISTS;
949   }
950
951   /* 
952    * memset the empty property 
953    */
954   memset(&newProperty, 0, sizeof(StgProperty));
955
956   newProperty.sizeOfNameString = (lstrlen32W(pwcsName)+1)*sizeof(WCHAR);
957
958   if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
959     return STG_E_INVALIDNAME;
960
961   lstrcpy32W(newProperty.name, pwcsName);
962
963   newProperty.propertyType  = PROPTYPE_STORAGE;
964   newProperty.startingBlock = BLOCK_END_OF_CHAIN;
965   newProperty.size.LowPart  = 0;
966   newProperty.size.HighPart = 0;
967
968   newProperty.previousProperty = PROPERTY_NULL;
969   newProperty.nextProperty     = PROPERTY_NULL;
970   newProperty.dirProperty      = PROPERTY_NULL;
971
972   /* call CoFileTime to get the current time 
973   newProperty.timeStampS1
974   newProperty.timeStampD1
975   newProperty.timeStampS2
976   newProperty.timeStampD2
977   */
978
979   /*  newStorageProperty.propertyUniqueID */
980
981   /* 
982    * Obtain a free property in the property chain
983    */
984   newPropertyIndex = getFreeProperty(This->ancestorStorage);
985
986   /*
987    * Save the new property into the new property spot
988    */  
989   Storage32Impl_WriteProperty(
990     This->ancestorStorage,
991     newPropertyIndex, 
992     &newProperty);
993
994   /* 
995    * Find a spot in the property chain for our newly created property.
996    */
997   updatePropertyChain(
998     This,
999     newPropertyIndex, 
1000     newProperty);
1001
1002   /* 
1003    * Open it to get a pointer to return.
1004    */
1005   hr = Storage32BaseImpl_OpenStorage(
1006          iface,
1007          (OLECHAR32*)pwcsName,
1008          0,
1009          grfMode,
1010          0,
1011          0,
1012          ppstg);
1013
1014   if( (hr != S_OK) || (*ppstg == NULL))
1015   {
1016     return hr;
1017   }
1018
1019   return S_OK;
1020 }
1021
1022
1023 /***************************************************************************
1024  *
1025  * Internal Method
1026  *
1027  * Get a free property or create a new one.
1028  */
1029 static ULONG getFreeProperty(
1030   Storage32Impl *storage)
1031 {
1032   ULONG       currentPropertyIndex = 0;
1033   ULONG       newPropertyIndex     = PROPERTY_NULL;
1034   BOOL32      readSucessful        = TRUE;
1035   StgProperty currentProperty;
1036
1037   do
1038   {
1039     /*
1040      * Start by reading the root property
1041      */
1042     readSucessful = Storage32Impl_ReadProperty(storage->ancestorStorage,
1043                                                currentPropertyIndex,
1044                                                &currentProperty);
1045     if (readSucessful)
1046     {
1047       if (currentProperty.sizeOfNameString == 0)
1048       {
1049         /* 
1050          * The property existis and is available, we found it.
1051          */
1052         newPropertyIndex = currentPropertyIndex;
1053       }
1054     }
1055     else
1056     {
1057       /*
1058        * We exhausted the property list, we will create more space below
1059        */
1060       newPropertyIndex = currentPropertyIndex;
1061     }
1062     currentPropertyIndex++;
1063
1064   } while (newPropertyIndex == PROPERTY_NULL);
1065
1066   /* 
1067    * grow the property chain 
1068    */
1069   if (! readSucessful)
1070   {
1071     StgProperty    emptyProperty;
1072     ULARGE_INTEGER newSize;
1073     ULONG          propertyIndex;
1074     ULONG          lastProperty  = 0;
1075     ULONG          blockCount    = 0;
1076
1077     /* 
1078      * obtain the new count of property blocks 
1079      */
1080     blockCount = BlockChainStream_GetCount(
1081                    storage->ancestorStorage->rootBlockChain)+1;
1082
1083     /* 
1084      * initialize the size used by the property stream 
1085      */
1086     newSize.HighPart = 0;
1087     newSize.LowPart  = storage->bigBlockSize * blockCount;
1088
1089     /* 
1090      * add a property block to the property chain 
1091      */
1092     BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1093
1094     /* 
1095      * memset the empty property in order to initialize the unused newly 
1096      * created property
1097      */
1098     memset(&emptyProperty, 0, sizeof(StgProperty));
1099
1100     /* 
1101      * initialize them
1102      */
1103     lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount; 
1104     
1105     for(
1106       propertyIndex = newPropertyIndex;
1107       propertyIndex < lastProperty;
1108       propertyIndex++)
1109     {
1110       Storage32Impl_WriteProperty(
1111         storage->ancestorStorage,
1112         propertyIndex, 
1113         &emptyProperty);
1114     }
1115   }
1116
1117   return newPropertyIndex;
1118 }
1119
1120 /****************************************************************************
1121  *
1122  * Internal Method
1123  *
1124  * Case insensitive comparaison of StgProperty.name by first considering 
1125  * their size.
1126  *
1127  * Returns <0 when newPrpoerty < currentProperty
1128  *         >0 when newPrpoerty > currentProperty
1129  *          0 when newPrpoerty == currentProperty
1130  */
1131 static LONG propertyNameCmp(
1132   OLECHAR32 *newProperty,
1133   OLECHAR32 *currentProperty)
1134 {
1135   LONG sizeOfNew = (lstrlen32W(newProperty)    +1) * sizeof(WCHAR);
1136   LONG sizeOfCur = (lstrlen32W(currentProperty)+1) * sizeof(WCHAR);
1137   LONG diff      = sizeOfNew - sizeOfCur;
1138
1139   if (diff == 0) 
1140   {
1141     /* 
1142      * We compare the string themselves only when they are of the same lenght
1143      */
1144     WCHAR wsnew[PROPERTY_NAME_MAX_LEN];    
1145     WCHAR wscur[PROPERTY_NAME_MAX_LEN];    
1146
1147     diff = lstrcmp32W( (LPCWSTR)CRTDLL__wcsupr(
1148                            lstrcpyn32W(wsnew, newProperty, sizeOfNew)), 
1149                        (LPCWSTR)CRTDLL__wcsupr(
1150                            lstrcpyn32W(wscur, currentProperty, sizeOfCur)));
1151   }
1152
1153   return diff;  
1154 }
1155
1156 /****************************************************************************
1157  *
1158  * Internal Method
1159  *
1160  * Properly link this new element in the property chain.
1161  */
1162 static void updatePropertyChain(
1163   Storage32Impl *storage,
1164   ULONG         newPropertyIndex,
1165   StgProperty   newProperty) 
1166 {
1167   StgProperty currentProperty;
1168
1169   /*
1170    * Read the root property
1171    */
1172   Storage32Impl_ReadProperty(storage->ancestorStorage,
1173                              storage->rootPropertySetIndex,
1174                              &currentProperty);
1175
1176   if (currentProperty.dirProperty != PROPERTY_NULL)
1177   {
1178     /* 
1179      * The root storage contains some element, therefore, start the research
1180      * for the appropriate location.
1181      */
1182     BOOL32 found = 0;
1183     ULONG  current, next, previous, currentPropertyId;
1184
1185     /*
1186      * Keep the StgProperty sequence number of the storage first property
1187      */
1188     currentPropertyId = currentProperty.dirProperty;
1189
1190     /*
1191      * Read 
1192      */
1193     Storage32Impl_ReadProperty(storage->ancestorStorage,
1194                                currentProperty.dirProperty,
1195                                &currentProperty);
1196
1197     previous = currentProperty.previousProperty;
1198     next     = currentProperty.nextProperty;
1199     current  = currentPropertyId;
1200
1201     while (found == 0)
1202     {
1203       LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1204   
1205       if (diff < 0)
1206       {
1207         if (previous != PROPERTY_NULL)
1208         {
1209           Storage32Impl_ReadProperty(storage->ancestorStorage,
1210                                      previous,
1211                                      &currentProperty);
1212           current = previous;
1213         }
1214         else
1215         {
1216           currentProperty.previousProperty = newPropertyIndex;
1217           Storage32Impl_WriteProperty(storage->ancestorStorage,
1218                                       current,
1219                                       &currentProperty);
1220           found = 1;
1221         }
1222       }
1223       else 
1224       {
1225         if (next != PROPERTY_NULL)
1226         {
1227           Storage32Impl_ReadProperty(storage->ancestorStorage,
1228                                      next,
1229                                      &currentProperty);
1230           current = next;
1231         }
1232         else
1233         {
1234           currentProperty.nextProperty = newPropertyIndex;
1235           Storage32Impl_WriteProperty(storage->ancestorStorage,
1236                                       current,
1237                                       &currentProperty);
1238           found = 1;
1239         }
1240       }
1241
1242       previous = currentProperty.previousProperty;
1243       next     = currentProperty.nextProperty;
1244     }
1245   }
1246   else
1247   {
1248     /* 
1249      * The root storage is empty, link the new property to it's dir property
1250      */
1251     currentProperty.dirProperty = newPropertyIndex;
1252     Storage32Impl_WriteProperty(storage->ancestorStorage,
1253                                 storage->rootPropertySetIndex,
1254                                 &currentProperty);
1255   }
1256 }
1257
1258       
1259 /*************************************************************************
1260  * CopyTo (IStorage)
1261  */
1262 HRESULT WINAPI Storage32Impl_CopyTo( 
1263   IStorage32*   iface,
1264   DWORD         ciidExclude,  /* [in] */ 
1265   const IID     *rgiidExclude,/* [size_is][unique][in] */ 
1266   SNB32         snbExclude,   /* [unique][in] */ 
1267   IStorage32    *pstgDest)    /* [unique][in] */ 
1268 {
1269   return E_NOTIMPL;
1270 }
1271         
1272 /*************************************************************************
1273  * MoveElementTo (IStorage)
1274  */
1275 HRESULT WINAPI Storage32Impl_MoveElementTo( 
1276   IStorage32*     iface,
1277   const OLECHAR32 *pwcsName,   /* [string][in] */ 
1278   IStorage32      *pstgDest,   /* [unique][in] */ 
1279   const OLECHAR32 *pwcsNewName,/* [string][in] */ 
1280   DWORD           grfFlags)    /* [in] */ 
1281 {
1282   return E_NOTIMPL;
1283 }
1284         
1285 /*************************************************************************
1286  * Commit (IStorage)
1287  */
1288 HRESULT WINAPI Storage32Impl_Commit( 
1289   IStorage32*   iface,
1290   DWORD         grfCommitFlags)/* [in] */ 
1291 {
1292   FIXME(ole, "(%ld): stub!\n", grfCommitFlags);
1293   return S_OK;
1294 }
1295         
1296 /*************************************************************************
1297  * Revert (IStorage)
1298  */
1299 HRESULT WINAPI Storage32Impl_Revert( 
1300   IStorage32* iface)
1301 {
1302   return E_NOTIMPL;
1303 }
1304
1305 /*************************************************************************
1306  * DestroyElement (IStorage)
1307  *
1308  * Stategy: This implementation is build this way for simplicity not for speed. 
1309  *          I always delete the top most element of the enumeration and adjust
1310  *          the deleted element pointer all the time.  This takes longer to 
1311  *          do but allow to reinvoke DestroyElement whenever we encounter a 
1312  *          storage object.  The optimisation reside in the usage of another
1313  *          enumeration stategy that would give all the leaves of a storage 
1314  *          first. (postfix order)
1315  */
1316 HRESULT WINAPI Storage32Impl_DestroyElement( 
1317   IStorage32*     iface,
1318   const OLECHAR32 *pwcsName)/* [string][in] */ 
1319 {
1320   Storage32Impl* const This=(Storage32Impl*)iface;
1321
1322   IEnumSTATSTGImpl* propertyEnumeration;
1323   HRESULT           hr = S_OK;
1324   BOOL32            res;
1325   StgProperty       propertyToDelete;
1326   StgProperty       parentProperty;
1327   ULONG             foundPropertyIndexToDelete;
1328   ULONG             typeOfRelation;
1329   ULONG             parentPropertyId;
1330
1331   /*
1332    * Perform a sanity check on the parameters.
1333    */
1334   if (pwcsName==NULL) 
1335     return STG_E_INVALIDPOINTER;
1336   
1337   /*
1338    * Create a property enumeration to search the property with the given name
1339    */
1340   propertyEnumeration = IEnumSTATSTGImpl_Construct(
1341     This->ancestorStorage, 
1342     This->rootPropertySetIndex);
1343   
1344   foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1345     propertyEnumeration,
1346     pwcsName,
1347     &propertyToDelete);
1348
1349   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1350
1351   if ( foundPropertyIndexToDelete == PROPERTY_NULL )  
1352   {
1353     return STG_E_FILENOTFOUND;
1354   }
1355
1356   /* 
1357    * Find the parent property of the property to delete (the one that 
1358    * link to it).  If This->dirProperty == foundPropertyIndexToDelete, 
1359    * the parent is This. Otherwise, the parent is one of it's sibling...
1360    */
1361
1362   /* 
1363    * First, read This's StgProperty..
1364    */
1365   res = Storage32Impl_ReadProperty( 
1366           This->ancestorStorage,
1367           This->rootPropertySetIndex,
1368           &parentProperty);
1369
1370   assert(res==TRUE);
1371
1372   /* 
1373    * Second, check to see if by any chance the actual storage (This) is not
1374    * the parent of the property to delete... We never know...
1375    */
1376   if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1377   {
1378     /* 
1379      * Set data as it would have been done in the else part...
1380      */
1381     typeOfRelation   = PROPERTY_RELATION_DIR;
1382     parentPropertyId = This->rootPropertySetIndex;
1383   }
1384   else 
1385   { 
1386     /*
1387      * Create a property enumeration to search the parent properties, and 
1388      * delete it once done.
1389      */
1390     IEnumSTATSTGImpl* propertyEnumeration2;
1391
1392     propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1393       This->ancestorStorage, 
1394       This->rootPropertySetIndex);
1395   
1396     typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1397       propertyEnumeration2,
1398       foundPropertyIndexToDelete,
1399       &parentProperty,
1400       &parentPropertyId);
1401
1402     IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1403   }
1404
1405   if ( propertyToDelete.propertyType == PROPTYPE_STORAGE ) 
1406   {
1407     hr = deleteStorageProperty(
1408            This, 
1409            propertyToDelete.name);
1410   } 
1411   else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1412   {
1413     hr = deleteStreamProperty(
1414            This, 
1415            foundPropertyIndexToDelete,
1416            propertyToDelete);
1417   }
1418
1419   if (hr!=S_OK) 
1420     return hr;
1421
1422   /*
1423    * Adjust the property chain
1424    */
1425   hr = adjustPropertyChain(
1426         This,
1427         propertyToDelete, 
1428         parentProperty,
1429         parentPropertyId,
1430         typeOfRelation);
1431
1432   return hr;
1433 }
1434
1435
1436 /*********************************************************************
1437  *
1438  * Internal Method
1439  *
1440  * Perform the deletion of a complete storage node
1441  *
1442  */
1443 static HRESULT deleteStorageProperty(
1444   Storage32Impl *parentStorage,
1445   OLECHAR32     *propertyToDeleteName)
1446 {
1447   IEnumSTATSTG *elements     = 0;
1448   IStorage32   *childStorage = 0;
1449   STATSTG      currentElement;
1450   HRESULT      hr;
1451   HRESULT      destroyHr = S_OK;
1452
1453   /*
1454    * Open the storage and enumerate it
1455    */
1456   hr = Storage32BaseImpl_OpenStorage(
1457         (IStorage32*)parentStorage,
1458         propertyToDeleteName,
1459         0,
1460         STGM_SHARE_EXCLUSIVE,
1461         0,
1462         0,
1463         &childStorage);
1464
1465   if (hr != S_OK)
1466   {
1467     return hr;
1468   }
1469
1470   /* 
1471    * Enumerate the elements
1472    */
1473   IStorage32_EnumElements( childStorage, 0, 0, 0, &elements);
1474
1475   do
1476   {
1477     /*
1478      * Obtain the next element
1479      */
1480     hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1481     if (hr==S_OK)
1482     {
1483       destroyHr = Storage32Impl_DestroyElement(
1484                     (IStorage32*)childStorage, 
1485                     (OLECHAR32*)currentElement.pwcsName);
1486
1487       CoTaskMemFree(currentElement.pwcsName);
1488     }
1489
1490     /*
1491      * We need to Reset the enumeration every time because we delete elements
1492      * and the enumeration could be invalid
1493      */
1494     IEnumSTATSTG_Reset(elements);
1495
1496   } while ((hr == S_OK) && (destroyHr == S_OK));
1497
1498   IStorage32_Release(childStorage);
1499   IEnumSTATSTG_Release(elements);
1500     
1501   return destroyHr;
1502 }
1503
1504 /*********************************************************************
1505  *
1506  * Internal Method
1507  *
1508  * Perform the deletion of a stream node
1509  *
1510  */
1511 static HRESULT deleteStreamProperty(
1512   Storage32Impl *parentStorage,
1513   ULONG         indexOfPropertyToDelete,
1514   StgProperty   propertyToDelete)
1515 {
1516   IStream32      *pis;
1517   HRESULT        hr;
1518   ULARGE_INTEGER size;
1519
1520   size.HighPart = 0;
1521   size.LowPart = 0;
1522
1523   hr = Storage32BaseImpl_OpenStream(
1524          (IStorage32*)parentStorage,
1525          (OLECHAR32*)propertyToDelete.name,
1526          NULL,
1527          STGM_SHARE_EXCLUSIVE,
1528          0,
1529          &pis);
1530     
1531   if (hr!=S_OK)
1532   {
1533     return(hr);
1534   }
1535
1536   /* 
1537    * Zap the stream 
1538    */ 
1539   hr = IStream32_SetSize(pis, size); 
1540
1541   if(hr != S_OK)
1542   {
1543     return hr;
1544   }
1545
1546   /* 
1547    * Invalidate the property by zeroing it's name member.
1548    */
1549   propertyToDelete.sizeOfNameString = 0;
1550
1551   /* 
1552    * Here we should re-read the property so we get the updated pointer
1553    * but since we are here to zap it, I don't do it...
1554    */
1555
1556   Storage32Impl_WriteProperty(
1557     parentStorage->ancestorStorage, 
1558     indexOfPropertyToDelete,
1559     &propertyToDelete);
1560
1561   return S_OK;
1562 }
1563
1564 /*********************************************************************
1565  *
1566  * Internal Method
1567  *
1568  * Finds a placeholder for the StgProperty within the Storage
1569  *
1570  */
1571 static HRESULT findPlaceholder(
1572   Storage32Impl *storage,
1573   ULONG         propertyIndexToStore,
1574   ULONG         storePropertyIndex,
1575   INT32         typeOfRelation)
1576 {
1577   StgProperty storeProperty;
1578   HRESULT     hr = S_OK;
1579   BOOL32      res = TRUE;
1580
1581   /*
1582    * Read the storage property
1583    */
1584   res = Storage32Impl_ReadProperty(
1585           storage->ancestorStorage,
1586           storePropertyIndex, 
1587           &storeProperty);
1588
1589   if(! res)
1590   {
1591     return E_FAIL;
1592   }
1593
1594   if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1595   {
1596     if (storeProperty.previousProperty != PROPERTY_NULL)
1597     {
1598       return findPlaceholder(
1599                storage,
1600                propertyIndexToStore, 
1601                storeProperty.previousProperty,
1602                typeOfRelation);
1603     }
1604     else
1605     {
1606       storeProperty.previousProperty = propertyIndexToStore;
1607     }
1608   }
1609   else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1610   {
1611     if (storeProperty.nextProperty != PROPERTY_NULL)
1612     {
1613       return findPlaceholder(
1614                storage,
1615                propertyIndexToStore, 
1616                storeProperty.nextProperty,
1617                typeOfRelation);
1618     }
1619     else
1620     {
1621       storeProperty.nextProperty = propertyIndexToStore;
1622     }
1623   } 
1624   else if (typeOfRelation == PROPERTY_RELATION_DIR)
1625   {
1626     if (storeProperty.dirProperty != PROPERTY_NULL)
1627     {
1628       return findPlaceholder(
1629                storage,
1630                propertyIndexToStore, 
1631                storeProperty.dirProperty,
1632                typeOfRelation);
1633     }
1634     else
1635     {
1636       storeProperty.dirProperty = propertyIndexToStore;
1637     }
1638   }
1639
1640   hr = Storage32Impl_WriteProperty(
1641          storage->ancestorStorage,
1642          storePropertyIndex, 
1643          &storeProperty);
1644
1645   if(! hr)
1646   {
1647     return E_FAIL;
1648   }
1649
1650   return S_OK;
1651 }
1652
1653 /*************************************************************************
1654  *
1655  * Internal Method
1656  *
1657  * This method takes the previous and the next property link of a property 
1658  * to be deleted and find them a place in the Storage.
1659  */
1660 static HRESULT adjustPropertyChain( 
1661   Storage32Impl *This,
1662   StgProperty   propertyToDelete,
1663   StgProperty   parentProperty,
1664   ULONG         parentPropertyId,
1665   INT32         typeOfRelation)
1666 {
1667   ULONG   newLinkProperty        = PROPERTY_NULL;
1668   BOOL32  needToFindAPlaceholder = FALSE;
1669   ULONG   storeNode              = PROPERTY_NULL;
1670   ULONG   toStoreNode            = PROPERTY_NULL;
1671   INT32   relationType           = 0;
1672   HRESULT hr                     = S_OK;
1673   BOOL32  res                    = TRUE;
1674   
1675   if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) 
1676   {
1677     if (propertyToDelete.previousProperty != PROPERTY_NULL)  
1678     {
1679       /* 
1680        * Set the parent previous to the property to delete previous
1681        */
1682       newLinkProperty = propertyToDelete.previousProperty;
1683
1684       if (propertyToDelete.nextProperty != PROPERTY_NULL)  
1685       {
1686         /*
1687          * We also need to find a storage for the other link, setup variables 
1688          * to do this at the end...
1689          */      
1690         needToFindAPlaceholder = TRUE;
1691         storeNode              = propertyToDelete.previousProperty;
1692         toStoreNode            = propertyToDelete.nextProperty;
1693         relationType           = PROPERTY_RELATION_NEXT;
1694       }
1695     } 
1696     else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
1697     {
1698       /* 
1699        * Set the parent previous to the property to delete next
1700        */
1701       newLinkProperty = propertyToDelete.nextProperty;
1702     }
1703    
1704     /* 
1705      * Link it for real...
1706      */ 
1707     parentProperty.previousProperty = newLinkProperty;
1708   
1709   } 
1710   else if (typeOfRelation == PROPERTY_RELATION_NEXT) 
1711   {
1712     if (propertyToDelete.previousProperty != PROPERTY_NULL)  
1713     {
1714       /* 
1715        * Set the parent next to the property to delete next previous
1716        */
1717       newLinkProperty = propertyToDelete.previousProperty;
1718       
1719       if (propertyToDelete.nextProperty != PROPERTY_NULL)  
1720       {
1721         /*
1722          * We also need to find a storage for the other link, setup variables 
1723          * to do this at the end...
1724          */      
1725         needToFindAPlaceholder = TRUE;
1726         storeNode              = propertyToDelete.previousProperty;
1727         toStoreNode            = propertyToDelete.nextProperty;
1728         relationType           = PROPERTY_RELATION_NEXT;
1729       }
1730     } 
1731     else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
1732     {
1733       /* 
1734        * Set the parent next to the property to delete next
1735        */
1736       newLinkProperty = propertyToDelete.nextProperty;
1737     }
1738
1739     /* 
1740      * Link it for real...
1741      */ 
1742     parentProperty.nextProperty = newLinkProperty;
1743   } 
1744   else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1745   {
1746     if (propertyToDelete.previousProperty != PROPERTY_NULL) 
1747     {
1748       /* 
1749        * Set the parent dir to the property to delete previous
1750        */
1751       newLinkProperty = propertyToDelete.previousProperty;
1752
1753       if (propertyToDelete.nextProperty != PROPERTY_NULL)  
1754       {
1755         /*
1756          * We also need to find a storage for the other link, setup variables 
1757          * to do this at the end...
1758          */      
1759         needToFindAPlaceholder = TRUE;
1760         storeNode              = propertyToDelete.previousProperty;
1761         toStoreNode            = propertyToDelete.nextProperty;
1762         relationType           = PROPERTY_RELATION_NEXT;
1763       }
1764     } 
1765     else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
1766     {
1767       /* 
1768        * Set the parent dir to the property to delete next
1769        */
1770       newLinkProperty = propertyToDelete.nextProperty;
1771     }
1772
1773     /* 
1774      * Link it for real...
1775      */ 
1776     parentProperty.dirProperty = newLinkProperty;
1777   }
1778
1779   /* 
1780    * Write back the parent property    
1781    */
1782   res = Storage32Impl_WriteProperty(
1783           This->ancestorStorage, 
1784           parentPropertyId,
1785           &parentProperty);
1786   if(! res)
1787   {
1788     return E_FAIL;
1789   }
1790
1791   /*
1792    * If a placeholder is required for the other link, then, find one and 
1793    * get out of here...
1794    */
1795   if (needToFindAPlaceholder) 
1796   {
1797     hr = findPlaceholder(
1798            This, 
1799            toStoreNode, 
1800            storeNode,
1801            relationType);
1802   }
1803
1804   return hr;
1805 }
1806
1807
1808 /******************************************************************************
1809  * SetElementTimes (IStorage)
1810  */
1811 HRESULT WINAPI Storage32Impl_SetElementTimes( 
1812   IStorage32*     iface,
1813   const OLECHAR32 *pwcsName,/* [string][in] */ 
1814   const FILETIME  *pctime,  /* [in] */ 
1815   const FILETIME  *patime,  /* [in] */ 
1816   const FILETIME  *pmtime)  /* [in] */ 
1817 {
1818   return E_NOTIMPL;
1819 }
1820
1821 /******************************************************************************
1822  * SetStateBits (IStorage)
1823  */
1824 HRESULT WINAPI Storage32Impl_SetStateBits( 
1825   IStorage32*   iface,
1826   DWORD         grfStateBits,/* [in] */ 
1827   DWORD         grfMask)     /* [in] */ 
1828 {
1829   return E_NOTIMPL;
1830 }
1831
1832 HRESULT Storage32Impl_Construct(
1833   Storage32Impl* This,
1834   HANDLE32       hFile,
1835   DWORD          openFlags)
1836 {
1837   HRESULT     hr = S_OK;
1838   StgProperty currentProperty;
1839   BOOL32      readSucessful;
1840   ULONG       currentPropertyIndex;
1841   
1842   if ( FAILED( validateSTGM(openFlags) ))
1843     return STG_E_INVALIDFLAG;
1844
1845   memset(This, 0, sizeof(Storage32Impl));
1846   
1847   /*
1848    * Initialize the virtual fgunction table.
1849    */
1850   This->lpvtbl       = &Storage32Impl_Vtbl;
1851   This->v_destructor = &Storage32Impl_Destroy;
1852   
1853   /*
1854    * This is the top-level storage so initialize the ancester pointer
1855    * to this.
1856    */
1857   This->ancestorStorage = This;
1858   
1859   /*
1860    * Initialize the physical support of the storage.
1861    */
1862   This->hFile = hFile;
1863   
1864   /*
1865    * Initialize the big block cache.
1866    */
1867   This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;
1868   This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
1869   This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,
1870                                                 openFlags,
1871                                                 This->bigBlockSize);
1872
1873   if (This->bigBlockFile == 0)
1874     return E_FAIL;
1875  
1876   if (openFlags & STGM_CREATE)
1877   {
1878     ULARGE_INTEGER size;
1879     BYTE* bigBlockBuffer;
1880
1881     /*
1882      * Initialize all header variables:
1883      * - The big block depot consists of one block and it is at block 0
1884      * - The properties start at block 1
1885      * - There is no small block depot
1886      */
1887     memset( This->bigBlockDepotStart,     
1888             BLOCK_UNUSED, 
1889             sizeof(This->bigBlockDepotStart));
1890
1891     This->bigBlockDepotCount    = 1;
1892     This->bigBlockDepotStart[0] = 0;
1893     This->rootStartBlock        = 1;
1894     This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
1895     This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;
1896     This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
1897     This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
1898     This->extBigBlockDepotCount = 0;
1899
1900     Storage32Impl_SaveFileHeader(This);
1901
1902     /*
1903      * Add one block for the big block depot and one block for the properties
1904      */
1905     size.HighPart = 0;
1906     size.LowPart  = This->bigBlockSize * 3;
1907     BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
1908
1909     /*
1910      * Initialize the big block depot
1911      */
1912     bigBlockBuffer = Storage32Impl_GetBigBlock(This, 0);
1913     memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
1914     StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
1915     StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
1916     Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
1917   }
1918   else
1919     {
1920       /*
1921        * Load the header for the file.
1922        */
1923       Storage32Impl_LoadFileHeader(This);
1924     }
1925   
1926   /*
1927    * Create the block chain abstractions.
1928    */
1929   This->rootBlockChain = 
1930     BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
1931
1932   This->smallBlockDepotChain = BlockChainStream_Construct(
1933                                  This, 
1934                                  &This->smallBlockDepotStart, 
1935                                  PROPERTY_NULL);
1936
1937   /*
1938    * Write the root property 
1939    */
1940   if (openFlags & STGM_CREATE)
1941   {
1942     StgProperty rootProp;
1943     /*
1944      * Initialize the property chain
1945      */
1946     memset(&rootProp, 0, sizeof(rootProp));
1947     lstrcpyAtoW(rootProp.name, rootPropertyName);
1948
1949     rootProp.sizeOfNameString = (lstrlen32W(rootProp.name)+1) * sizeof(WCHAR);
1950     rootProp.propertyType     = PROPTYPE_ROOT;
1951     rootProp.previousProperty = PROPERTY_NULL;
1952     rootProp.nextProperty     = PROPERTY_NULL;
1953     rootProp.dirProperty      = PROPERTY_NULL;
1954     rootProp.startingBlock    = BLOCK_END_OF_CHAIN;
1955     rootProp.size.HighPart    = 0;
1956     rootProp.size.LowPart     = 0;
1957
1958     Storage32Impl_WriteProperty(This, 0, &rootProp);
1959   }
1960
1961   /*
1962    * Find the ID of the root int he property sets.
1963    */
1964   currentPropertyIndex = 0;
1965   
1966   do
1967   {
1968     readSucessful = Storage32Impl_ReadProperty(
1969                       This, 
1970                       currentPropertyIndex, 
1971                       &currentProperty);
1972     
1973     if (readSucessful)
1974     {
1975       if ( (currentProperty.sizeOfNameString != 0 ) &&
1976            (currentProperty.propertyType     == PROPTYPE_ROOT) )
1977       {
1978         This->rootPropertySetIndex = currentPropertyIndex;
1979       }
1980     }
1981
1982     currentPropertyIndex++;
1983     
1984   } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1985   
1986   if (!readSucessful)
1987   {
1988     /* TODO CLEANUP */
1989     return E_FAIL;
1990   }
1991
1992   /*
1993    * Create the block chain abstraction for the small block root chain.
1994    */
1995   This->smallBlockRootChain = BlockChainStream_Construct(
1996                                 This, 
1997                                 NULL, 
1998                                 This->rootPropertySetIndex);
1999   
2000   return hr;
2001 }
2002
2003 void Storage32Impl_Destroy(
2004   Storage32Impl* This)
2005 {
2006   BlockChainStream_Destroy(This->smallBlockRootChain);
2007   BlockChainStream_Destroy(This->rootBlockChain);
2008   BlockChainStream_Destroy(This->smallBlockDepotChain);
2009
2010   BIGBLOCKFILE_Destructor(This->bigBlockFile);
2011   return;
2012 }
2013
2014 /******************************************************************************
2015  *      Storage32Impl_GetNextFreeBigBlock
2016  *
2017  * Returns the index of the next free big block.
2018  * If the big block depot is filled, this method will enlarge it.
2019  *
2020  * TODO: Handle the case when the big block depot becomes bigger
2021  *  than COUNT_BBDEPOTINHEADER.
2022  */
2023 ULONG Storage32Impl_GetNextFreeBigBlock(
2024   Storage32Impl* This)
2025 {
2026   ULONG depotBlockIndexPos;
2027   void  *depotBuffer;
2028   ULONG depotBlockOffset;
2029   ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
2030   ULONG nextBlockIndex    = BLOCK_SPECIAL;
2031   int   depotIndex        = 0;
2032   ULONG blockNoInSequence = 0;
2033
2034   /*
2035    * Scan the entire big block depot until we find a block marked free
2036    */
2037   while ( (depotIndex     <  COUNT_BBDEPOTINHEADER) && 
2038           (nextBlockIndex != BLOCK_UNUSED))
2039   {
2040     depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2041
2042     if (depotBlockIndexPos == BLOCK_UNUSED)
2043     {
2044       /*
2045        * No more space in the big block depot, we have to enlarge it
2046        */
2047       depotBlockIndexPos = depotIndex*blocksPerDepot;
2048       depotBuffer = Storage32Impl_GetBigBlock(This, depotBlockIndexPos);
2049
2050       depotBlockOffset = 0;
2051
2052       /* mark this block as being part of the big block depot
2053        */
2054       StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, BLOCK_SPECIAL);
2055       depotBlockOffset += sizeof(ULONG);
2056
2057       /* initialize blocks as free
2058        */
2059       while ((depotBlockOffset < blocksPerDepot))
2060       {
2061         StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, BLOCK_UNUSED);
2062         depotBlockOffset += sizeof(ULONG);
2063       }
2064
2065       Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2066
2067       /* Save the information to the file header
2068        */
2069       This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2070       This->bigBlockDepotCount++;
2071       Storage32Impl_SaveFileHeader(This);
2072     }
2073
2074     depotBuffer = Storage32Impl_GetROBigBlock(This, depotBlockIndexPos);
2075
2076     if (depotBuffer != 0)
2077     {
2078       depotBlockOffset = 0;
2079
2080       while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) && 
2081               ( nextBlockIndex != BLOCK_UNUSED))
2082       {
2083         StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2084
2085         if (nextBlockIndex != BLOCK_UNUSED)
2086           blockNoInSequence++;
2087
2088         depotBlockOffset += sizeof(ULONG);
2089       }
2090
2091       Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2092     }
2093
2094     depotIndex++;
2095   }
2096
2097   return blockNoInSequence;
2098 }
2099
2100 /******************************************************************************
2101  *      Storage32Impl_FreeBigBlock
2102  *
2103  * This method will flag the specified block as free in the big block depot.
2104  */
2105 void  Storage32Impl_FreeBigBlock(
2106   Storage32Impl* This,
2107   ULONG          blockIndex)
2108 {
2109   Storage32Impl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2110 }
2111
2112 /************************************************************************
2113  * Storage32Impl_GetNextBlockInChain
2114  *
2115  * This method will retrieve the block index of the next big block in
2116  * in the chain.
2117  *
2118  * Params:  This       - Pointer to the Storage object.
2119  *          blockIndex - Index of the block to retrieve the chain
2120  *                       for.
2121  *
2122  * Returns: This method returns the index of the next block in the chain.
2123  *          It will return the constants:
2124  *              BLOCK_SPECIAL - If the block given was not part of a
2125  *                              chain.
2126  *              BLOCK_END_OF_CHAIN - If the block given was the last in
2127  *                                   a chain.
2128  *              BLOCK_UNUSED - If the block given was not past of a chain
2129  *                             and is available.
2130  *          
2131  * See Windows documentation for more details on IStorage methods.
2132  */        
2133 ULONG Storage32Impl_GetNextBlockInChain(
2134   Storage32Impl* This,
2135   ULONG          blockIndex)
2136 {
2137   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
2138   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
2139   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2140   ULONG nextBlockIndex   = BLOCK_SPECIAL;
2141   void* depotBuffer;
2142   ULONG depotBlockIndexPos;
2143
2144   assert(depotBlockCount < This->bigBlockDepotCount);
2145   assert(depotBlockCount < COUNT_BBDEPOTINHEADER);
2146   
2147   depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2148   
2149   depotBuffer = Storage32Impl_GetROBigBlock(This, depotBlockIndexPos);
2150
2151   if (depotBuffer!=0)
2152   {
2153     StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2154     
2155     Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2156   }
2157   
2158   return nextBlockIndex;
2159 }
2160
2161 /******************************************************************************
2162  *      Storage32Impl_SetNextBlockInChain
2163  *
2164  * This method will write the index of the specified block's next block
2165  * in the big block depot.
2166  *
2167  * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2168  *              do the following
2169  *
2170  * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2171  * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2172  * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2173  *
2174  */
2175 void  Storage32Impl_SetNextBlockInChain(
2176           Storage32Impl* This,
2177           ULONG          blockIndex,
2178           ULONG          nextBlock)
2179 {
2180   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
2181   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
2182   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2183   ULONG depotBlockIndexPos;
2184   void* depotBuffer;
2185
2186   assert(depotBlockCount < This->bigBlockDepotCount);
2187   assert(depotBlockCount < COUNT_BBDEPOTINHEADER);
2188
2189   depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2190
2191   depotBuffer = Storage32Impl_GetBigBlock(This, depotBlockIndexPos);
2192
2193   if (depotBuffer!=0)
2194   {
2195     StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2196     Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2197   }
2198
2199   return;
2200 }
2201
2202 /******************************************************************************
2203  *      Storage32Impl_LoadFileHeader
2204  *
2205  * This method will read in the file header, i.e. big block index -1.
2206  */
2207 HRESULT Storage32Impl_LoadFileHeader(
2208           Storage32Impl* This)
2209 {
2210   HRESULT hr = STG_E_FILENOTFOUND;
2211   void*   headerBigBlock = NULL;
2212   int     index;
2213
2214   /*
2215    * Get a pointer to the big block of data containing the header.
2216    */
2217   headerBigBlock = Storage32Impl_GetROBigBlock(This, -1);
2218
2219   /*
2220    * Extract the information from the header.
2221    */
2222   if (headerBigBlock!=0)
2223   {
2224     /*
2225      * Check for the "magic number" signature and return an error if it is not
2226      * found.
2227      */
2228     if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2229     {
2230       Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2231       return STG_E_OLDFORMAT;
2232     }
2233
2234     if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2235     {
2236       Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2237       return STG_E_INVALIDHEADER;
2238     }
2239
2240     StorageUtl_ReadWord(
2241       headerBigBlock, 
2242       OFFSET_BIGBLOCKSIZEBITS,   
2243       &This->bigBlockSizeBits);
2244
2245     StorageUtl_ReadWord(
2246       headerBigBlock, 
2247       OFFSET_SMALLBLOCKSIZEBITS, 
2248       &This->smallBlockSizeBits);
2249
2250     StorageUtl_ReadDWord(
2251       headerBigBlock, 
2252       OFFSET_BBDEPOTCOUNT,      
2253       &This->bigBlockDepotCount);
2254
2255     StorageUtl_ReadDWord(
2256       headerBigBlock, 
2257       OFFSET_ROOTSTARTBLOCK,    
2258       &This->rootStartBlock);
2259
2260     StorageUtl_ReadDWord(
2261       headerBigBlock, 
2262       OFFSET_SBDEPOTSTART,      
2263       &This->smallBlockDepotStart);
2264
2265     StorageUtl_ReadDWord( 
2266       headerBigBlock, 
2267       OFFSET_EXTBBDEPOTSTART,   
2268       &This->extBigBlockDepotStart);
2269
2270     StorageUtl_ReadDWord(
2271       headerBigBlock, 
2272       OFFSET_EXTBBDEPOTCOUNT,   
2273       &This->extBigBlockDepotCount);
2274     
2275     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2276     {
2277       StorageUtl_ReadDWord(
2278         headerBigBlock, 
2279         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2280         &(This->bigBlockDepotStart[index]));
2281     }
2282     
2283     /*
2284      * Make the bitwise arithmetic to get the size of the blocks in bytes.
2285      */
2286     if ((1 << 2) == 4)
2287     {
2288       This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2289       This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2290     }
2291     else
2292     {
2293       This->bigBlockSize   = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2294       This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2295     }
2296     
2297     /*
2298      * Right now, the code is making some assumptions about the size of the 
2299      * blocks, just make sure they are what we're expecting.
2300      */
2301     assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) && 
2302             (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2303     
2304     /*
2305      * Release the block.
2306      */
2307     Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2308   }
2309   
2310   return hr;
2311 }
2312
2313 /******************************************************************************
2314  *      Storage32Impl_SaveFileHeader
2315  *
2316  * This method will save to the file the header, i.e. big block -1.
2317  */
2318 void Storage32Impl_SaveFileHeader(
2319           Storage32Impl* This)
2320 {
2321   BYTE   headerBigBlock[BIG_BLOCK_SIZE];
2322   int    index;
2323   BOOL32 success;
2324
2325   /*
2326    * Get a pointer to the big block of data containing the header.
2327    */
2328   success = Storage32Impl_ReadBigBlock(This, -1, headerBigBlock);
2329   
2330   /*
2331    * If the block read failed, the file is probably new.
2332    */
2333   if (!success)
2334   {
2335     /*
2336      * Initialize for all unknown fields.
2337      */
2338     memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2339     
2340     /*
2341      * Initialize the magic number.
2342      */
2343     memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2344     
2345     /*
2346      * And a bunch of things we don't know what they mean
2347      */
2348     StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
2349     StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
2350     StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
2351     StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2352     StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2353   }
2354   
2355   /*
2356    * Write the information to the header.
2357    */
2358   if (headerBigBlock!=0)
2359   {
2360     StorageUtl_WriteWord(
2361       headerBigBlock, 
2362       OFFSET_BIGBLOCKSIZEBITS,   
2363       This->bigBlockSizeBits);
2364
2365     StorageUtl_WriteWord(
2366       headerBigBlock, 
2367       OFFSET_SMALLBLOCKSIZEBITS, 
2368       This->smallBlockSizeBits);
2369
2370     StorageUtl_WriteDWord(
2371       headerBigBlock, 
2372       OFFSET_BBDEPOTCOUNT,      
2373       This->bigBlockDepotCount);
2374
2375     StorageUtl_WriteDWord(
2376       headerBigBlock, 
2377       OFFSET_ROOTSTARTBLOCK,    
2378       This->rootStartBlock);
2379
2380     StorageUtl_WriteDWord(
2381       headerBigBlock, 
2382       OFFSET_SBDEPOTSTART,      
2383       This->smallBlockDepotStart);
2384
2385     StorageUtl_WriteDWord(
2386       headerBigBlock, 
2387       OFFSET_EXTBBDEPOTSTART,   
2388       This->extBigBlockDepotStart);
2389
2390     StorageUtl_WriteDWord(
2391       headerBigBlock, 
2392       OFFSET_EXTBBDEPOTCOUNT,   
2393       This->extBigBlockDepotCount);
2394
2395     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2396     {
2397       StorageUtl_WriteDWord(
2398         headerBigBlock, 
2399         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2400         (This->bigBlockDepotStart[index]));
2401     }
2402   }
2403   
2404   /*
2405    * Write the big block back to the file.
2406    */
2407   Storage32Impl_WriteBigBlock(This, -1, headerBigBlock);
2408 }
2409
2410 /******************************************************************************
2411  *      Storage32Impl_ReadProperty
2412  *
2413  * This method will read the specified property from the property chain.
2414  */
2415 BOOL32 Storage32Impl_ReadProperty(
2416   Storage32Impl* This,
2417   ULONG          index,
2418   StgProperty*   buffer)
2419 {
2420   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
2421   ULARGE_INTEGER offsetInPropSet;
2422   BOOL32         readSucessful;
2423   ULONG          bytesRead;
2424   
2425   offsetInPropSet.HighPart = 0;
2426   offsetInPropSet.LowPart  = index * PROPSET_BLOCK_SIZE;
2427   
2428   readSucessful = BlockChainStream_ReadAt(
2429                     This->rootBlockChain,
2430                     offsetInPropSet,
2431                     PROPSET_BLOCK_SIZE,
2432                     currentProperty,
2433                     &bytesRead);
2434   
2435   if (readSucessful)
2436   {
2437     memset(buffer->name, 0, sizeof(buffer->name));
2438     memcpy(
2439       buffer->name, 
2440       currentProperty+OFFSET_PS_NAME, 
2441       PROPERTY_NAME_BUFFER_LEN );
2442
2443     memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2444     
2445     StorageUtl_ReadWord(
2446       currentProperty,  
2447       OFFSET_PS_NAMELENGTH,  
2448       &buffer->sizeOfNameString);
2449
2450     StorageUtl_ReadDWord(
2451       currentProperty, 
2452       OFFSET_PS_PREVIOUSPROP, 
2453       &buffer->previousProperty);
2454
2455     StorageUtl_ReadDWord(
2456       currentProperty, 
2457       OFFSET_PS_NEXTPROP,     
2458       &buffer->nextProperty);
2459
2460     StorageUtl_ReadDWord(
2461       currentProperty, 
2462       OFFSET_PS_DIRPROP,      
2463       &buffer->dirProperty);
2464
2465     StorageUtl_ReadGUID(
2466       currentProperty,  
2467       OFFSET_PS_GUID,        
2468       &buffer->propertyUniqueID);
2469
2470     StorageUtl_ReadDWord(
2471       currentProperty, 
2472       OFFSET_PS_TSS1,         
2473       &buffer->timeStampS1);
2474
2475     StorageUtl_ReadDWord(
2476       currentProperty, 
2477       OFFSET_PS_TSD1,         
2478       &buffer->timeStampD1);
2479
2480     StorageUtl_ReadDWord(
2481       currentProperty, 
2482       OFFSET_PS_TSS2,         
2483       &buffer->timeStampS2);
2484
2485     StorageUtl_ReadDWord(
2486       currentProperty, 
2487       OFFSET_PS_TSD2,         
2488       &buffer->timeStampD2);
2489
2490     StorageUtl_ReadDWord(
2491       currentProperty, 
2492       OFFSET_PS_STARTBLOCK,   
2493       &buffer->startingBlock);
2494
2495     StorageUtl_ReadDWord(
2496       currentProperty, 
2497       OFFSET_PS_SIZE,         
2498       &buffer->size.LowPart);
2499
2500     buffer->size.HighPart = 0;
2501   }
2502
2503   return readSucessful;
2504 }
2505
2506 /*********************************************************************
2507  * Write the specified property into the property chain
2508  */
2509 BOOL32 Storage32Impl_WriteProperty(
2510   Storage32Impl* This,
2511   ULONG          index,
2512   StgProperty*   buffer)
2513 {
2514   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
2515   ULARGE_INTEGER offsetInPropSet;
2516   BOOL32         writeSucessful;
2517   ULONG          bytesWritten;
2518
2519   offsetInPropSet.HighPart = 0;
2520   offsetInPropSet.LowPart  = index * PROPSET_BLOCK_SIZE;
2521
2522   memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2523
2524   memcpy(
2525     currentProperty + OFFSET_PS_NAME, 
2526     buffer->name, 
2527     PROPERTY_NAME_BUFFER_LEN );
2528
2529   memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
2530
2531   /* 
2532    * Reassign the size in case of mistake....
2533    */
2534   buffer->sizeOfNameString = (lstrlen32W(buffer->name)+1) * sizeof(WCHAR);
2535
2536   StorageUtl_WriteWord(
2537     currentProperty,  
2538       OFFSET_PS_NAMELENGTH,   
2539       buffer->sizeOfNameString);
2540
2541   StorageUtl_WriteDWord(
2542     currentProperty, 
2543       OFFSET_PS_PREVIOUSPROP, 
2544       buffer->previousProperty);
2545
2546   StorageUtl_WriteDWord(
2547     currentProperty, 
2548       OFFSET_PS_NEXTPROP,     
2549       buffer->nextProperty);
2550
2551   StorageUtl_WriteDWord(
2552     currentProperty, 
2553       OFFSET_PS_DIRPROP,      
2554       buffer->dirProperty);
2555
2556   StorageUtl_WriteGUID(
2557     currentProperty,  
2558       OFFSET_PS_GUID,        
2559       &buffer->propertyUniqueID);
2560
2561   StorageUtl_WriteDWord(
2562     currentProperty, 
2563       OFFSET_PS_TSS1,         
2564       buffer->timeStampS1);
2565
2566   StorageUtl_WriteDWord(
2567     currentProperty, 
2568       OFFSET_PS_TSD1,         
2569       buffer->timeStampD1);
2570
2571   StorageUtl_WriteDWord(
2572     currentProperty, 
2573       OFFSET_PS_TSS2,         
2574       buffer->timeStampS2);
2575
2576   StorageUtl_WriteDWord(
2577     currentProperty, 
2578       OFFSET_PS_TSD2,         
2579       buffer->timeStampD2);
2580
2581   StorageUtl_WriteDWord(
2582     currentProperty, 
2583       OFFSET_PS_STARTBLOCK,   
2584       buffer->startingBlock);
2585
2586   StorageUtl_WriteDWord(
2587     currentProperty, 
2588       OFFSET_PS_SIZE,         
2589       buffer->size.LowPart);
2590
2591   writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2592                                             offsetInPropSet,
2593                                             PROPSET_BLOCK_SIZE,
2594                                             currentProperty,
2595                                             &bytesWritten);
2596   return writeSucessful;
2597 }
2598
2599 BOOL32 Storage32Impl_ReadBigBlock(
2600   Storage32Impl* This,
2601   ULONG          blockIndex,
2602   void*          buffer)
2603 {
2604   void* bigBlockBuffer;
2605
2606   bigBlockBuffer = Storage32Impl_GetROBigBlock(This, blockIndex);
2607
2608   if (bigBlockBuffer!=0)
2609   {
2610     memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2611
2612     Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
2613
2614     return TRUE;
2615   }
2616
2617   return FALSE;
2618 }
2619
2620 BOOL32 Storage32Impl_WriteBigBlock(
2621   Storage32Impl* This,
2622   ULONG          blockIndex,
2623   void*          buffer)
2624 {
2625   void* bigBlockBuffer;
2626
2627   bigBlockBuffer = Storage32Impl_GetBigBlock(This, blockIndex);
2628
2629   if (bigBlockBuffer!=0)
2630   {
2631     memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2632
2633     Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
2634     
2635     return TRUE;
2636   }
2637   
2638   return FALSE;
2639 }
2640
2641 void* Storage32Impl_GetROBigBlock(
2642   Storage32Impl* This,
2643   ULONG          blockIndex)
2644 {
2645   return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2646 }
2647
2648 void* Storage32Impl_GetBigBlock(
2649   Storage32Impl* This,
2650   ULONG          blockIndex)
2651 {
2652   return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2653 }
2654
2655 void Storage32Impl_ReleaseBigBlock(
2656   Storage32Impl* This,
2657   void*          pBigBlock)
2658 {
2659   BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
2660 }
2661
2662 /******************************************************************************
2663  *              Storage32Impl_SmallBlocksToBigBlocks
2664  *
2665  * This method will convert a small block chain to a big block chain.
2666  * The small block chain will be destroyed.
2667  */
2668 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
2669                       Storage32Impl* This,
2670                       SmallBlockChainStream** ppsbChain)
2671 {
2672   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
2673   ULARGE_INTEGER size, offset;
2674   ULONG cbRead, cbWritten;
2675   ULONG propertyIndex;
2676   BOOL32 successRead, successWrite;
2677   StgProperty chainProperty;
2678   BYTE buffer[DEF_SMALL_BLOCK_SIZE];
2679   BlockChainStream *bbTempChain = NULL;
2680   BlockChainStream *bigBlockChain = NULL;
2681
2682   /*
2683    * Create a temporary big block chain that doesn't have
2684    * an associated property. This temporary chain will be
2685    * used to copy data from small blocks to big blocks.
2686    */
2687   bbTempChain = BlockChainStream_Construct(This,
2688                                            &bbHeadOfChain,
2689                                            PROPERTY_NULL);
2690
2691   /*
2692    * Grow the big block chain.
2693    */
2694   size = SmallBlockChainStream_GetSize(*ppsbChain);
2695   BlockChainStream_SetSize(bbTempChain, size);
2696
2697   /*
2698    * Copy the contents of the small block chain to the big block chain
2699    * by small block size increments.
2700    */
2701   offset.LowPart = 0;
2702   offset.HighPart = 0;
2703
2704   do
2705   {
2706     successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
2707                                                offset,
2708                                                sizeof(buffer),
2709                                                buffer,
2710                                                &cbRead);
2711     
2712     successWrite = BlockChainStream_WriteAt(bbTempChain,
2713                                             offset,
2714                                             sizeof(buffer),
2715                                             buffer,
2716                                             &cbWritten);
2717     offset.LowPart += This->smallBlockSize;
2718
2719   } while (successRead && successWrite);
2720
2721   assert(cbRead == cbWritten);
2722
2723   /*
2724    * Destroy the small block chain.
2725    */
2726   propertyIndex = (*ppsbChain)->ownerPropertyIndex;
2727   size.HighPart = 0;
2728   size.LowPart  = 0;
2729   SmallBlockChainStream_SetSize(*ppsbChain, size);
2730   SmallBlockChainStream_Destroy(*ppsbChain);
2731   *ppsbChain = 0;
2732
2733   /*
2734    * Change the property information. This chain is now a big block chain
2735    * and it doesn't reside in the small blocks chain anymore.
2736    */
2737   Storage32Impl_ReadProperty(This, propertyIndex, &chainProperty);
2738
2739   chainProperty.startingBlock = bbHeadOfChain;
2740
2741   Storage32Impl_WriteProperty(This, propertyIndex, &chainProperty);
2742
2743   /*
2744    * Destroy the temporary propertyless big block chain.
2745    * Create a new big block chain associated with this property.
2746    */
2747   BlockChainStream_Destroy(bbTempChain);
2748   bigBlockChain = BlockChainStream_Construct(This,
2749                                              NULL,
2750                                              propertyIndex);
2751
2752   return bigBlockChain;
2753 }
2754
2755 /******************************************************************************
2756 ** Storage32InternalImpl implementation
2757 */
2758
2759 Storage32InternalImpl* Storage32InternalImpl_Construct(
2760   Storage32Impl* ancestorStorage,  
2761   ULONG          rootPropertyIndex)
2762 {
2763   Storage32InternalImpl* newStorage;
2764
2765   /*
2766    * Allocate space for the new storage object
2767    */
2768   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32InternalImpl));
2769
2770   if (newStorage!=0)
2771   {
2772     memset(newStorage, 0, sizeof(Storage32InternalImpl));
2773
2774     /*
2775      * Initialize the virtual function table.
2776      */
2777     newStorage->lpvtbl       = &Storage32InternalImpl_Vtbl;
2778     newStorage->v_destructor = &Storage32InternalImpl_Destroy;
2779
2780     /*
2781      * Keep the ancestor storage pointer and nail a reference to it.
2782      */
2783     newStorage->ancestorStorage = ancestorStorage;
2784     Storage32BaseImpl_AddRef((IStorage32*)(newStorage->ancestorStorage));
2785
2786     /*
2787      * Keep the index of the root property set for this storage,
2788      */
2789     newStorage->rootPropertySetIndex = rootPropertyIndex;
2790
2791     return newStorage;
2792   }
2793
2794   return 0;
2795 }
2796
2797 void Storage32InternalImpl_Destroy(
2798   Storage32InternalImpl* This)
2799 {
2800   HeapFree(GetProcessHeap(), 0, This);
2801 }
2802
2803 /******************************************************************************
2804 **
2805 ** Storage32InternalImpl_Commit
2806 **
2807 ** The non-root storages cannot be opened in transacted mode thus this function
2808 ** does nothing.
2809 */
2810 HRESULT WINAPI Storage32InternalImpl_Commit( 
2811   IStorage32*            iface,
2812   DWORD                  grfCommitFlags)  /* [in] */ 
2813 {
2814   return S_OK;
2815 }
2816         
2817 /******************************************************************************
2818 **
2819 ** Storage32InternalImpl_Revert
2820 **
2821 ** The non-root storages cannot be opened in transacted mode thus this function
2822 ** does nothing.
2823 */
2824 HRESULT WINAPI Storage32InternalImpl_Revert( 
2825   IStorage32*            iface)
2826 {
2827   return S_OK;
2828 }
2829
2830 /******************************************************************************
2831 ** IEnumSTATSTGImpl implementation
2832 */
2833
2834 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
2835   Storage32Impl* parentStorage,
2836   ULONG          firstPropertyNode)
2837 {
2838   IEnumSTATSTGImpl* newEnumeration;
2839
2840   newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
2841   
2842   if (newEnumeration!=0)
2843   {
2844     /*
2845      * Set-up the virtual function table and reference count.
2846      */
2847     newEnumeration->lpvtbl = &IEnumSTATSTGImpl_Vtbl;
2848     newEnumeration->ref    = 0;
2849     
2850     /*
2851      * We want to nail-down the reference to the storage in case the
2852      * enumeration out-lives the storage in the client application.
2853      */
2854     newEnumeration->parentStorage = parentStorage;
2855     IStorage32_AddRef((IStorage32*)newEnumeration->parentStorage);
2856     
2857     newEnumeration->firstPropertyNode   = firstPropertyNode;
2858     
2859     /*
2860      * Initialize the search stack
2861      */
2862     newEnumeration->stackSize    = 0;
2863     newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
2864     newEnumeration->stackToVisit = 
2865       HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
2866     
2867     /*
2868      * Make sure the current node of the iterator is the first one.
2869      */
2870     IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
2871   }
2872   
2873   return newEnumeration;
2874 }
2875
2876 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
2877 {
2878   IStorage32_Release((IStorage32*)This->parentStorage);
2879   HeapFree(GetProcessHeap(), 0, This->stackToVisit);
2880   HeapFree(GetProcessHeap(), 0, This);
2881 }
2882
2883 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
2884   IEnumSTATSTG*     iface,
2885   REFIID            riid,
2886   void**            ppvObject)
2887 {
2888   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
2889
2890   /*
2891    * Perform a sanity check on the parameters.
2892    */
2893   if (ppvObject==0)
2894     return E_INVALIDARG;
2895
2896   /*
2897    * Initialize the return parameter.
2898    */
2899   *ppvObject = 0;
2900
2901   /*
2902    * Compare the riid with the interface IDs implemented by this object.
2903    */
2904   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
2905   {
2906     *ppvObject = (IEnumSTATSTG*)This;
2907   }
2908   else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0) 
2909   {
2910     *ppvObject = (IEnumSTATSTG*)This;
2911   }
2912
2913   /*
2914    * Check that we obtained an interface.
2915    */
2916   if ((*ppvObject)==0)
2917     return E_NOINTERFACE;
2918
2919   /*
2920    * Query Interface always increases the reference count by one when it is
2921    * successful
2922    */
2923   IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
2924
2925   return S_OK;
2926 }
2927         
2928 ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
2929   IEnumSTATSTG* iface)
2930 {
2931   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
2932
2933   This->ref++;
2934   return This->ref;
2935 }
2936         
2937 ULONG   WINAPI IEnumSTATSTGImpl_Release(
2938   IEnumSTATSTG* iface)
2939 {
2940   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
2941
2942   ULONG newRef;
2943
2944   This->ref--;
2945   newRef = This->ref;
2946
2947   /*
2948    * If the reference count goes down to 0, perform suicide.
2949    */
2950   if (newRef==0)
2951   {
2952     IEnumSTATSTGImpl_Destroy(This);
2953   }
2954
2955   return newRef;;
2956 }
2957
2958 HRESULT WINAPI IEnumSTATSTGImpl_Next(
2959   IEnumSTATSTG* iface,
2960   ULONG             celt,
2961   STATSTG*          rgelt,
2962   ULONG*            pceltFetched)
2963 {
2964   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
2965
2966   StgProperty currentProperty;
2967   STATSTG*    currentReturnStruct = rgelt;
2968   ULONG       objectFetched       = 0;
2969   ULONG      currentSearchNode;
2970
2971   /*
2972    * Perform a sanity check on the parameters.
2973    */
2974   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
2975     return E_INVALIDARG;  
2976   
2977   /*
2978    * To avoid the special case, get another pointer to a ULONG value if
2979    * the caller didn't supply one.
2980    */
2981   if (pceltFetched==0)
2982     pceltFetched = &objectFetched;
2983   
2984   /*
2985    * Start the iteration, we will iterate until we hit the end of the
2986    * linked list or until we hit the number of items to iterate through
2987    */
2988   *pceltFetched = 0;
2989
2990   /*
2991    * Start with the node at the top of the stack.
2992    */
2993   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
2994
2995   while ( ( *pceltFetched < celt) && 
2996           ( currentSearchNode!=PROPERTY_NULL) )
2997   {
2998     /* 
2999      * Remove the top node from the stack
3000      */
3001     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3002
3003     /*
3004      * Read the property from the storage.
3005      */
3006     Storage32Impl_ReadProperty(This->parentStorage,
3007       currentSearchNode, 
3008       &currentProperty);
3009
3010     /*
3011      * Copy the information to the return buffer.
3012      */
3013     StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3014       &currentProperty,
3015       STATFLAG_DEFAULT);
3016         
3017     /*
3018      * Step to the next item in the iteration
3019      */
3020     (*pceltFetched)++;
3021     currentReturnStruct++;
3022
3023     /*
3024      * Push the next search node in the search stack.
3025      */
3026     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3027
3028     /*
3029      * continue the iteration.
3030      */
3031     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3032   }
3033
3034   if (*pceltFetched == celt)
3035     return S_OK;
3036
3037   return S_FALSE;
3038 }
3039
3040         
3041 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3042   IEnumSTATSTG* iface,
3043   ULONG             celt)
3044 {
3045   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3046
3047   StgProperty currentProperty;
3048   ULONG       objectFetched       = 0;
3049   ULONG       currentSearchNode;
3050
3051   /*
3052    * Start with the node at the top of the stack.
3053    */
3054   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3055
3056   while ( (objectFetched < celt) && 
3057           (currentSearchNode!=PROPERTY_NULL) )
3058   {
3059     /* 
3060      * Remove the top node from the stack
3061      */
3062     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3063
3064     /*
3065      * Read the property from the storage.
3066      */
3067     Storage32Impl_ReadProperty(This->parentStorage,
3068       currentSearchNode, 
3069       &currentProperty);
3070     
3071     /*
3072      * Step to the next item in the iteration
3073      */
3074     objectFetched++;
3075
3076     /*
3077      * Push the next search node in the search stack.
3078      */
3079     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3080
3081     /*
3082      * continue the iteration.
3083      */
3084     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3085   }
3086
3087   if (objectFetched == celt)
3088     return S_OK;
3089
3090   return S_FALSE;
3091 }
3092         
3093 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3094   IEnumSTATSTG* iface)
3095 {
3096   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3097
3098   StgProperty rootProperty;
3099   BOOL32      readSucessful;
3100
3101   /*
3102    * Re-initialize the search stack to an empty stack
3103    */
3104   This->stackSize = 0;
3105
3106   /*
3107    * Read the root property from the storage.
3108    */
3109   readSucessful = Storage32Impl_ReadProperty(
3110                     This->parentStorage,
3111                     This->firstPropertyNode, 
3112                     &rootProperty);
3113
3114   if (readSucessful)
3115   {
3116     assert(rootProperty.sizeOfNameString!=0);
3117
3118     /*
3119      * Push the search node in the search stack.
3120      */
3121     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3122   }
3123
3124   return S_OK;
3125 }
3126         
3127 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3128   IEnumSTATSTG* iface,
3129   IEnumSTATSTG**    ppenum)
3130 {
3131   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3132
3133   IEnumSTATSTGImpl* newClone;
3134
3135   /*
3136    * Perform a sanity check on the parameters.
3137    */
3138   if (ppenum==0)
3139     return E_INVALIDARG;
3140   
3141   newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3142                This->firstPropertyNode);
3143
3144   
3145   /*
3146    * The new clone enumeration must point to the same current node as
3147    * the ole one.
3148    */
3149   newClone->stackSize    = This->stackSize    ;
3150   newClone->stackMaxSize = This->stackMaxSize ;
3151   newClone->stackToVisit = 
3152     HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3153
3154   memcpy(
3155     newClone->stackToVisit, 
3156     This->stackToVisit, 
3157     sizeof(ULONG) * newClone->stackSize);
3158
3159   *ppenum = (IEnumSTATSTG*)newClone;
3160
3161   /*
3162    * Don't forget to nail down a reference to the clone before
3163    * returning it.
3164    */
3165   IEnumSTATSTGImpl_AddRef(*ppenum);
3166
3167   return S_OK;
3168 }
3169
3170 INT32 IEnumSTATSTGImpl_FindParentProperty(
3171   IEnumSTATSTGImpl *This,
3172   ULONG             childProperty, 
3173   StgProperty      *currentProperty,
3174   ULONG            *thisNodeId)
3175 {
3176   ULONG currentSearchNode;
3177   ULONG foundNode;
3178
3179   /*
3180    * To avoid the special case, get another pointer to a ULONG value if
3181    * the caller didn't supply one.
3182    */
3183   if (thisNodeId==0)
3184     thisNodeId = &foundNode;
3185
3186   /*
3187    * Start with the node at the top of the stack.
3188    */
3189   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3190   
3191
3192   while (currentSearchNode!=PROPERTY_NULL)
3193   {
3194     /*
3195      * Store the current node in the returned parameters
3196      */
3197     *thisNodeId = currentSearchNode;
3198
3199     /* 
3200      * Remove the top node from the stack
3201      */
3202     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3203
3204     /*
3205      * Read the property from the storage.
3206      */
3207     Storage32Impl_ReadProperty(
3208       This->parentStorage,
3209       currentSearchNode, 
3210       currentProperty);
3211       
3212     if (currentProperty->previousProperty == childProperty)
3213       return PROPERTY_RELATION_PREVIOUS;
3214
3215     else if (currentProperty->nextProperty == childProperty)  
3216       return PROPERTY_RELATION_NEXT;
3217   
3218     else if (currentProperty->dirProperty == childProperty)
3219       return PROPERTY_RELATION_DIR;
3220        
3221     /*
3222      * Push the next search node in the search stack.
3223      */
3224     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3225
3226     /*
3227      * continue the iteration.
3228      */
3229     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3230   }
3231
3232   return PROPERTY_NULL;
3233 }
3234
3235 ULONG IEnumSTATSTGImpl_FindProperty(
3236   IEnumSTATSTGImpl* This,
3237   const OLECHAR32*  lpszPropName,
3238   StgProperty*      currentProperty)
3239 {
3240   ULONG currentSearchNode;
3241
3242   /*
3243    * Start with the node at the top of the stack.
3244    */
3245   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3246
3247   while (currentSearchNode!=PROPERTY_NULL)
3248   {
3249     /* 
3250      * Remove the top node from the stack
3251      */
3252     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3253
3254     /*
3255      * Read the property from the storage.
3256      */
3257     Storage32Impl_ReadProperty(This->parentStorage,
3258       currentSearchNode, 
3259       currentProperty);
3260
3261     if ( propertyNameCmp(
3262           (OLECHAR32*)currentProperty->name, 
3263           (OLECHAR32*)lpszPropName) == 0)
3264       return currentSearchNode;
3265
3266     /*
3267      * Push the next search node in the search stack.
3268      */
3269     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3270
3271     /*
3272      * continue the iteration.
3273      */
3274     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3275   }
3276
3277   return PROPERTY_NULL;
3278 }
3279
3280 void IEnumSTATSTGImpl_PushSearchNode(
3281   IEnumSTATSTGImpl* This,
3282   ULONG             nodeToPush)
3283 {
3284   StgProperty rootProperty;
3285   BOOL32      readSucessful;
3286
3287   /*
3288    * First, make sure we're not trying to push an unexisting node.
3289    */
3290   if (nodeToPush==PROPERTY_NULL)
3291     return;
3292
3293   /*
3294    * First push the node to the stack
3295    */
3296   if (This->stackSize == This->stackMaxSize)
3297   {
3298     This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3299
3300     This->stackToVisit = HeapReAlloc(
3301                            GetProcessHeap(), 
3302                            0,
3303                            This->stackToVisit,
3304                            sizeof(ULONG) * This->stackMaxSize);
3305   }
3306
3307   This->stackToVisit[This->stackSize] = nodeToPush;
3308   This->stackSize++;
3309
3310   /*
3311    * Read the root property from the storage.
3312    */
3313   readSucessful = Storage32Impl_ReadProperty(
3314                     This->parentStorage,
3315                     nodeToPush, 
3316                     &rootProperty);
3317
3318   if (readSucessful)
3319   {
3320     assert(rootProperty.sizeOfNameString!=0);
3321
3322     /*
3323      * Push the previous search node in the search stack.
3324      */
3325     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3326   }
3327 }
3328
3329 ULONG IEnumSTATSTGImpl_PopSearchNode(
3330   IEnumSTATSTGImpl* This,
3331   BOOL32            remove)
3332 {
3333   ULONG topNode;
3334
3335   if (This->stackSize == 0)
3336     return PROPERTY_NULL;
3337
3338   topNode = This->stackToVisit[This->stackSize-1];
3339
3340   if (remove)
3341     This->stackSize--;
3342
3343   return topNode;
3344 }
3345
3346 /******************************************************************************
3347 ** StorageUtl implementation
3348 */
3349
3350 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3351 {
3352   memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3353 }
3354
3355 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3356 {
3357   memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3358 }
3359
3360 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3361 {
3362   memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3363 }
3364
3365 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3366 {
3367   memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3368 }
3369
3370 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3371 {
3372   StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
3373   StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
3374   StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
3375
3376   memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3377 }
3378
3379 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3380 {
3381   StorageUtl_WriteDWord(buffer, offset,   value->Data1);
3382   StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
3383   StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
3384
3385   memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3386 }
3387
3388 void StorageUtl_CopyPropertyToSTATSTG(
3389   STATSTG*     destination,
3390   StgProperty* source,
3391   int          statFlags)
3392 {
3393   /*
3394    * The copy of the string occurs only when the flag is not set
3395    */
3396   if ((statFlags & STATFLAG_NONAME) != 0)
3397   {
3398     destination->pwcsName = 0;
3399   }
3400   else
3401   {
3402     destination->pwcsName = 
3403       CoTaskMemAlloc((lstrlen32W(source->name)+1)*sizeof(WCHAR));
3404
3405     lstrcpy32W((LPWSTR)destination->pwcsName, source->name);
3406   }
3407   
3408   switch (source->propertyType)
3409   {
3410     case PROPTYPE_STORAGE:
3411     case PROPTYPE_ROOT:
3412       destination->type = STGTY_STORAGE;
3413       break;
3414     case PROPTYPE_STREAM:
3415       destination->type = STGTY_STREAM;
3416       break;
3417     default:
3418       destination->type = STGTY_STREAM;
3419       break;        
3420   }
3421
3422   destination->cbSize            = source->size;
3423 /*    
3424   currentReturnStruct->mtime     = {0}; TODO
3425   currentReturnStruct->ctime     = {0};
3426   currentReturnStruct->atime     = {0}; 
3427 */
3428   destination->grfMode           = 0;
3429   destination->grfLocksSupported = 0; 
3430   destination->clsid             = source->propertyUniqueID;
3431   destination->grfStateBits      = 0; 
3432   destination->reserved          = 0; 
3433 }
3434
3435 /******************************************************************************
3436 ** BlockChainStream implementation
3437 */
3438
3439 BlockChainStream* BlockChainStream_Construct(
3440   Storage32Impl* parentStorage,  
3441   ULONG*         headOfStreamPlaceHolder,
3442   ULONG          propertyIndex)
3443 {
3444   BlockChainStream* newStream;
3445
3446   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
3447
3448   newStream->parentStorage           = parentStorage;
3449   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
3450   newStream->ownerPropertyIndex      = propertyIndex;
3451
3452   return newStream;
3453 }
3454
3455 void BlockChainStream_Destroy(BlockChainStream* This)
3456 {
3457   HeapFree(GetProcessHeap(), 0, This);
3458 }
3459
3460 /******************************************************************************
3461  *      BlockChainStream_GetHeadOfChain
3462  *
3463  * Returns the head of this stream chain.
3464  * Some special chains don't have properties, their heads are kept in
3465  * This->headOfStreamPlaceHolder.
3466  *
3467  */
3468 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
3469 {
3470   StgProperty chainProperty;
3471   BOOL32      readSucessful;
3472
3473   if (This->headOfStreamPlaceHolder != 0)
3474     return *(This->headOfStreamPlaceHolder);
3475
3476   if (This->ownerPropertyIndex != PROPERTY_NULL)
3477   {
3478     readSucessful = Storage32Impl_ReadProperty(
3479                       This->parentStorage,
3480                       This->ownerPropertyIndex,
3481                       &chainProperty);
3482
3483     if (readSucessful)
3484     {
3485       return chainProperty.startingBlock;
3486     }
3487   }
3488
3489   return BLOCK_END_OF_CHAIN;
3490 }
3491
3492 /******************************************************************************
3493  *       BlockChainStream_GetCount
3494  *
3495  * Returns the number of blocks that comprises this chain.
3496  * This is not the size of the stream as the last block may not be full!
3497  * 
3498  */
3499 ULONG BlockChainStream_GetCount(BlockChainStream* This)
3500 {
3501   ULONG blockIndex;
3502   ULONG count = 0;
3503
3504   blockIndex = BlockChainStream_GetHeadOfChain(This);
3505
3506   while (blockIndex != BLOCK_END_OF_CHAIN)
3507   {
3508     count++;
3509
3510     blockIndex = Storage32Impl_GetNextBlockInChain(
3511                    This->parentStorage, 
3512                    blockIndex);
3513   }
3514
3515   return count;
3516 }
3517
3518 /******************************************************************************
3519  *      BlockChainStream_ReadAt 
3520  *
3521  * Reads a specified number of bytes from this chain at the specified offset.
3522  * bytesRead may be NULL.
3523  * Failure will be returned if the specified number of bytes has not been read.
3524  */
3525 BOOL32 BlockChainStream_ReadAt(BlockChainStream* This,
3526   ULARGE_INTEGER offset,
3527   ULONG          size,
3528   void*          buffer,
3529   ULONG*         bytesRead)
3530 {
3531   ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3532   ULONG offsetInBlock     = offset.LowPart % This->parentStorage->bigBlockSize;
3533   ULONG bytesToReadInBuffer;
3534   ULONG blockIndex;
3535   BYTE* bufferWalker;
3536   BYTE* bigBlockBuffer;
3537
3538   /*
3539    * Find the first block in the stream that contains part of the buffer.
3540    */
3541   blockIndex = BlockChainStream_GetHeadOfChain(This);
3542
3543   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
3544   {
3545     blockIndex = 
3546       Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3547     
3548     blockNoInSequence--;
3549   }
3550
3551   /*
3552    * Start reading the buffer.
3553    */
3554   *bytesRead   = 0;
3555   bufferWalker = buffer;
3556   
3557   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3558   {
3559     /*
3560      * Calculate how many bytes we can copy from this big block.
3561      */
3562     bytesToReadInBuffer = 
3563       MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3564     
3565     /*
3566      * Copy those bytes to the buffer
3567      */
3568     bigBlockBuffer = 
3569       Storage32Impl_GetROBigBlock(This->parentStorage, blockIndex);
3570     
3571     memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
3572     
3573     Storage32Impl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3574     
3575     /*
3576      * Step to the next big block.
3577      */
3578     blockIndex    = 
3579       Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3580
3581     bufferWalker += bytesToReadInBuffer;
3582     size         -= bytesToReadInBuffer;
3583     *bytesRead   += bytesToReadInBuffer;
3584     offsetInBlock = 0;  /* There is no offset on the next block */
3585
3586   }
3587   
3588   return (size == 0);
3589 }
3590
3591 /******************************************************************************
3592  *      BlockChainStream_WriteAt
3593  *
3594  * Writes the specified number of bytes to this chain at the specified offset.
3595  * bytesWritten may be NULL.
3596  * Will fail if not all specified number of bytes have been written.
3597  */
3598 BOOL32 BlockChainStream_WriteAt(BlockChainStream* This,
3599   ULARGE_INTEGER    offset,
3600   ULONG             size,
3601   const void*       buffer,
3602   ULONG*            bytesWritten)
3603 {
3604   ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3605   ULONG offsetInBlock     = offset.LowPart % This->parentStorage->bigBlockSize;
3606   ULONG bytesToWrite;
3607   ULONG blockIndex;
3608   BYTE* bufferWalker;
3609   BYTE* bigBlockBuffer;
3610
3611   /*
3612    * Find the first block in the stream that contains part of the buffer.
3613    */
3614   blockIndex = BlockChainStream_GetHeadOfChain(This);
3615   
3616   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
3617   {
3618     blockIndex = 
3619       Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3620     
3621     blockNoInSequence--;
3622   }
3623
3624   /*
3625    * Here, I'm casting away the constness on the buffer variable
3626    * This is OK since we don't intend to modify that buffer.
3627    */
3628   *bytesWritten   = 0;
3629   bufferWalker = (BYTE*)buffer;
3630
3631   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3632   {
3633     /*
3634      * Calculate how many bytes we can copy from this big block.
3635      */
3636     bytesToWrite = 
3637       MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3638     
3639     /*
3640      * Copy those bytes to the buffer
3641      */
3642     bigBlockBuffer = Storage32Impl_GetBigBlock(This->parentStorage, blockIndex);
3643     
3644     memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
3645     
3646     Storage32Impl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3647     
3648     /*
3649      * Step to the next big block.
3650      */
3651     blockIndex    = 
3652       Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3653
3654     bufferWalker  += bytesToWrite;
3655     size          -= bytesToWrite;
3656     *bytesWritten += bytesToWrite;
3657     offsetInBlock  = 0;      /* There is no offset on the next block */
3658   }
3659   
3660   return (size == 0);
3661 }
3662
3663 /******************************************************************************
3664  *      BlockChainStream_Shrink
3665  *
3666  * Shrinks this chain in the big block depot.
3667  */
3668 BOOL32 BlockChainStream_Shrink(BlockChainStream* This,
3669                                ULARGE_INTEGER    newSize)
3670 {
3671   ULONG blockIndex, extraBlock;
3672   ULONG numBlocks;
3673   ULONG count = 1;
3674
3675   /*
3676    * Figure out how many blocks are needed to contain the new size
3677    */
3678   numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3679
3680   if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3681     numBlocks++;
3682
3683   blockIndex = BlockChainStream_GetHeadOfChain(This);
3684
3685   /*
3686    * Go to the new end of chain
3687    */
3688   while (count < numBlocks)
3689   {
3690     blockIndex = 
3691       Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3692
3693     count++;
3694   }
3695
3696   /* Get the next block before marking the new end */
3697   extraBlock = 
3698     Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3699
3700   /* Mark the new end of chain */
3701   Storage32Impl_SetNextBlockInChain(
3702     This->parentStorage, 
3703     blockIndex, 
3704     BLOCK_END_OF_CHAIN);
3705
3706   /*
3707    * Mark the extra blocks as free
3708    */
3709   while (extraBlock != BLOCK_END_OF_CHAIN)
3710   {
3711     blockIndex = 
3712       Storage32Impl_GetNextBlockInChain(This->parentStorage, extraBlock);
3713
3714     Storage32Impl_FreeBigBlock(This->parentStorage, extraBlock);
3715     extraBlock = blockIndex;
3716   }
3717
3718   return TRUE;
3719 }
3720
3721 /******************************************************************************
3722  *      BlockChainStream_Enlarge
3723  *
3724  * Grows this chain in the big block depot.
3725  */
3726 BOOL32 BlockChainStream_Enlarge(BlockChainStream* This,
3727                                 ULARGE_INTEGER    newSize)
3728 {
3729   ULONG blockIndex, currentBlock;
3730   ULONG newNumBlocks;
3731   ULONG oldNumBlocks = 0;
3732
3733   blockIndex = BlockChainStream_GetHeadOfChain(This);
3734
3735   /*
3736    * Empty chain. Create the head.
3737    */
3738   if (blockIndex == BLOCK_END_OF_CHAIN)
3739   {
3740     blockIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
3741     Storage32Impl_SetNextBlockInChain(This->parentStorage,
3742                                       blockIndex,
3743                                       BLOCK_END_OF_CHAIN);
3744
3745     if (This->headOfStreamPlaceHolder != 0)
3746     {
3747       *(This->headOfStreamPlaceHolder) = blockIndex;
3748     }
3749     else
3750     {
3751     StgProperty chainProp;
3752     assert(This->ownerPropertyIndex != PROPERTY_NULL);
3753
3754     Storage32Impl_ReadProperty(
3755       This->parentStorage, 
3756       This->ownerPropertyIndex,
3757       &chainProp);
3758
3759       chainProp.startingBlock = blockIndex; 
3760
3761     Storage32Impl_WriteProperty(
3762       This->parentStorage, 
3763       This->ownerPropertyIndex,
3764       &chainProp);
3765   }
3766   }
3767
3768   currentBlock = blockIndex;
3769
3770   /*
3771    * Figure out how many blocks are needed to contain this stream
3772    */
3773   newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3774
3775   if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3776     newNumBlocks++;
3777
3778   /*
3779    * Go to the current end of chain
3780    */
3781   while (blockIndex != BLOCK_END_OF_CHAIN)
3782   {
3783     oldNumBlocks++;
3784     currentBlock = blockIndex;
3785
3786     blockIndex = 
3787       Storage32Impl_GetNextBlockInChain(This->parentStorage, currentBlock);
3788   }
3789
3790   /*
3791    * Add new blocks to the chain
3792    */
3793   while (oldNumBlocks < newNumBlocks)
3794   {
3795     blockIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
3796
3797     Storage32Impl_SetNextBlockInChain(
3798       This->parentStorage, 
3799       currentBlock, 
3800       blockIndex);
3801
3802     Storage32Impl_SetNextBlockInChain(
3803       This->parentStorage, 
3804       blockIndex, 
3805       BLOCK_END_OF_CHAIN);
3806
3807     currentBlock = blockIndex;
3808     oldNumBlocks++;
3809   }
3810
3811   return TRUE;
3812 }
3813
3814 /******************************************************************************
3815  *      BlockChainStream_SetSize
3816  *
3817  * Sets the size of this stream. The big block depot will be updated.
3818  * The file will grow if we grow the chain.
3819  *
3820  * TODO: Free the actual blocks in the file when we shrink the chain.
3821  *       Currently, the blocks are still in the file. So the file size
3822  *       doesn't shrink even if we shrink streams. 
3823  */
3824 BOOL32 BlockChainStream_SetSize(
3825   BlockChainStream* This,
3826   ULARGE_INTEGER    newSize)
3827 {
3828   ULARGE_INTEGER size = BlockChainStream_GetSize(This);
3829
3830   if (newSize.LowPart == size.LowPart)
3831     return TRUE;
3832
3833   if (newSize.LowPart < size.LowPart)
3834   {
3835     BlockChainStream_Shrink(This, newSize);
3836   }
3837   else
3838   {
3839     ULARGE_INTEGER fileSize = 
3840       BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
3841
3842     ULONG diff = newSize.LowPart - size.LowPart;
3843
3844     /*
3845      * Make sure the file stays a multiple of blocksize
3846      */
3847     if ((diff % This->parentStorage->bigBlockSize) != 0)
3848       diff += (This->parentStorage->bigBlockSize - 
3849                 (diff % This->parentStorage->bigBlockSize) );
3850
3851     fileSize.LowPart += diff;
3852     BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
3853
3854     BlockChainStream_Enlarge(This, newSize);
3855   }
3856
3857   return TRUE;
3858 }
3859
3860 /******************************************************************************
3861  *      BlockChainStream_GetSize
3862  *
3863  * Returns the size of this chain.
3864  * Will return the block count if this chain doesn't have a property.
3865  */
3866 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
3867 {
3868   StgProperty chainProperty;
3869
3870   if(This->headOfStreamPlaceHolder == NULL)
3871   {
3872     /* 
3873      * This chain is a data stream read the property and return 
3874      * the appropriate size
3875      */
3876     Storage32Impl_ReadProperty(
3877       This->parentStorage,
3878       This->ownerPropertyIndex,
3879       &chainProperty);
3880
3881     return chainProperty.size;
3882   }
3883   else
3884   {
3885     /*
3886      * this chain is a chain that does not have a property, figure out the 
3887      * size by making the product number of used blocks times the 
3888      * size of them
3889      */
3890     ULARGE_INTEGER result;
3891     result.HighPart = 0;
3892
3893     result.LowPart  = 
3894       BlockChainStream_GetCount(This) * 
3895       This->parentStorage->bigBlockSize;
3896
3897     return result;
3898   }
3899 }
3900
3901 /******************************************************************************
3902 ** SmallBlockChainStream implementation
3903 */
3904
3905 SmallBlockChainStream* SmallBlockChainStream_Construct(
3906   Storage32Impl* parentStorage,  
3907   ULONG          propertyIndex)
3908 {
3909   SmallBlockChainStream* newStream;
3910
3911   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
3912
3913   newStream->parentStorage      = parentStorage;
3914   newStream->ownerPropertyIndex = propertyIndex;
3915
3916   return newStream;
3917 }
3918
3919 void SmallBlockChainStream_Destroy(
3920   SmallBlockChainStream* This)
3921 {
3922   HeapFree(GetProcessHeap(), 0, This);
3923 }
3924
3925 /******************************************************************************
3926  *      SmallBlockChainStream_GetHeadOfChain
3927  *
3928  * Returns the head of this chain of small blocks.
3929  */
3930 ULONG SmallBlockChainStream_GetHeadOfChain(
3931   SmallBlockChainStream* This)
3932 {
3933   StgProperty chainProperty;
3934   BOOL32      readSucessful;
3935
3936   if (This->ownerPropertyIndex)
3937   {
3938     readSucessful = Storage32Impl_ReadProperty(
3939                       This->parentStorage,
3940                       This->ownerPropertyIndex,
3941                       &chainProperty);
3942
3943     if (readSucessful)
3944     {
3945       return chainProperty.startingBlock;
3946     }
3947
3948   }
3949
3950   return BLOCK_END_OF_CHAIN;
3951 }
3952
3953 /******************************************************************************
3954  *      SmallBlockChainStream_GetNextBlockInChain
3955  *
3956  * Returns the index of the next small block in this chain.
3957  * 
3958  * Return Values:
3959  *    - BLOCK_END_OF_CHAIN: end of this chain
3960  *    - BLOCK_UNUSED: small block 'blockIndex' is free
3961  */
3962 ULONG SmallBlockChainStream_GetNextBlockInChain(
3963   SmallBlockChainStream* This,
3964   ULONG                  blockIndex)
3965 {
3966   ULARGE_INTEGER offsetOfBlockInDepot;
3967   DWORD  buffer;
3968   ULONG  nextBlockInChain = BLOCK_END_OF_CHAIN;
3969   ULONG  bytesRead;
3970   BOOL32 success;
3971
3972   offsetOfBlockInDepot.HighPart = 0;
3973   offsetOfBlockInDepot.LowPart  = blockIndex * sizeof(ULONG);
3974
3975   /*
3976    * Read those bytes in the buffer from the small block file.
3977    */
3978   success = BlockChainStream_ReadAt(
3979               This->parentStorage->smallBlockDepotChain,
3980               offsetOfBlockInDepot,
3981               sizeof(DWORD),
3982               &buffer,
3983               &bytesRead);
3984
3985   if (success)
3986   {
3987     StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
3988   }
3989
3990   return nextBlockInChain;
3991 }
3992
3993 /******************************************************************************
3994  *       SmallBlockChainStream_SetNextBlockInChain
3995  *
3996  * Writes the index of the next block of the specified block in the small
3997  * block depot.
3998  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
3999  * To flag a block as free use BLOCK_UNUSED as nextBlock.
4000  */
4001 void SmallBlockChainStream_SetNextBlockInChain(
4002   SmallBlockChainStream* This,
4003   ULONG                  blockIndex,
4004   ULONG                  nextBlock)
4005 {
4006   ULARGE_INTEGER offsetOfBlockInDepot;
4007   DWORD  buffer;
4008   ULONG  bytesWritten;
4009
4010   offsetOfBlockInDepot.HighPart = 0;
4011   offsetOfBlockInDepot.LowPart  = blockIndex * sizeof(ULONG);
4012
4013   StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4014
4015   /*
4016    * Read those bytes in the buffer from the small block file.
4017    */
4018   BlockChainStream_WriteAt(
4019     This->parentStorage->smallBlockDepotChain,
4020     offsetOfBlockInDepot,
4021     sizeof(DWORD),
4022     &buffer,
4023     &bytesWritten);
4024 }
4025
4026 /******************************************************************************
4027  *      SmallBlockChainStream_FreeBlock
4028  *
4029  * Flag small block 'blockIndex' as free in the small block depot.
4030  */
4031 void SmallBlockChainStream_FreeBlock(
4032   SmallBlockChainStream* This,
4033   ULONG                  blockIndex)
4034 {
4035   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4036 }
4037
4038 /******************************************************************************
4039  *      SmallBlockChainStream_GetNextFreeBlock
4040  *
4041  * Returns the index of a free small block. The small block depot will be
4042  * enlarged if necessary. The small block chain will also be enlarged if
4043  * necessary.
4044  */
4045 ULONG SmallBlockChainStream_GetNextFreeBlock(
4046   SmallBlockChainStream* This)
4047 {
4048   ULARGE_INTEGER offsetOfBlockInDepot;
4049   DWORD buffer;
4050   ULONG bytesRead;
4051   ULONG blockIndex = 0;
4052   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4053   BOOL32 success = TRUE;
4054   ULONG smallBlocksPerBigBlock;
4055
4056   offsetOfBlockInDepot.HighPart = 0;
4057
4058   /*
4059    * Scan the small block depot for a free block
4060    */
4061   while (nextBlockIndex != BLOCK_UNUSED)
4062   {
4063     offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4064
4065     success = BlockChainStream_ReadAt(
4066                 This->parentStorage->smallBlockDepotChain,
4067                 offsetOfBlockInDepot,
4068                 sizeof(DWORD),
4069                 &buffer,
4070                 &bytesRead);
4071
4072     /*
4073      * If we run out of space for the small block depot, enlarge it
4074      */
4075     if (success)
4076     {
4077       StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4078
4079       if (nextBlockIndex != BLOCK_UNUSED)
4080         blockIndex++;
4081     }
4082     else
4083     {
4084       ULONG count = 
4085         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4086
4087       ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4088       ULONG nextBlock, newsbdIndex;
4089       BYTE* smallBlockDepot;
4090
4091       nextBlock = sbdIndex;
4092       while (nextBlock != BLOCK_END_OF_CHAIN)
4093       {
4094         sbdIndex = nextBlock;
4095         nextBlock = 
4096           Storage32Impl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4097       }
4098
4099       newsbdIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
4100       if (sbdIndex != BLOCK_END_OF_CHAIN)
4101         Storage32Impl_SetNextBlockInChain(
4102           This->parentStorage, 
4103           sbdIndex, 
4104           newsbdIndex);
4105
4106       Storage32Impl_SetNextBlockInChain(
4107         This->parentStorage, 
4108         newsbdIndex, 
4109         BLOCK_END_OF_CHAIN);
4110
4111       /*
4112        * Initialize all the small blocks to free
4113        */
4114       smallBlockDepot = 
4115         Storage32Impl_GetBigBlock(This->parentStorage, newsbdIndex);
4116
4117       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4118       Storage32Impl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4119
4120       if (count == 0)
4121       {
4122         /*
4123          * We have just created the small block depot.
4124          */
4125         StgProperty rootProp;
4126         ULONG sbStartIndex; 
4127
4128         /*
4129          * Save it in the header
4130          */
4131         This->parentStorage->smallBlockDepotStart = newsbdIndex;
4132         Storage32Impl_SaveFileHeader(This->parentStorage);
4133
4134         /*
4135          * And allocate the first big block that will contain small blocks 
4136          */
4137         sbStartIndex = 
4138           Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
4139
4140         Storage32Impl_SetNextBlockInChain(
4141           This->parentStorage, 
4142           sbStartIndex, 
4143           BLOCK_END_OF_CHAIN);
4144
4145         Storage32Impl_ReadProperty(
4146           This->parentStorage, 
4147           This->parentStorage->rootPropertySetIndex, 
4148           &rootProp);
4149
4150         rootProp.startingBlock = sbStartIndex;
4151         rootProp.size.HighPart = 0;
4152         rootProp.size.LowPart  = This->parentStorage->bigBlockSize;
4153
4154         Storage32Impl_WriteProperty(
4155           This->parentStorage, 
4156           This->parentStorage->rootPropertySetIndex, 
4157           &rootProp);
4158       }
4159     }
4160   }
4161
4162   smallBlocksPerBigBlock = 
4163     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4164
4165   /*
4166    * Verify if we have to allocate big blocks to contain small blocks
4167    */
4168   if (blockIndex % smallBlocksPerBigBlock == 0)
4169   {
4170     StgProperty rootProp;
4171     ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4172
4173     Storage32Impl_ReadProperty(
4174       This->parentStorage, 
4175       This->parentStorage->rootPropertySetIndex, 
4176       &rootProp);
4177
4178     if (rootProp.size.LowPart < 
4179        (blocksRequired * This->parentStorage->bigBlockSize))
4180     {
4181       rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4182
4183       BlockChainStream_SetSize(
4184         This->parentStorage->smallBlockRootChain, 
4185         rootProp.size);
4186
4187       Storage32Impl_WriteProperty(
4188         This->parentStorage, 
4189         This->parentStorage->rootPropertySetIndex, 
4190         &rootProp);
4191     }
4192   }
4193
4194   return blockIndex;
4195 }
4196
4197 /******************************************************************************
4198  *      SmallBlockChainStream_ReadAt
4199  *
4200  * Reads a specified number of bytes from this chain at the specified offset.
4201  * bytesRead may be NULL.
4202  * Failure will be returned if the specified number of bytes has not been read. 
4203  */
4204 BOOL32 SmallBlockChainStream_ReadAt(
4205   SmallBlockChainStream* This,
4206   ULARGE_INTEGER         offset,
4207   ULONG                  size,
4208   void*                  buffer,
4209   ULONG*                 bytesRead)
4210 {
4211   ULARGE_INTEGER offsetInBigBlockFile;
4212   ULONG blockNoInSequence = 
4213     offset.LowPart / This->parentStorage->smallBlockSize;
4214
4215   ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4216   ULONG bytesToReadInBuffer;
4217   ULONG blockIndex;
4218   ULONG bytesReadFromBigBlockFile;
4219   BYTE* bufferWalker;
4220
4221   /*
4222    * This should never happen on a small block file.
4223    */
4224   assert(offset.HighPart==0);
4225
4226   /*
4227    * Find the first block in the stream that contains part of the buffer.
4228    */
4229   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4230
4231   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4232   {
4233     blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4234
4235     blockNoInSequence--;
4236   }
4237
4238   /*
4239    * Start reading the buffer.
4240    */
4241   *bytesRead   = 0;
4242   bufferWalker = buffer;
4243
4244   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4245   {
4246     /*
4247      * Calculate how many bytes we can copy from this small block.
4248      */
4249     bytesToReadInBuffer = 
4250       MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4251
4252     /*
4253      * Calculate the offset of the small block in the small block file.
4254      */
4255     offsetInBigBlockFile.HighPart  = 0;
4256     offsetInBigBlockFile.LowPart   = 
4257       blockIndex * This->parentStorage->smallBlockSize;
4258
4259     offsetInBigBlockFile.LowPart  += offsetInBlock;
4260
4261     /*
4262      * Read those bytes in the buffer from the small block file.
4263      */
4264     BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4265       offsetInBigBlockFile,
4266       bytesToReadInBuffer,
4267       bufferWalker,
4268       &bytesReadFromBigBlockFile);
4269
4270     assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4271
4272     /*
4273      * Step to the next big block.
4274      */
4275     blockIndex    = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4276     bufferWalker += bytesToReadInBuffer;
4277     size         -= bytesToReadInBuffer;
4278     *bytesRead   += bytesToReadInBuffer;
4279     offsetInBlock = 0;  /* There is no offset on the next block */
4280   }
4281
4282   return (size == 0);
4283 }
4284
4285 /******************************************************************************
4286  *       SmallBlockChainStream_WriteAt
4287  *
4288  * Writes the specified number of bytes to this chain at the specified offset.
4289  * bytesWritten may be NULL.
4290  * Will fail if not all specified number of bytes have been written.
4291  */
4292 BOOL32 SmallBlockChainStream_WriteAt(
4293   SmallBlockChainStream* This,
4294   ULARGE_INTEGER offset,
4295   ULONG          size,
4296   const void*    buffer,
4297   ULONG*         bytesWritten)
4298 {
4299   ULARGE_INTEGER offsetInBigBlockFile;
4300   ULONG blockNoInSequence = 
4301     offset.LowPart / This->parentStorage->smallBlockSize;
4302
4303   ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4304   ULONG bytesToWriteInBuffer;
4305   ULONG blockIndex;
4306   ULONG bytesWrittenFromBigBlockFile;
4307   BYTE* bufferWalker;
4308   
4309   /*
4310    * This should never happen on a small block file.
4311    */
4312   assert(offset.HighPart==0);
4313   
4314   /*
4315    * Find the first block in the stream that contains part of the buffer.
4316    */
4317   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4318   
4319   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4320   {
4321     blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4322     
4323     blockNoInSequence--;
4324   }
4325   
4326   /*
4327    * Start writing the buffer.
4328    *
4329    * Here, I'm casting away the constness on the buffer variable
4330    * This is OK since we don't intend to modify that buffer.
4331    */
4332   *bytesWritten   = 0;
4333   bufferWalker = (BYTE*)buffer;
4334   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4335   {
4336     /*
4337      * Calculate how many bytes we can copy to this small block.
4338      */
4339     bytesToWriteInBuffer = 
4340       MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4341     
4342     /*
4343      * Calculate the offset of the small block in the small block file.
4344      */
4345     offsetInBigBlockFile.HighPart  = 0;
4346     offsetInBigBlockFile.LowPart   = 
4347       blockIndex * This->parentStorage->smallBlockSize;
4348
4349     offsetInBigBlockFile.LowPart  += offsetInBlock;
4350     
4351     /*
4352      * Write those bytes in the buffer to the small block file.
4353      */
4354     BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
4355       offsetInBigBlockFile,
4356       bytesToWriteInBuffer,
4357       bufferWalker,
4358       &bytesWrittenFromBigBlockFile);
4359     
4360     assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
4361     
4362     /*
4363      * Step to the next big block.
4364      */
4365     blockIndex    = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4366     bufferWalker  += bytesToWriteInBuffer;
4367     size          -= bytesToWriteInBuffer;
4368     *bytesWritten += bytesToWriteInBuffer;
4369     offsetInBlock  = 0;     /* There is no offset on the next block */
4370   }
4371   
4372   return (size == 0);
4373 }
4374
4375 /******************************************************************************
4376  *       SmallBlockChainStream_Shrink
4377  *
4378  * Shrinks this chain in the small block depot. 
4379  */
4380 BOOL32 SmallBlockChainStream_Shrink(
4381   SmallBlockChainStream* This,
4382   ULARGE_INTEGER newSize)
4383 {
4384   ULONG blockIndex, extraBlock;
4385   ULONG numBlocks;
4386   ULONG count = 1;
4387
4388   numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4389
4390   if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4391     numBlocks++;
4392
4393   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4394
4395   /*
4396    * Go to the new end of chain
4397    */
4398   while (count < numBlocks)
4399   {
4400     blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4401     count++;
4402   }
4403
4404   /* Get the next block before marking the new end */
4405   extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4406
4407   /* Mark the new end of chain */
4408   SmallBlockChainStream_SetNextBlockInChain(
4409     This, 
4410     blockIndex, 
4411     BLOCK_END_OF_CHAIN);
4412
4413   /*
4414    * Mark the extra blocks as free
4415    */
4416   while (extraBlock != BLOCK_END_OF_CHAIN)
4417   {
4418     blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
4419     SmallBlockChainStream_FreeBlock(This, extraBlock);
4420     extraBlock = blockIndex;
4421   }
4422
4423   return TRUE;  
4424 }
4425
4426 /******************************************************************************
4427  *      SmallBlockChainStream_Enlarge
4428  *
4429  * Grows this chain in the small block depot.
4430  */
4431 BOOL32 SmallBlockChainStream_Enlarge(
4432   SmallBlockChainStream* This,
4433   ULARGE_INTEGER newSize)
4434 {
4435   ULONG blockIndex, currentBlock;
4436   ULONG newNumBlocks;
4437   ULONG oldNumBlocks = 0;
4438
4439   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4440
4441   /*
4442    * Empty chain
4443    */
4444   if (blockIndex == BLOCK_END_OF_CHAIN)
4445   {
4446     StgProperty chainProp;
4447
4448     Storage32Impl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4449                                &chainProp);
4450
4451     chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4452
4453     Storage32Impl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4454                                 &chainProp);
4455
4456     blockIndex = chainProp.startingBlock;
4457     SmallBlockChainStream_SetNextBlockInChain(
4458       This, 
4459       blockIndex, 
4460       BLOCK_END_OF_CHAIN);
4461   }
4462
4463   currentBlock = blockIndex;
4464
4465   /*
4466    * Figure out how many blocks are needed to contain this stream
4467    */
4468   newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4469
4470   if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4471     newNumBlocks++;
4472
4473   /*
4474    * Go to the current end of chain
4475    */
4476   while (blockIndex != BLOCK_END_OF_CHAIN)
4477   {
4478     oldNumBlocks++;
4479     currentBlock = blockIndex;
4480     blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
4481   }
4482
4483   /*
4484    * Add new blocks to the chain
4485    */
4486   while (oldNumBlocks < newNumBlocks)
4487   {
4488     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
4489     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
4490
4491     SmallBlockChainStream_SetNextBlockInChain(
4492       This, 
4493       blockIndex, 
4494       BLOCK_END_OF_CHAIN);
4495
4496     currentBlock = blockIndex;
4497     oldNumBlocks++;
4498   }
4499
4500   return TRUE;
4501 }
4502
4503 /******************************************************************************
4504  *      SmallBlockChainStream_GetCount
4505  *
4506  * Returns the number of blocks that comprises this chain.
4507  * This is not the size of this chain as the last block may not be full!
4508  */
4509 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
4510 {
4511   ULONG blockIndex;
4512   ULONG count = 0;
4513
4514   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4515
4516   while (blockIndex != BLOCK_END_OF_CHAIN)
4517   {
4518     count++;
4519
4520     blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4521   }
4522
4523   return count;
4524 }
4525
4526 /******************************************************************************
4527  *      SmallBlockChainStream_SetSize
4528  *
4529  * Sets the size of this stream.
4530  * The file will grow if we grow the chain.
4531  *
4532  * TODO: Free the actual blocks in the file when we shrink the chain.
4533  *       Currently, the blocks are still in the file. So the file size
4534  *       doesn't shrink even if we shrink streams. 
4535  */
4536 BOOL32 SmallBlockChainStream_SetSize(
4537                 SmallBlockChainStream* This,
4538                 ULARGE_INTEGER    newSize)
4539 {
4540   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
4541
4542   if (newSize.LowPart == size.LowPart)
4543     return TRUE;
4544
4545   if (newSize.LowPart < size.LowPart)
4546   {
4547     SmallBlockChainStream_Shrink(This, newSize);
4548   }
4549   else
4550   {
4551     SmallBlockChainStream_Enlarge(This, newSize);
4552   }
4553
4554   return TRUE;
4555 }
4556
4557 /******************************************************************************
4558  *      SmallBlockChainStream_GetSize
4559  *
4560  * Returns the size of this chain.
4561  */
4562 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
4563 {
4564   StgProperty chainProperty;
4565
4566   Storage32Impl_ReadProperty(
4567     This->parentStorage,
4568     This->ownerPropertyIndex,
4569     &chainProperty);
4570
4571   return chainProperty.size;
4572 }
4573
4574 /******************************************************************************
4575  *    StgCreateDocfile32  [OLE32.144]
4576  *    TODO Validate grfMode (STGM)
4577  */
4578 HRESULT WINAPI StgCreateDocfile32(
4579   LPCOLESTR32 pwcsName,
4580   DWORD       grfMode,
4581   DWORD       reserved,
4582   IStorage32  **ppstgOpen)
4583 {
4584   Storage32Impl* newStorage = 0;
4585   HANDLE32       hFile      = INVALID_HANDLE_VALUE32;
4586   HRESULT        hr         = S_OK;
4587   DWORD          shareMode;
4588   DWORD          accessMode;
4589   DWORD          creationMode;
4590   DWORD          fileAttributes;
4591
4592   /*
4593    * Validate the parameters
4594    */
4595   if ((ppstgOpen == 0) || (pwcsName == 0))
4596     return STG_E_INVALIDPOINTER;
4597
4598   /*
4599    * Validate the STGM flags
4600    */
4601   if ( FAILED( validateSTGM(grfMode) ))
4602     return STG_E_INVALIDFLAG;
4603
4604   /*
4605    * Interpret the STGM value grfMode 
4606    */
4607   shareMode    = GetShareModeFromSTGM(grfMode);
4608   accessMode   = GetAccessModeFromSTGM(grfMode);
4609   creationMode = GetCreationModeFromSTGM(grfMode);
4610
4611   if (grfMode & STGM_DELETEONRELEASE)
4612     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
4613   else
4614     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
4615
4616   if (grfMode & STGM_TRANSACTED)
4617     FIXME(ole, "Transacted mode not implemented.\n");
4618
4619   /*
4620    * Initialize the "out" parameter.
4621    */
4622   *ppstgOpen = 0;
4623
4624   hFile = CreateFile32W(pwcsName,
4625                         accessMode,
4626                         shareMode,
4627             NULL,
4628                         creationMode,
4629                         fileAttributes,
4630             0);
4631  
4632   if (hFile == INVALID_HANDLE_VALUE32)
4633   {
4634     return E_FAIL;
4635   }
4636
4637   /*
4638    * Allocate and initialize the new IStorage32object.
4639    */
4640   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl));
4641  
4642   if (newStorage == 0)
4643     return STG_E_INSUFFICIENTMEMORY;
4644
4645   hr = Storage32Impl_Construct(
4646          newStorage,
4647          hFile,
4648          grfMode);
4649  
4650   if (FAILED(hr))
4651     return hr;
4652
4653   /*
4654    * Get an "out" pointer for the caller.
4655    */
4656   hr = Storage32BaseImpl_QueryInterface(
4657          (IStorage32*)newStorage,
4658          (REFIID)&IID_IStorage,
4659          (void**)ppstgOpen);
4660
4661   return hr;
4662 }
4663
4664 /******************************************************************************
4665  *              StgOpenStorage32        [OLE32.148]
4666  */
4667 HRESULT WINAPI StgOpenStorage32(
4668   const OLECHAR32 *pwcsName,
4669   IStorage32      *pstgPriority,
4670   DWORD           grfMode,
4671   SNB32           snbExclude,
4672   DWORD           reserved, 
4673   IStorage32      **ppstgOpen)
4674 {
4675   Storage32Impl* newStorage = 0;
4676   HRESULT        hr = S_OK;
4677   HANDLE32       hFile = 0;
4678   DWORD          shareMode;
4679   DWORD          accessMode;
4680
4681   /*
4682    * Perform a sanity check
4683    */
4684   if (( pwcsName == 0) || (ppstgOpen == 0) )
4685     return STG_E_INVALIDPOINTER;
4686
4687   /*
4688    * Validate the STGM flags
4689    */
4690   if ( FAILED( validateSTGM(grfMode) ))
4691     return STG_E_INVALIDFLAG;
4692
4693   /*
4694    * Interpret the STGM value grfMode
4695    */
4696   shareMode    = GetShareModeFromSTGM(grfMode);
4697   accessMode   = GetAccessModeFromSTGM(grfMode);
4698
4699   /*
4700    * Initialize the "out" parameter.
4701    */
4702   *ppstgOpen = 0;
4703   
4704   hFile = CreateFile32W( pwcsName, 
4705                         accessMode,
4706                         shareMode,
4707             NULL,
4708             OPEN_EXISTING,
4709             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
4710             0);
4711   
4712   
4713   if (hFile==INVALID_HANDLE_VALUE32)
4714   {
4715     return E_FAIL;
4716   }
4717
4718   /*
4719    * Allocate and initialize the new IStorage32object.
4720    */
4721   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl));
4722   
4723   if (newStorage == 0)
4724     return STG_E_INSUFFICIENTMEMORY;
4725
4726   hr = Storage32Impl_Construct(
4727          newStorage,
4728          hFile,
4729          grfMode);
4730   
4731   if (FAILED(hr))
4732     return hr;
4733   
4734   /*
4735    * Get an "out" pointer for the caller.
4736    */
4737   hr = Storage32BaseImpl_QueryInterface(
4738          (IStorage32*)newStorage,
4739          (REFIID)&IID_IStorage,
4740          (void**)ppstgOpen);
4741   
4742   return hr;
4743 }
4744
4745 /******************************************************************************
4746  *              WriteClassStg32        [OLE32.148]
4747  *
4748  * This method will store the specified CLSID in the specified storage object
4749  */
4750 HRESULT WINAPI WriteClassStg32(IStorage32* pStg, REFCLSID rclsid)
4751 {
4752   HRESULT hRes;
4753
4754   assert(pStg != 0);
4755
4756   hRes = IStorage32_SetClass(pStg, rclsid);
4757
4758   return hRes;
4759 }
4760
4761
4762 /****************************************************************************
4763  * This method validate a STGM parameter that can contain the values below
4764  *
4765  * STGM_DIRECT               0x00000000
4766  * STGM_TRANSACTED           0x00010000
4767  * STGM_SIMPLE               0x08000000
4768  * 
4769  * STGM_READ                 0x00000000
4770  * STGM_WRITE                0x00000001
4771  * STGM_READWRITE            0x00000002
4772  * 
4773  * STGM_SHARE_DENY_NONE      0x00000040
4774  * STGM_SHARE_DENY_READ      0x00000030
4775  * STGM_SHARE_DENY_WRITE     0x00000020
4776  * STGM_SHARE_EXCLUSIVE      0x00000010
4777  * 
4778  * STGM_PRIORITY             0x00040000
4779  * STGM_DELETEONRELEASE      0x04000000
4780  *
4781  * STGM_CREATE               0x00001000
4782  * STGM_CONVERT              0x00020000
4783  * STGM_FAILIFTHERE          0x00000000
4784  *
4785  * STGM_NOSCRATCH            0x00100000
4786  * STGM_NOSNAPSHOT           0x00200000
4787  */
4788 static HRESULT validateSTGM(DWORD stgm)
4789 {
4790   BOOL32 bSTGM_TRANSACTED       = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
4791   BOOL32 bSTGM_SIMPLE           = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
4792   BOOL32 bSTGM_DIRECT           = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
4793    
4794   BOOL32 bSTGM_WRITE            = ((stgm & STGM_WRITE) == STGM_WRITE);
4795   BOOL32 bSTGM_READWRITE        = ((stgm & STGM_READWRITE) == STGM_READWRITE);
4796   BOOL32 bSTGM_READ             = ! (bSTGM_WRITE || bSTGM_READWRITE);
4797    
4798   BOOL32 bSTGM_SHARE_DENY_NONE  =
4799                      ((stgm & STGM_SHARE_DENY_NONE)  == STGM_SHARE_DENY_NONE);
4800
4801   BOOL32 bSTGM_SHARE_DENY_READ  =
4802                      ((stgm & STGM_SHARE_DENY_READ)  == STGM_SHARE_DENY_READ);
4803
4804   BOOL32 bSTGM_SHARE_DENY_WRITE =
4805                      ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
4806
4807   BOOL32 bSTGM_SHARE_EXCLUSIVE  =
4808                      ((stgm & STGM_SHARE_EXCLUSIVE)  == STGM_SHARE_EXCLUSIVE);
4809
4810   BOOL32 bSTGM_CREATE           = ((stgm & STGM_CREATE) == STGM_CREATE);
4811   BOOL32 bSTGM_CONVERT          = ((stgm & STGM_CONVERT) == STGM_CONVERT);
4812    
4813   BOOL32 bSTGM_NOSCRATCH        = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
4814   BOOL32 bSTGM_NOSNAPSHOT       = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
4815
4816   /* 
4817    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
4818    */
4819   if ( ! bSTGM_DIRECT )
4820     if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
4821       return E_FAIL;
4822
4823   /* 
4824    * STGM_WRITE |  STGM_READWRITE | STGM_READ
4825    */
4826   if ( ! bSTGM_READ )
4827     if( bSTGM_WRITE && bSTGM_READWRITE )
4828       return E_FAIL;
4829
4830   /*
4831    * STGM_SHARE_DENY_NONE | others 
4832    * (I assume here that DENY_READ implies DENY_WRITE)
4833    */
4834   if ( bSTGM_SHARE_DENY_NONE )
4835     if ( bSTGM_SHARE_DENY_READ ||
4836          bSTGM_SHARE_DENY_WRITE || 
4837          bSTGM_SHARE_EXCLUSIVE) 
4838       return E_FAIL;
4839
4840   /*
4841    * STGM_CREATE | STGM_CONVERT
4842    * if both are false, STGM_FAILIFTHERE is set to TRUE
4843    */
4844   if ( bSTGM_CREATE && bSTGM_CONVERT )
4845     return E_FAIL;
4846
4847   /*
4848    * STGM_NOSCRATCH requires STGM_TRANSACTED
4849    */
4850   if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
4851     return E_FAIL;
4852   
4853   /*
4854    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and 
4855    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
4856    */
4857   if (bSTGM_NOSNAPSHOT)
4858   {
4859     if ( ! ( bSTGM_TRANSACTED && 
4860            !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
4861     return E_FAIL;
4862   }
4863
4864   return S_OK;
4865 }
4866
4867 /****************************************************************************
4868  *      GetShareModeFromSTGM
4869  *
4870  * This method will return a share mode flag from a STGM value.
4871  * The STGM value is assumed valid. 
4872  */
4873 static DWORD GetShareModeFromSTGM(DWORD stgm)
4874 {
4875   DWORD dwShareMode = 0;
4876   BOOL32 bSTGM_SHARE_DENY_NONE  =
4877                      ((stgm & STGM_SHARE_DENY_NONE)  == STGM_SHARE_DENY_NONE);
4878
4879   BOOL32 bSTGM_SHARE_DENY_READ  =
4880                      ((stgm & STGM_SHARE_DENY_READ)  == STGM_SHARE_DENY_READ);
4881
4882   BOOL32 bSTGM_SHARE_DENY_WRITE =
4883                      ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
4884
4885   BOOL32 bSTGM_SHARE_EXCLUSIVE  =
4886                      ((stgm & STGM_SHARE_EXCLUSIVE)  == STGM_SHARE_EXCLUSIVE);
4887
4888   if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
4889     dwShareMode = 0;
4890
4891   if (bSTGM_SHARE_DENY_NONE)
4892     dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
4893
4894   if (bSTGM_SHARE_DENY_WRITE)
4895     dwShareMode = FILE_SHARE_READ;
4896
4897   return dwShareMode;
4898 }
4899
4900 /****************************************************************************
4901  *      GetAccessModeFromSTGM
4902  *
4903  * This method will return an access mode flag from a STGM value.
4904  * The STGM value is assumed valid.
4905  */
4906 static DWORD GetAccessModeFromSTGM(DWORD stgm)
4907 {
4908   DWORD dwDesiredAccess = 0;
4909   BOOL32 bSTGM_WRITE     = ((stgm & STGM_WRITE) == STGM_WRITE);
4910   BOOL32 bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
4911   BOOL32 bSTGM_READ      = ! (bSTGM_WRITE || bSTGM_READWRITE);
4912
4913   if (bSTGM_READ)
4914     dwDesiredAccess = GENERIC_READ;
4915
4916   if (bSTGM_WRITE)
4917     dwDesiredAccess |= GENERIC_WRITE;
4918
4919   if (bSTGM_READWRITE)
4920     dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
4921
4922   return dwDesiredAccess;
4923 }
4924
4925 /****************************************************************************
4926  *      GetCreationModeFromSTGM
4927  *
4928  * This method will return a creation mode flag from a STGM value.
4929  * The STGM value is assumed valid.
4930  */
4931 static DWORD GetCreationModeFromSTGM(DWORD stgm)
4932 {
4933   DWORD dwCreationDistribution;
4934   BOOL32 bSTGM_CREATE      = ((stgm & STGM_CREATE) == STGM_CREATE);
4935   BOOL32 bSTGM_CONVERT     = ((stgm & STGM_CONVERT) == STGM_CONVERT);
4936   BOOL32 bSTGM_FAILIFTHERE = ! (bSTGM_CREATE || bSTGM_CONVERT);
4937
4938   if (bSTGM_CREATE)
4939     dwCreationDistribution = CREATE_NEW;
4940   else if (bSTGM_FAILIFTHERE)
4941     dwCreationDistribution = CREATE_NEW;
4942   else if (bSTGM_CONVERT)
4943   {
4944     FIXME(ole, "STGM_CONVERT not implemented!\n");
4945     dwCreationDistribution = CREATE_NEW;
4946   }
4947
4948   return dwCreationDistribution;
4949 }
4950