~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ole32/storage32.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * Compound Storage (32 bit version)
  3  * Storage implementation
  4  *
  5  * This file contains the compound file implementation
  6  * of the storage interface.
  7  *
  8  * Copyright 1999 Francis Beaudet
  9  * Copyright 1999 Sylvain St-Germain
 10  * Copyright 1999 Thuy Nguyen
 11  * Copyright 2005 Mike McCormack
 12  *
 13  * This library is free software; you can redistribute it and/or
 14  * modify it under the terms of the GNU Lesser General Public
 15  * License as published by the Free Software Foundation; either
 16  * version 2.1 of the License, or (at your option) any later version.
 17  *
 18  * This library is distributed in the hope that it will be useful,
 19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 21  * Lesser General Public License for more details.
 22  *
 23  * You should have received a copy of the GNU Lesser General Public
 24  * License along with this library; if not, write to the Free Software
 25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 26  *
 27  * NOTES
 28  *  The compound file implementation of IStorage used for create
 29  *  and manage substorages and streams within a storage object
 30  *  residing in a compound file object.
 31  */
 32 
 33 #include <assert.h>
 34 #include <stdarg.h>
 35 #include <stdio.h>
 36 #include <stdlib.h>
 37 #include <string.h>
 38 
 39 #define COBJMACROS
 40 #define NONAMELESSUNION
 41 #define NONAMELESSSTRUCT
 42 
 43 #include "windef.h"
 44 #include "winbase.h"
 45 #include "winnls.h"
 46 #include "winuser.h"
 47 #include "wine/unicode.h"
 48 #include "wine/debug.h"
 49 
 50 #include "storage32.h"
 51 #include "ole2.h"      /* For Write/ReadClassStm */
 52 
 53 #include "winreg.h"
 54 #include "wine/wingdi16.h"
 55 
 56 WINE_DEFAULT_DEBUG_CHANNEL(storage);
 57 
 58 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
 59 #define OLESTREAM_ID 0x501
 60 #define OLESTREAM_MAX_STR_LEN 255
 61 
 62 /*
 63  * These are signatures to detect the type of Document file.
 64  */
 65 static const BYTE STORAGE_magic[8]    ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
 66 static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
 67 
 68 static const char rootPropertyName[] = "Root Entry";
 69 
 70 /****************************************************************************
 71  * Storage32InternalImpl definitions.
 72  *
 73  * Definition of the implementation structure for the IStorage32 interface.
 74  * This one implements the IStorage32 interface for storage that are
 75  * inside another storage.
 76  */
 77 struct StorageInternalImpl
 78 {
 79   struct StorageBaseImpl base;
 80   /*
 81    * There is no specific data for this class.
 82    */
 83 };
 84 typedef struct StorageInternalImpl StorageInternalImpl;
 85 
 86 /* Method definitions for the Storage32InternalImpl class. */
 87 static StorageInternalImpl* StorageInternalImpl_Construct(StorageImpl* ancestorStorage,
 88                                                           DWORD openFlags, ULONG rootTropertyIndex);
 89 static void StorageImpl_Destroy(StorageBaseImpl* iface);
 90 static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
 91 static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, const void* buffer);
 92 static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock);
 93 static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This);
 94 static void StorageImpl_SaveFileHeader(StorageImpl* This);
 95 
 96 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex);
 97 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
 98 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex);
 99 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex);
