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

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

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