~ [ 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 ( !FAILED(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   HRESULT     hr = S_OK;
2104   BOOL      res = TRUE;
2105 
2106   /*
2107    * Read the storage property
2108    */
2109   res = StorageImpl_ReadProperty(
2110           storage->base.ancestorStorage,
2111           storePropertyIndex,
2112           &storeProperty);
2113 
2114   if(! res)
2115   {
2116     return E_FAIL;
2117   }
2118 
2119   if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
2120   {
2121     if (storeProperty.previousProperty != PROPERTY_NULL)
2122     {
2123       return findPlaceholder(
2124                storage,
2125                propertyIndexToStore,
2126                storeProperty.previousProperty,
2127                typeOfRelation);
2128     }
2129     else
2130     {
2131       storeProperty.previousProperty = propertyIndexToStore;
2132     }
2133   }
2134   else if (typeOfRelation == PROPERTY_RELATION_NEXT)
2135   {
2136     if (storeProperty.nextProperty != PROPERTY_NULL)
2137     {
2138       return findPlaceholder(
2139                storage,
2140                propertyIndexToStore,
2141                storeProperty.nextProperty,
2142                typeOfRelation);
2143     }
2144     else
2145     {
2146       storeProperty.nextProperty = propertyIndexToStore;
2147     }
2148   }
2149   else if (typeOfRelation == PROPERTY_RELATION_DIR)
2150   {
2151     if (storeProperty.dirProperty != PROPERTY_NULL)
2152     {
2153       return findPlaceholder(
2154                storage,
2155                propertyIndexToStore,
2156                storeProperty.dirProperty,
2157                typeOfRelation);
2158     }
2159     else
2160     {
2161       storeProperty.dirProperty = propertyIndexToStore;
2162     }
2163   }
2164 
2165   hr = StorageImpl_WriteProperty(
2166          storage->base.ancestorStorage,
2167          storePropertyIndex,
2168          &storeProperty);
2169 
2170   if(! hr)
2171   {
2172     return E_FAIL;
2173   }
2174 
2175   return S_OK;
2176 }
2177 
2178 /*************************************************************************
2179  *
2180  * Internal Method
2181  *
2182  * This method takes the previous and the next property link of a property
2183  * to be deleted and find them a place in the Storage.
2184  */
2185 static HRESULT adjustPropertyChain(
2186   StorageImpl *This,
2187   StgProperty   propertyToDelete,
2188   StgProperty   parentProperty,
2189   ULONG         parentPropertyId,
2190   INT         typeOfRelation)
2191 {
2192   ULONG   newLinkProperty        = PROPERTY_NULL;
2193   BOOL  needToFindAPlaceholder = FALSE;
2194   ULONG   storeNode              = PROPERTY_NULL;
2195   ULONG   toStoreNode            = PROPERTY_NULL;
2196   INT   relationType           = 0;
2197   HRESULT hr                     = S_OK;
2198   BOOL  res                    = TRUE;
2199 
2200   if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
2201   {
2202     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2203     {
2204       /*
2205        * Set the parent previous to the property to delete previous
2206        */
2207       newLinkProperty = propertyToDelete.previousProperty;
2208 
2209       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2210       {
2211         /*
2212          * We also need to find a storage for the other link, setup variables
2213          * to do this at the end...
2214          */
2215         needToFindAPlaceholder = TRUE;
2216         storeNode              = propertyToDelete.previousProperty;
2217         toStoreNode            = propertyToDelete.nextProperty;
2218         relationType           = PROPERTY_RELATION_NEXT;
2219       }
2220     }
2221     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2222     {
2223       /*
2224        * Set the parent previous to the property to delete next
2225        */
2226       newLinkProperty = propertyToDelete.nextProperty;
2227     }
2228 
2229     /*
2230      * Link it for real...
2231      */
2232     parentProperty.previousProperty = newLinkProperty;
2233 
2234   }
2235   else if (typeOfRelation == PROPERTY_RELATION_NEXT)
2236   {
2237     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2238     {
2239       /*
2240        * Set the parent next to the property to delete next previous
2241        */
2242       newLinkProperty = propertyToDelete.previousProperty;
2243 
2244       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2245       {
2246         /*
2247          * We also need to find a storage for the other link, setup variables
2248          * to do this at the end...
2249          */
2250         needToFindAPlaceholder = TRUE;
2251         storeNode              = propertyToDelete.previousProperty;
2252         toStoreNode            = propertyToDelete.nextProperty;
2253         relationType           = PROPERTY_RELATION_NEXT;
2254       }
2255     }
2256     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2257     {
2258       /*
2259        * Set the parent next to the property to delete next
2260        */
2261       newLinkProperty = propertyToDelete.nextProperty;
2262     }
2263 
2264     /*
2265      * Link it for real...
2266      */
2267     parentProperty.nextProperty = newLinkProperty;
2268   }
2269   else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2270   {
2271     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2272     {
2273       /*
2274        * Set the parent dir to the property to delete previous
2275        */
2276       newLinkProperty = propertyToDelete.previousProperty;
2277 
2278       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2279       {
2280         /*
2281          * We also need to find a storage for the other link, setup variables
2282          * to do this at the end...
2283          */
2284         needToFindAPlaceholder = TRUE;
2285         storeNode              = propertyToDelete.previousProperty;
2286         toStoreNode            = propertyToDelete.nextProperty;
2287         relationType           = PROPERTY_RELATION_NEXT;
2288       }
2289     }
2290     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2291     {
2292       /*
2293        * Set the parent dir to the property to delete next
2294        */
2295       newLinkProperty = propertyToDelete.nextProperty;
2296     }
2297 
2298     /*
2299      * Link it for real...
2300      */
2301     parentProperty.dirProperty = newLinkProperty;
2302   }
2303 
2304   /*
2305    * Write back the parent property
2306    */
2307   res = StorageImpl_WriteProperty(
2308           This->base.ancestorStorage,
2309           parentPropertyId,
2310           &parentProperty);
2311   if(! res)
2312   {
2313     return E_FAIL;
2314   }
2315 
2316   /*
2317    * If a placeholder is required for the other link, then, find one and
2318    * get out of here...
2319    */
2320   if (needToFindAPlaceholder)
2321   {
2322     hr = findPlaceholder(
2323            This,
2324            toStoreNode,
2325            storeNode,
2326            relationType);
2327   }
2328 
2329   return hr;
2330 }
2331 
2332 
2333 /******************************************************************************
2334  * SetElementTimes (IStorage)
2335  */
2336 static HRESULT WINAPI StorageImpl_SetElementTimes(
2337   IStorage*     iface,
2338   const OLECHAR *pwcsName,/* [string][in] */
2339   const FILETIME  *pctime,  /* [in] */
2340   const FILETIME  *patime,  /* [in] */
2341   const FILETIME  *pmtime)  /* [in] */
2342 {
2343   FIXME("(%s,...), stub!\n",debugstr_w(pwcsName));
2344   return S_OK;
2345 }
2346 
2347 /******************************************************************************
2348  * SetStateBits (IStorage)
2349  */
2350 static HRESULT WINAPI StorageImpl_SetStateBits(
2351   IStorage*   iface,
2352   DWORD         grfStateBits,/* [in] */
2353   DWORD         grfMask)     /* [in] */
2354 {
2355   StorageImpl* const This = (StorageImpl*)iface;
2356   This->base.stateBits = (This->base.stateBits & ~grfMask) | (grfStateBits & grfMask);
2357   return S_OK;
2358 }
2359 
2360 /*
2361  * Virtual function table for the IStorage32Impl class.
2362  */
2363 static const IStorageVtbl Storage32Impl_Vtbl =
2364 {
2365     StorageBaseImpl_QueryInterface,
2366     StorageBaseImpl_AddRef,
2367     StorageBaseImpl_Release,
2368     StorageBaseImpl_CreateStream,
2369     StorageBaseImpl_OpenStream,
2370     StorageImpl_CreateStorage,
2371     StorageBaseImpl_OpenStorage,
2372     StorageImpl_CopyTo,
2373     StorageImpl_MoveElementTo,
2374     StorageImpl_Commit,
2375     StorageImpl_Revert,
2376     StorageBaseImpl_EnumElements,
2377     StorageImpl_DestroyElement,
2378     StorageBaseImpl_RenameElement,
2379     StorageImpl_SetElementTimes,
2380     StorageBaseImpl_SetClass,
2381     StorageImpl_SetStateBits,
2382     StorageImpl_Stat
2383 };
2384 
2385 static HRESULT StorageImpl_Construct(
2386   StorageImpl* This,
2387   HANDLE       hFile,
2388   LPCOLESTR    pwcsName,
2389   ILockBytes*  pLkbyt,
2390   DWORD        openFlags,
2391   BOOL         fileBased,
2392   BOOL         fileCreate)
2393 {
2394   HRESULT     hr = S_OK;
2395   StgProperty currentProperty;
2396   BOOL      readSuccessful;
2397   ULONG       currentPropertyIndex;
2398 
2399   if ( FAILED( validateSTGM(openFlags) ))
2400     return STG_E_INVALIDFLAG;
2401 
2402   memset(This, 0, sizeof(StorageImpl));
2403 
2404   /*
2405    * Initialize stream list
2406    */
2407 
2408   list_init(&This->base.strmHead);
2409 
2410   /*
2411    * Initialize the virtual function table.
2412    */
2413   This->base.lpVtbl = &Storage32Impl_Vtbl;
2414   This->base.pssVtbl = &IPropertySetStorage_Vtbl;
2415   This->base.v_destructor = StorageImpl_Destroy;
2416   This->base.openFlags = (openFlags & ~STGM_CREATE);
2417 
2418   /*
2419    * This is the top-level storage so initialize the ancestor pointer
2420    * to this.
2421    */
2422   This->base.ancestorStorage = This;
2423 
2424   /*
2425    * Initialize the physical support of the storage.
2426    */
2427   This->hFile = hFile;
2428 
2429   /*
2430    * Store copy of file path.
2431    */
2432   if(pwcsName) {
2433       This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
2434                                 (lstrlenW(pwcsName)+1)*sizeof(WCHAR));
2435       if (!This->pwcsName)
2436          return STG_E_INSUFFICIENTMEMORY;
2437       strcpyW(This->pwcsName, pwcsName);
2438   }
2439 
2440   /*
2441    * Initialize the big block cache.
2442    */
2443   This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;
2444   This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
2445   This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,
2446                                                 pLkbyt,
2447                                                 openFlags,
2448                                                 This->bigBlockSize,
2449                                                 fileBased);
2450 
2451   if (This->bigBlockFile == 0)
2452     return E_FAIL;
2453 
2454   if (fileCreate)
2455   {
2456     ULARGE_INTEGER size;
2457     BYTE bigBlockBuffer[BIG_BLOCK_SIZE];
2458 
2459     /*
2460      * Initialize all header variables:
2461      * - The big block depot consists of one block and it is at block 0
2462      * - The properties start at block 1
2463      * - There is no small block depot
2464      */
2465     memset( This->bigBlockDepotStart,
2466             BLOCK_UNUSED,
2467             sizeof(This->bigBlockDepotStart));
2468 
2469     This->bigBlockDepotCount    = 1;
2470     This->bigBlockDepotStart[0] = 0;
2471     This->rootStartBlock        = 1;
2472     This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
2473     This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;
2474     This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
2475     This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
2476     This->extBigBlockDepotCount = 0;
2477 
2478     StorageImpl_SaveFileHeader(This);
2479 
2480     /*
2481      * Add one block for the big block depot and one block for the properties
2482      */
2483     size.u.HighPart = 0;
2484     size.u.LowPart  = This->bigBlockSize * 3;
2485     BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
2486 
2487     /*
2488      * Initialize the big block depot
2489      */
2490     memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2491     StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
2492     StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
2493     StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
2494   }
2495   else
2496   {
2497     /*
2498      * Load the header for the file.
2499      */
2500     hr = StorageImpl_LoadFileHeader(This);
2501 
2502     if (FAILED(hr))
2503     {
2504       BIGBLOCKFILE_Destructor(This->bigBlockFile);
2505 
2506       return hr;
2507     }
2508   }
2509 
2510   /*
2511    * There is no block depot cached yet.
2512    */
2513   This->indexBlockDepotCached = 0xFFFFFFFF;
2514 
2515   /*
2516    * Start searching for free blocks with block 0.
2517    */
2518   This->prevFreeBlock = 0;
2519 
2520   /*
2521    * Create the block chain abstractions.
2522    */
2523   if(!(This->rootBlockChain =
2524        BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL)))
2525     return STG_E_READFAULT;
2526 
2527   if(!(This->smallBlockDepotChain =
2528        BlockChainStream_Construct(This, &This->smallBlockDepotStart,
2529                                   PROPERTY_NULL)))
2530     return STG_E_READFAULT;
2531 
2532   /*
2533    * Write the root property (memory only)
2534    */
2535   if (fileCreate)
2536   {
2537     StgProperty rootProp;
2538     /*
2539      * Initialize the property chain
2540      */
2541     memset(&rootProp, 0, sizeof(rootProp));
2542     MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name,
2543                          sizeof(rootProp.name)/sizeof(WCHAR) );
2544     rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR);
2545     rootProp.propertyType     = PROPTYPE_ROOT;
2546     rootProp.previousProperty = PROPERTY_NULL;
2547     rootProp.nextProperty     = PROPERTY_NULL;
2548     rootProp.dirProperty      = PROPERTY_NULL;
2549     rootProp.startingBlock    = BLOCK_END_OF_CHAIN;
2550     rootProp.size.u.HighPart    = 0;
2551     rootProp.size.u.LowPart     = 0;
2552 
2553     StorageImpl_WriteProperty(This, 0, &rootProp);
2554   }
2555 
2556   /*
2557    * Find the ID of the root in the property sets.
2558    */
2559   currentPropertyIndex = 0;
2560 
2561   do
2562   {
2563     readSuccessful = StorageImpl_ReadProperty(
2564                       This,
2565                       currentPropertyIndex,
2566                       &currentProperty);
2567 
2568     if (readSuccessful)
2569     {
2570       if ( (currentProperty.sizeOfNameString != 0 ) &&
2571            (currentProperty.propertyType     == PROPTYPE_ROOT) )
2572       {
2573         This->base.rootPropertySetIndex = currentPropertyIndex;
2574       }
2575     }
2576 
2577     currentPropertyIndex++;
2578 
2579   } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) );
2580 
2581   if (!readSuccessful)
2582   {
2583     /* TODO CLEANUP */
2584     return STG_E_READFAULT;
2585   }
2586 
2587   /*
2588    * Create the block chain abstraction for the small block root chain.
2589    */
2590   if(!(This->smallBlockRootChain =
2591        BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex)))
2592     return STG_E_READFAULT;
2593 
2594   return hr;
2595 }
2596 
2597 static void StorageImpl_Destroy(StorageBaseImpl* iface)
2598 {
2599   StorageImpl *This = (StorageImpl*) iface;
2600   TRACE("(%p)\n", This);
2601 
2602   StorageBaseImpl_DeleteAll(&This->base);
2603 
2604   HeapFree(GetProcessHeap(), 0, This->pwcsName);
2605 
2606   BlockChainStream_Destroy(This->smallBlockRootChain);
2607   BlockChainStream_Destroy(This->rootBlockChain);
2608   BlockChainStream_Destroy(This->smallBlockDepotChain);
2609 
2610   BIGBLOCKFILE_Destructor(This->bigBlockFile);
2611   HeapFree(GetProcessHeap(), 0, This);
2612 }
2613 
2614 /******************************************************************************
2615  *      Storage32Impl_GetNextFreeBigBlock
2616  *
2617  * Returns the index of the next free big block.
2618  * If the big block depot is filled, this method will enlarge it.
2619  *
2620  */
2621 static ULONG StorageImpl_GetNextFreeBigBlock(
2622   StorageImpl* This)
2623 {
2624   ULONG depotBlockIndexPos;
2625   BYTE depotBuffer[BIG_BLOCK_SIZE];
2626   BOOL success;
2627   ULONG depotBlockOffset;
2628   ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
2629   ULONG nextBlockIndex    = BLOCK_SPECIAL;
2630   int   depotIndex        = 0;
2631   ULONG freeBlock         = BLOCK_UNUSED;
2632 
2633   depotIndex = This->prevFreeBlock / blocksPerDepot;
2634   depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2635 
2636   /*
2637    * Scan the entire big block depot until we find a block marked free
2638    */
2639   while (nextBlockIndex != BLOCK_UNUSED)
2640   {
2641     if (depotIndex < COUNT_BBDEPOTINHEADER)
2642     {
2643       depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2644 
2645       /*
2646        * Grow the primary depot.
2647        */
2648       if (depotBlockIndexPos == BLOCK_UNUSED)
2649       {
2650         depotBlockIndexPos = depotIndex*blocksPerDepot;
2651 
2652         /*
2653          * Add a block depot.
2654          */
2655         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2656         This->bigBlockDepotCount++;
2657         This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2658 
2659         /*
2660          * Flag it as a block depot.
2661          */
2662         StorageImpl_SetNextBlockInChain(This,
2663                                           depotBlockIndexPos,
2664                                           BLOCK_SPECIAL);
2665 
2666         /* Save new header information.
2667          */
2668         StorageImpl_SaveFileHeader(This);
2669       }
2670     }
2671     else
2672     {
2673       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2674 
2675       if (depotBlockIndexPos == BLOCK_UNUSED)
2676       {
2677         /*
2678          * Grow the extended depot.
2679          */
2680         ULONG extIndex       = BLOCK_UNUSED;
2681         ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
2682         ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2683 
2684         if (extBlockOffset == 0)
2685         {
2686           /* We need an extended block.
2687            */
2688           extIndex = Storage32Impl_AddExtBlockDepot(This);
2689           This->extBigBlockDepotCount++;
2690           depotBlockIndexPos = extIndex + 1;
2691         }
2692         else
2693           depotBlockIndexPos = depotIndex * blocksPerDepot;
2694 
2695         /*
2696          * Add a block depot and mark it in the extended block.
2697          */
2698         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2699         This->bigBlockDepotCount++;
2700         Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2701 
2702         /* Flag the block depot.
2703          */
2704         StorageImpl_SetNextBlockInChain(This,
2705                                           depotBlockIndexPos,
2706                                           BLOCK_SPECIAL);
2707 
2708         /* If necessary, flag the extended depot block.
2709          */
2710         if (extIndex != BLOCK_UNUSED)
2711           StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2712 
2713         /* Save header information.
2714          */
2715         StorageImpl_SaveFileHeader(This);
2716       }
2717     }
2718 
2719     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
2720 
2721     if (success)
2722     {
2723       while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2724               ( nextBlockIndex != BLOCK_UNUSED))
2725       {
2726         StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2727 
2728         if (nextBlockIndex == BLOCK_UNUSED)
2729         {
2730           freeBlock = (depotIndex * blocksPerDepot) +
2731                       (depotBlockOffset/sizeof(ULONG));
2732         }
2733 
2734         depotBlockOffset += sizeof(ULONG);
2735       }
2736     }
2737 
2738     depotIndex++;
2739     depotBlockOffset = 0;
2740   }
2741 
2742   /*
2743    * make sure that the block physically exists before using it
2744    */
2745   BIGBLOCKFILE_EnsureExists(This->bigBlockFile, freeBlock);
2746 
2747   This->prevFreeBlock = freeBlock;
2748 
2749   return freeBlock;
2750 }
2751 
2752 /******************************************************************************
2753  *      Storage32Impl_AddBlockDepot
2754  *
2755  * This will create a depot block, essentially it is a block initialized
2756  * to BLOCK_UNUSEDs.
2757  */
2758 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2759 {
2760   BYTE blockBuffer[BIG_BLOCK_SIZE];
2761 
2762   /*
2763    * Initialize blocks as free
2764    */
2765   memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2766   StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
2767 }
2768 
2769 /******************************************************************************
2770  *      Storage32Impl_GetExtDepotBlock
2771  *
2772  * Returns the index of the block that corresponds to the specified depot
2773  * index. This method is only for depot indexes equal or greater than
2774  * COUNT_BBDEPOTINHEADER.
2775  */
2776 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2777 {
2778   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2779   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
2780   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
2781   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
2782   ULONG blockIndex             = BLOCK_UNUSED;
2783   ULONG extBlockIndex          = This->extBigBlockDepotStart;
2784 
2785   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2786 
2787   if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2788     return BLOCK_UNUSED;
2789 
2790   while (extBlockCount > 0)
2791   {
2792     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2793     extBlockCount--;
2794   }
2795 
2796   if (extBlockIndex != BLOCK_UNUSED)
2797     StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex,
2798                         extBlockOffset * sizeof(ULONG), &blockIndex);
2799 
2800   return blockIndex;
2801 }
2802 
2803 /******************************************************************************
2804  *      Storage32Impl_SetExtDepotBlock
2805  *
2806  * Associates the specified block index to the specified depot index.
2807  * This method is only for depot indexes equal or greater than
2808  * COUNT_BBDEPOTINHEADER.
2809  */
2810 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
2811 {
2812   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2813   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
2814   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
2815   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
2816   ULONG extBlockIndex          = This->extBigBlockDepotStart;
2817 
2818   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2819 
2820   while (extBlockCount > 0)
2821   {
2822     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2823     extBlockCount--;
2824   }
2825 
2826   if (extBlockIndex != BLOCK_UNUSED)
2827   {
2828     StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
2829                         extBlockOffset * sizeof(ULONG),
2830                         blockIndex);
2831   }
2832 }
2833 
2834 /******************************************************************************
2835  *      Storage32Impl_AddExtBlockDepot
2836  *
2837  * Creates an extended depot block.
2838  */
2839 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2840 {
2841   ULONG numExtBlocks           = This->extBigBlockDepotCount;
2842   ULONG nextExtBlock           = This->extBigBlockDepotStart;
2843   BYTE  depotBuffer[BIG_BLOCK_SIZE];
2844   ULONG index                  = BLOCK_UNUSED;
2845   ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
2846   ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
2847   ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2848 
2849   index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2850           blocksPerDepotBlock;
2851 
2852   if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2853   {
2854     /*
2855      * The first extended block.
2856      */
2857     This->extBigBlockDepotStart = index;
2858   }
2859   else
2860   {
2861     unsigned int i;
2862     /*
2863      * Follow the chain to the last one.
2864      */
2865     for (i = 0; i < (numExtBlocks - 1); i++)
2866     {
2867       nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2868     }
2869 
2870     /*
2871      * Add the new extended block to the chain.
2872      */
2873     StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
2874                                      index);
2875   }
2876 
2877   /*
2878    * Initialize this block.
2879    */
2880   memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2881   StorageImpl_WriteBigBlock(This, index, depotBuffer);
2882 
2883   return index;
2884 }
2885 
2886 /******************************************************************************
2887  *      Storage32Impl_FreeBigBlock
2888  *
2889  * This method will flag the specified block as free in the big block depot.
2890  */
2891 static void StorageImpl_FreeBigBlock(
2892   StorageImpl* This,
2893   ULONG          blockIndex)
2894 {
2895   StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2896 
2897   if (blockIndex < This->prevFreeBlock)
2898     This->prevFreeBlock = blockIndex;
2899 }
2900 
2901 /************************************************************************
2902  * Storage32Impl_GetNextBlockInChain
2903  *
2904  * This method will retrieve the block index of the next big block in
2905  * in the chain.
2906  *
2907  * Params:  This       - Pointer to the Storage object.
2908  *          blockIndex - Index of the block to retrieve the chain
2909  *                       for.
2910  *          nextBlockIndex - receives the return value.
2911  *
2912  * Returns: This method returns the index of the next block in the chain.
2913  *          It will return the constants:
2914  *              BLOCK_SPECIAL - If the block given was not part of a
2915  *                              chain.
2916  *              BLOCK_END_OF_CHAIN - If the block given was the last in
2917  *                                   a chain.
2918  *              BLOCK_UNUSED - If the block given was not past of a chain
2919  *                             and is available.
2920  *              BLOCK_EXTBBDEPOT - This block is part of the extended
2921  *                                 big block depot.
2922  *
2923  * See Windows documentation for more details on IStorage methods.
2924  */
2925 static HRESULT StorageImpl_GetNextBlockInChain(
2926   StorageImpl* This,
2927   ULONG        blockIndex,
2928   ULONG*       nextBlockIndex)
2929 {
2930   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
2931   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
2932   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2933   BYTE depotBuffer[BIG_BLOCK_SIZE];
2934   BOOL success;
2935   ULONG depotBlockIndexPos;
2936   int index;
2937 
2938   *nextBlockIndex   = BLOCK_SPECIAL;
2939 
2940   if(depotBlockCount >= This->bigBlockDepotCount)
2941   {
2942     WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount,
2943          This->bigBlockDepotCount);
2944     return STG_E_READFAULT;
2945   }
2946 
2947   /*
2948    * Cache the currently accessed depot block.
2949    */
2950   if (depotBlockCount != This->indexBlockDepotCached)
2951   {
2952     This->indexBlockDepotCached = depotBlockCount;
2953 
2954     if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2955     {
2956       depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2957     }
2958     else
2959     {
2960       /*
2961        * We have to look in the extended depot.
2962        */
2963       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2964     }
2965 
2966     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
2967 
2968     if (!success)
2969       return STG_E_READFAULT;
2970 
2971     for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2972     {
2973       StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
2974       This->blockDepotCached[index] = *nextBlockIndex;
2975     }
2976   }
2977 
2978   *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2979 
2980   return S_OK;
2981 }
2982 
2983 /******************************************************************************
2984  *      Storage32Impl_GetNextExtendedBlock
2985  *
2986  * Given an extended block this method will return the next extended block.
2987  *
2988  * NOTES:
2989  * The last ULONG of an extended block is the block index of the next
2990  * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2991  * depot.
2992  *
2993  * Return values:
2994  *    - The index of the next extended block
2995  *    - BLOCK_UNUSED: there is no next extended block.
2996  *    - Any other return values denotes failure.
2997  */
2998 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2999 {
3000   ULONG nextBlockIndex   = BLOCK_SPECIAL;
3001   ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
3002 
3003   StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
3004                         &nextBlockIndex);
3005 
3006   return nextBlockIndex;
3007 }
3008 
3009 /******************************************************************************
3010  *      Storage32Impl_SetNextBlockInChain
3011  *
3012  * This method will write the index of the specified block's next block
3013  * in the big block depot.
3014  *
3015  * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
3016  *              do the following
3017  *
3018  * Storage32Impl_SetNextBlockInChain(This, 3, 1);
3019  * Storage32Impl_SetNextBlockInChain(This, 1, 7);
3020  * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
3021  *
3022  */
3023 static void StorageImpl_SetNextBlockInChain(
3024           StorageImpl* This,
3025           ULONG          blockIndex,
3026           ULONG          nextBlock)
3027 {
3028   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
3029   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
3030   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
3031   ULONG depotBlockIndexPos;
3032 
3033   assert(depotBlockCount < This->bigBlockDepotCount);
3034   assert(blockIndex != nextBlock);
3035 
3036   if (depotBlockCount < COUNT_BBDEPOTINHEADER)
3037   {
3038     depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
3039   }
3040   else
3041   {
3042     /*
3043      * We have to look in the extended depot.
3044      */
3045     depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
3046   }
3047 
3048   StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
3049                         nextBlock);
3050   /*
3051    * Update the cached block depot, if necessary.
3052    */
3053   if (depotBlockCount == This->indexBlockDepotCached)
3054   {
3055     This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
3056   }
3057 }
3058 
3059 /******************************************************************************
3060  *      Storage32Impl_LoadFileHeader
3061  *
3062  * This method will read in the file header, i.e. big block index -1.
3063  */
3064 static HRESULT StorageImpl_LoadFileHeader(
3065           StorageImpl* This)
3066 {
3067   HRESULT hr = STG_E_FILENOTFOUND;
3068   BYTE    headerBigBlock[BIG_BLOCK_SIZE];
3069   BOOL    success;
3070   int     index;
3071 
3072   TRACE("\n");
3073   /*
3074    * Get a pointer to the big block of data containing the header.
3075    */
3076   success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
3077 
3078   /*
3079    * Extract the information from the header.
3080    */
3081   if (success)
3082   {
3083     /*
3084      * Check for the "magic number" signature and return an error if it is not
3085      * found.
3086      */
3087     if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
3088     {
3089       return STG_E_OLDFORMAT;
3090     }
3091 
3092     if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
3093     {
3094       return STG_E_INVALIDHEADER;
3095     }
3096 
3097     StorageUtl_ReadWord(
3098       headerBigBlock,
3099       OFFSET_BIGBLOCKSIZEBITS,
3100       &This->bigBlockSizeBits);
3101 
3102     StorageUtl_ReadWord(
3103       headerBigBlock,
3104       OFFSET_SMALLBLOCKSIZEBITS,
3105       &This->smallBlockSizeBits);
3106 
3107     StorageUtl_ReadDWord(
3108       headerBigBlock,
3109       OFFSET_BBDEPOTCOUNT,
3110       &This->bigBlockDepotCount);
3111 
3112     StorageUtl_ReadDWord(
3113       headerBigBlock,
3114       OFFSET_ROOTSTARTBLOCK,
3115       &This->rootStartBlock);
3116 
3117     StorageUtl_ReadDWord(
3118       headerBigBlock,
3119       OFFSET_SBDEPOTSTART,
3120       &This->smallBlockDepotStart);
3121 
3122     StorageUtl_ReadDWord(
3123       headerBigBlock,
3124       OFFSET_EXTBBDEPOTSTART,
3125       &This->extBigBlockDepotStart);
3126 
3127     StorageUtl_ReadDWord(
3128       headerBigBlock,
3129       OFFSET_EXTBBDEPOTCOUNT,
3130       &This->extBigBlockDepotCount);
3131 
3132     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3133     {
3134       StorageUtl_ReadDWord(
3135         headerBigBlock,
3136         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3137         &(This->bigBlockDepotStart[index]));
3138     }
3139 
3140     /*
3141      * Make the bitwise arithmetic to get the size of the blocks in bytes.
3142      */
3143     if ((1 << 2) == 4)
3144     {
3145       This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
3146       This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
3147     }
3148     else
3149     {
3150       This->bigBlockSize   = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
3151       This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
3152     }
3153 
3154     /*
3155      * Right now, the code is making some assumptions about the size of the
3156      * blocks, just make sure they are what we're expecting.
3157      */
3158     if (This->bigBlockSize != DEF_BIG_BLOCK_SIZE ||
3159         This->smallBlockSize != DEF_SMALL_BLOCK_SIZE)
3160     {
3161         WARN("Broken OLE storage file\n");
3162         hr = STG_E_INVALIDHEADER;
3163     }
3164     else
3165         hr = S_OK;
3166   }
3167 
3168   return hr;
3169 }
3170 
3171 /******************************************************************************
3172  *      Storage32Impl_SaveFileHeader
3173  *
3174  * This method will save to the file the header, i.e. big block -1.
3175  */
3176 static void StorageImpl_SaveFileHeader(
3177           StorageImpl* This)
3178 {
3179   BYTE   headerBigBlock[BIG_BLOCK_SIZE];
3180   int    index;
3181   BOOL success;
3182 
3183   /*
3184    * Get a pointer to the big block of data containing the header.
3185    */
3186   success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
3187 
3188   /*
3189    * If the block read failed, the file is probably new.
3190    */
3191   if (!success)
3192   {
3193     /*
3194      * Initialize for all unknown fields.
3195      */
3196     memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
3197 
3198     /*
3199      * Initialize the magic number.
3200      */
3201     memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
3202 
3203     /*
3204      * And a bunch of things we don't know what they mean
3205      */
3206     StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
3207     StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
3208     StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
3209     StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
3210   }
3211 
3212   /*
3213    * Write the information to the header.
3214    */
3215   StorageUtl_WriteWord(
3216     headerBigBlock,
3217     OFFSET_BIGBLOCKSIZEBITS,
3218     This->bigBlockSizeBits);
3219 
3220   StorageUtl_WriteWord(
3221     headerBigBlock,
3222     OFFSET_SMALLBLOCKSIZEBITS,
3223     This->smallBlockSizeBits);
3224 
3225   StorageUtl_WriteDWord(
3226     headerBigBlock,
3227     OFFSET_BBDEPOTCOUNT,
3228     This->bigBlockDepotCount);
3229 
3230   StorageUtl_WriteDWord(
3231     headerBigBlock,
3232     OFFSET_ROOTSTARTBLOCK,
3233     This->rootStartBlock);
3234 
3235   StorageUtl_WriteDWord(
3236     headerBigBlock,
3237     OFFSET_SBDEPOTSTART,
3238     This->smallBlockDepotStart);
3239 
3240   StorageUtl_WriteDWord(
3241     headerBigBlock,
3242     OFFSET_SBDEPOTCOUNT,
3243     This->smallBlockDepotChain ?
3244      BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
3245 
3246   StorageUtl_WriteDWord(
3247     headerBigBlock,
3248     OFFSET_EXTBBDEPOTSTART,
3249     This->extBigBlockDepotStart);
3250 
3251   StorageUtl_WriteDWord(
3252     headerBigBlock,
3253     OFFSET_EXTBBDEPOTCOUNT,
3254     This->extBigBlockDepotCount);
3255 
3256   for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3257   {
3258     StorageUtl_WriteDWord(
3259       headerBigBlock,
3260       OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3261       (This->bigBlockDepotStart[index]));
3262   }
3263 
3264   /*
3265    * Write the big block back to the file.
3266    */
3267   StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
3268 }
3269 
3270 /******************************************************************************
3271  *      Storage32Impl_ReadProperty
3272  *
3273  * This method will read the specified property from the property chain.
3274  */
3275 BOOL StorageImpl_ReadProperty(
3276   StorageImpl* This,
3277   ULONG          index,
3278   StgProperty*   buffer)
3279 {
3280   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
3281   ULARGE_INTEGER offsetInPropSet;
3282   HRESULT        readRes;
3283   ULONG          bytesRead;
3284 
3285   offsetInPropSet.u.HighPart = 0;
3286   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3287 
3288   readRes = BlockChainStream_ReadAt(
3289                     This->rootBlockChain,
3290                     offsetInPropSet,
3291                     PROPSET_BLOCK_SIZE,
3292                     currentProperty,
3293                     &bytesRead);
3294 
3295   if (SUCCEEDED(readRes))
3296   {
3297     /* replace the name of root entry (often "Root Entry") by the file name */
3298     WCHAR *propName = (index == This->base.rootPropertySetIndex) ?
3299                         This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME;
3300 
3301     memset(buffer->name, 0, sizeof(buffer->name));
3302     memcpy(
3303       buffer->name,
3304       propName,
3305       PROPERTY_NAME_BUFFER_LEN );
3306     TRACE("storage name: %s\n", debugstr_w(buffer->name));
3307 
3308     memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
3309 
3310     StorageUtl_ReadWord(
3311       currentProperty,
3312       OFFSET_PS_NAMELENGTH,
3313       &buffer->sizeOfNameString);
3314 
3315     StorageUtl_ReadDWord(
3316       currentProperty,
3317       OFFSET_PS_PREVIOUSPROP,
3318       &buffer->previousProperty);
3319 
3320     StorageUtl_ReadDWord(
3321       currentProperty,
3322       OFFSET_PS_NEXTPROP,
3323       &buffer->nextProperty);
3324 
3325     StorageUtl_ReadDWord(
3326       currentProperty,
3327       OFFSET_PS_DIRPROP,
3328       &buffer->dirProperty);
3329 
3330     StorageUtl_ReadGUID(
3331       currentProperty,
3332       OFFSET_PS_GUID,
3333       &buffer->propertyUniqueID);
3334 
3335     StorageUtl_ReadDWord(
3336       currentProperty,
3337       OFFSET_PS_TSS1,
3338       &buffer->timeStampS1);
3339 
3340     StorageUtl_ReadDWord(
3341       currentProperty,
3342       OFFSET_PS_TSD1,
3343       &buffer->timeStampD1);
3344 
3345     StorageUtl_ReadDWord(
3346       currentProperty,
3347       OFFSET_PS_TSS2,
3348       &buffer->timeStampS2);
3349 
3350     StorageUtl_ReadDWord(
3351       currentProperty,
3352       OFFSET_PS_TSD2,
3353       &buffer->timeStampD2);
3354 
3355     StorageUtl_ReadDWord(
3356       currentProperty,
3357       OFFSET_PS_STARTBLOCK,
3358       &buffer->startingBlock);
3359 
3360     StorageUtl_ReadDWord(
3361       currentProperty,
3362       OFFSET_PS_SIZE,
3363       &buffer->size.u.LowPart);
3364 
3365     buffer->size.u.HighPart = 0;
3366   }
3367 
3368   return SUCCEEDED(readRes) ? TRUE : FALSE;
3369 }
3370 
3371 /*********************************************************************
3372  * Write the specified property into the property chain
3373  */
3374 BOOL StorageImpl_WriteProperty(
3375   StorageImpl*          This,
3376   ULONG                 index,
3377   const StgProperty*    buffer)
3378 {
3379   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
3380   ULARGE_INTEGER offsetInPropSet;
3381   HRESULT        writeRes;
3382   ULONG          bytesWritten;
3383 
3384   offsetInPropSet.u.HighPart = 0;
3385   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3386 
3387   memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
3388 
3389   memcpy(
3390     currentProperty + OFFSET_PS_NAME,
3391     buffer->name,
3392     PROPERTY_NAME_BUFFER_LEN );
3393 
3394   memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
3395 
3396   StorageUtl_WriteWord(
3397     currentProperty,
3398       OFFSET_PS_NAMELENGTH,
3399       buffer->sizeOfNameString);
3400 
3401   StorageUtl_WriteDWord(
3402     currentProperty,
3403       OFFSET_PS_PREVIOUSPROP,
3404       buffer->previousProperty);
3405 
3406   StorageUtl_WriteDWord(
3407     currentProperty,
3408       OFFSET_PS_NEXTPROP,
3409       buffer->nextProperty);
3410 
3411   StorageUtl_WriteDWord(
3412     currentProperty,
3413       OFFSET_PS_DIRPROP,
3414       buffer->dirProperty);
3415 
3416   StorageUtl_WriteGUID(
3417     currentProperty,
3418       OFFSET_PS_GUID,
3419       &buffer->propertyUniqueID);
3420 
3421   StorageUtl_WriteDWord(
3422     currentProperty,
3423       OFFSET_PS_TSS1,
3424       buffer->timeStampS1);
3425 
3426   StorageUtl_WriteDWord(
3427     currentProperty,
3428       OFFSET_PS_TSD1,
3429       buffer->timeStampD1);
3430 
3431   StorageUtl_WriteDWord(
3432     currentProperty,
3433       OFFSET_PS_TSS2,
3434       buffer->timeStampS2);
3435 
3436   StorageUtl_WriteDWord(
3437     currentProperty,
3438       OFFSET_PS_TSD2,
3439       buffer->timeStampD2);
3440 
3441   StorageUtl_WriteDWord(
3442     currentProperty,
3443       OFFSET_PS_STARTBLOCK,
3444       buffer->startingBlock);
3445 
3446   StorageUtl_WriteDWord(
3447     currentProperty,
3448       OFFSET_PS_SIZE,
3449       buffer->size.u.LowPart);
3450 
3451   writeRes = BlockChainStream_WriteAt(This->rootBlockChain,
3452                                       offsetInPropSet,
3453                                       PROPSET_BLOCK_SIZE,
3454                                       currentProperty,
3455                                       &bytesWritten);
3456   return SUCCEEDED(writeRes) ? TRUE : FALSE;
3457 }
3458 
3459 static BOOL StorageImpl_ReadBigBlock(
3460   StorageImpl* This,
3461   ULONG          blockIndex,
3462   void*          buffer)
3463 {
3464   ULARGE_INTEGER ulOffset;
3465   DWORD  read;
3466 
3467   ulOffset.u.HighPart = 0;
3468   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3469 
3470   StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
3471   return (read == This->bigBlockSize);
3472 }
3473 
3474 static BOOL StorageImpl_ReadDWordFromBigBlock(
3475   StorageImpl*  This,
3476   ULONG         blockIndex,
3477   ULONG         offset,
3478   DWORD*        value)
3479 {
3480   ULARGE_INTEGER ulOffset;
3481   DWORD  read;
3482   DWORD  tmp;
3483 
3484   ulOffset.u.HighPart = 0;
3485   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3486   ulOffset.u.LowPart += offset;
3487 
3488   StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
3489   *value = le32toh(tmp);
3490   return (read == sizeof(DWORD));
3491 }
3492 
3493 static BOOL StorageImpl_WriteBigBlock(
3494   StorageImpl*  This,
3495   ULONG         blockIndex,
3496   const void*   buffer)
3497 {
3498   ULARGE_INTEGER ulOffset;
3499   DWORD  wrote;
3500 
3501   ulOffset.u.HighPart = 0;
3502   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3503 
3504   StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
3505   return (wrote == This->bigBlockSize);
3506 }
3507 
3508 static BOOL StorageImpl_WriteDWordToBigBlock(
3509   StorageImpl* This,
3510   ULONG         blockIndex,
3511   ULONG         offset,
3512   DWORD         value)
3513 {
3514   ULARGE_INTEGER ulOffset;
3515   DWORD  wrote;
3516 
3517   ulOffset.u.HighPart = 0;
3518   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3519   ulOffset.u.LowPart += offset;
3520 
3521   value = htole32(value);
3522   StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
3523   return (wrote == sizeof(DWORD));
3524 }
3525 
3526 /******************************************************************************
3527  *              Storage32Impl_SmallBlocksToBigBlocks
3528  *
3529  * This method will convert a small block chain to a big block chain.
3530  * The small block chain will be destroyed.
3531  */
3532 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3533                       StorageImpl* This,
3534                       SmallBlockChainStream** ppsbChain)
3535 {
3536   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3537   ULARGE_INTEGER size, offset;
3538   ULONG cbRead, cbWritten;
3539   ULARGE_INTEGER cbTotalRead;
3540   ULONG propertyIndex;
3541   HRESULT resWrite = S_OK;
3542   HRESULT resRead;
3543   StgProperty chainProperty;
3544   BYTE *buffer;
3545   BlockChainStream *bbTempChain = NULL;
3546   BlockChainStream *bigBlockChain = NULL;
3547 
3548   /*
3549    * Create a temporary big block chain that doesn't have
3550    * an associated property. This temporary chain will be
3551    * used to copy data from small blocks to big blocks.
3552    */
3553   bbTempChain = BlockChainStream_Construct(This,
3554                                            &bbHeadOfChain,
3555                                            PROPERTY_NULL);
3556   if(!bbTempChain) return NULL;
3557   /*
3558    * Grow the big block chain.
3559    */
3560   size = SmallBlockChainStream_GetSize(*ppsbChain);
3561   BlockChainStream_SetSize(bbTempChain, size);
3562 
3563   /*
3564    * Copy the contents of the small block chain to the big block chain
3565    * by small block size increments.
3566    */
3567   offset.u.LowPart = 0;
3568   offset.u.HighPart = 0;
3569   cbTotalRead.QuadPart = 0;
3570 
3571   buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3572   do
3573   {
3574     resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3575                                            offset,
3576                                            This->smallBlockSize,
3577                                            buffer,
3578                                            &cbRead);
3579     if (FAILED(resRead))
3580         break;
3581 
3582     if (cbRead > 0)
3583     {
3584         cbTotalRead.QuadPart += cbRead;
3585 
3586         resWrite = BlockChainStream_WriteAt(bbTempChain,
3587                                             offset,
3588                                             cbRead,
3589                                             buffer,
3590                                             &cbWritten);
3591 
3592         if (FAILED(resWrite))
3593             break;
3594 
3595         offset.u.LowPart += This->smallBlockSize;
3596     }
3597   } while (cbTotalRead.QuadPart < size.QuadPart);
3598   HeapFree(GetProcessHeap(),0,buffer);
3599 
3600   if (FAILED(resRead) || FAILED(resWrite))
3601   {
3602     ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
3603     BlockChainStream_Destroy(bbTempChain);
3604     return NULL;
3605   }
3606 
3607   /*
3608    * Destroy the small block chain.
3609    */
3610   propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3611   size.u.HighPart = 0;
3612   size.u.LowPart  = 0;
3613   SmallBlockChainStream_SetSize(*ppsbChain, size);
3614   SmallBlockChainStream_Destroy(*ppsbChain);
3615   *ppsbChain = 0;
3616 
3617   /*
3618    * Change the property information. This chain is now a big block chain
3619    * and it doesn't reside in the small blocks chain anymore.
3620    */
3621   StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3622 
3623   chainProperty.startingBlock = bbHeadOfChain;
3624 
3625   StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3626 
3627   /*
3628    * Destroy the temporary propertyless big block chain.
3629    * Create a new big block chain associated with this property.
3630    */
3631   BlockChainStream_Destroy(bbTempChain);
3632   bigBlockChain = BlockChainStream_Construct(This,
3633                                              NULL,
3634                                              propertyIndex);
3635 
3636   return bigBlockChain;
3637 }
3638 
3639 static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
3640 {
3641   StorageInternalImpl* This = (StorageInternalImpl*) iface;
3642 
3643   StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);
3644   HeapFree(GetProcessHeap(), 0, This);
3645 }
3646 
3647 /******************************************************************************
3648 **
3649 ** Storage32InternalImpl_Commit
3650 **
3651 ** The non-root storages cannot be opened in transacted mode thus this function
3652 ** does nothing.
3653 */
3654 static HRESULT WINAPI StorageInternalImpl_Commit(
3655   IStorage*            iface,
3656   DWORD                  grfCommitFlags)  /* [in] */
3657 {
3658   return S_OK;
3659 }
3660 
3661 /******************************************************************************
3662 **
3663 ** Storage32InternalImpl_Revert
3664 **
3665 ** The non-root storages cannot be opened in transacted mode thus this function
3666 ** does nothing.
3667 */
3668 static HRESULT WINAPI StorageInternalImpl_Revert(
3669   IStorage*            iface)
3670 {
3671   return S_OK;
3672 }
3673 
3674 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3675 {
3676   IStorage_Release((IStorage*)This->parentStorage);
3677   HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3678   HeapFree(GetProcessHeap(), 0, This);
3679 }
3680 
3681 static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3682   IEnumSTATSTG*     iface,
3683   REFIID            riid,
3684   void**            ppvObject)
3685 {
3686   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3687 
3688   /*
3689    * Perform a sanity check on the parameters.
3690    */
3691   if (ppvObject==0)
3692     return E_INVALIDARG;
3693 
3694   /*
3695    * Initialize the return parameter.
3696    */
3697   *ppvObject = 0;
3698 
3699   /*
3700    * Compare the riid with the interface IDs implemented by this object.
3701    */
3702   if (IsEqualGUID(&IID_IUnknown, riid) ||
3703       IsEqualGUID(&IID_IEnumSTATSTG, riid))
3704   {
3705     *ppvObject = (IEnumSTATSTG*)This;
3706     IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
3707     return S_OK;
3708   }
3709 
3710   return E_NOINTERFACE;
3711 }
3712 
3713 static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
3714   IEnumSTATSTG* iface)
3715 {
3716   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3717   return InterlockedIncrement(&This->ref);
3718 }
3719 
3720 static ULONG   WINAPI IEnumSTATSTGImpl_Release(
3721   IEnumSTATSTG* iface)
3722 {
3723   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3724 
3725   ULONG newRef;
3726 
3727   newRef = InterlockedDecrement(&This->ref);
3728 
3729   /*
3730    * If the reference count goes down to 0, perform suicide.
3731    */
3732   if (newRef==0)
3733   {
3734     IEnumSTATSTGImpl_Destroy(This);
3735   }
3736 
3737   return newRef;
3738 }
3739 
3740 static HRESULT WINAPI IEnumSTATSTGImpl_Next(
3741   IEnumSTATSTG* iface,
3742   ULONG             celt,
3743   STATSTG*          rgelt,
3744   ULONG*            pceltFetched)
3745 {
3746   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3747 
3748   StgProperty currentProperty;
3749   STATSTG*    currentReturnStruct = rgelt;
3750   ULONG       objectFetched       = 0;
3751   ULONG      currentSearchNode;
3752 
3753   /*
3754    * Perform a sanity check on the parameters.
3755    */
3756   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3757     return E_INVALIDARG;
3758 
3759   /*
3760    * To avoid the special case, get another pointer to a ULONG value if
3761    * the caller didn't supply one.
3762    */
3763   if (pceltFetched==0)
3764     pceltFetched = &objectFetched;
3765 
3766   /*
3767    * Start the iteration, we will iterate until we hit the end of the
3768    * linked list or until we hit the number of items to iterate through
3769    */
3770   *pceltFetched = 0;
3771 
3772   /*
3773    * Start with the node at the top of the stack.
3774    */
3775   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3776 
3777   while ( ( *pceltFetched < celt) &&
3778           ( currentSearchNode!=PROPERTY_NULL) )
3779   {
3780     /*
3781      * Remove the top node from the stack
3782      */
3783