100 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex);
101 
102 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This);
103 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This);
104 static ULONG BlockChainStream_GetCount(BlockChainStream* This);
105 
106 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This);
107 static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This,
108     ULONG blockIndex, ULONG offset, DWORD value);
109 static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl*  This,
110     ULONG blockIndex, ULONG offset, DWORD* value);
111 
112 /* OLESTREAM memory structure to use for Get and Put Routines */
113 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
114 typedef struct
115 {
116     DWORD dwOleID;
117     DWORD dwTypeID;
118     DWORD dwOleTypeNameLength;
119     CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];
120     CHAR  *pstrOleObjFileName;
121     DWORD dwOleObjFileNameLength;
122     DWORD dwMetaFileWidth;
123     DWORD dwMetaFileHeight;
124     CHAR  strUnknown[8]; /* don't know what this 8 byte information in OLE stream is. */
125     DWORD dwDataLength;
126     BYTE *pData;
127 }OLECONVERT_OLESTREAM_DATA;
128 
129 /* CompObj Stream structure */
130 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
131 typedef struct
132 {
133     BYTE byUnknown1[12];
134     CLSID clsid;
135     DWORD dwCLSIDNameLength;
136     CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
137     DWORD dwOleTypeNameLength;
138     CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
139     DWORD dwProgIDNameLength;
140     CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
141     BYTE byUnknown2[16];
142 }OLECONVERT_ISTORAGE_COMPOBJ;
143 
144 
145 /* Ole Presentation Stream structure */
146 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
147 typedef struct
148 {
149     BYTE byUnknown1[28];
150     DWORD dwExtentX;
151     DWORD dwExtentY;
152     DWORD dwSize;
153     BYTE *pData;
154 }OLECONVERT_ISTORAGE_OLEPRES;
155 
156 
157 
158 /***********************************************************************
159  * Forward declaration of internal functions used by the method DestroyElement
160  */
161 static HRESULT deleteStorageProperty(
162   StorageImpl *parentStorage,
163   ULONG        foundPropertyIndexToDelete,
164   StgProperty  propertyToDelete);
165 
166 static HRESULT deleteStreamProperty(
167   StorageImpl *parentStorage,
168   ULONG         foundPropertyIndexToDelete,
169   StgProperty   propertyToDelete);
170 
171 static HRESULT findPlaceholder(
172   StorageImpl *storage,
173   ULONG         propertyIndexToStore,
174   ULONG         storagePropertyIndex,
175   INT         typeOfRelation);
176 
177 static HRESULT adjustPropertyChain(
178   StorageImpl *This,
179   StgProperty   propertyToDelete,
180   StgProperty   parentProperty,
181   ULONG         parentPropertyId,
182   INT         typeOfRelation);
183 
184 /***********************************************************************
185  * Declaration of the functions used to manipulate StgProperty
186  */
187 
188 static ULONG getFreeProperty(
189   StorageImpl *storage);
190 
191 static void updatePropertyChain(
192   StorageImpl *storage,
193   ULONG       newPropertyIndex,
194   StgProperty newProperty);
195 
196 static LONG propertyNameCmp(
197     const OLECHAR *newProperty,
198     const OLECHAR *currentProperty);
199 
200 
201 /***********************************************************************
202  * Declaration of miscellaneous functions...
203  */
204 static HRESULT validateSTGM(DWORD stgmValue);
205 
206 static DWORD GetShareModeFromSTGM(DWORD stgm);
207 static DWORD GetAccessModeFromSTGM(DWORD stgm);
208 static DWORD GetCreationModeFromSTGM(DWORD stgm);
209 
210 extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
211 
212 
213 /****************************************************************************
214  * IEnumSTATSTGImpl definitions.
215  *
216  * Definition of the implementation structure for the IEnumSTATSTGImpl interface.
217  * This class allows iterating through the content of a storage and to find
218  * specific items inside it.
219  */
220 struct IEnumSTATSTGImpl
221 {
222   const IEnumSTATSTGVtbl *lpVtbl;    /* Needs to be the first item in the struct
223                                 * since we want to cast this in an IEnumSTATSTG pointer */
224 
225   LONG           ref;                   /* Reference count */
226   StorageImpl*   parentStorage;         /* Reference to the parent storage */
227   ULONG          firstPropertyNode;     /* Index of the root of the storage to enumerate */
228 
229   /*
230    * The current implementation of the IEnumSTATSTGImpl class uses a stack
231    * to walk the property sets to get the content of a storage. This stack
232    * is implemented by the following 3 data members
233    */
234   ULONG          stackSize;
235   ULONG          stackMaxSize;
236   ULONG*         stackToVisit;
237 
238 #define ENUMSTATSGT_SIZE_INCREMENT 10
239 };
240 
241 
242 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageImpl* This, ULONG firstPropertyNode);
243 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This);
244 static void IEnumSTATSTGImpl_PushSearchNode(IEnumSTATSTGImpl* This, ULONG nodeToPush);
245 static ULONG IEnumSTATSTGImpl_PopSearchNode(IEnumSTATSTGImpl* This, BOOL remove);
246 static ULONG IEnumSTATSTGImpl_FindProperty(IEnumSTATSTGImpl* This, const OLECHAR* lpszPropName,
247                                            StgProperty* buffer);
248 static INT IEnumSTATSTGImpl_FindParentProperty(IEnumSTATSTGImpl *This, ULONG childProperty,
249                                                StgProperty *currentProperty, ULONG *propertyId);
250 
251 /************************************************************************
252 ** Block Functions
253 */
254 
255 static ULONG BLOCK_GetBigBlockOffset(ULONG index)
256 {
257     if (index == 0xffffffff)
258         index = 0;
259     else
260         index ++;
261 
262     return index * BIG_BLOCK_SIZE;
263 }
264 
265 /************************************************************************
266 ** Storage32BaseImpl implementation
267 */
268 static HRESULT StorageImpl_ReadAt(StorageImpl* This,
269   ULARGE_INTEGER offset,
270   void*          buffer,
271   ULONG          size,
272   ULONG*         bytesRead)
273 {
274     return BIGBLOCKFILE_ReadAt(This->bigBlockFile,offset,buffer,size,bytesRead);
275 }
276 
277 static HRESULT StorageImpl_WriteAt(StorageImpl* This,
278   ULARGE_INTEGER offset,
279   const void*    buffer,
280   const ULONG    size,
281   ULONG*         bytesWritten)
282 {
283     return BIGBLOCKFILE_WriteAt(This->bigBlockFile,offset,buffer,size,bytesWritten);
284 }
285 
286 /************************************************************************
287  * Storage32BaseImpl_QueryInterface (IUnknown)
288  *
289  * This method implements the common QueryInterface for all IStorage32
290  * implementations contained in this file.
291  *
292  * See Windows documentation for more details on IUnknown methods.
293  */
294 static HRESULT WINAPI StorageBaseImpl_QueryInterface(
295   IStorage*        iface,
296   REFIID             riid,
297   void**             ppvObject)
298 {
299   StorageBaseImpl *This = (StorageBaseImpl *)iface;
300   /*
301    * Perform a sanity check on the parameters.
302    */
303   if ( (This==0) || (ppvObject==0) )
304     return E_INVALIDARG;
305 
306   /*
307    * Initialize the return parameter.
308    */
309   *ppvObject = 0;
310 
311   /*
312    * Compare the riid with the interface IDs implemented by this object.
313    */
314   if (IsEqualGUID(&IID_IUnknown, riid) ||
315       IsEqualGUID(&IID_IStorage, riid))
316   {
317     *ppvObject = (IStorage*)This;
318   }
319   else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
320   {
321     *ppvObject = (IStorage*)&This->pssVtbl;
322   }
323 
324   /*
325    * Check that we obtained an interface.
326    */
327   if ((*ppvObject)==0)
328     return E_NOINTERFACE;
329 
330   /*
331    * Query Interface always increases the reference count by one when it is
332    * successful
333    */
334   IStorage_AddRef(iface);
335 
336   return S_OK;
337 }
338 
339 /************************************************************************
340  * Storage32BaseImpl_AddRef (IUnknown)
341  *
342  * This method implements the common AddRef for all IStorage32
343  * implementations contained in this file.
344  *
345  * See Windows documentation for more details on IUnknown methods.
346  */
347 static ULONG WINAPI StorageBaseImpl_AddRef(
348             IStorage* iface)
349 {
350   StorageBaseImpl *This = (StorageBaseImpl *)iface;
351   ULONG ref = InterlockedIncrement(&This->ref);
352 
353   TRACE("(%p) AddRef to %d\n", This, ref);
354 
355   return ref;
356 }
357 
358 /************************************************************************
359  * Storage32BaseImpl_Release (IUnknown)
360  *
361  * This method implements the common Release for all IStorage32
362  * implementations contained in this file.
363  *
364  * See Windows documentation for more details on IUnknown methods.
365  */
366 static ULONG WINAPI StorageBaseImpl_Release(
367       IStorage* iface)
368 {
369   StorageBaseImpl *This = (StorageBaseImpl *)iface;
370   /*
371    * Decrease the reference count on this object.
372    */
373   ULONG ref = InterlockedDecrement(&This->ref);
374 
375   TRACE("(%p) ReleaseRef to %d\n", This, ref);
376 
377   /*
378    * If the reference count goes down to 0, perform suicide.
379    */
380   if (ref == 0)
381   {
382     /*
383      * Since we are using a system of base-classes, we want to call the
384      * destructor of the appropriate derived class. To do this, we are
385      * using virtual functions to implement the destructor.
386      */
387     This->v_destructor(This);
388   }
389 
390   return ref;
391 }
392 
393 /************************************************************************
394  * Storage32BaseImpl_OpenStream (IStorage)
395  *
396  * This method will open the specified stream object from the current storage.
397  *
398  * See Windows documentation for more details on IStorage methods.
399  */
400 static HRESULT WINAPI StorageBaseImpl_OpenStream(
401   IStorage*        iface,
402   const OLECHAR*   pwcsName,  /* [string][in] */
403   void*            reserved1, /* [unique][in] */
404   DWORD            grfMode,   /* [in]  */
405   DWORD            reserved2, /* [in]  */
406   IStream**        ppstm)     /* [out] */
407 {
408   StorageBaseImpl *This = (StorageBaseImpl *)iface;
409   IEnumSTATSTGImpl* propertyEnumeration;
410   StgStreamImpl*    newStream;
411   StgProperty       currentProperty;
412   ULONG             foundPropertyIndex;
413   HRESULT           res = STG_E_UNKNOWN;
414 
415   TRACE("(%p, %s, %p, %x, %d, %p)\n",
416         iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
417 
418   /*
419    * Perform a sanity check on the parameters.
420    */
421   if ( (pwcsName==NULL) || (ppstm==0) )
422   {
423     res = E_INVALIDARG;
424     goto end;
425   }
426 
427   /*
428    * Initialize the out parameter
429    */
430   *ppstm = NULL;
431 
432   /*
433    * Validate the STGM flags
434    */
435   if ( FAILED( validateSTGM(grfMode) ) ||
436        STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
437   {
438     res = STG_E_INVALIDFLAG;
439     goto end;
440   }
441 
442   /*
443    * As documented.
444    */
445   if ( (grfMode & STGM_DELETEONRELEASE) || (grfMode & STGM_TRANSACTED) )
446   {
447     res = STG_E_INVALIDFUNCTION;
448     goto end;
449   }
450 
451   /*
452    * Check that we're compatible with the parent's storage mode, but
453    * only if we are not in transacted mode
454    */
455   if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
456     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
457     {
458       res = STG_E_ACCESSDENIED;
459       goto end;
460     }
461   }
462 
463   /*
464    * Create a property enumeration to search the properties
465    */
466   propertyEnumeration = IEnumSTATSTGImpl_Construct(
467     This->ancestorStorage,
468     This->rootPropertySetIndex);
469 
470   /*
471    * Search the enumeration for the property with the given name
472    */
473   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
474     propertyEnumeration,
475     pwcsName,
476     &currentProperty);
477 
478   /*
479    * Delete the property enumeration since we don't need it anymore
480    */
481   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
482 
483   /*
484    * If it was found, construct the stream object and return a pointer to it.
485    */
486   if ( (foundPropertyIndex!=PROPERTY_NULL) &&
487        (currentProperty.propertyType==PROPTYPE_STREAM) )
488   {
489     newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
490 
491     if (newStream!=0)
492     {
493       newStream->grfMode = grfMode;
494       *ppstm = (IStream*)newStream;
495 
496       /*
497        * Since we are returning a pointer to the interface, we have to
498        * nail down the reference.
499        */
500       IStream_AddRef(*ppstm);
501 
502       res = S_OK;
503       goto end;
504     }
505 
506     res = E_OUTOFMEMORY;
507     goto end;
508   }
509 
510   res = STG_E_FILENOTFOUND;
511 
512 end:
513   if (res == S_OK)
514     TRACE("<-- IStream %p\n", *ppstm);
515   TRACE("<-- %08x\n", res);
516   return res;
517 }
518 
519 /************************************************************************
520  * Storage32BaseImpl_OpenStorage (IStorage)
521  *
522  * This method will open a new storage object from the current storage.
523  *
524  * See Windows documentation for more details on IStorage methods.
525  */
526 static HRESULT WINAPI StorageBaseImpl_OpenStorage(
527   IStorage*        iface,
528   const OLECHAR*   pwcsName,      /* [string][unique][in] */
529   IStorage*        pstgPriority,  /* [unique][in] */
530   DWORD            grfMode,       /* [in] */
531   SNB              snbExclude,    /* [unique][in] */
532   DWORD            reserved,      /* [in] */
533   IStorage**       ppstg)         /* [out] */
534 {
535   StorageBaseImpl *This = (StorageBaseImpl *)iface;
536   StorageInternalImpl* newStorage;
537   IEnumSTATSTGImpl*      propertyEnumeration;
538   StgProperty            currentProperty;
539   ULONG                  foundPropertyIndex;
540   HRESULT                res = STG_E_UNKNOWN;
541 
542   TRACE("(%p, %s, %p, %x, %p, %d, %p)\n",
543         iface, debugstr_w(pwcsName), pstgPriority,
544         grfMode, snbExclude, reserved, ppstg);
545 
546   /*
547    * Perform a sanity check on the parameters.
548    */
549   if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
550   {
551     res = E_INVALIDARG;
552     goto end;
553   }
554 
555   /* as documented */
556   if (snbExclude != NULL)
557   {
558     res = STG_E_INVALIDPARAMETER;
559     goto end;
560   }
561 
562   /*
563    * Validate the STGM flags
564    */
565   if ( FAILED( validateSTGM(grfMode) ))
566   {
567     res = STG_E_INVALIDFLAG;
568     goto end;
569   }
570 
571   /*
572    * As documented.
573    */
574   if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
575         (grfMode & STGM_DELETEONRELEASE) ||
576         (grfMode & STGM_PRIORITY) )
577   {
578     res = STG_E_INVALIDFUNCTION;
579     goto end;
580   }
581 
582   /*
583    * Check that we're compatible with the parent's storage mode,
584    * but only if we are not transacted
585    */
586   if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
587     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
588     {
589       res = STG_E_ACCESSDENIED;
590       goto end;
591     }
592   }
593 
594   /*
595    * Initialize the out parameter
596    */
597   *ppstg = NULL;
598 
599   /*
600    * Create a property enumeration to search the properties
601    */
602   propertyEnumeration = IEnumSTATSTGImpl_Construct(
603                           This->ancestorStorage,
604                           This->rootPropertySetIndex);
605 
606   /*
607    * Search the enumeration for the property with the given name
608    */
609   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
610                          propertyEnumeration,
611                          pwcsName,
612                          &currentProperty);
613 
614   /*
615    * Delete the property enumeration since we don't need it anymore
616    */
617   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
618 
619   /*
620    * If it was found, construct the stream object and return a pointer to it.
621    */
622   if ( (foundPropertyIndex!=PROPERTY_NULL) &&
623        (currentProperty.propertyType==PROPTYPE_STORAGE) )
624   {
625     /*
626      * Construct a new Storage object
627      */
628     newStorage = StorageInternalImpl_Construct(
629                    This->ancestorStorage,
630                    grfMode,
631                    foundPropertyIndex);
632 
633     if (newStorage != 0)
634     {
635       *ppstg = (IStorage*)newStorage;
636 
637       /*
638        * Since we are returning a pointer to the interface,
639        * we have to nail down the reference.
640        */
641       StorageBaseImpl_AddRef(*ppstg);
642 
643       res = S_OK;
644       goto end;
645     }
646 
647     res = STG_E_INSUFFICIENTMEMORY;
648     goto end;
649   }
650 
651   res = STG_E_FILENOTFOUND;
652 
653 end:
654   TRACE("<-- %08x\n", res);
655   return res;
656 }
657 
658 /************************************************************************
659  * Storage32BaseImpl_EnumElements (IStorage)
660  *
661  * This method will create an enumerator object that can be used to
662  * retrieve information about all the properties in the storage object.
663  *
664  * See Windows documentation for more details on IStorage methods.
665  */
666 static HRESULT WINAPI StorageBaseImpl_EnumElements(
667   IStorage*       iface,
668   DWORD           reserved1, /* [in] */
669   void*           reserved2, /* [size_is][unique][in] */
670   DWORD           reserved3, /* [in] */
671   IEnumSTATSTG**  ppenum)    /* [out] */
672 {
673   StorageBaseImpl *This = (StorageBaseImpl *)iface;
674   IEnumSTATSTGImpl* newEnum;
675 
676   TRACE("(%p, %d, %p, %d, %p)\n",
677         iface, reserved1, reserved2, reserved3, ppenum);
678 
679   /*
680    * Perform a sanity check on the parameters.
681    */
682   if ( (This==0) || (ppenum==0))
683     return E_INVALIDARG;
684 
685   /*
686    * Construct the enumerator.
687    */
688   newEnum = IEnumSTATSTGImpl_Construct(
689               This->ancestorStorage,
690               This->rootPropertySetIndex);
691 
692   if (newEnum!=0)
693   {
694     *ppenum = (IEnumSTATSTG*)newEnum;
695 
696     /*
697      * Don't forget to nail down a reference to the new object before
698      * returning it.
699      */
700     IEnumSTATSTG_AddRef(*ppenum);
701 
702     return S_OK;
703   }
704 
705   return E_OUTOFMEMORY;
706 }
707 
708 /************************************************************************
709  * Storage32BaseImpl_Stat (IStorage)
710  *
711  * This method will retrieve information about this storage object.
712  *
713  * See Windows documentation for more details on IStorage methods.
714  */
715 static HRESULT WINAPI StorageBaseImpl_Stat(
716   IStorage*        iface,
717   STATSTG*         pstatstg,     /* [out] */
718   DWORD            grfStatFlag)  /* [in] */
719 {
720   StorageBaseImpl *This = (StorageBaseImpl *)iface;
721   StgProperty    curProperty;
722   BOOL           readSuccessful;
723   HRESULT        res = STG_E_UNKNOWN;
724 
725   TRACE("(%p, %p, %x)\n",
726         iface, pstatstg, grfStatFlag);
727 
728   /*
729    * Perform a sanity check on the parameters.
730    */
731   if ( (This==0) || (pstatstg==0))
732   {
733     res = E_INVALIDARG;
734     goto end;
735   }
736 
737   /*
738    * Read the information from the property.
739    */
740   readSuccessful = StorageImpl_ReadProperty(
741                     This->ancestorStorage,
742                     This->rootPropertySetIndex,
743                     &curProperty);
744 
745   if (readSuccessful)
746   {
747     StorageUtl_CopyPropertyToSTATSTG(
748       pstatstg,
749       &curProperty,
750       grfStatFlag);
751 
752     pstatstg->grfMode = This->openFlags;
753     pstatstg->grfStateBits = This->stateBits;
754 
755     res = S_OK;
756     goto end;
757   }
758 
759   res = E_FAIL;
760 
761 end:
762   if (res == S_OK)
763   {
764     TRACE("<-- STATSTG: pwcsName: %s, type: %d, cbSize.Low/High: %d/%d, grfMode: %08x, grfLocksSupported: %d, grfStateBits: %08x\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
765   }
766   TRACE("<-- %08x\n", res);
767   return res;
768 }
769 
770 /************************************************************************
771  * Storage32BaseImpl_RenameElement (IStorage)
772  *
773  * This method will rename the specified element.
774  *
775  * See Windows documentation for more details on IStorage methods.
776  *
777  * Implementation notes: The method used to rename consists of creating a clone
778  *    of the deleted StgProperty object setting it with the new name and to
779  *    perform a DestroyElement of the old StgProperty.
780  */
781 static HRESULT WINAPI StorageBaseImpl_RenameElement(
782             IStorage*        iface,
783             const OLECHAR*   pwcsOldName,  /* [in] */
784             const OLECHAR*   pwcsNewName)  /* [in] */
785 {
786   StorageBaseImpl *This = (StorageBaseImpl *)iface;
787   IEnumSTATSTGImpl* propertyEnumeration;
788   StgProperty       currentProperty;
789   ULONG             foundPropertyIndex;
790 
791   TRACE("(%p, %s, %s)\n",
792         iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
793 
794   /*
795    * Create a property enumeration to search the properties
796    */
797   propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
798                                                    This->rootPropertySetIndex);
799 
800   /*
801    * Search the enumeration for the new property name
802    */
803   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
804                                                      pwcsNewName,
805                                                      &currentProperty);
806 
807   if (foundPropertyIndex != PROPERTY_NULL)
808   {
809     /*
810      * There is already a property with the new name
811      */
812     IEnumSTATSTGImpl_Destroy(propertyEnumeration);
813     return STG_E_FILEALREADYEXISTS;
814   }
815 
816   IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration);
817 
818   /*
819    * Search the enumeration for the old property name
820    */
821   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
822                                                      pwcsOldName,
823                                                      &currentProperty);
824 
825   /*
826    * Delete the property enumeration since we don't need it anymore
827    */
828   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
829 
830   if (foundPropertyIndex != PROPERTY_NULL)
831   {
832     StgProperty renamedProperty;
833     ULONG       renamedPropertyIndex;
834 
835     /*
836      * Setup a new property for the renamed property
837      */
838     renamedProperty.sizeOfNameString =
839       ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
840 
841     if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
842       return STG_E_INVALIDNAME;
843 
844     strcpyW(renamedProperty.name, pwcsNewName);
845 
846     renamedProperty.propertyType  = currentProperty.propertyType;
847     renamedProperty.startingBlock = currentProperty.startingBlock;
848     renamedProperty.size.u.LowPart  = currentProperty.size.u.LowPart;
849     renamedProperty.size.u.HighPart = currentProperty.size.u.HighPart;
850 
851     renamedProperty.previousProperty = PROPERTY_NULL;
852     renamedProperty.nextProperty     = PROPERTY_NULL;
853 
854     /*
855      * Bring the dirProperty link in case it is a storage and in which
856      * case the renamed storage elements don't require to be reorganized.
857      */
858     renamedProperty.dirProperty = currentProperty.dirProperty;
859 
860     /* call CoFileTime to get the current time
861     renamedProperty.timeStampS1
862     renamedProperty.timeStampD1
863     renamedProperty.timeStampS2
864     renamedProperty.timeStampD2
865     renamedProperty.propertyUniqueID
866     */
867 
868     /*
869      * Obtain a free property in the property chain
870      */
871     renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
872 
873     /*
874      * Save the new property into the new property spot
875      */
876     StorageImpl_WriteProperty(
877       This->ancestorStorage,
878       renamedPropertyIndex,
879       &renamedProperty);
880 
881     /*
882      * Find a spot in the property chain for our newly created property.
883      */
884     updatePropertyChain(
885       (StorageImpl*)This,
886       renamedPropertyIndex,
887       renamedProperty);
888 
889     /*
890      * At this point the renamed property has been inserted in the tree,
891      * now, before Destroying the old property we must zero its dirProperty
892      * otherwise the DestroyProperty below will zap it all and we do not want
893      * this to happen.
894      * Also, we fake that the old property is a storage so the DestroyProperty
895      * will not do a SetSize(0) on the stream data.
896      *
897      * This means that we need to tweak the StgProperty if it is a stream or a
898      * non empty storage.
899      */
900     StorageImpl_ReadProperty(This->ancestorStorage,
901                              foundPropertyIndex,
902                              &currentProperty);
903 
904     currentProperty.dirProperty  = PROPERTY_NULL;
905     currentProperty.propertyType = PROPTYPE_STORAGE;
906     StorageImpl_WriteProperty(
907       This->ancestorStorage,
908       foundPropertyIndex,
909       &currentProperty);
910 
911     /*
912      * Invoke Destroy to get rid of the ole property and automatically redo
913      * the linking of its previous and next members...
914      */
915     IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
916 
917   }
918   else
919   {
920     /*
921      * There is no property with the old name
922      */
923     return STG_E_FILENOTFOUND;
924   }
925 
926   return S_OK;
927 }
928 
929 /************************************************************************
930  * Storage32BaseImpl_CreateStream (IStorage)
931  *
932  * This method will create a stream object within this storage
933  *
934  * See Windows documentation for more details on IStorage methods.
935  */
936 static HRESULT WINAPI StorageBaseImpl_CreateStream(
937             IStorage*        iface,
938             const OLECHAR*   pwcsName,  /* [string][in] */
939             DWORD            grfMode,   /* [in] */
940             DWORD            reserved1, /* [in] */
941             DWORD            reserved2, /* [in] */
942             IStream**        ppstm)     /* [out] */
943 {
944   StorageBaseImpl *This = (StorageBaseImpl *)iface;
945   IEnumSTATSTGImpl* propertyEnumeration;
946   StgStreamImpl*    newStream;
947   StgProperty       currentProperty, newStreamProperty;
948   ULONG             foundPropertyIndex, newPropertyIndex;
949 
950   TRACE("(%p, %s, %x, %d, %d, %p)\n",
951         iface, debugstr_w(pwcsName), grfMode,
952         reserved1, reserved2, ppstm);
953 
954   /*
955    * Validate parameters
956    */
957   if (ppstm == 0)
958     return STG_E_INVALIDPOINTER;
959 
960   if (pwcsName == 0)
961     return STG_E_INVALIDNAME;
962 
963   if (reserved1 || reserved2)
964     return STG_E_INVALIDPARAMETER;
965 
966   /*
967    * Validate the STGM flags
968    */
969   if ( FAILED( validateSTGM(grfMode) ))
970     return STG_E_INVALIDFLAG;
971 
972   if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) 
973     return STG_E_INVALIDFLAG;
974 
975   /*
976    * As documented.
977    */
978   if ((grfMode & STGM_DELETEONRELEASE) ||
979       (grfMode & STGM_TRANSACTED))
980     return STG_E_INVALIDFUNCTION;
981 
982   /*
983    * Check that we're compatible with the parent's storage mode
984    * if not in transacted mode
985    */
986   if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
987     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
988       return STG_E_ACCESSDENIED;
989   }
990 
991   /*
992    * Initialize the out parameter
993    */
994   *ppstm = 0;
995 
996   /*
997    * Create a property enumeration to search the properties
998    */
999   propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
1000                                                    This->rootPropertySetIndex);
1001 
1002   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
1003                                                      pwcsName,
1004                                                      &currentProperty);
1005 
1006   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1007 
1008   if (foundPropertyIndex != PROPERTY_NULL)
1009   {
1010     /*
1011      * An element with this name already exists
1012      */
1013     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
1014     {
1015       StgStreamImpl *strm;
1016 
1017       LIST_FOR_EACH_ENTRY(strm, &This->strmHead, StgStreamImpl, StrmListEntry)
1018       {
1019         if (strm->ownerProperty == foundPropertyIndex)
1020         {
1021           TRACE("Stream deleted %p\n", strm);
1022           strm->parentStorage = NULL;
1023           list_remove(&strm->StrmListEntry);
1024         }
1025       }
1026       IStorage_DestroyElement(iface, pwcsName);
1027     }
1028     else
1029       return STG_E_FILEALREADYEXISTS;
1030   }
1031   else if (STGM_ACCESS_MODE(This->openFlags) == STGM_READ)
1032   {
1033     WARN("read-only storage\n");
1034     return STG_E_ACCESSDENIED;
1035   }
1036 
1037   /*
1038    * memset the empty property
1039    */
1040   memset(&newStreamProperty, 0, sizeof(StgProperty));
1041 
1042   newStreamProperty.sizeOfNameString =
1043       ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
1044 
1045   if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
1046     return STG_E_INVALIDNAME;
1047 
1048   strcpyW(newStreamProperty.name, pwcsName);
1049 
1050   newStreamProperty.propertyType  = PROPTYPE_STREAM;
1051   newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
1052   newStreamProperty.size.u.LowPart  = 0;
1053   newStreamProperty.size.u.HighPart = 0;
1054 
1055   newStreamProperty.previousProperty = PROPERTY_NULL;
1056   newStreamProperty.nextProperty     = PROPERTY_NULL;
1057   newStreamProperty.dirProperty      = PROPERTY_NULL;
1058 
1059   /* call CoFileTime to get the current time
1060   newStreamProperty.timeStampS1
1061   newStreamProperty.timeStampD1
1062   newStreamProperty.timeStampS2
1063   newStreamProperty.timeStampD2
1064   */
1065 
1066   /*  newStreamProperty.propertyUniqueID */
1067 
1068   /*
1069    * Get a free property or create a new one
1070    */
1071   newPropertyIndex = getFreeProperty(This->ancestorStorage);
1072 
1073   /*
1074    * Save the new property into the new property spot
1075    */
1076   StorageImpl_WriteProperty(
1077     This->ancestorStorage,
1078     newPropertyIndex,
1079     &newStreamProperty);
1080 
1081   /*
1082    * Find a spot in the property chain for our newly created property.
1083    */
1084   updatePropertyChain(
1085     (StorageImpl*)This,
1086     newPropertyIndex,
1087     newStreamProperty);
1088 
1089   /*
1090    * Open the stream to return it.
1091    */
1092   newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
1093 
1094   if (newStream != 0)
1095   {
1096     *ppstm = (IStream*)newStream;
1097 
1098     /*
1099      * Since we are returning a pointer to the interface, we have to nail down
1100      * the reference.
1101      */
1102     IStream_AddRef(*ppstm);
1103   }
1104   else
1105   {
1106     return STG_E_INSUFFICIENTMEMORY;
1107   }
1108 
1109   return S_OK;
1110 }
1111 
1112 /************************************************************************
1113  * Storage32BaseImpl_SetClass (IStorage)
1114  *
1115  * This method will write the specified CLSID in the property of this
1116  * storage.
1117  *
1118  * See Windows documentation for more details on IStorage methods.
1119  */
1120 static HRESULT WINAPI StorageBaseImpl_SetClass(
1121   IStorage*        iface,
1122   REFCLSID         clsid) /* [in] */
1123 {
1124   StorageBaseImpl *This = (StorageBaseImpl *)iface;
1125   HRESULT hRes = E_FAIL;
1126   StgProperty curProperty;
1127   BOOL success;
1128 
1129   TRACE("(%p, %p)\n", iface, clsid);
1130 
1131   success = StorageImpl_ReadProperty(This->ancestorStorage,
1132                                        This->rootPropertySetIndex,
1133                                        &curProperty);
1134   if (success)
1135   {
1136     curProperty.propertyUniqueID = *clsid;
1137 
1138     success =  StorageImpl_WriteProperty(This->ancestorStorage,
1139                                            This->rootPropertySetIndex,
1140                                            &curProperty);
1141     if (success)
1142       hRes = S_OK;
1143   }
1144 
1145   return hRes;
1146 }
1147 
1148 /************************************************************************
1149 ** Storage32Impl implementation
1150 */
1151 
1152 /************************************************************************
1153  * Storage32Impl_CreateStorage (IStorage)
1154  *
1155  * This method will create the storage object within the provided storage.
1156  *
1157  * See Windows documentation for more details on IStorage methods.
1158  */
1159 static HRESULT WINAPI StorageImpl_CreateStorage(
1160   IStorage*      iface,
1161   const OLECHAR  *pwcsName, /* [string][in] */
1162   DWORD            grfMode,   /* [in] */
1163   DWORD            reserved1, /* [in] */
1164   DWORD            reserved2, /* [in] */
1165   IStorage       **ppstg)   /* [out] */
1166 {
1167   StorageImpl* const This=(StorageImpl*)iface;
1168 
1169   IEnumSTATSTGImpl *propertyEnumeration;
1170   StgProperty      currentProperty;
1171   StgProperty      newProperty;
1172   ULONG            foundPropertyIndex;
1173   ULONG            newPropertyIndex;
1174   HRESULT          hr;
1175 
1176   TRACE("(%p, %s, %x, %d, %d, %p)\n",
1177         iface, debugstr_w(pwcsName), grfMode,
1178         reserved1, reserved2, ppstg);
1179 
1180   /*
1181    * Validate parameters
1182    */
1183   if (ppstg == 0)
1184     return STG_E_INVALIDPOINTER;
1185 
1186   if (pwcsName == 0)
1187     return STG_E_INVALIDNAME;
1188 
1189   /*
1190    * Initialize the out parameter
1191    */
1192   *ppstg = NULL;
1193 
1194   /*
1195    * Validate the STGM flags
1196    */
1197   if ( FAILED( validateSTGM(grfMode) ) ||
1198        (grfMode & STGM_DELETEONRELEASE) )
1199   {
1200     WARN("bad grfMode: 0x%x\n", grfMode);
1201     return STG_E_INVALIDFLAG;
1202   }
1203 
1204   /*
1205    * Check that we're compatible with the parent's storage mode
1206    */
1207   if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->base.openFlags ) )
1208   {
1209     WARN("access denied\n");
1210     return STG_E_ACCESSDENIED;
1211   }
1212 
1213   /*
1214    * Create a property enumeration and search the properties
1215    */
1216   propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage,
1217                                                     This->base.rootPropertySetIndex);
1218 
1219   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
1220                                                      pwcsName,
1221                                                      &currentProperty);
1222   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1223 
1224   if (foundPropertyIndex != PROPERTY_NULL)
1225   {
1226     /*
1227      * An element with this name already exists
1228      */
1229     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
1230       IStorage_DestroyElement(iface, pwcsName);
1231     else
1232     {
1233       WARN("file already exists\n");
1234       return STG_E_FILEALREADYEXISTS;
1235     }
1236   }
1237   else if (STGM_ACCESS_MODE(This->base.openFlags) == STGM_READ)
1238   {
1239     WARN("read-only storage\n");
1240     return STG_E_ACCESSDENIED;
1241   }
1242 
1243   /*
1244    * memset the empty property
1245    */
1246   memset(&newProperty, 0, sizeof(StgProperty));
1247 
1248   newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
1249 
1250   if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
1251   {
1252     FIXME("name too long\n");
1253     return STG_E_INVALIDNAME;
1254   }
1255 
1256   strcpyW(newProperty.name, pwcsName);
1257 
1258   newProperty.propertyType  = PROPTYPE_STORAGE;
1259   newProperty.startingBlock = BLOCK_END_OF_CHAIN;
1260   newProperty.size.u.LowPart  = 0;
1261   newProperty.size.u.HighPart = 0;
1262 
1263   newProperty.previousProperty = PROPERTY_NULL;
1264   newProperty.nextProperty     = PROPERTY_NULL;
1265   newProperty.dirProperty      = PROPERTY_NULL;
1266 
1267   /* call CoFileTime to get the current time
1268   newProperty.timeStampS1
1269   newProperty.timeStampD1
1270   newProperty.timeStampS2
1271   newProperty.timeStampD2
1272   */
1273 
1274   /*  newStorageProperty.propertyUniqueID */
1275 
1276   /*
1277    * Obtain a free property in the property chain
1278    */
1279   newPropertyIndex = getFreeProperty(This->base.ancestorStorage);
1280 
1281   /*
1282    * Save the new property into the new property spot
1283    */
1284   StorageImpl_WriteProperty(
1285     This->base.ancestorStorage,
1286     newPropertyIndex,
1287     &newProperty);
1288 
1289   /*
1290    * Find a spot in the property chain for our newly created property.
1291    */
1292   updatePropertyChain(
1293     This,
1294     newPropertyIndex,
1295     newProperty);
1296 
1297   /*
1298    * Open it to get a pointer to return.
1299    */
1300   hr = IStorage_OpenStorage(iface, pwcsName, 0, grfMode, 0, 0, ppstg);
1301 
1302   if( (hr != S_OK) || (*ppstg == NULL))
1303   {
1304     return hr;
1305   }
1306 
1307 
1308   return S_OK;
1309 }
1310 
1311 
1312 /***************************************************************************
1313  *
1314  * Internal Method
1315  *
1316  * Get a free property or create a new one.
1317  */
1318 static ULONG getFreeProperty(
1319   StorageImpl *storage)
1320 {
1321   ULONG       currentPropertyIndex = 0;
1322   ULONG       newPropertyIndex     = PROPERTY_NULL;
1323   BOOL      readSuccessful        = TRUE;
1324   StgProperty currentProperty;
1325 
1326   do
1327   {
1328     /*
1329      * Start by reading the root property
1330      */
1331     readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage,
1332                                                currentPropertyIndex,
1333                                                &currentProperty);
1334     if (readSuccessful)
1335     {
1336       if (currentProperty.sizeOfNameString == 0)
1337       {
1338         /*
1339          * The property existis and is available, we found it.
1340          */
1341         newPropertyIndex = currentPropertyIndex;
1342       }
1343     }
1344     else
1345     {
1346       /*
1347        * We exhausted the property list, we will create more space below
1348        */
1349       newPropertyIndex = currentPropertyIndex;
1350     }
1351     currentPropertyIndex++;
1352 
1353   } while (newPropertyIndex == PROPERTY_NULL);
1354 
1355   /*
1356    * grow the property chain
1357    */
1358   if (! readSuccessful)
1359   {
1360     StgProperty    emptyProperty;
1361     ULARGE_INTEGER newSize;
1362     ULONG          propertyIndex;
1363     ULONG          lastProperty  = 0;
1364     ULONG          blockCount    = 0;
1365 
1366     /*
1367      * obtain the new count of property blocks
1368      */
1369     blockCount = BlockChainStream_GetCount(
1370                    storage->base.ancestorStorage->rootBlockChain)+1;
1371 
1372     /*
1373      * initialize the size used by the property stream
1374      */
1375     newSize.u.HighPart = 0;
1376     newSize.u.LowPart  = storage->bigBlockSize * blockCount;
1377 
1378     /*
1379      * add a property block to the property chain
1380      */
1381     BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize);
1382 
1383     /*
1384      * memset the empty property in order to initialize the unused newly
1385      * created property
1386      */
1387     memset(&emptyProperty, 0, sizeof(StgProperty));
1388 
1389     /*
1390      * initialize them
1391      */
1392     lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1393 
1394     for(
1395       propertyIndex = newPropertyIndex;
1396       propertyIndex < lastProperty;
1397       propertyIndex++)
1398     {
1399       StorageImpl_WriteProperty(
1400         storage->base.ancestorStorage,
1401         propertyIndex,
1402         &emptyProperty);
1403     }
1404   }
1405 
1406   return newPropertyIndex;
1407 }
1408 
1409 /****************************************************************************
1410  *
1411  * Internal Method
1412  *
1413  * Case insensitive comparison of StgProperty.name by first considering
1414  * their size.
1415  *
1416  * Returns <0 when newProperty < currentProperty
1417  *         >0 when newProperty > currentProperty
1418  *          0 when newProperty == currentProperty
1419  */
1420 static LONG propertyNameCmp(
1421     const OLECHAR *newProperty,
1422     const OLECHAR *currentProperty)
1423 {
1424   LONG diff      = lstrlenW(newProperty) - lstrlenW(currentProperty);
1425 
1426   if (diff == 0)
1427   {
1428     /*
1429      * We compare the string themselves only when they are of the same length
1430      */
1431     diff = lstrcmpiW( newProperty, currentProperty);
1432   }
1433 
1434   return diff;
1435 }
1436 
1437 /****************************************************************************
1438  *
1439  * Internal Method
1440  *
1441  * Properly link this new element in the property chain.
1442  */
1443 static void updatePropertyChain(
1444   StorageImpl *storage,
1445   ULONG         newPropertyIndex,
1446   StgProperty   newProperty)
1447 {
1448   StgProperty currentProperty;
1449 
1450   /*
1451    * Read the root property
1452    */
1453   StorageImpl_ReadProperty(storage->base.ancestorStorage,
1454                              storage->base.rootPropertySetIndex,
1455                              &currentProperty);
1456 
1457   if (currentProperty.dirProperty != PROPERTY_NULL)
1458   {
1459     /*
1460      * The root storage contains some element, therefore, start the research
1461      * for the appropriate location.
1462      */
1463     BOOL found = 0;
1464     ULONG  current, next, previous, currentPropertyId;
1465 
1466     /*
1467      * Keep the StgProperty sequence number of the storage first property
1468      */
1469     currentPropertyId = currentProperty.dirProperty;
1470 
1471     /*
1472      * Read
1473      */
1474     StorageImpl_ReadProperty(storage->base.ancestorStorage,
1475                                currentProperty.dirProperty,
1476                                &currentProperty);
1477 
1478     previous = currentProperty.previousProperty;
1479     next     = currentProperty.nextProperty;
1480     current  = currentPropertyId;
1481 
1482     while (found == 0)
1483     {
1484       LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1485 
1486       if (diff < 0)
1487       {
1488         if (previous != PROPERTY_NULL)
1489         {
1490           StorageImpl_ReadProperty(storage->base.ancestorStorage,
1491                                      previous,
1492                                      &currentProperty);
1493           current = previous;
1494         }
1495         else
1496         {
1497           currentProperty.previousProperty = newPropertyIndex;
1498           StorageImpl_WriteProperty(storage->base.ancestorStorage,
1499                                       current,
1500                                       &currentProperty);
1501           found = 1;
1502         }
1503       }
1504       else if (diff > 0)
1505       {
1506         if (next != PROPERTY_NULL)
1507         {
1508           StorageImpl_ReadProperty(storage->base.ancestorStorage,
1509                                      next,
1510                                      &currentProperty);
1511           current = next;
1512         }
1513         else
1514         {
1515           currentProperty.nextProperty = newPropertyIndex;
1516           StorageImpl_WriteProperty(storage->base.ancestorStorage,
1517                                       current,
1518                                       &currentProperty);
1519           found = 1;
1520         }
1521       }
1522       else
1523       {
1524         /*
1525          * Trying to insert an item with the same name in the
1526          * subtree structure.
1527          */
1528         assert(FALSE);
1529       }
1530 
1531       previous = currentProperty.previousProperty;
1532       next     = currentProperty.nextProperty;
1533     }
1534   }
1535   else
1536   {
1537     /*
1538      * The root storage is empty, link the new property to its dir property
1539      */
1540     currentProperty.dirProperty = newPropertyIndex;
1541     StorageImpl_WriteProperty(storage->base.ancestorStorage,
1542                                 storage->base.rootPropertySetIndex,
1543                                 &currentProperty);
1544   }
1545 }
1546 
1547 
1548 /*************************************************************************
1549  * CopyTo (IStorage)
1550  */
1551 static HRESULT WINAPI StorageImpl_CopyTo(
1552   IStorage*   iface,
1553   DWORD       ciidExclude,  /* [in] */
1554   const IID*  rgiidExclude, /* [size_is][unique][in] */
1555   SNB         snbExclude,   /* [unique][in] */
1556   IStorage*   pstgDest)     /* [unique][in] */
1557 {
1558   IEnumSTATSTG *elements     = 0;
1559   STATSTG      curElement, strStat;
1560   HRESULT      hr;
1561   IStorage     *pstgTmp, *pstgChild;
1562   IStream      *pstrTmp, *pstrChild;
1563 
1564   if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
1565     FIXME("Exclude option not implemented\n");
1566 
1567   TRACE("(%p, %d, %p, %p, %p)\n",
1568         iface, ciidExclude, rgiidExclude,
1569         snbExclude, pstgDest);
1570 
1571   /*
1572    * Perform a sanity check
1573    */
1574   if ( pstgDest == 0 )
1575     return STG_E_INVALIDPOINTER;
1576 
1577   /*
1578    * Enumerate the elements
1579    */
1580   hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
1581 
1582   if ( hr != S_OK )
1583     return hr;
1584 
1585   /*
1586    * set the class ID
1587    */
1588   IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
1589   IStorage_SetClass( pstgDest, &curElement.clsid );
1590 
1591   do
1592   {
1593     /*
1594      * Obtain the next element
1595      */
1596     hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
1597 
1598     if ( hr == S_FALSE )
1599     {
1600       hr = S_OK;   /* done, every element has been copied */
1601       break;
1602     }
1603 
1604     if (curElement.type == STGTY_STORAGE)
1605     {
1606       /*
1607        * open child source storage
1608        */
1609       hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
1610                                  STGM_READ|STGM_SHARE_EXCLUSIVE,
1611                                  NULL, 0, &pstgChild );
1612 
1613       if (hr != S_OK)
1614         break;
1615 
1616       /*
1617        * Check if destination storage is not a child of the source
1618        * storage, which will cause an infinite loop
1619        */
1620       if (pstgChild == pstgDest)
1621       {
1622         IEnumSTATSTG_Release(elements);
1623 
1624         return STG_E_ACCESSDENIED;
1625       }
1626 
1627       /*
1628        * create a new storage in destination storage
1629        */
1630       hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
1631                                    STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1632                                    0, 0,
1633                                    &pstgTmp );
1634       /*
1635        * if it already exist, don't create a new one use this one
1636        */
1637       if (hr == STG_E_FILEALREADYEXISTS)
1638       {
1639         hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
1640                                    STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1641                                    NULL, 0, &pstgTmp );
1642       }
1643 
1644       if (hr != S_OK)
1645         break;
1646 
1647 
1648       /*
1649        * do the copy recursively
1650        */
1651       hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
1652                                snbExclude, pstgTmp );
1653 
1654       IStorage_Release( pstgTmp );
1655       IStorage_Release( pstgChild );
1656     }
1657     else if (curElement.type == STGTY_STREAM)
1658     {
1659       /*
1660        * create a new stream in destination storage. If the stream already
1661        * exist, it will be deleted and a new one will be created.
1662        */
1663       hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
1664                                   STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1665                                   0, 0, &pstrTmp );
1666 
1667       if (hr != S_OK)
1668         break;
1669 
1670       /*
1671        * open child stream storage
1672        */
1673       hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
1674                                 STGM_READ|STGM_SHARE_EXCLUSIVE,
1675                                 0, &pstrChild );
1676 
1677       if (hr != S_OK)
1678         break;
1679 
1680       /*
1681        * Get the size of the source stream
1682        */
1683       IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1684 
1685       /*
1686        * Set the size of the destination stream.
1687        */
1688       IStream_SetSize(pstrTmp, strStat.cbSize);
1689 
1690       /*
1691        * do the copy
1692        */
1693       hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1694                            NULL, NULL );
1695 
1696       IStream_Release( pstrTmp );
1697       IStream_Release( pstrChild );
1698     }
1699     else
1700     {
1701       WARN("unknown element type: %d\n", curElement.type);
1702     }
1703 
1704   } while (hr == S_OK);
1705 
1706   /*
1707    * Clean-up
1708    */
1709   IEnumSTATSTG_Release(elements);
1710 
1711   return hr;
1712 }
1713 
1714 /*************************************************************************
1715  * MoveElementTo (IStorage)
1716  */
1717 static HRESULT WINAPI StorageImpl_MoveElementTo(
1718   IStorage*     iface,
1719   const OLECHAR *pwcsName,   /* [string][in] */
1720   IStorage      *pstgDest,   /* [unique][in] */
1721   const OLECHAR *pwcsNewName,/* [string][in] */
1722   DWORD           grfFlags)    /* [in] */
1723 {
1724   FIXME("(%p %s %p %s %u): stub\n", iface,
1725          debugstr_w(pwcsName), pstgDest,
1726          debugstr_w(pwcsNewName), grfFlags);
1727   return E_NOTIMPL;
1728 }
1729 
1730 /*************************************************************************
1731  * Commit (IStorage)
1732  *
1733  * Ensures that any changes made to a storage object open in transacted mode
1734  * are reflected in the parent storage
1735  *
1736  * NOTES
1737  *  Wine doesn't implement transacted mode, which seems to be a basic
1738  *  optimization, so we can ignore this stub for now.
1739  */
1740 static HRESULT WINAPI StorageImpl_Commit(
1741   IStorage*   iface,
1742   DWORD         grfCommitFlags)/* [in] */
1743 {
1744   FIXME("(%p %d): stub\n", iface, grfCommitFlags);
1745   return S_OK;
1746 }
1747 
1748 /*************************************************************************
1749  * Revert (IStorage)
1750  *
1751  * Discard all changes that have been made since the last commit operation
1752  */
1753 static HRESULT WINAPI StorageImpl_Revert(
1754   IStorage* iface)
1755 {
1756   FIXME("(%p): stub\n", iface);
1757   return E_NOTIMPL;
1758 }
1759 
1760 /*************************************************************************
1761  * DestroyElement (IStorage)
1762  *
1763  * Strategy: This implementation is built this way for simplicity not for speed.
1764  *          I always delete the topmost element of the enumeration and adjust
1765  *          the deleted element pointer all the time.  This takes longer to
1766  *          do but allow to reinvoke DestroyElement whenever we encounter a
1767  *          storage object.  The optimisation resides in the usage of another
1768  *          enumeration strategy that would give all the leaves of a storage
1769  *          first. (postfix order)
1770  */
1771 static HRESULT WINAPI StorageImpl_DestroyElement(
1772   IStorage*     iface,
1773   const OLECHAR *pwcsName)/* [string][in] */
1774 {
1775   StorageImpl* const This=(StorageImpl*)iface;
1776 
1777   IEnumSTATSTGImpl* propertyEnumeration;
1778   HRESULT           hr = S_OK;
1779   BOOL            res;
1780   StgProperty       propertyToDelete;
1781   StgProperty       parentProperty;
1782   ULONG             foundPropertyIndexToDelete;
1783   ULONG             typeOfRelation;
1784   ULONG             parentPropertyId = 0;
1785 
1786   TRACE("(%p, %s)\n",
1787         iface, debugstr_w(pwcsName));
1788 
1789   /*
1790    * Perform a sanity check on the parameters.
1791    */
1792   if (pwcsName==NULL)
1793     return STG_E_INVALIDPOINTER;
1794 
1795   /*
1796    * Create a property enumeration to search the property with the given name
1797    */
1798   propertyEnumeration = IEnumSTATSTGImpl_Construct(
1799     This->base.ancestorStorage,
1800     This->base.rootPropertySetIndex);
1801 
1802   foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1803     propertyEnumeration,
1804     pwcsName,
1805     &propertyToDelete);
1806 
1807   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1808 
1809   if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1810   {
1811     return STG_E_FILENOTFOUND;
1812   }
1813 
1814   /*
1815    * Find the parent property of the property to delete (the one that
1816    * link to it).  If This->dirProperty == foundPropertyIndexToDelete,
1817    * the parent is This. Otherwise, the parent is one of its sibling...
1818    */
1819 
1820   /*
1821    * First, read This's StgProperty..
1822    */
1823   res = StorageImpl_ReadProperty(
1824           This->base.ancestorStorage,
1825           This->base.rootPropertySetIndex,
1826           &parentProperty);
1827 
1828   assert(res);
1829 
1830   /*
1831    * Second, check to see if by any chance the actual storage (This) is not
1832    * the parent of the property to delete... We never know...
1833    */
1834   if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1835   {
1836     /*
1837      * Set data as it would have been done in the else part...
1838      */
1839     typeOfRelation   = PROPERTY_RELATION_DIR;
1840     parentPropertyId = This->base.rootPropertySetIndex;
1841   }
1842   else
1843   {
1844     /*
1845      * Create a property enumeration to search the parent properties, and
1846      * delete it once done.
1847      */
1848     IEnumSTATSTGImpl* propertyEnumeration2;
1849 
1850     propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1851       This->base.ancestorStorage,
1852       This->base.rootPropertySetIndex);
1853 
1854     typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1855       propertyEnumeration2,
1856       foundPropertyIndexToDelete,
1857       &parentProperty,
1858       &parentPropertyId);
1859 
1860     IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1861   }
1862 
1863   if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1864   {
1865     hr = deleteStorageProperty(
1866            This,
1867            foundPropertyIndexToDelete,
1868            propertyToDelete);
1869   }
1870   else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1871   {
1872     hr = deleteStreamProperty(
1873            This,
1874            foundPropertyIndexToDelete,
1875            propertyToDelete);
1876   }
1877 
1878   if (hr!=S_OK)
1879     return hr;
1880 
1881   /*
1882    * Adjust the property chain
1883    */
1884   hr = adjustPropertyChain(
1885         This,
1886         propertyToDelete,
1887         parentProperty,
1888         parentPropertyId,
1889         typeOfRelation);
1890 
1891   return hr;
1892 }
1893 
1894 
1895 /************************************************************************
1896  * StorageImpl_Stat (IStorage)
1897  *
1898  * This method will retrieve information about this storage object.
1899  *
1900  * See Windows documentation for more details on IStorage methods.
1901  */
1902 static HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
1903                                  STATSTG*  pstatstg,     /* [out] */
1904                                  DWORD     grfStatFlag)  /* [in] */
1905 {
1906   StorageImpl* const This = (StorageImpl*)iface;
1907   HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag );
1908 
1909   if ( SUCCEEDED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName )
1910   {
1911       CoTaskMemFree(pstatstg->pwcsName);
1912       pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
1913       strcpyW(pstatstg->pwcsName, This->pwcsName);
1914   }
1915 
1916   return result;
1917 }
1918 
1919 /******************************************************************************
1920  * Internal stream list handlers
1921  */
1922 
1923 void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm)
1924 {
1925   TRACE("Stream added (stg=%p strm=%p)\n", stg, strm);
1926   list_add_tail(&stg->strmHead,&strm->StrmListEntry);
1927 }
1928 
1929 void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm)
1930 {
1931   TRACE("Stream removed (stg=%p strm=%p)\n", stg,strm);
1932   list_remove(&(strm->StrmListEntry));
1933 }
1934 
1935 static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg)
1936 {
1937   struct list *cur, *cur2;
1938   StgStreamImpl *strm=NULL;
1939 
1940   LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) {
1941     strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry);
1942     TRACE("Streams deleted (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev);
1943     strm->parentStorage = NULL;
1944     list_remove(cur);
1945   }
1946 }
1947 
1948 
1949 /*********************************************************************
1950  *
1951  * Internal Method
1952  *
1953  * Perform the deletion of a complete storage node
1954  *
1955  */
1956 static HRESULT deleteStorageProperty(
1957   StorageImpl *parentStorage,
1958   ULONG        indexOfPropertyToDelete,
1959   StgProperty  propertyToDelete)
1960 {
1961   IEnumSTATSTG *elements     = 0;
1962   IStorage   *childStorage = 0;
1963   STATSTG      currentElement;
1964   HRESULT      hr;
1965   HRESULT      destroyHr = S_OK;
1966 
1967   /*
1968    * Open the storage and enumerate it
1969    */
1970   hr = StorageBaseImpl_OpenStorage(
1971         (IStorage*)parentStorage,
1972         propertyToDelete.name,
1973         0,
1974         STGM_WRITE | STGM_SHARE_EXCLUSIVE,
1975         0,
1976         0,
1977         &childStorage);
1978 
1979   if (hr != S_OK)
1980   {
1981     return hr;
1982   }
1983 
1984   /*
1985    * Enumerate the elements
1986    */
1987   IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1988 
1989   do
1990   {
1991     /*
1992      * Obtain the next element
1993      */
1994     hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1995     if (hr==S_OK)
1996     {
1997       destroyHr = StorageImpl_DestroyElement(childStorage, currentElement.pwcsName);
1998 
1999       CoTaskMemFree(currentElement.pwcsName);
2000     }
2001 
2002     /*
2003      * We need to Reset the enumeration every time because we delete elements
2004      * and the enumeration could be invalid
2005      */
2006     IEnumSTATSTG_Reset(elements);
2007 
2008   } while ((hr == S_OK) && (destroyHr == S_OK));
2009 
2010   /*
2011    * Invalidate the property by zeroing its name member.
2012    */
2013   propertyToDelete.sizeOfNameString = 0;
2014 
2015   StorageImpl_WriteProperty(parentStorage->base.ancestorStorage,
2016                             indexOfPropertyToDelete,
2017                             &propertyToDelete);
2018 
2019   IStorage_Release(childStorage);
2020   IEnumSTATSTG_Release(elements);
2021 
2022   return destroyHr;
2023 }
2024 
2025 /*********************************************************************
2026  *
2027  * Internal Method
2028  *
2029  * Perform the deletion of a stream node
2030  *
2031  */
2032 static HRESULT deleteStreamProperty(
2033   StorageImpl *parentStorage,
2034   ULONG         indexOfPropertyToDelete,
2035   StgProperty   propertyToDelete)
2036 {
2037   IStream      *pis;
2038   HRESULT        hr;
2039   ULARGE_INTEGER size;
2040 
2041   size.u.HighPart = 0;
2042   size.u.LowPart = 0;
2043 
2044   hr = StorageBaseImpl_OpenStream(
2045          (IStorage*)parentStorage,
2046          (OLECHAR*)propertyToDelete.name,
2047          NULL,
2048          STGM_WRITE | STGM_SHARE_EXCLUSIVE,
2049          0,
2050          &pis);
2051 
2052   if (hr!=S_OK)
2053   {
2054     return(hr);
2055   }
2056 
2057   /*
2058    * Zap the stream
2059    */
2060   hr = IStream_SetSize(pis, size);
2061 
2062   if(hr != S_OK)
2063   {
2064     return hr;
2065   }
2066 
2067   /*
2068    * Release the stream object.
2069    */
2070   IStream_Release(pis);
2071 
2072   /*
2073    * Invalidate the property by zeroing its name member.
2074    */
2075   propertyToDelete.sizeOfNameString = 0;
2076 
2077   /*
2078    * Here we should re-read the property so we get the updated pointer
2079    * but since we are here to zap it, I don't do it...
2080    */
2081   StorageImpl_WriteProperty(
2082     parentStorage->base.ancestorStorage,
2083     indexOfPropertyToDelete,
2084     &propertyToDelete);
2085 
2086   return S_OK;
2087 }
2088 
2089 /*********************************************************************
2090  *
2091  * Internal Method
2092  *
2093  * Finds a placeholder for the StgProperty within the Storage
2094  *
2095  */
2096 static HRESULT findPlaceholder(
2097   StorageImpl *storage,
2098   ULONG         propertyIndexToStore,
2099   ULONG         storePropertyIndex,
2100   INT         typeOfRelation)
2101 {
2102   StgProperty storeProperty;
2103   BOOL      res = TRUE;
2104 
2105   /*
2106    * Read the storage property
2107    */
2108   res = StorageImpl_ReadProperty(
2109           storage->base.ancestorStorage,
2110           storePropertyIndex,
2111           &storeProperty);
2112 
2113   if(! res)
2114   {
2115     return E_FAIL;
2116   }
2117 
2118   if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
2119   {
2120     if (storeProperty.previousProperty != PROPERTY_NULL)
2121     {
2122       return findPlaceholder(
2123                storage,
2124                propertyIndexToStore,
2125                storeProperty.previousProperty,
2126                typeOfRelation);
2127     }
2128     else
2129     {
2130       storeProperty.previousProperty = propertyIndexToStore;
2131     }
2132   }
2133   else if (typeOfRelation == PROPERTY_RELATION_NEXT)
2134   {
2135     if (storeProperty.nextProperty != PROPERTY_NULL)
2136     {
2137       return findPlaceholder(
2138                storage,
2139                propertyIndexToStore,
2140                storeProperty.nextProperty,
2141                typeOfRelation);
2142     }
2143     else
2144     {
2145       storeProperty.nextProperty = propertyIndexToStore;
2146     }
2147   }
2148   else if (typeOfRelation == PROPERTY_RELATION_DIR)
2149   {
2150     if (storeProperty.dirProperty != PROPERTY_NULL)
2151     {
2152       return findPlaceholder(
2153                storage,
2154                propertyIndexToStore,
2155                storeProperty.dirProperty,
2156                typeOfRelation);
2157     }
2158     else
2159     {
2160       storeProperty.dirProperty = propertyIndexToStore;
2161     }
2162   }
2163 
2164   res = StorageImpl_WriteProperty(
2165          storage->base.ancestorStorage,
2166          storePropertyIndex,
2167          &storeProperty);
2168 
2169   if(!res)
2170   {
2171     return E_FAIL;
2172   }
2173 
2174   return S_OK;
2175 }
2176 
2177 /*************************************************************************
2178  *
2179  * Internal Method
2180  *
2181  * This method takes the previous and the next property link of a property
2182  * to be deleted and find them a place in the Storage.
2183  */
2184 static HRESULT adjustPropertyChain(
2185   StorageImpl *This,
2186   StgProperty   propertyToDelete,
2187   StgProperty   parentProperty,
2188   ULONG         parentPropertyId,
2189   INT         typeOfRelation)
2190 {
2191   ULONG   newLinkProperty        = PROPERTY_NULL;
2192   BOOL  needToFindAPlaceholder = FALSE;
2193   ULONG   storeNode              = PROPERTY_NULL;
2194   ULONG   toStoreNode            = PROPERTY_NULL;
2195   INT   relationType           = 0;
2196   HRESULT hr                     = S_OK;
2197   BOOL  res                    = TRUE;
2198 
2199   if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
2200   {
2201     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2202     {
2203       /*
2204        * Set the parent previous to the property to delete previous
2205        */
2206       newLinkProperty = propertyToDelete.previousProperty;
2207 
2208       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2209       {
2210         /*
2211          * We also need to find a storage for the other link, setup variables
2212          * to do this at the end...
2213          */
2214         needToFindAPlaceholder = TRUE;
2215         storeNode              = propertyToDelete.previousProperty;
2216         toStoreNode            = propertyToDelete.nextProperty;
2217         relationType           = PROPERTY_RELATION_NEXT;
2218       }
2219     }
2220     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2221     {
2222       /*
2223        * Set the parent previous to the property to delete next
2224        */
2225       newLinkProperty = propertyToDelete.nextProperty;
2226     }
2227 
2228     /*
2229      * Link it for real...
2230      */
2231     parentProperty.previousProperty = newLinkProperty;
2232 
2233   }
2234   else if (typeOfRelation == PROPERTY_RELATION_NEXT)
2235   {
2236     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2237     {
2238       /*
2239        * Set the parent next to the property to delete next previous
2240        */
2241       newLinkProperty = propertyToDelete.previousProperty;
2242 
2243       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2244       {
2245         /*
2246          * We also need to find a storage for the other link, setup variables
2247          * to do this at the end...
2248          */
2249         needToFindAPlaceholder = TRUE;
2250         storeNode              = propertyToDelete.previousProperty;
2251         toStoreNode            = propertyToDelete.nextProperty;
2252         relationType           = PROPERTY_RELATION_NEXT;
2253       }
2254     }
2255     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2256     {
2257       /*
2258        * Set the parent next to the property to delete next
2259        */
2260       newLinkProperty = propertyToDelete.nextProperty;
2261     }
2262 
2263     /*
2264      * Link it for real...
2265      */
2266     parentProperty.nextProperty = newLinkProperty;
2267   }
2268   else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2269   {
2270     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2271     {
2272       /*
2273        * Set the parent dir to the property to delete previous
2274        */
2275       newLinkProperty = propertyToDelete.previousProperty;
2276 
2277       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2278       {
2279         /*
2280          * We also need to find a storage for the other link, setup variables
2281          * to do this at the end...
2282          */
2283         needToFindAPlaceholder = TRUE;
2284         storeNode              = propertyToDelete.previousProperty;
2285         toStoreNode            = propertyToDelete.nextProperty;
2286         relationType           = PROPERTY_RELATION_NEXT;
2287       }
2288     }
2289     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2290     {
2291       /*
2292        * Set the parent dir to the property to delete next
2293        */
2294       newLinkProperty = propertyToDelete.nextProperty;
2295     }
2296 
2297     /*
2298      * Link it for real...
2299      */
2300     parentProperty.dirProperty = newLinkProperty;
2301   }
2302 
2303   /*
2304    * Write back the parent property
2305    */
2306   res = StorageImpl_WriteProperty(
2307           This->base.ancestorStorage,
2308           parentPropertyId,
2309           &parentProperty);
2310   if(! res)
2311   {
2312     return E_FAIL;
2313   }
2314 
2315   /*
2316    * If a placeholder is required for the other link, then, find one and
2317    * get out of here...
2318    */
2319   if (needToFindAPlaceholder)
2320   {
2321     hr = findPlaceholder(
2322            This,
2323            toStoreNode,
2324            storeNode,
2325            relationType);
2326   }
2327 
2328   return hr;
2329 }
2330 
2331 
2332 /******************************************************************************
2333  * SetElementTimes (IStorage)
2334  */
2335 static HRESULT WINAPI StorageImpl_SetElementTimes(
2336   IStorage*     iface,
2337   const OLECHAR *pwcsName,/* [string][in] */
2338   const FILETIME  *pctime,  /* [in] */
2339   const FILETIME  *patime,  /* [in] */
2340   const FILETIME  *pmtime)  /* [in] */
2341 {
2342   FIXME("(%s,...), stub!\n",debugstr_w(pwcsName));
2343   return S_OK;
2344 }
2345 
2346 /******************************************************************************
2347  * SetStateBits (IStorage)
2348  */
2349 static HRESULT WINAPI StorageImpl_SetStateBits(
2350   IStorage*   iface,
2351   DWORD         grfStateBits,/* [in] */
2352   DWORD         grfMask)     /* [in] */
2353 {
2354   StorageImpl* const This = (StorageImpl*)iface;
2355   This->base.stateBits = (This->base.stateBits & ~grfMask) | (grfStateBits & grfMask);
2356   return S_OK;
2357 }
2358 
2359 /*
2360  * Virtual function table for the IStorage32Impl class.
2361  */
2362 static const IStorageVtbl Storage32Impl_Vtbl =
2363 {
2364     StorageBaseImpl_QueryInterface,
2365     StorageBaseImpl_AddRef,
2366     StorageBaseImpl_Release,
2367     StorageBaseImpl_CreateStream,
2368     StorageBaseImpl_OpenStream,
2369     StorageImpl_CreateStorage,
2370     StorageBaseImpl_OpenStorage,
2371     StorageImpl_CopyTo,
2372     StorageImpl_MoveElementTo,
2373     StorageImpl_Commit,
2374     StorageImpl_Revert,
2375     StorageBaseImpl_EnumElements,
2376     StorageImpl_DestroyElement,
2377     StorageBaseImpl_RenameElement,
2378     StorageImpl_SetElementTimes,
2379     StorageBaseImpl_SetClass,
2380     StorageImpl_SetStateBits,
2381     StorageImpl_Stat
2382 };
2383 
2384 static HRESULT StorageImpl_Construct(
2385   StorageImpl* This,
2386   HANDLE       hFile,
2387   LPCOLESTR    pwcsName,
2388   ILockBytes*  pLkbyt,
2389   DWORD        openFlags,
2390   BOOL         fileBased,
2391   BOOL         fileCreate)
2392 {
2393   HRESULT     hr = S_OK;
2394   StgProperty currentProperty;
2395   BOOL      readSuccessful;
2396   ULONG       currentPropertyIndex;
2397 
2398   if ( FAILED( validateSTGM(openFlags) ))
2399     return STG_E_INVALIDFLAG;
2400 
2401   memset(This, 0, sizeof(StorageImpl));
2402 
2403   /*
2404    * Initialize stream list
2405    */
2406 
2407   list_init(&This->base.strmHead);
2408 
2409   /*
2410    * Initialize the virtual function table.
2411    */
2412   This->base.lpVtbl = &Storage32Impl_Vtbl;
2413   This->base.pssVtbl = &IPropertySetStorage_Vtbl;
2414   This->base.v_destructor = StorageImpl_Destroy;
2415   This->base.openFlags = (openFlags & ~STGM_CREATE);
2416 
2417   /*
2418    * This is the top-level storage so initialize the ancestor pointer
2419    * to this.
2420    */
2421   This->base.ancestorStorage = This;
2422 
2423   /*
2424    * Initialize the physical support of the storage.
2425    */
2426   This->hFile = hFile;
2427 
2428   /*
2429    * Store copy of file path.
2430    */
2431   if(pwcsName) {
2432       This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
2433                                 (lstrlenW(pwcsName)+1)*sizeof(WCHAR));
2434       if (!This->pwcsName)
2435          return STG_E_INSUFFICIENTMEMORY;
2436       strcpyW(This->pwcsName, pwcsName);
2437   }
2438 
2439   /*
2440    * Initialize the big block cache.
2441    */
2442   This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;
2443   This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
2444   This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,
2445                                                 pLkbyt,
2446                                                 openFlags,
2447                                                 This->bigBlockSize,
2448                                                 fileBased);
2449 
2450   if (This->bigBlockFile == 0)
2451     return E_FAIL;
2452 
2453   if (fileCreate)
2454   {
2455     ULARGE_INTEGER size;
2456     BYTE bigBlockBuffer[BIG_BLOCK_SIZE];
2457 
2458     /*
2459      * Initialize all header variables:
2460      * - The big block depot consists of one block and it is at block 0
2461      * - The properties start at block 1
2462      * - There is no small block depot
2463      */
2464     memset( This->bigBlockDepotStart,
2465             BLOCK_UNUSED,
2466             sizeof(This->bigBlockDepotStart));
2467 
2468     This->bigBlockDepotCount    = 1;
2469     This->bigBlockDepotStart[0] = 0;
2470     This->rootStartBlock        = 1;
2471     This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
2472     This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;
2473     This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
2474     This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
2475     This->extBigBlockDepotCount = 0;
2476 
2477     StorageImpl_SaveFileHeader(This);
2478 
2479     /*
2480      * Add one block for the big block depot and one block for the properties
2481      */
2482     size.u.HighPart = 0;
2483     size.u.LowPart  = This->bigBlockSize * 3;
2484     BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
2485 
2486     /*
2487      * Initialize the big block depot
2488      */
2489     memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2490     StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
2491     StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
2492     StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
2493   }
2494   else
2495   {
2496     /*
2497      * Load the header for the file.
2498      */
2499     hr = StorageImpl_LoadFileHeader(This);
2500 
2501     if (FAILED(hr))
2502     {
2503       BIGBLOCKFILE_Destructor(This->bigBlockFile);
2504 
2505       return hr;
2506     }
2507   }
2508 
2509   /*
2510    * There is no block depot cached yet.
2511    */
2512   This->indexBlockDepotCached = 0xFFFFFFFF;
2513 
2514   /*
2515    * Start searching for free blocks with block 0.
2516    */
2517   This->prevFreeBlock = 0;
2518 
2519   /*
2520    * Create the block chain abstractions.
2521    */
2522   if(!(This->rootBlockChain =
2523        BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL)))
2524     return STG_E_READFAULT;
2525 
2526   if(!(This->smallBlockDepotChain =
2527        BlockChainStream_Construct(This, &This->smallBlockDepotStart,
2528                                   PROPERTY_NULL)))
2529     return STG_E_READFAULT;
2530 
2531   /*
2532    * Write the root property (memory only)
2533    */
2534   if (fileCreate)
2535   {
2536     StgProperty rootProp;
2537     /*
2538      * Initialize the property chain
2539      */
2540     memset(&rootProp, 0, sizeof(rootProp));
2541     MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name,
2542                          sizeof(rootProp.name)/sizeof(WCHAR) );
2543     rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR);
2544     rootProp.propertyType     = PROPTYPE_ROOT;
2545     rootProp.previousProperty = PROPERTY_NULL;
2546     rootProp.nextProperty     = PROPERTY_NULL;
2547     rootProp.dirProperty      = PROPERTY_NULL;
2548     rootProp.startingBlock    = BLOCK_END_OF_CHAIN;
2549     rootProp.size.u.HighPart    = 0;
2550     rootProp.size.u.LowPart     = 0;
2551 
2552     StorageImpl_WriteProperty(This, 0, &rootProp);
2553   }
2554 
2555   /*
2556    * Find the ID of the root in the property sets.
2557    */
2558   currentPropertyIndex = 0;
2559 
2560   do
2561   {
2562     readSuccessful = StorageImpl_ReadProperty(
2563                       This,
2564                       currentPropertyIndex,
2565                       &currentProperty);
2566 
2567     if (readSuccessful)
2568     {
2569       if ( (currentProperty.sizeOfNameString != 0 ) &&
2570            (currentProperty.propertyType     == PROPTYPE_ROOT) )
2571       {
2572         This->base.rootPropertySetIndex = currentPropertyIndex;
2573       }
2574     }
2575 
2576     currentPropertyIndex++;
2577 
2578   } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) );
2579 
2580   if (!readSuccessful)
2581   {
2582     /* TODO CLEANUP */
2583     return STG_E_READFAULT;
2584   }
2585 
2586   /*
2587    * Create the block chain abstraction for the small block root chain.
2588    */
2589   if(!(This->smallBlockRootChain =
2590        BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex)))
2591     return STG_E_READFAULT;
2592 
2593   return hr;
2594 }
2595 
2596 static void StorageImpl_Destroy(StorageBaseImpl* iface)
2597 {
2598   StorageImpl *This = (StorageImpl*) iface;
2599   TRACE("(%p)\n", This);
2600 
2601   StorageBaseImpl_DeleteAll(&This->base);
2602 
2603   HeapFree(GetProcessHeap(), 0, This->pwcsName);
2604 
2605   BlockChainStream_Destroy(This->smallBlockRootChain);
2606   BlockChainStream_Destroy(This->rootBlockChain);
2607   BlockChainStream_Destroy(This->smallBlockDepotChain);
2608 
2609   BIGBLOCKFILE_Destructor(This->bigBlockFile);
2610   HeapFree(GetProcessHeap(), 0, This);
2611 }
2612 
2613 /******************************************************************************
2614  *      Storage32Impl_GetNextFreeBigBlock
2615  *
2616  * Returns the index of the next free big block.
2617  * If the big block depot is filled, this method will enlarge it.
2618  *
2619  */
2620 static ULONG StorageImpl_GetNextFreeBigBlock(
2621   StorageImpl* This)
2622 {
2623   ULONG depotBlockIndexPos;
2624   BYTE depotBuffer[BIG_BLOCK_SIZE];
2625   BOOL success;
2626   ULONG depotBlockOffset;
2627   ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
2628   ULONG nextBlockIndex    = BLOCK_SPECIAL;
2629   int   depotIndex        = 0;
2630   ULONG freeBlock         = BLOCK_UNUSED;
2631 
2632   depotIndex = This->prevFreeBlock / blocksPerDepot;
2633   depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2634 
2635   /*
2636    * Scan the entire big block depot until we find a block marked free
2637    */
2638   while (nextBlockIndex != BLOCK_UNUSED)
2639   {
2640     if (depotIndex < COUNT_BBDEPOTINHEADER)
2641     {
2642       depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2643 
2644       /*
2645        * Grow the primary depot.
2646        */
2647       if (depotBlockIndexPos == BLOCK_UNUSED)
2648       {
2649         depotBlockIndexPos = depotIndex*blocksPerDepot;
2650 
2651         /*
2652          * Add a block depot.
2653          */
2654         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2655         This->bigBlockDepotCount++;
2656         This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2657 
2658         /*
2659          * Flag it as a block depot.
2660          */
2661         StorageImpl_SetNextBlockInChain(This,
2662                                           depotBlockIndexPos,
2663                                           BLOCK_SPECIAL);
2664 
2665         /* Save new header information.
2666          */
2667         StorageImpl_SaveFileHeader(This);
2668       }
2669     }
2670     else
2671     {
2672       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2673 
2674       if (depotBlockIndexPos == BLOCK_UNUSED)
2675       {
2676         /*
2677          * Grow the extended depot.
2678          */
2679         ULONG extIndex       = BLOCK_UNUSED;
2680         ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
2681         ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2682 
2683         if (extBlockOffset == 0)
2684         {
2685           /* We need an extended block.
2686            */
2687           extIndex = Storage32Impl_AddExtBlockDepot(This);
2688           This->extBigBlockDepotCount++;
2689           depotBlockIndexPos = extIndex + 1;
2690         }
2691         else
2692           depotBlockIndexPos = depotIndex * blocksPerDepot;
2693 
2694         /*
2695          * Add a block depot and mark it in the extended block.
2696          */
2697         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2698         This->bigBlockDepotCount++;
2699         Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2700 
2701         /* Flag the block depot.
2702          */
2703         StorageImpl_SetNextBlockInChain(This,
2704                                           depotBlockIndexPos,
2705                                           BLOCK_SPECIAL);
2706 
2707         /* If necessary, flag the extended depot block.
2708          */
2709         if (extIndex != BLOCK_UNUSED)
2710           StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2711 
2712         /* Save header information.
2713          */
2714         StorageImpl_SaveFileHeader(This);
2715       }
2716     }
2717 
2718     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
2719 
2720     if (success)
2721     {
2722       while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2723               ( nextBlockIndex != BLOCK_UNUSED))
2724       {
2725         StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2726 
2727         if (nextBlockIndex == BLOCK_UNUSED)
2728         {
2729           freeBlock = (depotIndex * blocksPerDepot) +
2730                       (depotBlockOffset/sizeof(ULONG));
2731         }
2732 
2733         depotBlockOffset += sizeof(ULONG);
2734       }
2735     }
2736 
2737     depotIndex++;
2738     depotBlockOffset = 0;
2739   }
2740 
2741   /*
2742    * make sure that the block physically exists before using it
2743    */
2744   BIGBLOCKFILE_EnsureExists(This->bigBlockFile, freeBlock);
2745 
2746   This->prevFreeBlock = freeBlock;
2747 
2748   return freeBlock;
2749 }
2750 
2751 /******************************************************************************
2752  *      Storage32Impl_AddBlockDepot
2753  *
2754  * This will create a depot block, essentially it is a block initialized
2755  * to BLOCK_UNUSEDs.
2756  */
2757 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2758 {
2759   BYTE blockBuffer[BIG_BLOCK_SIZE];
2760 
2761   /*
2762    * Initialize blocks as free
2763    */
2764   memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2765   StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
2766 }
2767 
2768 /******************************************************************************
2769  *      Storage32Impl_GetExtDepotBlock
2770  *
2771  * Returns the index of the block that corresponds to the specified depot
2772  * index. This method is only for depot indexes equal or greater than
2773  * COUNT_BBDEPOTINHEADER.
2774  */
2775 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2776 {
2777   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2778   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
2779   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
2780   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
2781   ULONG blockIndex             = BLOCK_UNUSED;
2782   ULONG extBlockIndex          = This->extBigBlockDepotStart;
2783 
2784   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2785 
2786   if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2787     return BLOCK_UNUSED;
2788 
2789   while (extBlockCount > 0)
2790   {
2791     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2792     extBlockCount--;
2793   }
2794 
2795   if (extBlockIndex != BLOCK_UNUSED)
2796     StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex,
2797                         extBlockOffset * sizeof(ULONG), &blockIndex);
2798 
2799   return blockIndex;
2800 }
2801 
2802 /******************************************************************************
2803  *      Storage32Impl_SetExtDepotBlock
2804  *
2805  * Associates the specified block index to the specified depot index.
2806  * This method is only for depot indexes equal or greater than
2807  * COUNT_BBDEPOTINHEADER.
2808  */
2809 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
2810 {
2811   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2812   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
2813   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
2814   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
2815   ULONG extBlockIndex          = This->extBigBlockDepotStart;
2816 
2817   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2818 
2819   while (extBlockCount > 0)
2820   {
2821     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2822     extBlockCount--;
2823   }
2824 
2825   if (extBlockIndex != BLOCK_UNUSED)
2826   {
2827     StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
2828                         extBlockOffset * sizeof(ULONG),
2829                         blockIndex);
2830   }
2831 }
2832 
2833 /******************************************************************************
2834  *      Storage32Impl_AddExtBlockDepot
2835  *
2836  * Creates an extended depot block.
2837  */
2838 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2839 {
2840   ULONG numExtBlocks           = This->extBigBlockDepotCount;
2841   ULONG nextExtBlock           = This->extBigBlockDepotStart;
2842   BYTE  depotBuffer[BIG_BLOCK_SIZE];
2843   ULONG index                  = BLOCK_UNUSED;
2844   ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
2845   ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
2846   ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2847 
2848   index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2849           blocksPerDepotBlock;
2850 
2851   if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2852   {
2853     /*
2854      * The first extended block.
2855      */
2856     This->extBigBlockDepotStart = index;
2857   }
2858   else
2859   {
2860     unsigned int i;
2861     /*
2862      * Follow the chain to the last one.
2863      */
2864     for (i = 0; i < (numExtBlocks - 1); i++)
2865     {
2866       nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2867     }
2868 
2869     /*
2870      * Add the new extended block to the chain.
2871      */
2872     StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
2873                                      index);
2874   }
2875 
2876   /*
2877    * Initialize this block.
2878    */
2879   memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2880   StorageImpl_WriteBigBlock(This, index, depotBuffer);
2881 
2882   return index;
2883 }
2884 
2885 /******************************************************************************
2886  *      Storage32Impl_FreeBigBlock
2887  *
2888  * This method will flag the specified block as free in the big block depot.
2889  */
2890 static void StorageImpl_FreeBigBlock(
2891   StorageImpl* This,
2892   ULONG          blockIndex)
2893 {
2894   StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2895 
2896   if (blockIndex < This->prevFreeBlock)
2897     This->prevFreeBlock = blockIndex;
2898 }
2899 
2900 /************************************************************************
2901  * Storage32Impl_GetNextBlockInChain
2902  *
2903  * This method will retrieve the block index of the next big block in
2904  * in the chain.
2905  *
2906  * Params:  This       - Pointer to the Storage object.
2907  *          blockIndex - Index of the block to retrieve the chain
2908  *                       for.
2909  *          nextBlockIndex - receives the return value.
2910  *
2911  * Returns: This method returns the index of the next block in the chain.
2912  *          It will return the constants:
2913  *              BLOCK_SPECIAL - If the block given was not part of a
2914  *                              chain.
2915  *              BLOCK_END_OF_CHAIN - If the block given was the last in
2916  *                                   a chain.
2917  *              BLOCK_UNUSED - If the block given was not past of a chain
2918  *                             and is available.
2919  *              BLOCK_EXTBBDEPOT - This block is part of the extended
2920  *                                 big block depot.
2921  *
2922  * See Windows documentation for more details on IStorage methods.
2923  */
2924 static HRESULT StorageImpl_GetNextBlockInChain(
2925   StorageImpl* This,
2926   ULONG        blockIndex,
2927   ULONG*       nextBlockIndex)
2928 {
2929   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
2930   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
2931   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2932   BYTE depotBuffer[BIG_BLOCK_SIZE];
2933   BOOL success;
2934   ULONG depotBlockIndexPos;
2935   int index;
2936 
2937   *nextBlockIndex   = BLOCK_SPECIAL;
2938 
2939   if(depotBlockCount >= This->bigBlockDepotCount)
2940   {
2941     WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount,
2942          This->bigBlockDepotCount);
2943     return STG_E_READFAULT;
2944   }
2945 
2946   /*
2947    * Cache the currently accessed depot block.
2948    */
2949   if (depotBlockCount != This->indexBlockDepotCached)
2950   {
2951     This->indexBlockDepotCached = depotBlockCount;
2952 
2953     if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2954     {
2955       depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2956     }
2957     else
2958     {
2959       /*
2960        * We have to look in the extended depot.
2961        */
2962       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2963     }
2964 
2965     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
2966 
2967     if (!success)
2968       return STG_E_READFAULT;
2969 
2970     for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2971     {
2972       StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
2973       This->blockDepotCached[index] = *nextBlockIndex;
2974     }
2975   }
2976 
2977   *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2978 
2979   return S_OK;
2980 }
2981 
2982 /******************************************************************************
2983  *      Storage32Impl_GetNextExtendedBlock
2984  *
2985  * Given an extended block this method will return the next extended block.
2986  *
2987  * NOTES:
2988  * The last ULONG of an extended block is the block index of the next
2989  * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2990  * depot.
2991  *
2992  * Return values:
2993  *    - The index of the next extended block
2994  *    - BLOCK_UNUSED: there is no next extended block.
2995  *    - Any other return values denotes failure.
2996  */
2997 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2998 {
2999   ULONG nextBlockIndex   = BLOCK_SPECIAL;
3000   ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
3001 
3002   StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
3003                         &nextBlockIndex);
3004 
3005   return nextBlockIndex;
3006 }
3007 
3008 /******************************************************************************
3009  *      Storage32Impl_SetNextBlockInChain
3010  *
3011  * This method will write the index of the specified block's next block
3012  * in the big block depot.
3013  *
3014  * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
3015  *              do the following
3016  *
3017  * Storage32Impl_SetNextBlockInChain(This, 3, 1);
3018  * Storage32Impl_SetNextBlockInChain(This, 1, 7);
3019  * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
3020  *
3021  */
3022 static void StorageImpl_SetNextBlockInChain(
3023           StorageImpl* This,
3024           ULONG          blockIndex,
3025           ULONG          nextBlock)
3026 {
3027   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
3028   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
3029   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
3030   ULONG depotBlockIndexPos;
3031 
3032   assert(depotBlockCount < This->bigBlockDepotCount);
3033   assert(blockIndex != nextBlock);
3034 
3035   if (depotBlockCount < COUNT_BBDEPOTINHEADER)
3036   {
3037     depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
3038   }
3039   else
3040   {
3041     /*
3042      * We have to look in the extended depot.
3043      */
3044     depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
3045   }
3046 
3047   StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
3048                         nextBlock);
3049   /*
3050    * Update the cached block depot, if necessary.
3051    */
3052   if (depotBlockCount == This->indexBlockDepotCached)
3053   {
3054     This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
3055   }
3056 }
3057 
3058 /******************************************************************************
3059  *      Storage32Impl_LoadFileHeader
3060  *
3061  * This method will read in the file header, i.e. big block index -1.
3062  */
3063 static HRESULT StorageImpl_LoadFileHeader(
3064           StorageImpl* This)
3065 {
3066   HRESULT hr = STG_E_FILENOTFOUND;
3067   BYTE    headerBigBlock[BIG_BLOCK_SIZE];
3068   BOOL    success;
3069   int     index;
3070 
3071   TRACE("\n");
3072   /*
3073    * Get a pointer to the big block of data containing the header.
3074    */
3075   success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
3076 
3077   /*
3078    * Extract the information from the header.
3079    */
3080   if (success)
3081   {
3082     /*
3083      * Check for the "magic number" signature and return an error if it is not
3084      * found.
3085      */
3086     if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
3087     {
3088       return STG_E_OLDFORMAT;
3089     }
3090 
3091     if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
3092     {
3093       return STG_E_INVALIDHEADER;
3094     }
3095 
3096     StorageUtl_ReadWord(
3097       headerBigBlock,
3098       OFFSET_BIGBLOCKSIZEBITS,
3099       &This->bigBlockSizeBits);
3100 
3101     StorageUtl_ReadWord(
3102       headerBigBlock,
3103       OFFSET_SMALLBLOCKSIZEBITS,
3104       &This->smallBlockSizeBits);
3105 
3106     StorageUtl_ReadDWord(
3107       headerBigBlock,
3108       OFFSET_BBDEPOTCOUNT,
3109       &This->bigBlockDepotCount);
3110 
3111     StorageUtl_ReadDWord(
3112       headerBigBlock,
3113       OFFSET_ROOTSTARTBLOCK,
3114       &This->rootStartBlock);
3115 
3116     StorageUtl_ReadDWord(
3117       headerBigBlock,
3118       OFFSET_SBDEPOTSTART,
3119       &This->smallBlockDepotStart);
3120 
3121     StorageUtl_ReadDWord(
3122       headerBigBlock,
3123       OFFSET_EXTBBDEPOTSTART,
3124       &This->extBigBlockDepotStart);
3125 
3126     StorageUtl_ReadDWord(
3127       headerBigBlock,
3128       OFFSET_EXTBBDEPOTCOUNT,
3129       &This->extBigBlockDepotCount);
3130 
3131     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3132     {
3133       StorageUtl_ReadDWord(
3134         headerBigBlock,
3135         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3136         &(This->bigBlockDepotStart[index]));
3137     }
3138 
3139     /*
3140      * Make the bitwise arithmetic to get the size of the blocks in bytes.
3141      */
3142     This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
3143     This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
3144 
3145     /*
3146      * Right now, the code is making some assumptions about the size of the
3147      * blocks, just make sure they are what we're expecting.
3148      */
3149     if (This->bigBlockSize != DEF_BIG_BLOCK_SIZE ||
3150         This->smallBlockSize != DEF_SMALL_BLOCK_SIZE)
3151     {
3152         WARN("Broken OLE storage file\n");
3153         hr = STG_E_INVALIDHEADER;
3154     }
3155     else
3156         hr = S_OK;
3157   }
3158 
3159   return hr;
3160 }
3161 
3162 /******************************************************************************
3163  *      Storage32Impl_SaveFileHeader
3164  *
3165  * This method will save to the file the header, i.e. big block -1.
3166  */
3167 static void StorageImpl_SaveFileHeader(
3168           StorageImpl* This)
3169 {
3170   BYTE   headerBigBlock[BIG_BLOCK_SIZE];
3171   int    index;
3172   BOOL success;
3173 
3174   /*
3175    * Get a pointer to the big block of data containing the header.
3176    */
3177   success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
3178 
3179   /*
3180    * If the block read failed, the file is probably new.
3181    */
3182   if (!success)
3183   {
3184     /*
3185      * Initialize for all unknown fields.
3186      */
3187     memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
3188 
3189     /*
3190      * Initialize the magic number.
3191      */
3192     memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
3193 
3194     /*
3195      * And a bunch of things we don't know what they mean
3196      */
3197     StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
3198     StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
3199     StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
3200     StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
3201   }
3202 
3203   /*
3204    * Write the information to the header.
3205    */
3206   StorageUtl_WriteWord(
3207     headerBigBlock,
3208     OFFSET_BIGBLOCKSIZEBITS,
3209     This->bigBlockSizeBits);
3210 
3211   StorageUtl_WriteWord(
3212     headerBigBlock,
3213     OFFSET_SMALLBLOCKSIZEBITS,
3214     This->smallBlockSizeBits);
3215 
3216   StorageUtl_WriteDWord(
3217     headerBigBlock,
3218     OFFSET_BBDEPOTCOUNT,
3219     This->bigBlockDepotCount);
3220 
3221   StorageUtl_WriteDWord(
3222     headerBigBlock,
3223     OFFSET_ROOTSTARTBLOCK,
3224     This->rootStartBlock);
3225 
3226   StorageUtl_WriteDWord(
3227     headerBigBlock,
3228     OFFSET_SBDEPOTSTART,
3229     This->smallBlockDepotStart);
3230 
3231   StorageUtl_WriteDWord(
3232     headerBigBlock,
3233     OFFSET_SBDEPOTCOUNT,
3234     This->smallBlockDepotChain ?
3235      BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
3236 
3237   StorageUtl_WriteDWord(
3238     headerBigBlock,
3239     OFFSET_EXTBBDEPOTSTART,
3240     This->extBigBlockDepotStart);
3241 
3242   StorageUtl_WriteDWord(
3243     headerBigBlock,
3244     OFFSET_EXTBBDEPOTCOUNT,
3245     This->extBigBlockDepotCount);
3246 
3247   for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3248   {
3249     StorageUtl_WriteDWord(
3250       headerBigBlock,
3251       OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3252       (This->bigBlockDepotStart[index]));
3253   }
3254 
3255   /*
3256    * Write the big block back to the file.
3257    */
3258   StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
3259 }
3260 
3261 /******************************************************************************
3262  *      Storage32Impl_ReadProperty
3263  *
3264  * This method will read the specified property from the property chain.
3265  */
3266 BOOL StorageImpl_ReadProperty(
3267   StorageImpl* This,
3268   ULONG          index,
3269   StgProperty*   buffer)
3270 {
3271   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
3272   ULARGE_INTEGER offsetInPropSet;
3273   HRESULT        readRes;
3274   ULONG          bytesRead;
3275 
3276   offsetInPropSet.u.HighPart = 0;
3277   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3278 
3279   readRes = BlockChainStream_ReadAt(
3280                     This->rootBlockChain,
3281                     offsetInPropSet,
3282                     PROPSET_BLOCK_SIZE,
3283                     currentProperty,
3284                     &bytesRead);
3285 
3286   if (SUCCEEDED(readRes))
3287   {
3288     /* replace the name of root entry (often "Root Entry") by the file name */
3289     WCHAR *propName = (index == This->base.rootPropertySetIndex) ?
3290                         This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME;
3291 
3292     memset(buffer->name, 0, sizeof(buffer->name));
3293     memcpy(
3294       buffer->name,
3295       propName,
3296       PROPERTY_NAME_BUFFER_LEN );
3297     TRACE("storage name: %s\n", debugstr_w(buffer->name));
3298 
3299     memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
3300 
3301     StorageUtl_ReadWord(
3302       currentProperty,
3303       OFFSET_PS_NAMELENGTH,
3304       &buffer->sizeOfNameString);
3305 
3306     StorageUtl_ReadDWord(
3307       currentProperty,
3308       OFFSET_PS_PREVIOUSPROP,
3309       &buffer->previousProperty);
3310 
3311     StorageUtl_ReadDWord(
3312       currentProperty,
3313       OFFSET_PS_NEXTPROP,
3314       &buffer->nextProperty);
3315 
3316     StorageUtl_ReadDWord(
3317       currentProperty,
3318       OFFSET_PS_DIRPROP,
3319       &buffer->dirProperty);
3320 
3321     StorageUtl_ReadGUID(
3322       currentProperty,
3323       OFFSET_PS_GUID,
3324       &buffer->propertyUniqueID);
3325 
3326     StorageUtl_ReadDWord(
3327       currentProperty,
3328       OFFSET_PS_TSS1,
3329       &buffer->timeStampS1);
3330 
3331     StorageUtl_ReadDWord(
3332       currentProperty,
3333       OFFSET_PS_TSD1,
3334       &buffer->timeStampD1);
3335 
3336     StorageUtl_ReadDWord(
3337       currentProperty,
3338       OFFSET_PS_TSS2,
3339       &buffer->timeStampS2);
3340 
3341     StorageUtl_ReadDWord(
3342       currentProperty,
3343       OFFSET_PS_TSD2,
3344       &buffer->timeStampD2);
3345 
3346     StorageUtl_ReadDWord(
3347       currentProperty,
3348       OFFSET_PS_STARTBLOCK,
3349       &buffer->startingBlock);
3350 
3351     StorageUtl_ReadDWord(
3352       currentProperty,
3353       OFFSET_PS_SIZE,
3354       &buffer->size.u.LowPart);
3355 
3356     buffer->size.u.HighPart = 0;
3357   }
3358 
3359   return SUCCEEDED(readRes) ? TRUE : FALSE;
3360 }
3361 
3362 /*********************************************************************
3363  * Write the specified property into the property chain
3364  */
3365 BOOL StorageImpl_WriteProperty(
3366   StorageImpl*          This,
3367   ULONG                 index,
3368   const StgProperty*    buffer)
3369 {
3370   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
3371   ULARGE_INTEGER offsetInPropSet;
3372   HRESULT        writeRes;
3373   ULONG          bytesWritten;
3374 
3375   offsetInPropSet.u.HighPart = 0;
3376   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3377 
3378   memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
3379 
3380   memcpy(
3381     currentProperty + OFFSET_PS_NAME,
3382     buffer->name,
3383     PROPERTY_NAME_BUFFER_LEN );
3384 
3385   memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
3386 
3387   StorageUtl_WriteWord(
3388     currentProperty,
3389       OFFSET_PS_NAMELENGTH,
3390       buffer->sizeOfNameString);
3391 
3392   StorageUtl_WriteDWord(
3393     currentProperty,
3394       OFFSET_PS_PREVIOUSPROP,
3395       buffer->previousProperty);
3396 
3397   StorageUtl_WriteDWord(
3398     currentProperty,
3399       OFFSET_PS_NEXTPROP,
3400       buffer->nextProperty);
3401 
3402   StorageUtl_WriteDWord(
3403     currentProperty,
3404       OFFSET_PS_DIRPROP,
3405       buffer->dirProperty);
3406 
3407   StorageUtl_WriteGUID(
3408     currentProperty,
3409       OFFSET_PS_GUID,
3410       &buffer->propertyUniqueID);
3411 
3412   StorageUtl_WriteDWord(
3413     currentProperty,
3414       OFFSET_PS_TSS1,
3415       buffer->timeStampS1);
3416 
3417   StorageUtl_WriteDWord(
3418     currentProperty,
3419       OFFSET_PS_TSD1,
3420       buffer->timeStampD1);
3421 
3422   StorageUtl_WriteDWord(
3423     currentProperty,
3424       OFFSET_PS_TSS2,
3425       buffer->timeStampS2);
3426 
3427   StorageUtl_WriteDWord(
3428     currentProperty,
3429       OFFSET_PS_TSD2,
3430       buffer->timeStampD2);
3431 
3432   StorageUtl_WriteDWord(
3433     currentProperty,
3434       OFFSET_PS_STARTBLOCK,
3435       buffer->startingBlock);
3436 
3437   StorageUtl_WriteDWord(
3438     currentProperty,
3439       OFFSET_PS_SIZE,
3440       buffer->size.u.LowPart);
3441 
3442   writeRes = BlockChainStream_WriteAt(This->rootBlockChain,
3443                                       offsetInPropSet,
3444                                       PROPSET_BLOCK_SIZE,
3445                                       currentProperty,
3446                                       &bytesWritten);
3447   return SUCCEEDED(writeRes) ? TRUE : FALSE;
3448 }
3449 
3450 static BOOL StorageImpl_ReadBigBlock(
3451   StorageImpl* This,
3452   ULONG          blockIndex,
3453   void*          buffer)
3454 {
3455   ULARGE_INTEGER ulOffset;
3456   DWORD  read;
3457 
3458   ulOffset.u.HighPart = 0;
3459   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3460 
3461   StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
3462   return (read == This->bigBlockSize);
3463 }
3464 
3465 static BOOL StorageImpl_ReadDWordFromBigBlock(
3466   StorageImpl*  This,
3467   ULONG         blockIndex,
3468   ULONG         offset,
3469   DWORD*        value)
3470 {
3471   ULARGE_INTEGER ulOffset;
3472   DWORD  read;
3473   DWORD  tmp;
3474 
3475   ulOffset.u.HighPart = 0;
3476   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3477   ulOffset.u.LowPart += offset;
3478 
3479   StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
3480   *value = le32toh(tmp);
3481   return (read == sizeof(DWORD));
3482 }
3483 
3484 static BOOL StorageImpl_WriteBigBlock(
3485   StorageImpl*  This,
3486   ULONG         blockIndex,
3487   const void*   buffer)
3488 {
3489   ULARGE_INTEGER ulOffset;
3490   DWORD  wrote;
3491 
3492   ulOffset.u.HighPart = 0;
3493   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3494 
3495   StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
3496   return (wrote == This->bigBlockSize);
3497 }
3498 
3499 static BOOL StorageImpl_WriteDWordToBigBlock(
3500   StorageImpl* This,
3501   ULONG         blockIndex,
3502   ULONG         offset,
3503   DWORD         value)
3504 {
3505   ULARGE_INTEGER ulOffset;
3506   DWORD  wrote;
3507 
3508   ulOffset.u.HighPart = 0;
3509   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3510   ulOffset.u.LowPart += offset;
3511 
3512   value = htole32(value);
3513   StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
3514   return (wrote == sizeof(DWORD));
3515 }
3516 
3517 /******************************************************************************
3518  *              Storage32Impl_SmallBlocksToBigBlocks
3519  *
3520  * This method will convert a small block chain to a big block chain.
3521  * The small block chain will be destroyed.
3522  */
3523 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3524                       StorageImpl* This,
3525                       SmallBlockChainStream** ppsbChain)
3526 {
3527   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3528   ULARGE_INTEGER size, offset;
3529   ULONG cbRead, cbWritten;
3530   ULARGE_INTEGER cbTotalRead;
3531   ULONG propertyIndex;
3532   HRESULT resWrite = S_OK;
3533   HRESULT resRead;
3534   StgProperty chainProperty;
3535   BYTE *buffer;
3536   BlockChainStream *bbTempChain = NULL;
3537   BlockChainStream *bigBlockChain = NULL;
3538 
3539   /*
3540    * Create a temporary big block chain that doesn't have
3541    * an associated property. This temporary chain will be
3542    * used to copy data from small blocks to big blocks.
3543    */
3544   bbTempChain = BlockChainStream_Construct(This,
3545                                            &bbHeadOfChain,
3546                                            PROPERTY_NULL);
3547   if(!bbTempChain) return NULL;
3548   /*
3549    * Grow the big block chain.
3550    */
3551   size = SmallBlockChainStream_GetSize(*ppsbChain);
3552   BlockChainStream_SetSize(bbTempChain, size);
3553 
3554   /*
3555    * Copy the contents of the small block chain to the big block chain
3556    * by small block size increments.
3557    */
3558   offset.u.LowPart = 0;
3559   offset.u.HighPart = 0;
3560   cbTotalRead.QuadPart = 0;
3561 
3562   buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3563   do
3564   {
3565     resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3566                                            offset,
3567                                            This->smallBlockSize,
3568                                            buffer,
3569                                            &cbRead);
3570     if (FAILED(resRead))
3571         break;
3572 
3573     if (cbRead > 0)
3574     {
3575         cbTotalRead.QuadPart += cbRead;
3576 
3577         resWrite = BlockChainStream_WriteAt(bbTempChain,
3578                                             offset,
3579                                             cbRead,
3580                                             buffer,
3581                                             &cbWritten);
3582 
3583         if (FAILED(resWrite))
3584             break;
3585 
3586         offset.u.LowPart += This->smallBlockSize;
3587     }
3588   } while (cbTotalRead.QuadPart < size.QuadPart);
3589   HeapFree(GetProcessHeap(),0,buffer);
3590 
3591   if (FAILED(resRead) || FAILED(resWrite))
3592   {
3593     ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
3594     BlockChainStream_Destroy(bbTempChain);
3595     return NULL;
3596   }
3597 
3598   /*
3599    * Destroy the small block chain.
3600    */
3601   propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3602   size.u.HighPart = 0;
3603   size.u.LowPart  = 0;
3604   SmallBlockChainStream_SetSize(*ppsbChain, size);
3605   SmallBlockChainStream_Destroy(*ppsbChain);
3606   *ppsbChain = 0;
3607 
3608   /*
3609    * Change the property information. This chain is now a big block chain
3610    * and it doesn't reside in the small blocks chain anymore.
3611    */
3612   StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3613 
3614   chainProperty.startingBlock = bbHeadOfChain;
3615 
3616   StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3617 
3618   /*
3619    * Destroy the temporary propertyless big block chain.
3620    * Create a new big block chain associated with this property.
3621    */
3622   BlockChainStream_Destroy(bbTempChain);
3623   bigBlockChain = BlockChainStream_Construct(This,
3624                                              NULL,
3625                                              propertyIndex);
3626 
3627   return bigBlockChain;
3628 }
3629 
3630 static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
3631 {
3632   StorageInternalImpl* This = (StorageInternalImpl*) iface;
3633 
3634   StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);
3635   HeapFree(GetProcessHeap(), 0, This);
3636 }
3637 
3638 /******************************************************************************
3639 **
3640 ** Storage32InternalImpl_Commit
3641 **
3642 ** The non-root storages cannot be opened in transacted mode thus this function
3643 ** does nothing.
3644 */
3645 static HRESULT WINAPI StorageInternalImpl_Commit(
3646   IStorage*            iface,
3647   DWORD                  grfCommitFlags)  /* [in] */
3648 {
3649   return S_OK;
3650 }
3651 
3652 /******************************************************************************
3653 **
3654 ** Storage32InternalImpl_Revert
3655 **
3656 ** The non-root storages cannot be opened in transacted mode thus this function
3657 ** does nothing.
3658 */
3659 static HRESULT WINAPI StorageInternalImpl_Revert(
3660   IStorage*            iface)
3661 {
3662   return S_OK;
3663 }
3664 
3665 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3666 {
3667   IStorage_Release((IStorage*)This->parentStorage);
3668   HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3669   HeapFree(GetProcessHeap(), 0, This);
3670 }
3671 
3672 static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3673   IEnumSTATSTG*     iface,
3674   REFIID            riid,
3675   void**            ppvObject)
3676 {
3677   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3678 
3679   /*
3680    * Perform a sanity check on the parameters.
3681    */
3682   if (ppvObject==0)
3683     return E_INVALIDARG;
3684 
3685   /*
3686    * Initialize the return parameter.
3687    */
3688   *ppvObject = 0;
3689 
3690   /*
3691    * Compare the riid with the interface IDs implemented by this object.
3692    */
3693   if (IsEqualGUID(&IID_IUnknown, riid) ||
3694       IsEqualGUID(&IID_IEnumSTATSTG, riid))
3695   {
3696     *ppvObject = (IEnumSTATSTG*)This;
3697     IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
3698     return S_OK;
3699   }
3700 
3701   return E_NOINTERFACE;
3702 }
3703 
3704 static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
3705   IEnumSTATSTG* iface)
3706 {
3707   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3708   return InterlockedIncrement(&This->ref);
3709 }
3710 
3711 static ULONG   WINAPI IEnumSTATSTGImpl_Release(
3712   IEnumSTATSTG* iface)
3713 {
3714   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3715 
3716   ULONG newRef;
3717 
3718   newRef = InterlockedDecrement(&This->ref);
3719 
3720   /*
3721    * If the reference count goes down to 0, perform suicide.
3722    */
3723   if (newRef==0)
3724   {
3725     IEnumSTATSTGImpl_Destroy(This);
3726   }
3727 
3728   return newRef;
3729 }
3730 
3731 static HRESULT WINAPI IEnumSTATSTGImpl_Next(
3732   IEnumSTATSTG* iface,
3733   ULONG             celt,
3734   STATSTG*          rgelt,
3735   ULONG*            pceltFetched)
3736 {
3737